borodache commited on
Commit
27dae43
·
verified ·
1 Parent(s): 0b92bb9

Add new app.py

Browse files
Files changed (3) hide show
  1. app.py +186 -186
  2. requirements.txt +4 -7
  3. run-agent.py +34 -0
app.py CHANGED
@@ -1,187 +1,187 @@
1
- import json
2
- import asyncio
3
- from typing import Any
4
- from textblob import TextBlob
5
- import gradio as gr
6
- from mcp import Tool
7
- from mcp.server import Server
8
- from mcp.types import TextContent
9
-
10
- # Try to import SSE server (may need: pip install mcp[sse] or sse-starlette)
11
- try:
12
- from mcp.server.sse import SseServerTransport
13
- from starlette.applications import Starlette
14
- from starlette.routing import Route
15
- from starlette.responses import Response
16
- import uvicorn
17
- SSE_AVAILABLE = True
18
- except ImportError:
19
- SSE_AVAILABLE = False
20
- print("Warning: SSE dependencies not available. Install with: pip install sse-starlette uvicorn")
21
-
22
- # Shared sentiment analysis function
23
- def sentiment_analysis(text: str) -> dict:
24
- """
25
- Analyze the sentiment of the given text.
26
-
27
- Returns:
28
- dict: Contains polarity, subjectivity, and assessment
29
- """
30
- if not text or not text.strip():
31
- return {
32
- "error": "No text provided",
33
- "polarity": 0,
34
- "subjectivity": 0,
35
- "assessment": "neutral"
36
- }
37
-
38
- blob = TextBlob(text)
39
- sentiment = blob.sentiment
40
-
41
- result = {
42
- "polarity": round(sentiment.polarity, 2),
43
- "subjectivity": round(sentiment.subjectivity, 2),
44
- "assessment": "positive" if sentiment.polarity > 0 else "negative" if sentiment.polarity < 0 else "neutral"
45
- }
46
-
47
- return result
48
-
49
- # Gradio wrapper
50
- def sentiment_analysis_gradio(text: str) -> str:
51
- """Gradio-compatible wrapper that returns JSON string."""
52
- result = sentiment_analysis(text)
53
- return json.dumps(result, indent=2)
54
-
55
- # Create MCP server
56
- mcp_server = Server("sentiment-analysis")
57
-
58
- @mcp_server.list_tools()
59
- async def handle_list_tools() -> list[Tool]:
60
- """List available tools."""
61
- return [
62
- Tool(
63
- name="analyze_sentiment",
64
- description="Analyze the sentiment of text using TextBlob. Returns polarity (-1 to 1), subjectivity (0 to 1), and assessment (positive/negative/neutral).",
65
- inputSchema={
66
- "type": "object",
67
- "properties": {
68
- "text": {
69
- "type": "string",
70
- "description": "The text to analyze for sentiment"
71
- }
72
- },
73
- "required": ["text"]
74
- }
75
- )
76
- ]
77
-
78
- @mcp_server.call_tool()
79
- async def handle_call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
80
- """Handle tool calls."""
81
- if name == "analyze_sentiment":
82
- text = arguments.get("text", "")
83
- result = sentiment_analysis(text)
84
- return [TextContent(type="text", text=json.dumps(result, indent=2))]
85
-
86
- return [TextContent(type="text", text=f"Unknown tool: {name}")]
87
-
88
- # Create Gradio interface
89
- gradio_interface = gr.Interface(
90
- fn=sentiment_analysis_gradio,
91
- inputs=gr.Textbox(
92
- placeholder="Enter text to analyze...",
93
- label="Input Text",
94
- lines=5
95
- ),
96
- outputs=gr.Textbox(
97
- label="Sentiment Analysis Result (JSON)",
98
- lines=10
99
- ),
100
- title="Text Sentiment Analysis",
101
- description="Analyze the sentiment of text using TextBlob. Also exposes MCP server at http://localhost:8000/sse",
102
- examples=[
103
- ["I absolutely love this product! It's amazing and works perfectly."],
104
- ["This is the worst experience I've ever had. Terrible service."],
105
- ["The weather today is cloudy with a chance of rain."],
106
- ]
107
- )
108
-
109
- if SSE_AVAILABLE:
110
- # Create SSE endpoint for MCP
111
- async def handle_sse(request):
112
- """Handle SSE connections for MCP."""
113
- transport = SseServerTransport("/messages")
114
-
115
- async with transport.connect_sse(
116
- request.scope,
117
- request.receive,
118
- request._send
119
- ) as streams:
120
- await mcp_server.run(
121
- streams[0],
122
- streams[1],
123
- mcp_server.create_initialization_options()
124
- )
125
-
126
- return Response()
127
-
128
- async def handle_messages(request):
129
- """Handle message endpoint."""
130
- return Response("MCP Server Ready", media_type="text/plain")
131
-
132
- # Create Starlette app for MCP
133
- starlette_app = Starlette(
134
- routes=[
135
- Route("/sse", endpoint=handle_sse),
136
- Route("/messages", endpoint=handle_messages, methods=["POST"]),
137
- ]
138
- )
139
-
140
- def run_mcp_http_server():
141
- """Run MCP server over HTTP."""
142
- print("Starting MCP server on http://localhost:8000")
143
- uvicorn.run(starlette_app, host="0.0.0.0", port=8000, log_level="info")
144
-
145
- def main():
146
- """Run both servers."""
147
- import threading
148
-
149
- print("=" * 60)
150
- print("Starting Combined Sentiment Analysis Server")
151
- print("=" * 60)
152
- print("📊 Gradio UI: http://localhost:7860")
153
- print("🔌 MCP Server: http://localhost:8000/sse")
154
- print("=" * 60)
155
-
156
- # Start MCP server in separate thread
157
- mcp_thread = threading.Thread(target=run_mcp_http_server, daemon=True)
158
- mcp_thread.start()
159
-
160
- # Give MCP server time to start
161
- asyncio.sleep(1)
162
-
163
- # Start Gradio (blocking)
164
- gradio_interface.launch(
165
- server_name="0.0.0.0",
166
- server_port=7860,
167
- share=False
168
- )
169
-
170
- else:
171
- # Fallback: Gradio only if SSE not available
172
- def main():
173
- print("=" * 60)
174
- print("SSE dependencies not installed. Running Gradio only.")
175
- print("To enable MCP over HTTP, install: pip install sse-starlette uvicorn")
176
- print("=" * 60)
177
- print("📊 Gradio UI: http://localhost:7860")
178
- print("=" * 60)
179
-
180
- gradio_interface.launch(
181
- server_name="0.0.0.0",
182
- server_port=7860,
183
- share=False
184
- )
185
-
186
- if __name__ == "__main__":
187
  main()
 
1
+ import json
2
+ import asyncio
3
+ from typing import Any
4
+ from textblob import TextBlob
5
+ import gradio as gr
6
+ from mcp import Tool
7
+ from mcp.server import Server
8
+ from mcp.types import TextContent
9
+
10
+ # Try to import SSE server (may need: pip install mcp[sse] or sse-starlette)
11
+ try:
12
+ from mcp.server.sse import SseServerTransport
13
+ from starlette.applications import Starlette
14
+ from starlette.routing import Route
15
+ from starlette.responses import Response
16
+ import uvicorn
17
+ SSE_AVAILABLE = True
18
+ except ImportError:
19
+ SSE_AVAILABLE = False
20
+ print("Warning: SSE dependencies not available. Install with: pip install sse-starlette uvicorn")
21
+
22
+ # Shared sentiment analysis function
23
+ def sentiment_analysis(text: str) -> dict:
24
+ """
25
+ Analyze the sentiment of the given text.
26
+
27
+ Returns:
28
+ dict: Contains polarity, subjectivity, and assessment
29
+ """
30
+ if not text or not text.strip():
31
+ return {
32
+ "error": "No text provided",
33
+ "polarity": 0,
34
+ "subjectivity": 0,
35
+ "assessment": "neutral"
36
+ }
37
+
38
+ blob = TextBlob(text)
39
+ sentiment = blob.sentiment
40
+
41
+ result = {
42
+ "polarity": round(sentiment.polarity, 2),
43
+ "subjectivity": round(sentiment.subjectivity, 2),
44
+ "assessment": "positive" if sentiment.polarity > 0 else "negative" if sentiment.polarity < 0 else "neutral"
45
+ }
46
+
47
+ return result
48
+
49
+ # Gradio wrapper
50
+ def sentiment_analysis_gradio(text: str) -> str:
51
+ """Gradio-compatible wrapper that returns JSON string."""
52
+ result = sentiment_analysis(text)
53
+ return json.dumps(result, indent=2)
54
+
55
+ # Create MCP server
56
+ mcp_server = Server("sentiment-analysis")
57
+
58
+ @mcp_server.list_tools()
59
+ async def handle_list_tools() -> list[Tool]:
60
+ """List available tools."""
61
+ return [
62
+ Tool(
63
+ name="analyze_sentiment",
64
+ description="Analyze the sentiment of text using TextBlob. Returns polarity (-1 to 1), subjectivity (0 to 1), and assessment (positive/negative/neutral).",
65
+ inputSchema={
66
+ "type": "object",
67
+ "properties": {
68
+ "text": {
69
+ "type": "string",
70
+ "description": "The text to analyze for sentiment"
71
+ }
72
+ },
73
+ "required": ["text"]
74
+ }
75
+ )
76
+ ]
77
+
78
+ @mcp_server.call_tool()
79
+ async def handle_call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
80
+ """Handle tool calls."""
81
+ if name == "analyze_sentiment":
82
+ text = arguments.get("text", "")
83
+ result = sentiment_analysis(text)
84
+ return [TextContent(type="text", text=json.dumps(result, indent=2))]
85
+
86
+ return [TextContent(type="text", text=f"Unknown tool: {name}")]
87
+
88
+ # Create Gradio interface
89
+ gradio_interface = gr.Interface(
90
+ fn=sentiment_analysis_gradio,
91
+ inputs=gr.Textbox(
92
+ placeholder="Enter text to analyze...",
93
+ label="Input Text",
94
+ lines=5
95
+ ),
96
+ outputs=gr.Textbox(
97
+ label="Sentiment Analysis Result (JSON)",
98
+ lines=10
99
+ ),
100
+ title="Text Sentiment Analysis",
101
+ description="Analyze the sentiment of text using TextBlob. Also exposes MCP server at http://localhost:8000/sse",
102
+ examples=[
103
+ ["I absolutely love this product! It's amazing and works perfectly."],
104
+ ["This is the worst experience I've ever had. Terrible service."],
105
+ ["The weather today is cloudy with a chance of rain."],
106
+ ]
107
+ )
108
+
109
+ if SSE_AVAILABLE:
110
+ # Create SSE endpoint for MCP
111
+ async def handle_sse(request):
112
+ """Handle SSE connections for MCP."""
113
+ transport = SseServerTransport("/messages")
114
+
115
+ async with transport.connect_sse(
116
+ request.scope,
117
+ request.receive,
118
+ request._send
119
+ ) as streams:
120
+ await mcp_server.run(
121
+ streams[0],
122
+ streams[1],
123
+ mcp_server.create_initialization_options()
124
+ )
125
+
126
+ return Response()
127
+
128
+ async def handle_messages(request):
129
+ """Handle message endpoint."""
130
+ return Response("MCP Server Ready", media_type="text/plain")
131
+
132
+ # Create Starlette app for MCP
133
+ starlette_app = Starlette(
134
+ routes=[
135
+ Route("/sse", endpoint=handle_sse),
136
+ Route("/messages", endpoint=handle_messages, methods=["POST"]),
137
+ ]
138
+ )
139
+
140
+ def run_mcp_http_server():
141
+ """Run MCP server over HTTP."""
142
+ print("Starting MCP server on http://localhost:8000")
143
+ uvicorn.run(starlette_app, host="0.0.0.0", port=8000, log_level="info")
144
+
145
+ def main():
146
+ """Run both servers."""
147
+ import threading
148
+
149
+ print("=" * 60)
150
+ print("Starting Combined Sentiment Analysis Server")
151
+ print("=" * 60)
152
+ print("📊 Gradio UI: http://localhost:7860")
153
+ print("🔌 MCP Server: http://localhost:8000/sse")
154
+ print("=" * 60)
155
+
156
+ # Start MCP server in separate thread
157
+ mcp_thread = threading.Thread(target=run_mcp_http_server, daemon=True)
158
+ mcp_thread.start()
159
+
160
+ # Give MCP server time to start
161
+ asyncio.sleep(1)
162
+
163
+ # Start Gradio (blocking)
164
+ gradio_interface.launch(
165
+ server_name="0.0.0.0",
166
+ server_port=7860,
167
+ share=True
168
+ )
169
+
170
+ else:
171
+ # Fallback: Gradio only if SSE not available
172
+ def main():
173
+ print("=" * 60)
174
+ print("SSE dependencies not installed. Running Gradio only.")
175
+ print("To enable MCP over HTTP, install: pip install sse-starlette uvicorn")
176
+ print("=" * 60)
177
+ print("📊 Gradio UI: http://localhost:7860")
178
+ print("=" * 60)
179
+
180
+ gradio_interface.launch(
181
+ server_name="0.0.0.0",
182
+ server_port=7860,
183
+ share=True
184
+ )
185
+
186
+ if __name__ == "__main__":
187
  main()
requirements.txt CHANGED
@@ -1,7 +1,4 @@
1
- gradio[mcp]
2
- textblob
3
- mcp
4
- sse-starlette
5
- uvicorn
6
- textblob
7
- gradio
 
1
+ textblob
2
+ mcp
3
+ gradio
4
+ starlette
 
 
 
run-agent.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ HuggingFace MCP Agent Runner
4
+
5
+ This script provides a CLI interface to run HuggingFace MCP agents.
6
+ Usage: python run-agent.py <agent-config.json>
7
+ """
8
+
9
+ import sys
10
+ import asyncio
11
+ from pathlib import Path
12
+
13
+ def main():
14
+ if len(sys.argv) != 2:
15
+ print("Usage: python run-agent.py <agent-config.json>")
16
+ print("Example: python run-agent.py my-agent/agent.json")
17
+ sys.exit(1)
18
+
19
+ config_path = sys.argv[1]
20
+ if not Path(config_path).exists():
21
+ print(f"Error: Config file '{config_path}' not found")
22
+ sys.exit(1)
23
+
24
+ try:
25
+ from huggingface_hub.inference._mcp.cli import run_agent
26
+ asyncio.run(run_agent(config_path))
27
+ except KeyboardInterrupt:
28
+ print("\nAgent stopped by user")
29
+ except Exception as e:
30
+ print(f"Error running agent: {e}")
31
+ sys.exit(1)
32
+
33
+ if __name__ == "__main__":
34
+ main()