File size: 10,203 Bytes
812b4d8
8c03bb8
812b4d8
7dd9b39
812b4d8
4d5810f
812b4d8
 
 
 
 
 
 
b7c0594
 
 
812b4d8
 
4d5810f
812b4d8
 
 
 
4d5810f
812b4d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1cf2b92
812b4d8
 
8c03bb8
 
 
 
 
1cf2b92
8c03bb8
 
 
1cf2b92
8c03bb8
 
 
812b4d8
 
1cf2b92
 
812b4d8
 
1cf2b92
812b4d8
1cf2b92
8c03bb8
 
 
 
1cf2b92
 
812b4d8
1cf2b92
812b4d8
 
 
1cf2b92
812b4d8
 
 
1cf2b92
812b4d8
 
 
 
 
1cf2b92
 
8c03bb8
 
 
 
7dd9b39
 
8c03bb8
 
 
 
1cf2b92
8c03bb8
 
 
 
 
 
1cf2b92
8c03bb8
 
 
 
 
 
 
 
 
 
 
 
1cf2b92
8c03bb8
 
 
 
 
 
1cf2b92
8c03bb8
 
 
 
 
 
 
 
 
 
1cf2b92
8c03bb8
 
 
812b4d8
bf33fca
812b4d8
 
 
 
 
 
 
b7c0594
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
812b4d8
 
 
7dd9b39
 
812b4d8
 
 
 
b7c0594
812b4d8
 
 
 
 
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
import json
import os
import requests
import gradio as gr
from smolagents import Tool, CodeAgent, InferenceClientModel

class SentimentAnalysisTool(Tool):
    """
    Tool that connects to the MCP sentiment analysis server.
    Analyzes the sentiment of text using the remote MCP server.
    """
    name = "sentiment_analysis"
    description = """
    Analyze the sentiment of text to determine if it's positive, negative, or neutral.
    Use this tool when the user asks about sentiment, emotion, feeling, or opinion in text.
    Returns polarity score (-1 to 1), subjectivity (0 to 1), and assessment (positive/negative/neutral).
    This tool connects to the MCP sentiment analysis server.
    """

    inputs = {
        "text": {
            "type": "string",
            "description": "The text to analyze for sentiment",
        }
    }

    output_type = "string"

    def __init__(self, mcp_server_url: str = "https://s2v-general-mcp-sentiment.hf.space/gradio_api/mcp/"):
        """
        Initialize the sentiment analysis tool with MCP server URL.
        
        Args:
            mcp_server_url: The URL of the MCP sentiment analysis server
        """
        super().__init__()
        self.mcp_server_url = mcp_server_url

    def forward(self, text: str) -> str:
        """
        Call the MCP sentiment analysis server to analyze text.
        
        Args:
            text: The text to analyze
            
        Returns:
            JSON string with sentiment analysis results
        """
        try:
            # Call the Gradio MCP endpoint
            # Gradio MCP endpoints typically use SSE or JSON-RPC over HTTP
            # Try calling the function directly via the Gradio API
            api_url = self.mcp_server_url.rstrip('/')
            if not api_url.endswith('/api'):
                # Try the Gradio predict endpoint
                predict_url = api_url.replace('/gradio_api/mcp/', '/api/predict/')
            else:
                predict_url = api_url
            
            # Try calling via Gradio's predict API
            payload = {
                "data": [text],
                "fn_index": 0
            }
            
            response = requests.post(
                predict_url,
                json=payload,
                headers={"Content-Type": "application/json"},
                timeout=10
            )
            
            if response.status_code == 200:
                result = response.json()
                # Gradio returns {"data": [result]}
                if "data" in result and len(result["data"]) > 0:
                    return result["data"][0]
                else:
                    return json.dumps(result, indent=2)
            else:
                # Fallback: Use TextBlob directly (same as MCP server)
                from textblob import TextBlob
                blob = TextBlob(text)
                sentiment = blob.sentiment
                result = {
                    "polarity": round(sentiment.polarity, 2),
                    "subjectivity": round(sentiment.subjectivity, 2),
                    "assessment": "positive" if sentiment.polarity > 0 else "negative" if sentiment.polarity < 0 else "neutral"
                }
                return json.dumps(result, indent=2)
                
        except requests.exceptions.RequestException:
            # Fallback: Use TextBlob directly (same as MCP server)
            try:
                from textblob import TextBlob
                blob = TextBlob(text)
                sentiment = blob.sentiment
                result = {
                    "polarity": round(sentiment.polarity, 2),
                    "subjectivity": round(sentiment.subjectivity, 2),
                    "assessment": "positive" if sentiment.polarity > 0 else "negative" if sentiment.polarity < 0 else "neutral"
                }
                return json.dumps(result, indent=2)
            except Exception as e:
                return f"Error analyzing sentiment: {str(e)}"
        except Exception as e:
            return f"Error: {str(e)}"


# Initialize the sentiment analysis tool with MCP server connection
sentiment_tool = SentimentAnalysisTool()

# Create the agent with the MCP sentiment analysis tool
# ============================================================================
# LLM Configuration - Current: Qwen/Qwen2.5-72B-Instruct via HuggingFace Inference API
# ============================================================================
# 
# API KEY SETUP:
#   
#   HUGGINGFACE SPACE DEPLOYMENT:
#   - HF_TOKEN is automatically available in HuggingFace Spaces
#   - You can also set secrets in Space Settings → Secrets
#   - Add secret: HF_TOKEN with your token value
#
#   LOCAL SETUP:
#   1. Environment variable: export HF_TOKEN="your_huggingface_token"
#   2. Or login via: huggingface-cli login
#
#   Get your HuggingFace token from: https://huggingface.co/settings/tokens
#
# PRIMARY MODEL (Currently Active):
#   Model: Qwen/Qwen2.5-72B-Instruct
#   Provider: HuggingFace Inference API (default, no provider specified)
#   Usage: High-performance model via HuggingFace Inference API
#
# ALTERNATIVE MODELS (for rate limit fallbacks):
#   If you hit rate limits, uncomment one of these alternatives:
#
# Option 1: Other HuggingFace Inference API models (uses HF_TOKEN)
#   model=InferenceClientModel(model_id="meta-llama/Meta-Llama-3-8B-Instruct", token=api_token)
#   model=InferenceClientModel(model_id="mistralai/Mistral-7B-Instruct-v0.2", token=api_token)
#   model=InferenceClientModel(model_id="Qwen/Qwen2.5-7B-Instruct", token=api_token)
#   model=InferenceClientModel(model_id="google/gemma-2-2b-it", token=api_token)
#   model=InferenceClientModel(model_id="Qwen/Qwen2.5-32B-Instruct", token=api_token)
#   model=InferenceClientModel(model_id="meta-llama/Llama-3.1-70B-Instruct", token=api_token)
#
# Option 2: OpenAI (requires API key: export OPENAI_API_KEY="your_key")
#   from smolagents import OpenAIModel
#   model=OpenAIModel(model="gpt-4o-mini")  # or "gpt-4o", "gpt-3.5-turbo"
#
# Option 3: Anthropic Claude (requires API key: export ANTHROPIC_API_KEY="your_key")
#   from smolagents import AnthropicModel
#   model=AnthropicModel(model="claude-3-5-sonnet-20241022")  # or "claude-3-opus-20240229"
#
# Option 4: Local Ollama (for offline/local use)
#   from smolagents import OllamaModel
#   model=OllamaModel(model="llama3.1")  # or "mistral", "qwen", etc.
#
# ============================================================================

# Get API token from environment variables
# Priority: HF_TOKEN > HUGGINGFACE_TOKEN
# In HuggingFace Spaces, HF_TOKEN is automatically available
api_token = (
    os.getenv("HF_TOKEN") or 
    os.getenv("HUGGINGFACE_TOKEN")
)

# Check if running in HuggingFace Space
is_hf_space = os.getenv("SPACE_ID") is not None

# Initialize the model with API token
# Using HuggingFace Inference API (no provider specified = default HF Inference API)
if api_token:
    try:
        agent = CodeAgent(
            tools=[sentiment_tool],
            model=InferenceClientModel(
                model_id="Qwen/Qwen2.5-72B-Instruct",
                token=api_token  # Uses HuggingFace Inference API by default
            )
        )
        if is_hf_space:
            print("✅ Agent initialized successfully using HuggingFace Space token")
        else:
            print("✅ Agent initialized successfully using local API token")
    except Exception as e:
        print(f"❌ Error initializing agent with token: {e}")
        print("Falling back to tokenless initialization...")
        agent = CodeAgent(
            tools=[sentiment_tool],
            model=InferenceClientModel(
                model_id="Qwen/Qwen2.5-72B-Instruct"
            )
        )
else:
    # Try without explicit token (will use HuggingFace login if available)
    if is_hf_space:
        print("⚠️ Warning: No API token found in HuggingFace Space secrets.")
        print("Please add HF_TOKEN in Space Settings → Secrets")
    else:
        print("⚠️ Warning: No API token found. Attempting to use HuggingFace login...")
        print("If this fails, set one of these environment variables:")
        print("  - HF_TOKEN (HuggingFace token)")
        print("  - HUGGINGFACE_TOKEN (alternative HuggingFace token)")
        print("\nOr login via: huggingface-cli login")
    
    agent = CodeAgent(
        tools=[sentiment_tool],
        model=InferenceClientModel(
            model_id="Qwen/Qwen2.5-72B-Instruct"
        )
    )


def chat_with_agent(message, history, request: gr.Request):
    """
    Wrapper function to use the agent's run method with Gradio.
    The agent is stateful and manages history internally.
    """
    try:
        # Run the agent and get the response
        result = agent.run(message)
        
        # Convert result to string if it's not already
        if isinstance(result, dict):
            # Format dictionary results nicely
            if "polarity" in result and "subjectivity" in result and "assessment" in result:
                formatted_result = f"""Sentiment Analysis Results:
- **Polarity**: {result['polarity']} (range: -1 to 1)
- **Subjectivity**: {result['subjectivity']} (range: 0 to 1)
- **Assessment**: {result['assessment'].upper()}"""
                return formatted_result
            else:
                # Format other dictionaries as JSON
                import json
                return json.dumps(result, indent=2)
        elif isinstance(result, (list, tuple)):
            # Convert lists/tuples to string
            return str(result)
        else:
            # Already a string or other type that can be converted
            return str(result)
    except Exception as e:
        return f"Error: {str(e)}"


# Create and launch the Gradio Chat Interface
demo = gr.ChatInterface(
    fn=chat_with_agent,
    title="MCP Sentiment Analysis Agent",
    description="Chat with an AI agent that can analyze sentiment using the MCP sentiment analysis server.",
    chatbot=gr.Chatbot(layout="bubble", show_copy_button=True, type="messages"),
    type="messages"
)

if __name__ == "__main__":
    demo.launch()