Gaurav vashistha commited on
Commit
683cf64
·
1 Parent(s): 3598ffe

Fix Veo generation loop with op.result()

Browse files
Files changed (1) hide show
  1. agent.py +28 -25
agent.py CHANGED
@@ -8,9 +8,8 @@ from google import genai
8
  from google.genai import types
9
  from config import Settings
10
  from utils import download_to_temp, download_blob, save_video_bytes, update_job_status, stitch_videos
11
-
12
  logging.basicConfig(level=logging.INFO)
13
- logger = logging.getLogger(__name__)
14
 
15
  def get_file_hash(filepath):
16
  """Calculates MD5 hash of file to prevent duplicate uploads."""
@@ -52,7 +51,7 @@ def analyze_only(path_a, path_c, job_id=None):
52
  {
53
  "analysis_a": "Brief description of Video A",
54
  "analysis_c": "Brief description of Video C",
55
- "visual_prompt_b": "A surreal, seamless morphing prompt that transforms A into C. DO NOT use words like 'dissolve' or 'cut'."
56
  }
57
  """
58
  update_job_status(job_id, "analyzing", 30, "Director drafting creative morph...")
@@ -87,27 +86,32 @@ def analyze_only(path_a, path_c, job_id=None):
87
  def generate_only(prompt, path_a, path_c, job_id, style, audio, neg, guidance, motion):
88
  update_job_status(job_id, "generating", 50, "Production started (Veo 3.1)...")
89
  full_prompt = f"{style} style. {prompt} Soundtrack: {audio}"
90
- if neg:
91
- full_prompt += f" --no {neg}"
92
 
93
  job_failed = False
94
  try:
95
  if Settings.GCP_PROJECT_ID:
96
  client = genai.Client(vertexai=True, project=Settings.GCP_PROJECT_ID, location=Settings.GCP_LOCATION)
 
 
97
  op = client.models.generate_videos(
98
  model='veo-3.1-generate-preview',
99
  prompt=full_prompt,
100
  config=types.GenerateVideosConfig(number_of_videos=1)
101
  )
102
 
103
- # Wait loop
104
- while not op.done: time.sleep(5)
 
 
 
 
 
105
 
106
- if op.result and op.result.generated_videos:
107
- vid = op.result.generated_videos[0]
108
  bridge_path = None
109
 
110
- # Handle Video Download
111
  if vid.video.uri:
112
  bridge_path = tempfile.mktemp(suffix=".mp4")
113
  download_blob(vid.video.uri, bridge_path)
@@ -115,33 +119,32 @@ def generate_only(prompt, path_a, path_c, job_id, style, audio, neg, guidance, m
115
  bridge_path = save_video_bytes(vid.video.video_bytes)
116
 
117
  if bridge_path:
118
- # --- STITCHING PHASE ---
119
- update_job_status(job_id, "stitching", 80, "Stitching Director's Cut...", video_url=bridge_path)
120
- final_cut_path = os.path.join("outputs", f"{job_id}_merged_temp.mp4")
 
 
121
 
122
- try:
123
- # Attempt the new robust stitch
124
- final_output = stitch_videos(path_a, bridge_path, path_c, final_cut_path)
125
- # If successful, return BOTH urls
126
- update_job_status(job_id, "completed", 100, "Done!", video_url=bridge_path, merged_video_url=final_output)
127
- except Exception as e:
128
- # If stitch fails, log it and return ONLY the bridge.
129
- # DO NOT FAIL THE JOB.
130
- logging.error(f"Stitch failed, returning bridge only: {e}")
131
- update_job_status(job_id, "completed", 100, "Stitch failed (Bridge Saved).", video_url=bridge_path)
132
  return
133
  else:
134
  raise Exception("Veo returned no videos.")
135
  else:
136
  raise Exception("GCP_PROJECT_ID not set.")
137
  except Exception as e:
138
- logging.error(f"Gen Fail: {e}")
139
  update_job_status(job_id, "error", 0, f"Error: {e}")
140
  job_failed = True
141
  finally:
 
142
  if not job_failed:
143
  try:
144
  with open(f"outputs/{job_id}.json", "r") as f:
145
  if json.load(f).get("status") not in ["completed", "error"]:
146
- update_job_status(job_id, "error", 0, "Zombie Job Terminated")
147
  except: pass
 
8
  from google.genai import types
9
  from config import Settings
10
  from utils import download_to_temp, download_blob, save_video_bytes, update_job_status, stitch_videos
 
11
  logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(name)
13
 
14
  def get_file_hash(filepath):
15
  """Calculates MD5 hash of file to prevent duplicate uploads."""
 
51
  {
52
  "analysis_a": "Brief description of Video A",
53
  "analysis_c": "Brief description of Video C",
54
+ "visual_prompt_b": "A surreal, seamless morphing prompt that transforms A into C. DO NOT use words like 'dissolve' or 'cut'. Focus on shape and texture transformation."
55
  }
56
  """
57
  update_job_status(job_id, "analyzing", 30, "Director drafting creative morph...")
 
86
  def generate_only(prompt, path_a, path_c, job_id, style, audio, neg, guidance, motion):
87
  update_job_status(job_id, "generating", 50, "Production started (Veo 3.1)...")
88
  full_prompt = f"{style} style. {prompt} Soundtrack: {audio}"
89
+ if neg: full_prompt += f" --no {neg}"
 
90
 
91
  job_failed = False
92
  try:
93
  if Settings.GCP_PROJECT_ID:
94
  client = genai.Client(vertexai=True, project=Settings.GCP_PROJECT_ID, location=Settings.GCP_LOCATION)
95
+
96
+ # 1. Start Long-Running Operation
97
  op = client.models.generate_videos(
98
  model='veo-3.1-generate-preview',
99
  prompt=full_prompt,
100
  config=types.GenerateVideosConfig(number_of_videos=1)
101
  )
102
 
103
+ # 2. CRITICAL FIX: Use .result() to wait.
104
+ # 'while not op.done' causes infinite loops if op doesn't auto-refresh.
105
+ if hasattr(op, 'result'):
106
+ result = op.result()
107
+ else:
108
+ # Fallback for synchronous responses
109
+ result = op
110
 
111
+ if result and result.generated_videos:
112
+ vid = result.generated_videos[0]
113
  bridge_path = None
114
 
 
115
  if vid.video.uri:
116
  bridge_path = tempfile.mktemp(suffix=".mp4")
117
  download_blob(vid.video.uri, bridge_path)
 
119
  bridge_path = save_video_bytes(vid.video.video_bytes)
120
 
121
  if bridge_path:
122
+ # 3. Stitching Phase (Optional/Bypassable)
123
+ update_job_status(job_id, "stitching", 80, "Checking Stitch Capability...", video_url=bridge_path)
124
+
125
+ final_cut = os.path.join("outputs", f"{job_id}_merged_temp.mp4")
126
+ merged_path = stitch_videos(path_a, bridge_path, path_c, final_cut)
127
 
128
+ if merged_path:
129
+ msg = "Done! (Merged)"
130
+ else:
131
+ msg = "Done! (Bridge Only - No Stitch)"
132
+
133
+ update_job_status(job_id, "completed", 100, msg, video_url=bridge_path, merged_video_url=merged_path)
 
 
 
 
134
  return
135
  else:
136
  raise Exception("Veo returned no videos.")
137
  else:
138
  raise Exception("GCP_PROJECT_ID not set.")
139
  except Exception as e:
140
+ logging.error(f"Gen Job Failed: {e}")
141
  update_job_status(job_id, "error", 0, f"Error: {e}")
142
  job_failed = True
143
  finally:
144
+ # 4. DEAD MAN'S SWITCH
145
  if not job_failed:
146
  try:
147
  with open(f"outputs/{job_id}.json", "r") as f:
148
  if json.load(f).get("status") not in ["completed", "error"]:
149
+ update_job_status(job_id, "error", 0, "Job timed out (Zombie).")
150
  except: pass