File size: 6,253 Bytes
05c2ac8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
185
186
187
188
189
190
191
192
193
import os
from datetime import datetime
from typing import List, Dict, Any, Optional

from fastapi import FastAPI, Request, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
import gradio as gr
import uvicorn
from pydantic import BaseModel
from huggingface_hub.inference._mcp.agent import Agent
from dotenv import load_dotenv

load_dotenv()

# Configuration
WEBHOOK_SECRET = os.getenv("WEBHOOK_SECRET", "your-webhook-secret")
HF_TOKEN = os.getenv("HF_TOKEN")
HF_MODEL = os.getenv("HF_MODEL", "microsoft/DialoGPT-medium")
HF_PROVIDER = os.getenv("HF_PROVIDER", "huggingface")

# Simple storage for processed comments
comments_store: List[Dict[str, Any]] = []

# Agent instance
agent_instance: Optional[Agent] = None


class WebhookEvent(BaseModel):
    event: Dict[str, str]
    comment: Dict[str, Any]
    discussion: Dict[str, Any]
    repo: Dict[str, str]


app = FastAPI(title="HF Discussion Bot")
app.add_middleware(CORSMiddleware, allow_origins=["*"])


async def get_agent():
    """Get or create Agent instance"""
    global agent_instance
    if agent_instance is None and HF_TOKEN:
        agent_instance = Agent(
            model=HF_MODEL,
            provider=HF_PROVIDER,
            api_key=HF_TOKEN,
            servers=[
                {
                    "type": "stdio",
                    "config": {"command": "python", "args": ["mcp_server.py"]},
                }
            ],
        )
        await agent_instance.load_tools()
    return agent_instance


async def process_webhook_comment(webhook_data: Dict[str, Any]):
    """Process webhook using Agent with MCP tools"""
    comment_content = webhook_data["comment"]["content"]
    discussion_title = webhook_data["discussion"]["title"]
    repo_name = webhook_data["repo"]["name"]
    discussion_num = webhook_data["discussion"]["num"]

    agent = await get_agent()
    if not agent:
        ai_response = "Error: Agent not configured (missing HF_TOKEN)"
    else:
        # Use Agent to respond to the discussion
        prompt = f"""
        Please respond to this HuggingFace discussion comment using the available tools.
        
        Repository: {repo_name}
        Discussion: {discussion_title} (#{discussion_num})
        Comment: {comment_content}
        
        First use generate_discussion_response to create a helpful response, then use post_discussion_comment to post it.
        """

        try:
            response_parts = []
            async for item in agent.run(prompt):
                # Collect the agent's response
                if hasattr(item, "content") and item.content:
                    response_parts.append(item.content)
                elif isinstance(item, str):
                    response_parts.append(item)

            ai_response = (
                " ".join(response_parts) if response_parts else "No response generated"
            )
        except Exception as e:
            ai_response = f"Error using agent: {str(e)}"

    # Store the interaction with reply link
    discussion_url = f"https://huggingface.co/{repo_name}/discussions/{discussion_num}"

    interaction = {
        "timestamp": datetime.now().isoformat(),
        "repo": repo_name,
        "discussion_title": discussion_title,
        "discussion_num": discussion_num,
        "discussion_url": discussion_url,
        "original_comment": comment_content,
        "ai_response": ai_response,
        "comment_author": webhook_data["comment"]["author"],
    }

    comments_store.append(interaction)
    return ai_response


@app.post("/webhook")
async def webhook_handler(request: Request, background_tasks: BackgroundTasks):
    """Handle HF Hub webhooks"""
    webhook_secret = request.headers.get("X-Webhook-Secret")
    if webhook_secret != WEBHOOK_SECRET:
        return {"error": "Invalid webhook secret"}

    payload = await request.json()
    event = payload.get("event", {})

    if event.get("action") == "create" and event.get("scope") == "discussion.comment":
        background_tasks.add_task(process_webhook_comment, payload)
        return {"status": "processing"}

    return {"status": "ignored"}


async def simulate_webhook(
    repo_name: str, discussion_title: str, comment_content: str
) -> str:
    """Simulate webhook for testing"""
    if not all([repo_name, discussion_title, comment_content]):
        return "Please fill in all fields."

    mock_payload = {
        "event": {"action": "create", "scope": "discussion.comment"},
        "comment": {
            "content": comment_content,
            "author": "test-user",
            "created_at": datetime.now().isoformat(),
        },
        "discussion": {
            "title": discussion_title,
            "num": len(comments_store) + 1,
        },
        "repo": {"name": repo_name},
    }

    response = await process_webhook_comment(mock_payload)
    return f"βœ… Processed! AI Response: {response}"


def create_gradio_app():
    """Create Gradio interface"""
    with gr.Blocks(title="HF Discussion Bot", theme=gr.themes.Soft()) as demo:
        gr.Markdown("# πŸ€– HF Discussion Bot Dashboard")
        gr.Markdown("*Powered by HuggingFace Tiny Agents + FastMCP*")

        with gr.Column():
            sim_repo = gr.Textbox(label="Repository", value="microsoft/DialoGPT-medium")
            sim_title = gr.Textbox(label="Discussion Title", value="Test Discussion")
            sim_comment = gr.Textbox(
                label="Comment",
                lines=3,
                value="How do I use this model?",
            )
            sim_btn = gr.Button("πŸ“€ Test Webhook")

        with gr.Column():
            sim_result = gr.Textbox(label="Result", lines=8)

        sim_btn.click(
            fn=simulate_webhook,
            inputs=[sim_repo, sim_title, sim_comment],
            outputs=[sim_result],
        )

    return demo


# Mount Gradio app
gradio_app = create_gradio_app()
app = gr.mount_gradio_app(app, gradio_app, path="/gradio")


if __name__ == "__main__":
    print("πŸš€ Starting HF Discussion Bot with Tiny Agents...")
    print("πŸ“Š Dashboard: http://localhost:8001/gradio")
    print("πŸ”— Webhook: http://localhost:8001/webhook")
    uvicorn.run("server:app", host="0.0.0.0", port=8001, reload=True)