jebin2 commited on
Commit
3a1dbcc
Β·
1 Parent(s): 1a31454

Refactor: Move Gemini SDK, centralize GCS utils, optimize downloads

Browse files
src/a2e_avatar.py CHANGED
@@ -9,7 +9,7 @@ from dataclasses import dataclass
9
  from enum import Enum
10
  import os
11
  from utils import logger
12
- import gemini_sdk
13
  import json_repair
14
  from data_holder import DataHolder
15
  from moviepy.editor import AudioFileClip
@@ -369,7 +369,7 @@ Image Prompt: {image_prompt}
369
  Available Voices: {available_voices}
370
  Available Avatars with Usage Count: {available_avatar}
371
  """
372
- response = gemini_sdk.generate(model_input)
373
 
374
  response_text = response.strip()
375
 
 
9
  from enum import Enum
10
  import os
11
  from utils import logger
12
+ from google_src import ai_studio_sdk
13
  import json_repair
14
  from data_holder import DataHolder
15
  from moviepy.editor import AudioFileClip
 
369
  Available Voices: {available_voices}
370
  Available Avatars with Usage Count: {available_avatar}
371
  """
372
+ response = ai_studio_sdk.generate(model_input)
373
 
374
  response_text = response.strip()
375
 
src/api_clients.py CHANGED
@@ -23,12 +23,13 @@ from google.cloud import storage, texttospeech
23
  import asyncio
24
  from utils import logger
25
  from data_holder import DataHolder
 
26
 
27
 
28
  # --- NEW IMPORTS ---
29
  from google.oauth2 import service_account
30
  import vertexai
31
- from google_src.gcs_utils import get_gcs_client, get_gcs_credentials, upload_file_to_gcs, list_gcs_files
32
  from google_src.setup_gcs_permissions import setup_bucket_permissions
33
 
34
  # --------------------
@@ -36,7 +37,7 @@ from google_src.setup_gcs_permissions import setup_bucket_permissions
36
  import base64
37
  from pathlib import Path
38
 
39
- import gemini_sdk
40
  import uuid
41
 
42
  class APIClients:
@@ -53,7 +54,7 @@ class APIClients:
53
  self.gcs_bucket = self.gcs_client.bucket(gcs_bucket_name)
54
 
55
  # Create main bucket if it doesn't exist
56
- self.create_bucket_if_not_exists(self.gcs_client, gcs_bucket_name)
57
 
58
  # Apply permissions to the main bucket
59
  try:
@@ -100,36 +101,6 @@ class APIClients:
100
  await self.store_in_cache(file_path, f"{method_type}_{duration}", ".txt")
101
  except: pass
102
 
103
- def _fallback_timed_transcript(self, audio_file_path: str) -> List[Dict]:
104
- """Fallback transcript generation when Speech-to-Text fails"""
105
- try:
106
- from mutagen.mp3 import MP3
107
-
108
- audio = MP3(audio_file_path)
109
- duration = audio.info.length
110
-
111
- # Simple word splitting with estimated timing
112
- import tempfile
113
-
114
- temp_script = "This is a fallback transcript with estimated timing."
115
- words = temp_script.split()
116
- word_duration = duration / len(words)
117
-
118
- return [
119
- {"word": word, "start_time": i * word_duration, "end_time": (i + 1) * word_duration, "confidence": 0.8}
120
- for i, word in enumerate(words)
121
- ]
122
- except:
123
- return []
124
-
125
- def _format_srt_time(self, seconds: float) -> str:
126
- """Convert seconds to SRT time format"""
127
- hours = int(seconds // 3600)
128
- minutes = int((seconds % 3600) // 60)
129
- secs = seconds % 60
130
- milliseconds = int((secs - int(secs)) * 1000)
131
- return f"{hours:02d}:{minutes:02d}:{int(secs):02d},{milliseconds:03d}"
132
-
133
  async def generate_image(self, prompt: str) -> Optional[str]:
134
  """
135
  Generate image using Vertex AI Imagen 4 Ultra
@@ -149,7 +120,7 @@ class APIClients:
149
  return url
150
 
151
  logger.info(f"🎨 Generating image with Imagen 4 Ultra: {prompt[:200]}...")
152
- image_path = gemini_sdk.generate_image(prompt)
153
  if image_path:
154
  await self.store_in_cache(image_path, "generate_image", ".jpg")
155
  return image_path
@@ -200,34 +171,6 @@ class APIClients:
200
  logger.error(f"❌ Imagen 4 Ultra generation failed: {e}")
201
  raise
202
 
203
- async def generate_captions(self) -> str:
204
- """Auto-generate captions from TTS script"""
205
- try:
206
- logger.info("Auto-generating captions...")
207
-
208
- instruction = f"""Create engaging social media captions for this TikTok/Instagram video script.
209
-
210
- Requirements:
211
- - Hook viewers in first 3 words
212
- - Use line breaks for readability
213
- - Include relevant emojis naturally
214
- - Keep total under 150 characters
215
- - Make it scroll-stopping
216
-
217
- Script: {self.data_holder.tts_script}
218
-
219
- Return ONLY the caption text, nothing else."""
220
-
221
- response = gemini_sdk.generate(instruction)
222
-
223
- caption = response.strip()
224
- logger.info(f"βœ“ Generated caption: {caption[:100]}...")
225
- return caption
226
-
227
- except Exception as e:
228
- logger.error(f"Caption generation failed: {e}")
229
- return self.data_holder.tts_script.split(".")[0][:150]
230
-
231
  async def generate_video(self, prompt: str, duration: int, image_input: str = None) -> Dict:
232
  """
233
  Generate video using RunwayML gen4_turbo ($0.25 per video / 25 credits)
@@ -308,11 +251,11 @@ class APIClients:
308
  if os.getenv("USE_GEMIMI_VIDEO", "false").lower() == "true":
309
  logger.info("Using Gemini SDK for video generation...")
310
 
311
- output_path = await self.get_cache_url(f"gemini_sdk.generate_video_{model_name}", ".mp4")
312
  if not output_path:
313
  output_path = f'/tmp/video_{duration}_{model_name}_{uuid.uuid4().hex[:8]}.mp4'
314
- gemini_sdk.generate_video(prompt, output_path, image_input)
315
- await self.store_in_cache(output_path, f"gemini_sdk.generate_video_{model_name}", ".mp4")
316
 
317
  video_result = {
318
  "local_path": output_path,
@@ -394,30 +337,7 @@ class APIClients:
394
  logger.error(f"❌ Video generation error: {e}")
395
  raise
396
 
397
- async def download_file(self, url: str, filename: str) -> str:
398
- """Download file from URL to local temporary file"""
399
- if os.getenv("TEST_AUTOMATION", "").lower() == "true":
400
- if not url.startswith("http"):
401
- return url
402
- import aiohttp
403
- import tempfile
404
- from pathlib import Path
405
-
406
- local_path = Path(tempfile.gettempdir()) / filename
407
 
408
- try:
409
- async with aiohttp.ClientSession() as session:
410
- async with session.get(url) as response:
411
- if response.status == 200:
412
- with open(local_path, "wb") as f:
413
- f.write(await response.read())
414
- logger.info(f"βœ“ Downloaded {filename} from {url}")
415
- return str(local_path)
416
- else:
417
- raise Exception(f"Download failed: {response.status}")
418
- except Exception as e:
419
- logger.error(f"Failed to download {url}: {e}")
420
- raise
421
 
422
 
423
  async def store_in_cache(self, file_path: str, method_type: str, file_ext: str = ".mp4") -> str:
@@ -515,197 +435,30 @@ class APIClients:
515
 
516
  logger.info(f"☁️ Found matching file: gs://{self.gcs_bucket.name}/{blob_name}")
517
 
518
- blob = self.gcs_bucket.blob(blob_name)
519
- if not blob.exists():
520
- logger.error(f"❌ Blob not found in GCS: {blob_name}")
521
- return None
522
-
523
- os.makedirs(local_dir, exist_ok=True)
524
- local_path = os.path.join(local_dir, os.path.basename(blob_name))
525
-
526
- # Download the blob
527
- blob.download_to_filename(local_path)
528
- file_size = os.path.getsize(local_path)
529
- logger.info(f"βœ… Downloaded {blob_name} β†’ {local_path} ({file_size/1024:.1f} KB)")
530
-
531
- return local_path
532
-
533
- except Exception as e:
534
- logger.error(f"❌ GCS download failed: {e}")
535
- return None
536
-
537
- async def generate_srt_content(self, words: List[Dict]) -> str:
538
- """Convert timed words to SRT subtitle format"""
539
- srt_content = ""
540
- subtitle_index = 1
541
-
542
- # Group words into phrases (3-4 words per subtitle)
543
- phrase_words = []
544
- current_phrase = []
545
-
546
- for word in words:
547
- current_phrase.append(word)
548
- if len(current_phrase) >= 3 or any(p in word["word"] for p in [".", ",", "!", "?"]):
549
- phrase_words.append(current_phrase)
550
- current_phrase = []
551
-
552
- if current_phrase:
553
- phrase_words.append(current_phrase)
554
-
555
- # Create SRT entries
556
- for phrase in phrase_words:
557
- if not phrase:
558
- continue
559
-
560
- start_time = phrase[0]["start_time"]
561
- end_time = phrase[-1]["end_time"]
562
-
563
- # Format times for SRT (HH:MM:SS,mmm)
564
- start_str = self._format_srt_time(start_time)
565
- end_str = self._format_srt_time(end_time)
566
-
567
- # Create phrase text
568
- phrase_text = " ".join(word["word"] for word in phrase)
569
-
570
- srt_content += f"{subtitle_index}\n"
571
- srt_content += f"{start_str} --> {end_str}\n"
572
- srt_content += f"{phrase_text}\n\n"
573
-
574
- subtitle_index += 1
575
-
576
- return srt_content
577
-
578
- def _format_srt_time(self, seconds: float) -> str:
579
- """Convert seconds to SRT time format"""
580
- hours = int(seconds // 3600)
581
- minutes = int((seconds % 3600) // 60)
582
- secs = seconds % 60
583
- milliseconds = int((secs - int(secs)) * 1000)
584
- return f"{hours:02d}:{minutes:02d}:{int(secs):02d},{milliseconds:03d}"
585
-
586
-
587
-
588
- # ===============================
589
- # temp GCS UPLOAD SUPPORT
590
- # ===============================
591
-
592
- def init_temp_gcs(self):
593
- """
594
- One-time initialization of temp GCS client using VERTEX_TEMP_AI_CREDENTIALS_JSON.
595
- This sets up a reusable client and bucket reference for later uploads.
596
- """
597
- try:
598
- vertex_creds_json_str = os.getenv("VERTEX_TEMP_AI_CREDENTIALS_JSON")
599
- if not vertex_creds_json_str:
600
- logger.error("❌ Missing VERTEX_TEMP_AI_CREDENTIALS_JSON for temp GCS initialization")
601
- return False
602
-
603
- # Try as file path first, fall back to raw JSON if that fails
604
- try:
605
- if Path(vertex_creds_json_str).exists():
606
- logger.info(f"Loading GCP credentials from file: {vertex_creds_json_str}")
607
- with open(vertex_creds_json_str, "r") as f:
608
- creds_info = json.load(f)
609
- else:
610
- raise FileNotFoundError("Not a valid file path")
611
- except Exception:
612
- # Fall back to parsing as raw JSON string
613
- logger.info("Parsing GCP credentials as JSON string")
614
- creds_info = json.loads(vertex_creds_json_str)
615
-
616
- creds = service_account.Credentials.from_service_account_info(creds_info)
617
- project_id = creds_info.get("project_id")
618
-
619
- # Allow override or fallback naming
620
- my_bucket_name = os.getenv("MY_TEMP_GCS_BUCKET") or f"{project_id}-temp-uploads"
621
-
622
- # Create the storage client
623
- self.my_temp_gcs_client = storage.Client(credentials=creds, project=project_id)
624
- self.my_temp_gcs_bucket = self.my_temp_gcs_client.bucket(my_bucket_name)
625
-
626
- # Create bucket if it doesn't exist
627
- self.create_bucket_if_not_exists(self.my_temp_gcs_client, my_bucket_name)
628
-
629
- logger.info(f"πŸ” temp GCS authenticated successfully β†’ gs://{my_bucket_name}")
630
- return True
631
-
632
- except Exception as e:
633
- logger.error(f"❌ Failed to initialize temp GCS client: {e}")
634
- self.my_temp_gcs_client = None
635
- self.my_temp_gcs_bucket = None
636
- return False
637
-
638
- def create_bucket_if_not_exists(self, client, bucket_name: str, location: str = "us-central1") -> bool:
639
- """
640
- Create a GCS bucket if it doesn't already exist.
641
-
642
- Args:
643
- client: GCS storage client to use
644
- bucket_name: Name of the bucket to create
645
- location: GCS location for the bucket (default: us-central1)
646
 
647
- Returns:
648
- True if bucket exists or was created successfully, False otherwise
649
- """
650
- try:
651
- bucket = client.bucket(bucket_name)
 
652
 
653
- if bucket.exists():
654
- logger.info(f"βœ“ Bucket already exists: gs://{bucket_name}")
655
- return True
656
 
657
- # Bucket doesn't exist, create it
658
- logger.info(f"πŸ“¦ Creating new bucket: gs://{bucket_name} in {location}")
659
- new_bucket = client.create_bucket(bucket_name, location=location)
660
- logger.info(f"βœ… Bucket created successfully: gs://{new_bucket.name}")
661
- return True
662
 
663
- except Exception as e:
664
- logger.error(f"❌ Failed to create bucket {bucket_name}: {e}")
665
- return False
666
-
667
-
668
- async def upload_to_temp_gcs(self, file_path: str, folder: str = "video") -> Optional[str]:
669
- """
670
- Upload MP4 file to the temp GCS bucket initialized by init_temp_gcs().
671
-
672
- Args:
673
- file_path: Path to the .mp4 file
674
- folder: Folder name in GCS (default: 'videos')
675
-
676
- Returns:
677
- Public URL of uploaded video, or None on failure.
678
- """
679
- try:
680
- # Check initialization first
681
- if not getattr(self, "my_temp_gcs_bucket", None):
682
- logger.error("⚠️ temp GCS not initialized. Call init_temp_gcs() first.")
683
- return None
684
-
685
- if not os.path.exists(file_path):
686
- logger.error(f"❌ File not found: {file_path}")
687
- return None
688
-
689
- filename = f'{self.data_holder.hash_tts_script}_{os.path.basename(file_path)}'
690
- if not filename.endswith(".mp4"):
691
- logger.warning("⚠️ Skipping non-MP4 file upload.")
692
- return None
693
-
694
- blob_name = f"{folder}/{filename}"
695
- blob = self.my_temp_gcs_bucket.blob(blob_name)
696
- blob.content_type = "video/mp4"
697
-
698
- logger.info(f"☁️ Uploading {filename} β†’ gs://{self.my_temp_gcs_bucket.name}/{blob_name}")
699
- blob.upload_from_filename(file_path)
700
-
701
- # Optional: make it public (comment out if you want private URLs)
702
- # blob.make_public()
703
- public_url = f"https://storage.googleapis.com/{self.my_temp_gcs_bucket.name}/{blob_name}"
704
-
705
- logger.info(f"βœ… temp GCS upload complete: {public_url}")
706
- return public_url
707
 
708
  except Exception as e:
709
- logger.error(f"❌ temp GCS upload failed: {e}")
710
  return None
711
 
 
 
23
  import asyncio
24
  from utils import logger
25
  from data_holder import DataHolder
26
+ from file_downloader import FileDownloader
27
 
28
 
29
  # --- NEW IMPORTS ---
30
  from google.oauth2 import service_account
31
  import vertexai
32
+ from google_src.gcs_utils import get_gcs_client, get_gcs_credentials, upload_file_to_gcs, list_gcs_files, create_bucket_if_not_exists
33
  from google_src.setup_gcs_permissions import setup_bucket_permissions
34
 
35
  # --------------------
 
37
  import base64
38
  from pathlib import Path
39
 
40
+ from google_src import ai_studio_sdk
41
  import uuid
42
 
43
  class APIClients:
 
54
  self.gcs_bucket = self.gcs_client.bucket(gcs_bucket_name)
55
 
56
  # Create main bucket if it doesn't exist
57
+ create_bucket_if_not_exists(self.gcs_client, gcs_bucket_name)
58
 
59
  # Apply permissions to the main bucket
60
  try:
 
101
  await self.store_in_cache(file_path, f"{method_type}_{duration}", ".txt")
102
  except: pass
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  async def generate_image(self, prompt: str) -> Optional[str]:
105
  """
106
  Generate image using Vertex AI Imagen 4 Ultra
 
120
  return url
121
 
122
  logger.info(f"🎨 Generating image with Imagen 4 Ultra: {prompt[:200]}...")
123
+ image_path = ai_studio_sdk.generate_image(prompt)
124
  if image_path:
125
  await self.store_in_cache(image_path, "generate_image", ".jpg")
126
  return image_path
 
171
  logger.error(f"❌ Imagen 4 Ultra generation failed: {e}")
172
  raise
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  async def generate_video(self, prompt: str, duration: int, image_input: str = None) -> Dict:
175
  """
176
  Generate video using RunwayML gen4_turbo ($0.25 per video / 25 credits)
 
251
  if os.getenv("USE_GEMIMI_VIDEO", "false").lower() == "true":
252
  logger.info("Using Gemini SDK for video generation...")
253
 
254
+ output_path = await self.get_cache_url(f"ai_studio_sdk.generate_video_{model_name}", ".mp4")
255
  if not output_path:
256
  output_path = f'/tmp/video_{duration}_{model_name}_{uuid.uuid4().hex[:8]}.mp4'
257
+ ai_studio_sdk.generate_video(prompt, output_path, image_input)
258
+ await self.store_in_cache(output_path, f"ai_studio_sdk.generate_video_{model_name}", ".mp4")
259
 
260
  video_result = {
261
  "local_path": output_path,
 
337
  logger.error(f"❌ Video generation error: {e}")
338
  raise
339
 
 
 
 
 
 
 
 
 
 
 
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
 
343
  async def store_in_cache(self, file_path: str, method_type: str, file_ext: str = ".mp4") -> str:
 
435
 
436
  logger.info(f"☁️ Found matching file: gs://{self.gcs_bucket.name}/{blob_name}")
437
 
438
+ # Construct GCS URL
439
+ gs_url = f"gs://{self.gcs_bucket.name}/{blob_name}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
 
441
+ # Use FileDownloader
442
+ downloader = FileDownloader()
443
+ # We can download mostly anywhere, but let's stick to the default behavior or local_dir if needed.
444
+ # safe_download uses temp dir by default. The original code used local_dir="/tmp/tts_downloads".
445
+ # FileDownloader uses its own temp dir logic.
446
+ # Let's see if we can pass output path. safe_download takes output_path.
447
 
448
+ local_path = os.path.join(local_dir, os.path.basename(blob_name))
 
 
449
 
450
+ downloaded = downloader.safe_download(gs_url, output_path=local_path)
 
 
 
 
451
 
452
+ if downloaded:
453
+ file_size = os.path.getsize(downloaded)
454
+ logger.info(f"βœ… Downloaded {blob_name} β†’ {downloaded} ({file_size/1024:.1f} KB)")
455
+ return str(downloaded)
456
+ else:
457
+ logger.error(f"❌ FileDownloader failed for {gs_url}")
458
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
459
 
460
  except Exception as e:
461
+ logger.error(f"❌ GCS download failed: {e}")
462
  return None
463
 
464
+
src/asset_manager/asset_processor.py CHANGED
@@ -10,8 +10,7 @@ from typing import List, Dict, Optional, Tuple
10
  import pandas as pd
11
  import json_repair
12
  from moviepy.editor import VideoFileClip
13
-
14
- import gemini_sdk
15
  from utils import logger
16
  from .video_lib import get_video_lib
17
 
@@ -86,7 +85,7 @@ USER PROMPT:
86
  TTS Script: {tts_script}
87
  Video Options: {video_context}
88
  """
89
- response = gemini_sdk.generate(model_input)
90
 
91
  response_text = response.strip()
92
 
 
10
  import pandas as pd
11
  import json_repair
12
  from moviepy.editor import VideoFileClip
13
+ from google_src import ai_studio_sdk
 
14
  from utils import logger
15
  from .video_lib import get_video_lib
16
 
 
85
  TTS Script: {tts_script}
86
  Video Options: {video_context}
87
  """
88
+ response = ai_studio_sdk.generate(model_input)
89
 
90
  response_text = response.strip()
91
 
src/automation.py CHANGED
@@ -6,7 +6,7 @@ import asyncio
6
  import os
7
  import time
8
  import json
9
- import gemini_sdk
10
  from typing import Dict, List, Optional, Any
11
  from pathlib import Path
12
  from api_clients import APIClients
@@ -467,9 +467,6 @@ class ContentAutomation:
467
  if strategy.get("captions"):
468
  captions = strategy["captions"]
469
  logger.info(f"Using provided captions: {captions[:50]}...")
470
- else:
471
- captions = await self.api_clients.generate_captions()
472
- logger.info(f"Auto-generated captions: {captions[:50]}...")
473
 
474
  # Step 1: Generate image using Imagen 4 Ultra
475
  image_path = await self.api_clients.generate_image(strategy["gemini_prompt"])
@@ -484,7 +481,7 @@ class ContentAutomation:
484
  prompt=strategy["runway_prompt"], image_input=image_path, duration=strategy.get("duration", 3)
485
  )
486
 
487
- video_data["captions"] = captions
488
  video_data["script"] = self.data_holder.tts_script
489
 
490
  if os.getenv("USE_VEO", "false").lower() == "true":
@@ -524,7 +521,7 @@ class ContentAutomation:
524
  "style": "casual"
525
  }}"""
526
 
527
- response = gemini_sdk.generate(analysis_prompt)
528
 
529
  # Parse response
530
  response_text = response.strip()
 
6
  import os
7
  import time
8
  import json
9
+ from google_src import ai_studio_sdk
10
  from typing import Dict, List, Optional, Any
11
  from pathlib import Path
12
  from api_clients import APIClients
 
467
  if strategy.get("captions"):
468
  captions = strategy["captions"]
469
  logger.info(f"Using provided captions: {captions[:50]}...")
 
 
 
470
 
471
  # Step 1: Generate image using Imagen 4 Ultra
472
  image_path = await self.api_clients.generate_image(strategy["gemini_prompt"])
 
481
  prompt=strategy["runway_prompt"], image_input=image_path, duration=strategy.get("duration", 3)
482
  )
483
 
484
+ video_data["captions"] = captions or "No captions provided"
485
  video_data["script"] = self.data_holder.tts_script
486
 
487
  if os.getenv("USE_VEO", "false").lower() == "true":
 
521
  "style": "casual"
522
  }}"""
523
 
524
+ response = ai_studio_sdk.generate(analysis_prompt)
525
 
526
  # Parse response
527
  response_text = response.strip()
src/generate_content.py CHANGED
@@ -6,8 +6,7 @@ from datetime import datetime
6
  from pathlib import Path
7
  from dotenv import load_dotenv
8
  import argparse
9
-
10
- import gemini_sdk
11
 
12
  class GenerateContent:
13
  def __init__(self, commit: bool = False):
@@ -59,7 +58,7 @@ class GenerateContent:
59
  """Generate 10 unique scenarios using Gemini and save to CSV."""
60
  print("πŸ€– Generating scenarios...")
61
 
62
- model = gemini_sdk.generate("gemini-2.5-pro")
63
  model_input = f"""SYSTEM INSTRUCTION::
64
  {self._get_system_instruction()}
65
 
 
6
  from pathlib import Path
7
  from dotenv import load_dotenv
8
  import argparse
9
+ from google_src import ai_studio_sdk
 
10
 
11
  class GenerateContent:
12
  def __init__(self, commit: bool = False):
 
58
  """Generate 10 unique scenarios using Gemini and save to CSV."""
59
  print("πŸ€– Generating scenarios...")
60
 
61
+ model = ai_studio_sdk.generate("gemini-2.5-pro")
62
  model_input = f"""SYSTEM INSTRUCTION::
63
  {self._get_system_instruction()}
64
 
src/{gemini_sdk.py β†’ google_src/ai_studio_sdk.py} RENAMED
@@ -250,4 +250,4 @@ if __name__ == "__main__":
250
  "Morning violence against self visible, broken NPC movement, glitchy character lighting, camera shows malfunction, cinematic realistic style",
251
  "test.mp4",
252
  image="testData/image.png"
253
- )
 
250
  "Morning violence against self visible, broken NPC movement, glitchy character lighting, camera shows malfunction, cinematic realistic style",
251
  "test.mp4",
252
  image="testData/image.png"
253
+ )
src/google_src/gcs_utils.py CHANGED
@@ -203,3 +203,24 @@ def list_gcs_files(prefix: str = "video/", account_name: str = "final_data") ->
203
  except Exception as e:
204
  logger.error(f"❌ Failed to list files: {e}")
205
  return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  except Exception as e:
204
  logger.error(f"❌ Failed to list files: {e}")
205
  return []
206
+
207
+ def create_bucket_if_not_exists(client, bucket_name: str, location: str = "us-central1") -> bool:
208
+ """
209
+ Create a GCS bucket if it doesn't already exist.
210
+ """
211
+ try:
212
+ bucket = client.bucket(bucket_name)
213
+
214
+ if bucket.exists():
215
+ logger.info(f"βœ“ Bucket already exists: gs://{bucket_name}")
216
+ return True
217
+
218
+ # Bucket doesn't exist, create it
219
+ logger.info(f"πŸ“¦ Creating new bucket: gs://{bucket_name} in {location}")
220
+ new_bucket = client.create_bucket(bucket_name, location=location)
221
+ logger.info(f"βœ… Bucket created successfully: gs://{new_bucket.name}")
222
+ return True
223
+
224
+ except Exception as e:
225
+ logger.error(f"❌ Failed to create bucket {bucket_name}: {e}")
226
+ return False