ladybug11 commited on
Commit
3f357fe
Β·
1 Parent(s): 6d68d5c
Files changed (1) hide show
  1. app.py +123 -54
app.py CHANGED
@@ -41,7 +41,7 @@ except Exception as e:
41
  @tool
42
  def generate_quote_tool(niche: str, style: str) -> str:
43
  """
44
- Generate a unique inspirational quote using the HybridQuoteGenerator.
45
 
46
  Args:
47
  niche: The category of the quote (e.g. Motivation, Fitness, Mindfulness).
@@ -81,7 +81,7 @@ def search_pexels_video_tool(style: str, niche: str) -> dict:
81
 
82
  Args:
83
  style: Visual style (e.g. Cinematic, Nature, Urban, Minimal, Abstract).
84
- niche: Content niche (e.g. Motivation, Business/Entrepreneurship, Fitness).
85
 
86
  Returns:
87
  A dictionary with:
@@ -91,7 +91,8 @@ def search_pexels_video_tool(style: str, niche: str) -> dict:
91
  - pexels_url: The Pexels page URL (or None).
92
  - error: Optional error message on failure.
93
  """
94
- search_strategies = {
 
95
  "Motivation": {
96
  "Cinematic": ["person climbing mountain", "running sunrise", "achievement success"],
97
  "Nature": ["sunrise mountain peak", "ocean waves powerful", "forest light"],
@@ -143,7 +144,29 @@ def search_pexels_video_tool(style: str, niche: str) -> dict:
143
  },
144
  }
145
 
146
- queries = search_strategies.get(niche, {}).get(style, ["aesthetic nature"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  try:
149
  if not PEXELS_API_KEY:
@@ -156,8 +179,8 @@ def search_pexels_video_tool(style: str, niche: str) -> dict:
156
  }
157
 
158
  headers = {"Authorization": PEXELS_API_KEY}
159
- query = random.choice(queries)
160
 
 
161
  url = (
162
  f"https://api.pexels.com/videos/search"
163
  f"?query={query}&per_page=15&orientation=portrait"
@@ -245,6 +268,7 @@ def create_quote_video_tool(
245
 
246
  try:
247
  print(f"πŸš€ Processing on Modal (fast!) with text_style={text_style}...")
 
248
  response = requests.post(
249
  modal_endpoint,
250
  json={
@@ -298,7 +322,8 @@ def create_quote_video_tool(
298
  @tool
299
  def get_trending_topics_tool(platform: str, niche: str, max_topics: int = 6) -> dict:
300
  """
301
- Suggest trending content angles and hooks for short-form quote videos.
 
302
 
303
  Args:
304
  platform: Main platform (e.g. 'TikTok', 'Instagram Reels', 'YouTube Shorts', or 'General').
@@ -320,10 +345,20 @@ def get_trending_topics_tool(platform: str, niche: str, max_topics: int = 6) ->
320
  You are helping a creator make short quote videos.
321
 
322
  Platform: {platform}
323
- Niche: {niche}
 
 
 
 
 
 
 
 
 
 
324
 
325
  Task:
326
- - Propose {max_topics} SPECIFIC trending-style topics/angles that would perform well on {platform}.
327
  - Think in terms of what actually shows up on TikTok/Reels/Shorts: concrete micro-themes and patterns, not vague ideas.
328
 
329
  For each topic, include:
@@ -332,7 +367,7 @@ For each topic, include:
332
 
333
  Constraints:
334
  - No generic motivational fluff like "follow your dreams" or "believe in yourself".
335
- - Make it feel current: you can use language like "soft life", "discipline era", "glow up", "reset routine" where it fits.
336
  - Keep everything under 20 words per topic name and per hook.
337
 
338
  Return a JSON object with EXACTLY this structure:
@@ -446,10 +481,10 @@ def mcp_agent_pipeline(
446
  MAIN PIPELINE: uses smolagents CodeAgent.run to plan & call tools.
447
 
448
  The agent:
449
- - calls generate_quote_tool
450
- - calls search_pexels_video_tool multiple times
 
451
  - calls create_quote_video_tool for each variation
452
- - returns JSON with status_log + video_paths
453
  """
454
  base_log = ["πŸ€– **MCP AGENT RUN**"]
455
 
@@ -469,66 +504,100 @@ def mcp_agent_pipeline(
469
  base_prefix = os.path.join(output_dir, f"agent_{timestamp}_v")
470
 
471
  user_task = f"""
472
- You are an autonomous Python agent helping creators generate short vertical quote videos.
 
 
473
 
474
- Niche: {niche}
475
- Visual Style: {style}
476
- Text style for quotes: {text_style}
477
- Number of variations: {num_variations}
478
 
479
- You have these TOOLS available:
 
 
 
480
 
481
- 1. generate_quote_tool(niche: str, style: str) -> str
482
- - Returns a single SHORT quote as plain text.
483
 
484
- 2. search_pexels_video_tool(style: str, niche: str) -> dict
485
  - Returns a dict with:
486
  - "success": bool
487
  - "video_url": str or None
488
 
489
- 3. create_quote_video_tool(
490
  video_url: str,
491
  quote_text: str,
492
  output_path: str,
493
  text_style: str = "classic_center"
494
  ) -> dict
495
- - Writes a video file to output_path and returns a dict with:
496
  - "success": bool
497
  - "output_path": str or None
498
 
499
- You MAY also optionally call:
500
- 4. get_trending_topics_tool(platform: str, niche: str, max_topics: int = 6) -> dict
501
- - Use platform="TikTok" and the given niche to get trending angles.
502
- - If you call it, you can use the first topic/hook as inspiration for the quote content.
503
-
504
- Your job:
505
-
506
- 1. (Optional) Call get_trending_topics_tool("TikTok", "{niche}", 4) to see trending angles.
507
- - If you do, mention in the status_log which topic you used as inspiration.
508
- 2. Call generate_quote_tool once to obtain quote_text (optionally influenced by a chosen topic).
509
- 3. For each variation i from 1 to {num_variations}:
510
- - Call search_pexels_video_tool(style, niche).
511
- - If it succeeds, compute output_path exactly as:
512
- "{base_prefix}" + str(i) + ".mp4"
513
- - Call create_quote_video_tool(video_url, quote_text, output_path, text_style="{text_style}").
514
- 4. Collect only variations where create_quote_video_tool returns success == True and a non-empty output_path.
515
- 5. Build a human-readable status_log string summarizing:
516
- - Which tools you called (including whether you used get_trending_topics_tool)
517
- - How many videos succeeded or failed
518
- 6. Return ONLY a valid JSON object of the form:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
519
 
520
  {{
521
- "status_log": "multi-line human readable description of what you did",
522
- "video_paths": [
523
- "{base_prefix}1.mp4",
524
- "... only paths that actually succeeded ..."
525
- ]
526
  }}
527
 
528
  CRITICAL:
529
- - Do NOT wrap the JSON in markdown or backticks.
530
- - Do NOT add extra keys.
531
- - Do NOT print anything except the JSON object as your final answer.
532
  """
533
 
534
  agent_result = agent.run(user_task)
@@ -670,17 +739,17 @@ with gr.Blocks(
670
 
671
  **Key Features:**
672
  - 🌟 Short, non-repeating Gemini quotes (per niche history)
 
673
  - πŸ€– smolagents CodeAgent for tool planning
674
  - πŸ”— Optional MCP client integration
675
  - πŸŽ₯ Modal for fast video rendering
676
  - πŸ…°οΈ Text style controls (font & placement)
677
- - πŸ”₯ Trending topics / angle helper
678
  """
679
  )
680
 
681
  with gr.Accordion("πŸ“Έ Example Gallery - Recent Videos", open=True):
682
  gr.Markdown(
683
- "See what others (or you) have generated. Auto-updates after each run."
684
  )
685
 
686
  with gr.Row():
@@ -828,11 +897,11 @@ with gr.Blocks(
828
  ---
829
  ### ✨ Features
830
  - 🌟 Gemini-powered, short non-repeating quotes (per niche)
 
831
  - 🎨 Multiple aesthetic video & text layouts
832
  - ⚑ Modal-accelerated rendering
833
  - πŸ€– smolagents CodeAgent for autonomous tool-calling
834
  - πŸ”— Optional MCP integration via MCPClient
835
- - πŸ”₯ Trend helper to shape topics & hooks
836
 
837
  ### πŸ† Hackathon: MCP 1st Birthday
838
  **Track:** Track 2 - MCP in Action
 
41
  @tool
42
  def generate_quote_tool(niche: str, style: str) -> str:
43
  """
44
+ Generate a unique, short inspirational quote using the HybridQuoteGenerator.
45
 
46
  Args:
47
  niche: The category of the quote (e.g. Motivation, Fitness, Mindfulness).
 
81
 
82
  Args:
83
  style: Visual style (e.g. Cinematic, Nature, Urban, Minimal, Abstract).
84
+ niche: Content niche or free-text theme (e.g. Motivation, Soft Life Mornings).
85
 
86
  Returns:
87
  A dictionary with:
 
91
  - pexels_url: The Pexels page URL (or None).
92
  - error: Optional error message on failure.
93
  """
94
+ # ---- Canonical mapping (your original curated niches) ----
95
+ canonical_strategies = {
96
  "Motivation": {
97
  "Cinematic": ["person climbing mountain", "running sunrise", "achievement success"],
98
  "Nature": ["sunrise mountain peak", "ocean waves powerful", "forest light"],
 
144
  },
145
  }
146
 
147
+ # Normalize style so we don't crash on unexpected input
148
+ normalized_style = style or "Cinematic"
149
+ normalized_style = normalized_style.strip().title()
150
+ if normalized_style not in ["Cinematic", "Nature", "Urban", "Minimal", "Abstract"]:
151
+ normalized_style = "Cinematic"
152
+
153
+ # Decide queries:
154
+ # 1) If niche is one of the canonical categories -> use curated mapping
155
+ # 2) Otherwise, treat niche as free-text theme and build dynamic queries
156
+ if niche in canonical_strategies:
157
+ queries = canonical_strategies[niche].get(normalized_style, ["aesthetic nature"])
158
+ else:
159
+ base = (niche or "").lower().strip()
160
+ style_word = normalized_style.lower()
161
+ if not base:
162
+ base = "aesthetic vertical"
163
+
164
+ queries = [
165
+ f"{base} {style_word} aesthetic vertical video",
166
+ f"{base} b-roll {style_word}",
167
+ f"{base} lifestyle aesthetic",
168
+ f"{base} cinematic b-roll",
169
+ ]
170
 
171
  try:
172
  if not PEXELS_API_KEY:
 
179
  }
180
 
181
  headers = {"Authorization": PEXELS_API_KEY}
 
182
 
183
+ query = random.choice(queries)
184
  url = (
185
  f"https://api.pexels.com/videos/search"
186
  f"?query={query}&per_page=15&orientation=portrait"
 
268
 
269
  try:
270
  print(f"πŸš€ Processing on Modal (fast!) with text_style={text_style}...")
271
+ # Note: modal_video_processing.py currently ignores text_style; it's safe to send it
272
  response = requests.post(
273
  modal_endpoint,
274
  json={
 
322
  @tool
323
  def get_trending_topics_tool(platform: str, niche: str, max_topics: int = 6) -> dict:
324
  """
325
+ Suggest trending content angles and hooks for short-form quote videos,
326
+ tightly aligned with the given niche.
327
 
328
  Args:
329
  platform: Main platform (e.g. 'TikTok', 'Instagram Reels', 'YouTube Shorts', or 'General').
 
345
  You are helping a creator make short quote videos.
346
 
347
  Platform: {platform}
348
+ Creator niche: {niche}
349
+
350
+ All suggested topics MUST be tightly aligned with this niche.
351
+
352
+ Examples of alignment:
353
+ - If niche = Mindfulness β†’ topics about calm lifestyle, awareness, mental clarity, soft-life energy, nervous system regulation.
354
+ - If niche = Motivation β†’ topics about discipline era, glow up routines, self-improvement, consistency, habit stacking.
355
+ - If niche = Love & Relationships β†’ topics about healing, attachment, secure love, boundaries, heartbreak recovery.
356
+ - If niche = Stoicism β†’ topics about emotional resilience, fate, control vs. acceptance, inner strength.
357
+ - If niche = Leadership β†’ topics about leading teams, decision-making, emotional intelligence at work.
358
+ - If niche = Business/Entrepreneurship β†’ topics about founders, failure, shipping, building in public, risk.
359
 
360
  Task:
361
+ - Propose {max_topics} SPECIFIC trending-style topics/angles that would perform well on {platform} for THIS niche.
362
  - Think in terms of what actually shows up on TikTok/Reels/Shorts: concrete micro-themes and patterns, not vague ideas.
363
 
364
  For each topic, include:
 
367
 
368
  Constraints:
369
  - No generic motivational fluff like "follow your dreams" or "believe in yourself".
370
+ - Make it feel current: you can use language like "soft life", "discipline era", "glow up", "reset routine", etc., only if it fits the niche.
371
  - Keep everything under 20 words per topic name and per hook.
372
 
373
  Return a JSON object with EXACTLY this structure:
 
481
  MAIN PIPELINE: uses smolagents CodeAgent.run to plan & call tools.
482
 
483
  The agent:
484
+ - calls get_trending_topics_tool to pick a trend
485
+ - calls generate_quote_tool with style influenced by that trend
486
+ - calls search_pexels_video_tool using the TRENDING TOPIC as niche (free-text support)
487
  - calls create_quote_video_tool for each variation
 
488
  """
489
  base_log = ["πŸ€– **MCP AGENT RUN**"]
490
 
 
504
  base_prefix = os.path.join(output_dir, f"agent_{timestamp}_v")
505
 
506
  user_task = f"""
507
+ You are an autonomous Python agent helping a creator generate short vertical quote videos that follow TikTok-style trends.
508
+
509
+ You MUST follow these steps exactly, using the provided TOOLS:
510
 
511
+ AVAILABLE TOOLS (with signatures):
 
 
 
512
 
513
+ 1. get_trending_topics_tool(platform: str, niche: str, max_topics: int) -> dict
514
+ - Returns a dict with:
515
+ - "topics": list of {{"topic": str, "hook": str}}
516
+ - "notes": str
517
 
518
+ 2. generate_quote_tool(niche: str, style: str) -> str
519
+ - Returns a single short quote as plain text.
520
 
521
+ 3. search_pexels_video_tool(style: str, niche: str) -> dict
522
  - Returns a dict with:
523
  - "success": bool
524
  - "video_url": str or None
525
 
526
+ 4. create_quote_video_tool(
527
  video_url: str,
528
  quote_text: str,
529
  output_path: str,
530
  text_style: str = "classic_center"
531
  ) -> dict
532
+ - Writes a video file to output_path and returns:
533
  - "success": bool
534
  - "output_path": str or None
535
 
536
+ RUNTIME PARAMETERS:
537
+
538
+ - base_niche = "{niche}"
539
+ - base_style = "{style}"
540
+ - text_style = "{text_style}"
541
+ - num_variations = {num_variations}
542
+ - base_output_prefix = "{base_prefix}"
543
+
544
+ STEP-BY-STEP PLAN (YOU MUST FOLLOW):
545
+
546
+ 1. Call get_trending_topics_tool with:
547
+ - platform = "TikTok"
548
+ - niche = base_niche
549
+ - max_topics = 5
550
+
551
+ From the returned dict:
552
+ - If "topics" is non-empty:
553
+ trending_topic = topics[0]["topic"]
554
+ trending_hook = topics[0]["hook"]
555
+ Otherwise:
556
+ trending_topic = base_niche
557
+ trending_hook = ""
558
+
559
+ 2. Call generate_quote_tool with:
560
+ - niche = base_niche
561
+ - style = base_style + " β€” trend: " + trending_topic
562
+
563
+ Store the result as:
564
+ - quote_text
565
+
566
+ 3. For i from 1 to num_variations (inclusive):
567
+ a) Call search_pexels_video_tool with:
568
+ style = base_style
569
+ niche = trending_topic
570
+ Let this result be search_result.
571
+ b) If search_result["success"] is True AND search_result["video_url"] is a non-empty string:
572
+ - Set:
573
+ output_path = base_output_prefix + str(i) + ".mp4"
574
+ - Call create_quote_video_tool with:
575
+ video_url = search_result["video_url"]
576
+ quote_text = quote_text
577
+ output_path = output_path
578
+ text_style = text_style
579
+ Let this be video_result.
580
+ - If video_result["success"] is True AND video_result["output_path"] is a non-empty string:
581
+ append video_result["output_path"] to a Python list called final_video_paths.
582
+ Otherwise, skip this variation.
583
+
584
+ 4. Build a multi-line, human-readable string called status_log summarizing:
585
+ - base_niche, base_style, text_style
586
+ - The chosen trending_topic and trending_hook (or that you fell back to base_niche)
587
+ - The final quote_text
588
+ - How many variations succeeded vs how many were attempted
589
+
590
+ 5. Return ONLY the following JSON object as your final answer (no markdown, no backticks):
591
 
592
  {{
593
+ "status_log": "your multi-line human readable log here",
594
+ "video_paths": ["... list of successful output_path strings from final_video_paths ..."]
 
 
 
595
  }}
596
 
597
  CRITICAL:
598
+ - Do NOT include any other keys.
599
+ - Do NOT return Python objects; everything must be JSON-serializable.
600
+ - Do NOT print anything else beyond that single JSON object.
601
  """
602
 
603
  agent_result = agent.run(user_task)
 
739
 
740
  **Key Features:**
741
  - 🌟 Short, non-repeating Gemini quotes (per niche history)
742
+ - πŸ”₯ Trending topics actually drive the quote + visuals
743
  - πŸ€– smolagents CodeAgent for tool planning
744
  - πŸ”— Optional MCP client integration
745
  - πŸŽ₯ Modal for fast video rendering
746
  - πŸ…°οΈ Text style controls (font & placement)
 
747
  """
748
  )
749
 
750
  with gr.Accordion("πŸ“Έ Example Gallery - Recent Videos", open=True):
751
  gr.Markdown(
752
+ "See what has been generated. Auto-updates after each run."
753
  )
754
 
755
  with gr.Row():
 
897
  ---
898
  ### ✨ Features
899
  - 🌟 Gemini-powered, short non-repeating quotes (per niche)
900
+ - πŸ”₯ Trend-aware: topics influence quotes + videos
901
  - 🎨 Multiple aesthetic video & text layouts
902
  - ⚑ Modal-accelerated rendering
903
  - πŸ€– smolagents CodeAgent for autonomous tool-calling
904
  - πŸ”— Optional MCP integration via MCPClient
 
905
 
906
  ### πŸ† Hackathon: MCP 1st Birthday
907
  **Track:** Track 2 - MCP in Action