Deadmon commited on
Commit
987e891
·
verified ·
1 Parent(s): 7e0cee7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -63
app.py CHANGED
@@ -12,16 +12,13 @@ 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" # Make sure this is replaced!
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
27
  hf_token = os.environ.get("HF_TOKEN")
@@ -33,26 +30,42 @@ else:
33
 
34
  # Part B: Google Cloud Authentication
35
  creds_json_str = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS_JSON")
36
- if not creds_json_str:
37
- print("FATAL: 'GOOGLE_APPLICATION_CREDENTIALS_JSON' secret not found. App cannot authenticate with Google Cloud.")
 
 
 
 
 
 
 
 
 
 
38
  def generate_video(prompt):
39
- raise gr.Error("Authentication failed. Server is missing Google Cloud credentials. Please check the Hugging Face Space secrets.")
40
  else:
 
 
 
 
 
 
 
 
 
41
  with open("gcp_creds.json", "w") as f:
42
  f.write(creds_json_str)
43
 
44
  SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
45
  credentials, _ = google.auth.load_credentials_from_file("gcp_creds.json", scopes=SCOPES)
46
- print("GCP credentials loaded successfully.")
47
-
48
 
49
  def get_access_token():
50
  auth_req = google.auth.transport.requests.Request()
51
  credentials.refresh(auth_req)
52
  return credentials.token
53
 
54
- # --- 2. Core Video Generation Logic (WITH FINAL FIX) ---
55
-
56
  def generate_video(prompt: str):
57
  if not prompt:
58
  raise gr.Error("Prompt cannot be empty.")
@@ -65,7 +78,6 @@ else:
65
  "Authorization": f"Bearer {access_token}",
66
  "Content-Type": "application/json",
67
  }
68
-
69
  payload = {
70
  "instances": [{"prompt": prompt}],
71
  "parameters": {
@@ -74,92 +86,55 @@ else:
74
  "includeRaiReason": True, "generateAudio": True,
75
  }
76
  }
77
-
78
  response = requests.post(PREDICT_URL, headers=headers, json=payload)
79
  response.raise_for_status()
80
-
81
  operation_name = response.json()["name"]
82
  print(f"Successfully submitted job. Operation Name: {operation_name}")
83
 
84
  MAX_POLL_ATTEMPTS = 60
85
  for i in range(MAX_POLL_ATTEMPTS):
86
- status_message = f"Status: Job submitted. Polling for result (Attempt {i+1}/{MAX_POLL_ATTEMPTS})... Please wait."
87
- yield status_message, None
88
-
89
  access_token = get_access_token()
90
  headers["Authorization"] = f"Bearer {access_token}"
91
-
92
  fetch_payload = {"operationName": operation_name}
93
  poll_response = requests.post(FETCH_URL, headers=headers, json=fetch_payload)
94
  poll_response.raise_for_status()
95
-
96
  poll_result = poll_response.json()
97
 
98
  if poll_result.get("done"):
99
  print("Job finished successfully.")
100
- print(f"Full successful response payload: {json.dumps(poll_result, indent=2)}")
101
-
102
  response_data = poll_result.get("response", {})
103
-
104
- # <<< FIX: Changed "predictions" to "videos" to match the actual API response >>>
105
  if "videos" in response_data and response_data["videos"]:
106
  video_base64 = response_data["videos"][0]["bytesBase64Encoded"]
107
  video_bytes = base64.b64decode(video_base64)
108
-
109
  temp_video_path = "generated_video.mp4"
110
  with open(temp_video_path, "wb") as f:
111
  f.write(video_bytes)
112
-
113
- yield "Status: Done! Video generated successfully.", temp_video_path
114
  return
115
  else:
116
- error_message = "Video generation finished, but the content was blocked by safety filters or another issue prevented video creation."
117
- print(f"ERROR: {error_message}")
118
- raise gr.Error(error_message)
119
-
120
  time.sleep(10)
121
-
122
- raise gr.Error("Operation timed out after several minutes.")
123
-
124
- except requests.exceptions.HTTPError as e:
125
- print(f"HTTP Error: {e.response.text}")
126
- raise gr.Error(f"API Error: {e.response.status_code}. Details: {e.response.text}")
127
  except Exception as e:
128
- print(f"An error occurred in the generation process: {e}")
129
  raise gr.Error(str(e))
130
 
131
-
132
- # --- 3. Gradio User Interface (Unchanged) ---
133
-
134
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
135
  gr.Markdown("# 🎬 Vertex AI VEO Video Generator")
136
- gr.Markdown(
137
- "Generate short videos from a text prompt using Google's VEO model. "
138
- "Generation can take several minutes. Please be patient."
139
- )
140
-
141
  with gr.Row():
142
  with gr.Column(scale=1):
143
- prompt_input = gr.Textbox(
144
- label="Prompt",
145
- placeholder="A majestic lion roaming the savanna at sunrise, cinematic 4K.",
146
- lines=3
147
- )
148
  submit_button = gr.Button("Generate Video", variant="primary")
149
-
150
  with gr.Column(scale=1):
151
  status_output = gr.Markdown("Status: Ready")
152
  video_output = gr.Video(label="Generated Video", interactive=False)
153
-
154
  gr.Examples(
155
- examples=[
156
- "A high-speed drone shot flying through a futuristic city with flying vehicles.",
157
- "A raccoon happily eating popcorn in a movie theater, cinematic lighting.",
158
- "A beautiful time-lapse of a flower blooming, from bud to full blossom, ultra-realistic.",
159
- ],
160
  inputs=prompt_input,
161
  )
162
-
163
  submit_button.click(
164
  fn=generate_video,
165
  inputs=prompt_input,
 
12
 
13
  # --- 1. Configuration and Authentication ---
14
 
15
+ # <<< START: CODE UPDATE >>>
16
+ # Load configuration from Hugging Face Secrets instead of hardcoding.
17
+ GCP_PROJECT_ID = os.environ.get("GCP_PROJECT_ID")
18
+ GCP_LOCATION = os.environ.get("GCP_LOCATION")
19
+ # <<< END: CODE UPDATE >>>
 
 
20
 
21
+ # --- Authentication and Sanity Checks Block ---
 
22
 
23
  # Part A: Hugging Face Hub Authentication
24
  hf_token = os.environ.get("HF_TOKEN")
 
30
 
31
  # Part B: Google Cloud Authentication
32
  creds_json_str = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS_JSON")
33
+
34
+ # Check if all necessary secrets are loaded
35
+ if not all([GCP_PROJECT_ID, GCP_LOCATION, creds_json_str]):
36
+ # This block runs if any of the crucial secrets are missing.
37
+ missing_secrets = []
38
+ if not GCP_PROJECT_ID: missing_secrets.append("GCP_PROJECT_ID")
39
+ if not GCP_LOCATION: missing_secrets.append("GCP_LOCATION")
40
+ if not creds_json_str: missing_secrets.append("GOOGLE_APPLICATION_CREDENTIALS_JSON")
41
+
42
+ error_message = f"FATAL: The following required secrets are missing: {', '.join(missing_secrets)}. Please set them in the Space settings."
43
+ print(error_message)
44
+ # Define a dummy function to show a clear error in the UI.
45
  def generate_video(prompt):
46
+ raise gr.Error(error_message)
47
  else:
48
+ # This block runs only if all secrets are present.
49
+ print("All required secrets (GCP Project, Location, Credentials, HF Token) are loaded.")
50
+
51
+ # Construct API URLs now that we have the project and location
52
+ MODEL_ID = "veo-3.0-generate-preview"
53
+ API_ENDPOINT = f"{GCP_LOCATION}-aiplatform.googleapis.com"
54
+ PREDICT_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:predictLongRunning"
55
+ FETCH_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:fetchPredictOperation"
56
+
57
  with open("gcp_creds.json", "w") as f:
58
  f.write(creds_json_str)
59
 
60
  SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
61
  credentials, _ = google.auth.load_credentials_from_file("gcp_creds.json", scopes=SCOPES)
 
 
62
 
63
  def get_access_token():
64
  auth_req = google.auth.transport.requests.Request()
65
  credentials.refresh(auth_req)
66
  return credentials.token
67
 
68
+ # --- 2. Core Video Generation Logic ---
 
69
  def generate_video(prompt: str):
70
  if not prompt:
71
  raise gr.Error("Prompt cannot be empty.")
 
78
  "Authorization": f"Bearer {access_token}",
79
  "Content-Type": "application/json",
80
  }
 
81
  payload = {
82
  "instances": [{"prompt": prompt}],
83
  "parameters": {
 
86
  "includeRaiReason": True, "generateAudio": True,
87
  }
88
  }
 
89
  response = requests.post(PREDICT_URL, headers=headers, json=payload)
90
  response.raise_for_status()
 
91
  operation_name = response.json()["name"]
92
  print(f"Successfully submitted job. Operation Name: {operation_name}")
93
 
94
  MAX_POLL_ATTEMPTS = 60
95
  for i in range(MAX_POLL_ATTEMPTS):
96
+ yield f"Status: Polling for result (Attempt {i+1}/{MAX_POLL_ATTEMPTS})...", None
 
 
97
  access_token = get_access_token()
98
  headers["Authorization"] = f"Bearer {access_token}"
 
99
  fetch_payload = {"operationName": operation_name}
100
  poll_response = requests.post(FETCH_URL, headers=headers, json=fetch_payload)
101
  poll_response.raise_for_status()
 
102
  poll_result = poll_response.json()
103
 
104
  if poll_result.get("done"):
105
  print("Job finished successfully.")
 
 
106
  response_data = poll_result.get("response", {})
 
 
107
  if "videos" in response_data and response_data["videos"]:
108
  video_base64 = response_data["videos"][0]["bytesBase64Encoded"]
109
  video_bytes = base64.b64decode(video_base64)
 
110
  temp_video_path = "generated_video.mp4"
111
  with open(temp_video_path, "wb") as f:
112
  f.write(video_bytes)
113
+ yield "Status: Done! Video generated.", temp_video_path
 
114
  return
115
  else:
116
+ raise gr.Error("Video generation finished, but content was blocked or another issue occurred.")
 
 
 
117
  time.sleep(10)
118
+ raise gr.Error("Operation timed out.")
 
 
 
 
 
119
  except Exception as e:
120
+ print(f"An error occurred: {e}")
121
  raise gr.Error(str(e))
122
 
123
+ # --- 3. Gradio User Interface ---
 
 
124
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
125
  gr.Markdown("# 🎬 Vertex AI VEO Video Generator")
126
+ gr.Markdown("Generate short videos from a text prompt using Google's VEO model.")
 
 
 
 
127
  with gr.Row():
128
  with gr.Column(scale=1):
129
+ prompt_input = gr.Textbox(label="Prompt", placeholder="A majestic lion...", lines=3)
 
 
 
 
130
  submit_button = gr.Button("Generate Video", variant="primary")
 
131
  with gr.Column(scale=1):
132
  status_output = gr.Markdown("Status: Ready")
133
  video_output = gr.Video(label="Generated Video", interactive=False)
 
134
  gr.Examples(
135
+ ["A high-speed drone shot flying through a futuristic city with flying vehicles."],
 
 
 
 
136
  inputs=prompt_input,
137
  )
 
138
  submit_button.click(
139
  fn=generate_video,
140
  inputs=prompt_input,