|
|
|
|
|
import os |
|
import gradio as gr |
|
import requests |
|
import json |
|
import time |
|
import base64 |
|
import google.auth |
|
import google.auth.transport.requests |
|
from huggingface_hub import login |
|
|
|
|
|
GCP_PROJECT_ID = os.environ.get("GCP_PROJECT_ID") |
|
GCP_LOCATION = os.environ.get("GCP_LOCATION") |
|
|
|
|
|
hf_token = os.environ.get("HF_TOKEN") |
|
if hf_token: |
|
print("Hugging Face token found. Logging in.") |
|
login(token=hf_token) |
|
else: |
|
print("WARNING: Hugging Face token ('HF_TOKEN') not found.") |
|
|
|
creds_json_str = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS_JSON") |
|
|
|
if not all([GCP_PROJECT_ID, GCP_LOCATION, creds_json_str]): |
|
missing_secrets = [s for s, v in {"GCP_PROJECT_ID": GCP_PROJECT_ID, "GCP_LOCATION": GCP_LOCATION, "GOOGLE_APPLICATION_CREDENTIALS_JSON": creds_json_str}.items() if not v] |
|
error_message = f"FATAL: Missing required secrets: {', '.join(missing_secrets)}." |
|
print(error_message) |
|
|
|
raise RuntimeError(error_message) |
|
|
|
print("All required secrets are loaded. Initializing API service.") |
|
MODEL_ID = "veo-3.0-generate-preview" |
|
API_ENDPOINT = f"{GCP_LOCATION}-aiplatform.googleapis.com" |
|
PREDICT_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:predictLongRunning" |
|
FETCH_URL = f"https://{API_ENDPOINT}/v1/projects/{GCP_PROJECT_ID}/locations/{GCP_LOCATION}/publishers/google/models/{MODEL_ID}:fetchPredictOperation" |
|
|
|
with open("gcp_creds.json", "w") as f: f.write(creds_json_str) |
|
SCOPES = ["https://www.googleapis.com/auth/cloud-platform"] |
|
credentials, _ = google.auth.load_credentials_from_file("gcp_creds.json", scopes=SCOPES) |
|
|
|
def get_access_token(): |
|
auth_req = google.auth.transport.requests.Request() |
|
credentials.refresh(auth_req) |
|
return credentials.token |
|
|
|
|
|
|
|
def generate_video_api(prompt: str): |
|
if not prompt: |
|
return {"status": "error", "message": "Prompt cannot be empty."} |
|
|
|
try: |
|
headers = {"Authorization": f"Bearer {get_access_token()}", "Content-Type": "application/json"} |
|
payload = {"instances": [{"prompt": prompt}], "parameters": {"aspectRatio": "16:9", "sampleCount": 1, "durationSeconds": 8, "personGeneration": "allow_all", "addWatermark": True, "includeRaiReason": True, "generateAudio": True}} |
|
|
|
|
|
response = requests.post(PREDICT_URL, headers=headers, json=payload) |
|
response.raise_for_status() |
|
operation_name = response.json()["name"] |
|
print(f"Successfully submitted job. Operation Name: {operation_name}") |
|
|
|
|
|
MAX_POLL_ATTEMPTS = 60 |
|
for i in range(MAX_POLL_ATTEMPTS): |
|
print(f"Polling (Attempt {i+1}/{MAX_POLL_ATTEMPTS})...") |
|
time.sleep(10) |
|
|
|
headers["Authorization"] = f"Bearer {get_access_token()}" |
|
fetch_payload = {"operationName": operation_name} |
|
poll_response = requests.post(FETCH_URL, headers=headers, json=fetch_payload) |
|
poll_response.raise_for_status() |
|
poll_result = poll_response.json() |
|
|
|
if poll_result.get("done"): |
|
print("Job finished.") |
|
response_data = poll_result.get("response", {}) |
|
|
|
|
|
if "videos" in response_data and response_data["videos"]: |
|
video_base64 = response_data["videos"][0]["bytesBase64Encoded"] |
|
return {"status": "success", "video_base64": video_base64} |
|
|
|
|
|
error_message = "Video generation failed." |
|
if "error" in poll_result: |
|
error_details = poll_result["error"].get("message", "No details provided.") |
|
error_message += f" API Error: {error_details}" |
|
elif "raiResult" in response_data: |
|
rai_reason = response_data.get("raiMediaFilteredReason", "Unknown reason.") |
|
error_message += f" Content was blocked by safety filters ({rai_reason})." |
|
else: |
|
error_message += " The API did not return a video or a specific error." |
|
|
|
return {"status": "error", "message": error_message} |
|
|
|
return {"status": "error", "message": "Operation timed out."} |
|
|
|
except requests.exceptions.HTTPError as e: |
|
print(f"HTTP Error: {e.response.text}") |
|
return {"status": "error", "message": f"API Error: {e.response.status_code}. Details: {e.response.text}"} |
|
except Exception as e: |
|
print(f"An unexpected error occurred: {e}") |
|
return {"status": "error", "message": f"An unexpected error occurred: {str(e)}"} |
|
|
|
|
|
|
|
with gr.Blocks() as demo: |
|
|
|
prompt_input = gr.Textbox(label="prompt", visible=False) |
|
output_json = gr.JSON(label="result", visible=False) |
|
|
|
|
|
|
|
gr.Interface( |
|
fn=generate_video_api, |
|
inputs=prompt_input, |
|
outputs=output_json, |
|
api_name="predict" |
|
) |
|
|
|
|
|
demo.launch() |