Spaces:
Running
Running
File size: 8,846 Bytes
282394c ae800e3 282394c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
import gradio as gr
import os
import httpx
from typing import Dict, Any
# --- Backend Client Functions ---
# These functions call the Modal/backend endpoints.
async def call_video_analysis_backend(video_url: str) -> Dict[str, Any]:
"""Calls the backend to analyze a single video."""
# Default to a placeholder if the env var is not set, to avoid crashing.
backend_url = os.getenv("BACKEND_VIDEO_URL", "https://your-backend-hf-space-for-video/process_video_analysis")
if not video_url:
return {"status": "error", "message": "Video URL cannot be empty."}
print(f"Sending request to backend for video: {video_url}")
payload = {"video_url": video_url}
try:
async with httpx.AsyncClient(timeout=1800.0) as client:
response = await client.post(backend_url, json=payload)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
return {"status": "error", "message": f"Backend Error: {e.response.status_code}", "details": e.response.text}
except Exception as e:
return {"status": "error", "message": "Failed to connect to backend", "details": str(e)}
async def call_topic_analysis_backend(topic: str, max_videos: int) -> Dict[str, Any]:
"""Calls the backend to analyze videos for a topic."""
backend_url = os.getenv("BACKEND_TOPIC_URL", "https://your-backend-hf-space-for-topic/analyze_topic")
if not topic:
return {"status": "error", "message": "Topic cannot be empty."}
print(f"Sending request to backend for topic: {topic} ({max_videos} videos)")
payload = {"topic": topic, "max_videos": max_videos}
try:
async with httpx.AsyncClient(timeout=3600.0) as client:
response = await client.post(backend_url, json=payload)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
return {"status": "error", "message": f"Backend Error: {e.response.status_code}", "details": e.response.text}
except Exception as e:
return {"status": "error", "message": "Failed to connect to backend", "details": str(e)}
# --- Gradio Tool Functions (Wrappers for MCP) ---
async def analyze_video(video_url: str):
"""
Triggers a comprehensive analysis of a single video from a URL.
This tool calls a backend service to perform multiple analyses:
- Transcribes audio to text.
- Generates a descriptive caption for the video content.
- Recognizes main actions in the video.
- Detects objects in keyframes.
:param video_url: The public URL of the video to be processed (e.g., a YouTube link).
:return: A JSON object containing the full analysis results from the backend.
"""
status_update = f"Analyzing video: {video_url}..."
results = await call_video_analysis_backend(video_url)
if isinstance(results, dict) and results.get("analysis") is None:
status_update = f"Error analyzing video: {results.get('error', 'Unknown error')}"
else:
status_update = "Video analysis complete."
return status_update, results
async def analyze_topic(topic: str, max_videos: int):
"""
Finds and analyzes multiple videos based on a given topic.
This tool calls a backend service that searches for videos related to the topic,
then runs a comprehensive analysis on each video found.
:param topic: The topic to search for (e.g., 'latest AI advancements').
:param max_videos: The maximum number of videos to find and analyze (1-5).
:return: A JSON object with the aggregated analysis results for all videos.
"""
status_update = f"Analyzing topic '{topic}' with {max_videos} videos... this can take a very long time."
results = await call_topic_analysis_backend(topic, max_videos)
if isinstance(results, dict) and results.get("results") is None:
status_update = f"Error analyzing topic: {results.get('error', 'Unknown error')}"
else:
status_update = "Topic analysis complete."
return status_update, results
# --- Gradio UI ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# LLM Video Interpretation MCP")
gr.Markdown("This Hugging Face Space provides tools for processing video context for AI agents. Use the tools below to analyze videos by URL or by topic.")
with gr.Tab("Single Video Analysis"):
gr.Markdown("## Analyze a single video from a URL")
with gr.Row():
video_url_input = gr.Textbox(label="Video URL", placeholder="Enter a YouTube or direct video URL...", scale=4)
submit_button = gr.Button("Analyze Video", variant="primary")
status_text = gr.Textbox(label="Status", interactive=False)
json_output = gr.JSON(label="Analysis Results")
submit_button.click(
analyze_video,
inputs=[video_url_input],
outputs=[status_text, json_output],
api_name="analyze_video"
)
gr.Examples(
examples=["https://www.youtube.com/watch?v=3wLg_t_H2Xw", "https://www.youtube.com/watch?v=h42dDpgE7g8"],
inputs=video_url_input
)
with gr.Tab("Topic Video Analysis"):
gr.Markdown("## Analyze multiple videos based on a topic")
with gr.Row():
topic_input = gr.Textbox(label="Enter a topic", placeholder="e.g., 'Apple Vision Pro review'", scale=3)
max_videos_slider = gr.Slider(minimum=1, maximum=5, value=2, step=1, label="Number of Videos to Analyze")
topic_submit_button = gr.Button("Analyze Topic", variant="primary")
topic_status_text = gr.Textbox(label="Status", interactive=False)
topic_json_output = gr.JSON(label="Analysis Results")
topic_submit_button.click(
analyze_topic,
inputs=[topic_input, max_videos_slider],
outputs=[topic_status_text, topic_json_output],
api_name="analyze_topic"
)
gr.Examples(
examples=[["self-driving car technology", 2], ["open source large language models", 3]],
inputs=[topic_input, max_videos_slider]
)
# Set environment variables in your Hugging Face Space settings, not here.
# BACKEND_VIDEO_URL = "https://your-modal-or-backend-url/process_video_analysis"
# BACKEND_TOPIC_URL = "https://your-modal-or-backend-url/analyze_topic"
demo.launch()
gr.Markdown("**Processing can take several minutes** depending on video length and model inference times. The cache on the Modal backend will speed up repeated requests for the same video.")
with gr.Tab("Demo (for Manual Testing)"):
gr.Markdown("### Manually test video URLs or paths for interpretation and observe the JSON response.")
demo_interface.render()
with gr.Tab("Topic Video Analysis"):
gr.Markdown("### Analyze Multiple Videos Based on a Topic")
gr.Markdown("Enter a topic, and the system will search for relevant videos, analyze them, and provide an aggregated JSON output.")
with gr.Row():
topic_input = gr.Textbox(label="Enter Topic", placeholder="e.g., 'best cat videos', 'Python programming tutorials'", scale=3)
max_videos_input = gr.Number(label="Max Videos to Analyze", value=3, minimum=1, maximum=5, step=1, scale=1) # Max 5 for UI, backend might support more
topic_analysis_output = gr.JSON(label="Topic Analysis Results")
with gr.Row():
topic_submit_button = gr.Button("Analyze Topic Videos", variant="primary")
topic_clear_button = gr.Button("Clear")
topic_submit_button.click(
fn=call_topic_analysis_endpoint,
inputs=[topic_input, max_videos_input],
outputs=[topic_analysis_output]
)
def clear_topic_outputs():
return [None, 3, None] # topic_input, max_videos_input (reset to default), topic_analysis_output
topic_clear_button.click(fn=clear_topic_outputs, inputs=[], outputs=[topic_input, max_videos_input, topic_analysis_output])
gr.Examples(
examples=[
["AI in healthcare", 2],
["sustainable energy solutions", 3],
["how to make sourdough bread", 1]
],
inputs=[topic_input, max_videos_input],
outputs=topic_analysis_output,
fn=call_topic_analysis_endpoint,
cache_examples=False
)
gr.Markdown("**Note:** This process involves searching for videos and then analyzing each one. It can take a significant amount of time, especially for multiple videos. The backend has a long timeout, but please be patient.")
# Launch the Gradio application
if __name__ == "__main__":
app.launch(debug=True, server_name="0.0.0.0")
|