File size: 6,389 Bytes
0cff18c
 
7e2a742
 
 
 
 
 
 
 
 
 
 
 
996f027
7e2a742
 
b046b1d
7e2a742
 
 
 
 
 
b046b1d
7e2a742
0cff18c
7e2a742
 
 
 
 
0036cd7
7e2a742
 
0036cd7
7e2a742
 
 
 
 
 
0036cd7
7e2a742
87d643a
7e2a742
3ddb139
7e2a742
 
 
87d643a
7e2a742
 
 
 
 
87d643a
7e2a742
 
 
 
 
 
 
 
 
 
1ff9b41
7e2a742
 
 
1ff9b41
7e2a742
 
1ff9b41
7e2a742
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b046b1d
7e2a742
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b046b1d
7e2a742
 
 
 
 
 
0036cd7
7e2a742
 
 
 
0036cd7
7e2a742
9443255
 
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
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,
            fn=analyze_video,
            outputs=[status_text, json_output]
        )

    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],
            fn=analyze_topic,
            outputs=[topic_status_text, topic_json_output]
        )

# Final launch of the Gradio app
demo.launch()