Deadmon commited on
Commit
c1c563f
·
verified ·
1 Parent(s): 5ba7367

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +173 -0
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
+ import os
4
+ import gradio as gr
5
+ import requests
6
+ import json
7
+ import time
8
+ import base64
9
+ import google.auth
10
+ import google.auth.transport.requests
11
+ from huggingface_hub import login
12
+
13
+ # --- 1. Configuration and Authentication ---
14
+
15
+ # IMPORTANT: Replace with your Google Cloud Project ID
16
+ GCP_PROJECT_ID = "gen-lang-client-0193353123"
17
+ GCP_LOCATION = "us-central1"
18
+ MODEL_ID = "veo-3.0-generate-preview"
19
+ API_ENDPOINT = f"{GCP_LOCATION}-aiplatform.googleapis.com"
20
+ PREDICT_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:predictLongRunning"
21
+ FETCH_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:fetchPredictOperation"
22
+
23
+
24
+ # --- Authentication Block ---
25
+
26
+ # Part A: Hugging Face Hub Authentication (NEW)
27
+ # This section looks for a secret named 'HF_TOKEN' to log into the Hub.
28
+ hf_token = os.environ.get("HF_TOKEN")
29
+ if hf_token:
30
+ print("Hugging Face token found. Logging in.")
31
+ login(token=hf_token)
32
+ else:
33
+ print("WARNING: Hugging Face token ('HF_TOKEN') not found. Hub-related features may be disabled.")
34
+
35
+
36
+ # Part B: Google Cloud Authentication (Unchanged)
37
+ # This section expects a secret named 'GOOGLE_APPLICATION_CREDENTIALS_JSON'
38
+ creds_json_str = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS_JSON")
39
+ if not creds_json_str:
40
+ print("FATAL: 'GOOGLE_APPLICATION_CREDENTIALS_JSON' secret not found. App cannot authenticate with Google Cloud.")
41
+ # Define a dummy function to show an error in the UI
42
+ def generate_video(prompt):
43
+ raise gr.Error("Authentication failed. Server is missing Google Cloud credentials. Please check the Hugging Face Space secrets.")
44
+ else:
45
+ with open("gcp_creds.json", "w") as f:
46
+ f.write(creds_json_str)
47
+
48
+ SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
49
+ credentials, _ = google.auth.load_credentials_from_file("gcp_creds.json", scopes=SCOPES)
50
+ print("GCP credentials loaded successfully.")
51
+
52
+
53
+ def get_access_token():
54
+ """Generates a fresh short-lived access token for Google Cloud."""
55
+ auth_req = google.auth.transport.requests.Request()
56
+ credentials.refresh(auth_req)
57
+ return credentials.token
58
+
59
+ # --- 2. Core Video Generation Logic (Unchanged) ---
60
+
61
+ def generate_video(prompt: str):
62
+ """
63
+ The main function to generate a video. It submits, polls, and returns the result.
64
+ """
65
+ if not prompt:
66
+ raise gr.Error("Prompt cannot be empty.")
67
+
68
+ yield "Status: Authenticating and submitting job...", None
69
+
70
+ try:
71
+ access_token = get_access_token()
72
+ headers = {
73
+ "Authorization": f"Bearer {access_token}",
74
+ "Content-Type": "application/json",
75
+ }
76
+
77
+ # --- Step A: Submit the long-running prediction job ---
78
+ payload = {
79
+ "instances": [{"prompt": prompt}],
80
+ "parameters": {
81
+ "aspectRatio": "16:9",
82
+ "sampleCount": 1,
83
+ "durationSeconds": 8,
84
+ "personGeneration": "allow_all",
85
+ "addWatermark": True,
86
+ "includeRaiReason": True,
87
+ "generateAudio": True,
88
+ }
89
+ }
90
+
91
+ response = requests.post(PREDICT_URL, headers=headers, json=payload)
92
+ response.raise_for_status()
93
+
94
+ operation_name = response.json()["name"]
95
+ print(f"Successfully submitted job. Operation Name: {operation_name}")
96
+
97
+ # --- Step B: Poll for the result ---
98
+ MAX_POLL_ATTEMPTS = 60
99
+ for i in range(MAX_POLL_ATTEMPTS):
100
+ status_message = f"Status: Job submitted. Polling for result (Attempt {i+1}/{MAX_POLL_ATTEMPTS})... Please wait."
101
+ yield status_message, None
102
+
103
+ access_token = get_access_token()
104
+ headers["Authorization"] = f"Bearer {access_token}"
105
+
106
+ fetch_payload = {"operationName": operation_name}
107
+ poll_response = requests.post(FETCH_URL, headers=headers, json=fetch_payload)
108
+ poll_response.raise_for_status()
109
+
110
+ poll_result = poll_response.json()
111
+
112
+ if poll_result.get("done"):
113
+ print("Job finished successfully.")
114
+ video_base64 = poll_result["response"]["predictions"][0]["bytesBase64Encoded"]
115
+ video_bytes = base64.b64decode(video_base64)
116
+
117
+ temp_video_path = "generated_video.mp4"
118
+ with open(temp_video_path, "wb") as f:
119
+ f.write(video_bytes)
120
+
121
+ yield "Status: Done!", temp_video_path
122
+ return
123
+
124
+ time.sleep(10)
125
+
126
+ raise gr.Error("Operation timed out after several minutes. The job may have failed or is taking too long.")
127
+
128
+ except requests.exceptions.HTTPError as e:
129
+ print(f"HTTP Error: {e.response.text}")
130
+ raise gr.Error(f"API Error: {e.response.status_code}. Details: {e.response.text}")
131
+ except Exception as e:
132
+ print(f"An unexpected error occurred: {e}")
133
+ raise gr.Error(f"An unexpected error occurred: {str(e)}")
134
+
135
+
136
+ # --- 3. Gradio User Interface (Unchanged) ---
137
+
138
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
139
+ gr.Markdown("# 🎬 Vertex AI VEO Video Generator")
140
+ gr.Markdown(
141
+ "Generate short videos from a text prompt using Google's VEO model. "
142
+ "Generation can take several minutes. Please be patient."
143
+ )
144
+
145
+ with gr.Row():
146
+ with gr.Column(scale=1):
147
+ prompt_input = gr.Textbox(
148
+ label="Prompt",
149
+ placeholder="A majestic lion roaming the savanna at sunrise, cinematic 4K.",
150
+ lines=3
151
+ )
152
+ submit_button = gr.Button("Generate Video", variant="primary")
153
+
154
+ with gr.Column(scale=1):
155
+ status_output = gr.Markdown("Status: Ready")
156
+ video_output = gr.Video(label="Generated Video", interactive=False)
157
+
158
+ gr.Examples(
159
+ examples=[
160
+ "A high-speed drone shot flying through a futuristic city with flying vehicles.",
161
+ "A raccoon happily eating popcorn in a movie theater, cinematic lighting.",
162
+ "A beautiful time-lapse of a flower blooming, from bud to full blossom, ultra-realistic.",
163
+ ],
164
+ inputs=prompt_input,
165
+ )
166
+
167
+ submit_button.click(
168
+ fn=generate_video,
169
+ inputs=prompt_input,
170
+ outputs=[status_output, video_output]
171
+ )
172
+
173
+ demo.launch()