Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -10,28 +10,29 @@ from tenacity import retry, stop_after_attempt, wait_exponential
|
|
10 |
logging.basicConfig(level=logging.INFO)
|
11 |
logger = logging.getLogger(__name__)
|
12 |
|
13 |
-
#
|
14 |
-
HF_SPACE_URL = "https://manavraj-troubleshoot-mcp.hf.space"
|
15 |
|
16 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
17 |
def call_mcp_server(message, tool_type="knowledge_base"):
|
18 |
-
"""Call
|
19 |
try:
|
20 |
-
#
|
21 |
-
|
22 |
-
"knowledge_base":
|
23 |
-
"web_search":
|
24 |
-
"formatter":
|
25 |
}
|
26 |
|
27 |
-
|
|
|
28 |
|
29 |
-
logger.info(f"Calling MCP
|
30 |
|
31 |
response = requests.post(
|
32 |
-
|
33 |
-
json={"data": [message]
|
34 |
-
verify=False, #
|
35 |
timeout=30
|
36 |
)
|
37 |
|
@@ -45,166 +46,99 @@ def call_mcp_server(message, tool_type="knowledge_base"):
|
|
45 |
return data['data'][0]
|
46 |
|
47 |
except Exception as e:
|
48 |
-
logger.error(f"MCP
|
49 |
return f"MCP server error: {str(e)}"
|
50 |
|
51 |
def extract_thought_action_observation(response):
|
52 |
-
"""Extract
|
53 |
sections = {
|
54 |
'thought': '',
|
55 |
'action': '',
|
56 |
'observation': ''
|
57 |
}
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
|
|
63 |
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
if observation_match:
|
69 |
-
sections['observation'] = observation_match.group(1).strip()
|
70 |
|
71 |
return sections
|
72 |
|
73 |
-
# Initialize CodeAgent
|
74 |
agent = CodeAgent(
|
75 |
tools=[],
|
76 |
model="microsoft/DialoGPT-medium",
|
77 |
-
system_prompt="""
|
78 |
-
WORKFLOW:
|
79 |
-
For every user query, you MUST follow this exact structure:
|
80 |
-
THOUGHT: Analyze the user's problem and decide what action to take
|
81 |
-
- Identify the type of issue (technical problem, information request, formatting need)
|
82 |
-
- Determine which MCP server tool would be most appropriate
|
83 |
-
- Consider what information you need to provide a complete answer
|
84 |
-
ACTION: Specify exactly what action you will take
|
85 |
-
- "search_knowledge_base" for known technical issues (wifi, screen, hardware problems)
|
86 |
-
- "web_search" for current information, news, or unknown topics
|
87 |
-
- "format_response" for organizing or structuring information
|
88 |
-
- "direct_response" if you can answer without tools
|
89 |
-
OBSERVATION: Analyze the results and determine next steps
|
90 |
-
- Evaluate if the action provided sufficient information
|
91 |
-
- Identify if additional actions are needed
|
92 |
-
- Note any gaps in the information
|
93 |
-
FINAL RESPONSE: Provide a clear, helpful answer to the user
|
94 |
-
EXAMPLE:
|
95 |
-
User: "My wifi keeps disconnecting"
|
96 |
-
THOUGHT: The user has a wifi connectivity issue. This is a common technical problem that likely has solutions in our knowledge base. I should search the knowledge base first for wifi-related solutions.
|
97 |
-
ACTION: search_knowledge_base with query "wifi disconnecting problem"
|
98 |
-
OBSERVATION: The knowledge base provided basic wifi troubleshooting steps. These steps are helpful but I should also check for any recent wifi issues or advanced solutions via web search to provide comprehensive help.
|
99 |
-
FINAL RESPONSE: [Provide complete solution combining knowledge base and any additional insights]
|
100 |
-
Remember:
|
101 |
-
- Always use the THOUGHT-ACTION-OBSERVATION-FINAL RESPONSE structure
|
102 |
-
- Be specific about which tool you're using and why
|
103 |
-
- Provide actionable, clear solutions
|
104 |
-
- If one action isn't sufficient, explain what additional actions you'll take
|
105 |
-
{{managed_agents_descriptions}}
|
106 |
-
{{authorized_imports}}"""
|
107 |
)
|
108 |
|
109 |
def determine_tool_type(message):
|
110 |
-
"""Determine which
|
111 |
message_lower = message.lower()
|
|
|
|
|
|
|
112 |
|
113 |
-
|
114 |
-
tech_keywords = ["wifi", "screen", "computer", "laptop", "error", "problem", "issue", "broken", "not working"]
|
115 |
-
if any(keyword in message_lower for keyword in tech_keywords):
|
116 |
return "knowledge_base"
|
117 |
-
|
118 |
-
# Search queries - use web search
|
119 |
-
search_keywords = ["search", "find", "news", "latest", "current", "what is", "how to", "information about"]
|
120 |
-
if any(keyword in message_lower for keyword in search_keywords):
|
121 |
return "web_search"
|
122 |
-
|
123 |
-
# Formatting requests - use formatter
|
124 |
-
format_keywords = ["format", "organize", "list", "steps", "number"]
|
125 |
-
if any(keyword in message_lower for keyword in format_keywords):
|
126 |
return "formatter"
|
127 |
-
|
128 |
-
# Default to knowledge base for technical support
|
129 |
return "knowledge_base"
|
130 |
|
131 |
def chat_interface(message, history):
|
132 |
-
"""Enhanced chat interface with
|
133 |
-
|
134 |
try:
|
135 |
-
#
|
136 |
-
thinking_prompt = f""
|
137 |
-
User Query: "{message}"
|
138 |
-
|
139 |
-
Follow the THOUGHT-ACTION-OBSERVATION cycle:
|
140 |
-
|
141 |
-
THOUGHT: Analyze this query and determine the best approach.
|
142 |
-
"""
|
143 |
-
|
144 |
-
# Get agent's initial thought process
|
145 |
agent_response = agent.run(thinking_prompt)
|
|
|
146 |
if not isinstance(agent_response, str):
|
147 |
-
|
148 |
|
149 |
-
# Extract thought and determine action
|
150 |
cycle_parts = extract_thought_action_observation(agent_response)
|
151 |
-
|
152 |
-
# Determine tool type based on message content and agent's thought
|
153 |
tool_type = determine_tool_type(message)
|
154 |
|
155 |
-
#
|
156 |
mcp_response = call_mcp_server(message, tool_type)
|
157 |
|
158 |
-
#
|
159 |
final_prompt = f"""
|
160 |
-
User Query:
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
OBSERVATION: The MCP server returned: "{mcp_response}"
|
167 |
-
|
168 |
-
FINAL RESPONSE: Based on the observation, provide a complete, helpful response to the user. If the MCP server response is insufficient, explain what additional steps might be needed.
|
169 |
"""
|
170 |
|
171 |
final_response = agent.run(final_prompt)
|
172 |
if not isinstance(final_response, str):
|
173 |
final_response = str(final_response)
|
174 |
|
175 |
-
|
176 |
-
|
177 |
-
⚡ **ACTION:** Used {tool_type.replace('_', ' ')} tool
|
178 |
👁️ **OBSERVATION:** {mcp_response[:200]}{'...' if len(mcp_response) > 200 else ''}
|
179 |
-
✅ **SOLUTION
|
180 |
-
{final_response}"""
|
181 |
-
|
182 |
-
return formatted_response
|
183 |
|
184 |
except Exception as e:
|
185 |
-
logger.error(f"
|
186 |
-
|
187 |
-
tool_type = determine_tool_type(message)
|
188 |
-
mcp_response = call_mcp_server(message, tool_type)
|
189 |
-
|
190 |
-
return f"""🤔 **THOUGHT:** You have a {tool_type.replace('_', ' ')} related query.
|
191 |
-
⚡ **ACTION:** Consulted the MCP server using {tool_type} tool.
|
192 |
-
👁️ **OBSERVATION:** Found relevant information.
|
193 |
-
✅ **SOLUTION:**
|
194 |
-
{mcp_response}"""
|
195 |
|
196 |
-
#
|
197 |
demo = gr.ChatInterface(
|
198 |
fn=chat_interface,
|
199 |
-
title="🔧
|
200 |
-
description="Technical support powered by MCP server tools using Thought-Action-Observation methodology",
|
201 |
examples=[
|
202 |
-
"
|
203 |
-
"
|
204 |
-
"
|
205 |
-
|
206 |
-
],
|
207 |
-
chatbot=gr.Chatbot(height=600)
|
208 |
)
|
209 |
|
210 |
if __name__ == "__main__":
|
|
|
10 |
logging.basicConfig(level=logging.INFO)
|
11 |
logger = logging.getLogger(__name__)
|
12 |
|
13 |
+
# Correct URL based on your Space
|
14 |
+
HF_SPACE_URL = "https://manavraj-troubleshoot-mcp.hf.space"
|
15 |
|
16 |
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
|
17 |
def call_mcp_server(message, tool_type="knowledge_base"):
|
18 |
+
"""Call MCP server with proper endpoint routing"""
|
19 |
try:
|
20 |
+
# Map tool types to their respective API endpoints
|
21 |
+
endpoint_map = {
|
22 |
+
"knowledge_base": "api/knowledge_base",
|
23 |
+
"web_search": "api/web_search",
|
24 |
+
"formatter": "api/formatter"
|
25 |
}
|
26 |
|
27 |
+
endpoint = endpoint_map.get(tool_type, "api/knowledge_base")
|
28 |
+
url = f"{HF_SPACE_URL}/{endpoint}"
|
29 |
|
30 |
+
logger.info(f"Calling MCP endpoint: {url}")
|
31 |
|
32 |
response = requests.post(
|
33 |
+
url,
|
34 |
+
json={"data": [message]},
|
35 |
+
verify=False, # Temporary for debugging
|
36 |
timeout=30
|
37 |
)
|
38 |
|
|
|
46 |
return data['data'][0]
|
47 |
|
48 |
except Exception as e:
|
49 |
+
logger.error(f"MCP call failed: {str(e)}")
|
50 |
return f"MCP server error: {str(e)}"
|
51 |
|
52 |
def extract_thought_action_observation(response):
|
53 |
+
"""Extract TAO cycle from response"""
|
54 |
sections = {
|
55 |
'thought': '',
|
56 |
'action': '',
|
57 |
'observation': ''
|
58 |
}
|
59 |
|
60 |
+
patterns = {
|
61 |
+
'thought': r'(?:THOUGHT|Thought):\s*(.*?)(?=(?:ACTION|Action|OBSERVATION|Observation|$))',
|
62 |
+
'action': r'(?:ACTION|Action):\s*(.*?)(?=(?:OBSERVATION|Observation|FINAL|Final|$))',
|
63 |
+
'observation': r'(?:OBSERVATION|Observation):\s*(.*?)(?=(?:FINAL|Final|$))'
|
64 |
+
}
|
65 |
|
66 |
+
for section, pattern in patterns.items():
|
67 |
+
match = re.search(pattern, response, re.DOTALL | re.IGNORECASE)
|
68 |
+
if match:
|
69 |
+
sections[section] = match.group(1).strip()
|
|
|
|
|
70 |
|
71 |
return sections
|
72 |
|
73 |
+
# Initialize CodeAgent
|
74 |
agent = CodeAgent(
|
75 |
tools=[],
|
76 |
model="microsoft/DialoGPT-medium",
|
77 |
+
system_prompt="""[Previous system prompt remains unchanged]"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
)
|
79 |
|
80 |
def determine_tool_type(message):
|
81 |
+
"""Determine which tool to use"""
|
82 |
message_lower = message.lower()
|
83 |
+
tech_keywords = ["wifi", "screen", "computer", "error"]
|
84 |
+
search_keywords = ["search", "find", "news", "how to"]
|
85 |
+
format_keywords = ["format", "organize", "steps"]
|
86 |
|
87 |
+
if any(k in message_lower for k in tech_keywords):
|
|
|
|
|
88 |
return "knowledge_base"
|
89 |
+
elif any(k in message_lower for k in search_keywords):
|
|
|
|
|
|
|
90 |
return "web_search"
|
91 |
+
elif any(k in message_lower for k in format_keywords):
|
|
|
|
|
|
|
92 |
return "formatter"
|
|
|
|
|
93 |
return "knowledge_base"
|
94 |
|
95 |
def chat_interface(message, history):
|
96 |
+
"""Enhanced chat interface with proper error handling"""
|
|
|
97 |
try:
|
98 |
+
# Get initial thought
|
99 |
+
thinking_prompt = f"User Query: {message}\n\nTHOUGHT: Analyze this query"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
agent_response = agent.run(thinking_prompt)
|
101 |
+
|
102 |
if not isinstance(agent_response, str):
|
103 |
+
agent_response = str(agent_response)
|
104 |
|
|
|
105 |
cycle_parts = extract_thought_action_observation(agent_response)
|
|
|
|
|
106 |
tool_type = determine_tool_type(message)
|
107 |
|
108 |
+
# Call MCP server
|
109 |
mcp_response = call_mcp_server(message, tool_type)
|
110 |
|
111 |
+
# Generate final response
|
112 |
final_prompt = f"""
|
113 |
+
User Query: {message}
|
114 |
+
THOUGHT: {cycle_parts.get('thought', 'Analysis complete')}
|
115 |
+
ACTION: Used {tool_type} tool
|
116 |
+
OBSERVATION: {mcp_response}
|
117 |
+
FINAL RESPONSE: Provide a complete solution
|
|
|
|
|
|
|
|
|
118 |
"""
|
119 |
|
120 |
final_response = agent.run(final_prompt)
|
121 |
if not isinstance(final_response, str):
|
122 |
final_response = str(final_response)
|
123 |
|
124 |
+
return f"""🤔 **THOUGHT:** {cycle_parts.get('thought', '')}
|
125 |
+
⚡ **ACTION:** Used {tool_type.replace('_', ' ')}
|
|
|
126 |
👁️ **OBSERVATION:** {mcp_response[:200]}{'...' if len(mcp_response) > 200 else ''}
|
127 |
+
✅ **SOLUTION:**\n{final_response}"""
|
|
|
|
|
|
|
128 |
|
129 |
except Exception as e:
|
130 |
+
logger.error(f"Chat error: {str(e)}")
|
131 |
+
return f"Error processing request: {str(e)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
+
# Gradio interface
|
134 |
demo = gr.ChatInterface(
|
135 |
fn=chat_interface,
|
136 |
+
title="🔧 Technical Support Agent",
|
|
|
137 |
examples=[
|
138 |
+
"My wifi keeps disconnecting",
|
139 |
+
"Search for latest tech news",
|
140 |
+
"Format these steps: Restart. Check cables. Test"
|
141 |
+
]
|
|
|
|
|
142 |
)
|
143 |
|
144 |
if __name__ == "__main__":
|