ysharma HF Staff commited on
Commit
87bbbcd
Β·
verified Β·
1 Parent(s): fdd3874

Update chat_handler.py

Browse files
Files changed (1) hide show
  1. chat_handler.py +49 -33
chat_handler.py CHANGED
@@ -1,9 +1,10 @@
1
  """
2
- Chat handling logic for Universal MCP Client - Updated with ChatMessage support
3
  """
4
  import re
5
  import logging
6
  import traceback
 
7
  from datetime import datetime
8
  from typing import Dict, Any, List, Tuple, Optional
9
  import gradio as gr
@@ -16,16 +17,26 @@ from mcp_client import UniversalMCPClient
16
  logger = logging.getLogger(__name__)
17
 
18
  class ChatHandler:
19
- """Handles chat interactions with Claude and MCP servers using ChatMessage dataclass"""
20
 
21
  def __init__(self, mcp_client: UniversalMCPClient):
22
  self.mcp_client = mcp_client
23
 
24
  def process_multimodal_message(self, message: Dict[str, Any], history: List) -> Tuple[List[ChatMessage], Dict[str, Any]]:
25
- """Enhanced MCP chat function with multimodal input support and ChatMessage formatting"""
26
 
27
- if not self.mcp_client.anthropic_client:
28
- error_msg = "❌ Anthropic API key not configured. Please set ANTHROPIC_API_KEY environment variable."
 
 
 
 
 
 
 
 
 
 
29
  history.append(ChatMessage(role="user", content=error_msg))
30
  history.append(ChatMessage(role="assistant", content=error_msg))
31
  return history, gr.MultimodalTextbox(value=None, interactive=False)
@@ -44,7 +55,7 @@ class ChatHandler:
44
  user_text = message
45
  user_files = []
46
 
47
- logger.info(f"πŸ’¬ Processing multimodal message:")
48
  logger.info(f" πŸ“ Text: {user_text}")
49
  logger.info(f" πŸ“ Files: {len(user_files)} files uploaded")
50
  logger.info(f" πŸ“‹ History type: {type(history)}, length: {len(history)}")
@@ -86,11 +97,14 @@ class ChatHandler:
86
  if not user_text.strip() and not user_files:
87
  return history, gr.MultimodalTextbox(value=None, interactive=False)
88
 
89
- # Create messages for Claude API
90
- messages = self._prepare_claude_messages(history)
91
 
92
- # Process the chat and get structured responses
93
- response_messages = self._call_claude_api(messages, user_files)
 
 
 
94
 
95
  # Add all response messages to history
96
  history.extend(response_messages)
@@ -112,11 +126,11 @@ class ChatHandler:
112
  history.append(ChatMessage(role="assistant", content=error_msg))
113
  return history, gr.MultimodalTextbox(value=None, interactive=False)
114
 
115
- def _prepare_claude_messages(self, history: List) -> List[Dict[str, Any]]:
116
- """Convert history (ChatMessage or dict) to Claude API format"""
117
  messages = []
118
 
119
- # Convert history to Claude API format (text only for context)
120
  recent_history = history[-16:] if len(history) > 16 else history
121
  for msg in recent_history:
122
  # Handle both ChatMessage objects and dictionary format for backward compatibility
@@ -160,8 +174,8 @@ class ChatHandler:
160
 
161
  return messages
162
 
163
- def _call_claude_api(self, messages: List[Dict[str, Any]], user_files: List[str]) -> List[ChatMessage]:
164
- """Call Claude API and return structured ChatMessage responses"""
165
 
166
  # Check if we have MCP servers to use
167
  if not self.mcp_client.servers:
@@ -169,6 +183,26 @@ class ChatHandler:
169
  else:
170
  return self._call_claude_with_mcp(messages, user_files)
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  def _call_claude_without_mcp(self, messages: List[Dict[str, Any]]) -> List[ChatMessage]:
173
  """Call Claude API without MCP servers"""
174
  logger.info("πŸ’¬ No MCP servers available, using regular Claude chat")
@@ -501,26 +535,8 @@ IMPORTANT - For uploaded images:
501
  - **Image Editing/Enhancement**: Use MCP image processing tools
502
  - **Image Generation**: Use MCP image generation tools
503
 
504
- IMPORTANT - File URL Conversion for MCP Tools:
505
- When using MCP tools that require file inputs, you need to be aware that uploaded files have local paths that remote MCP servers cannot access.
506
-
507
- For uploaded files in MCP tool calls:
508
- - If an MCP tool fails with "Invalid file data format" or similar errors about file paths
509
- - The issue is that remote MCP servers cannot access local file paths like '/tmp/gradio/...'
510
- - In such cases, inform the user that the MCP server requires files to be accessible via public URLs
511
- - Suggest that they need a "File Upload" MCP server or that the specific MCP server may need configuration for file handling
512
-
513
- Current uploaded files that may need URL conversion:
514
- {uploaded_files_context}
515
-
516
  IMPORTANT - GRADIO MEDIA DISPLAY:
517
  When MCP tools return media, end your response with "MEDIA_GENERATED: [URL]" where [URL] is the actual media URL.
518
 
519
- Examples:
520
- - User uploads image + "What's in this image?" β†’ Use NATIVE vision (no MCP needed)
521
- - User uploads image + "Make this vintage" β†’ Use MCP image editing tool
522
- - User says "Generate a sunset image" β†’ Use MCP image generation tool
523
- - User uploads audio + "Transcribe this" β†’ Use MCP transcription tool
524
-
525
  Current time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
526
  Available MCP servers: {list(self.mcp_client.servers.keys())}"""
 
1
  """
2
+ Chat handling logic for Universal MCP Client - Enhanced with Inference Provider Support
3
  """
4
  import re
5
  import logging
6
  import traceback
7
+ import asyncio
8
  from datetime import datetime
9
  from typing import Dict, Any, List, Tuple, Optional
10
  import gradio as gr
 
17
  logger = logging.getLogger(__name__)
18
 
19
  class ChatHandler:
20
+ """Handles chat interactions with multiple LLM backends and MCP servers using ChatMessage dataclass"""
21
 
22
  def __init__(self, mcp_client: UniversalMCPClient):
23
  self.mcp_client = mcp_client
24
 
25
  def process_multimodal_message(self, message: Dict[str, Any], history: List) -> Tuple[List[ChatMessage], Dict[str, Any]]:
26
+ """Enhanced MCP chat function with multimodal input support and multiple LLM backends"""
27
 
28
+ # Check if any LLM backend is configured
29
+ backend_configured = False
30
+
31
+ if self.mcp_client.anthropic_client and AppConfig.ANTHROPIC_API_KEY:
32
+ backend_configured = True
33
+ backend_type = "anthropic"
34
+ elif self.mcp_client.hf_client and self.mcp_client.current_provider:
35
+ backend_configured = True
36
+ backend_type = "hf_inference"
37
+
38
+ if not backend_configured:
39
+ error_msg = "❌ No LLM backend configured. Please configure either Anthropic API key or HuggingFace Inference Provider."
40
  history.append(ChatMessage(role="user", content=error_msg))
41
  history.append(ChatMessage(role="assistant", content=error_msg))
42
  return history, gr.MultimodalTextbox(value=None, interactive=False)
 
55
  user_text = message
56
  user_files = []
57
 
58
+ logger.info(f"πŸ’¬ Processing multimodal message with {backend_type} backend:")
59
  logger.info(f" πŸ“ Text: {user_text}")
60
  logger.info(f" πŸ“ Files: {len(user_files)} files uploaded")
61
  logger.info(f" πŸ“‹ History type: {type(history)}, length: {len(history)}")
 
97
  if not user_text.strip() and not user_files:
98
  return history, gr.MultimodalTextbox(value=None, interactive=False)
99
 
100
+ # Create messages for LLM API
101
+ messages = self._prepare_llm_messages(history)
102
 
103
+ # Process the chat based on backend type
104
+ if backend_type == "anthropic":
105
+ response_messages = self._call_anthropic_api(messages, user_files)
106
+ else: # hf_inference
107
+ response_messages = self._call_hf_inference_api(messages, user_files)
108
 
109
  # Add all response messages to history
110
  history.extend(response_messages)
 
126
  history.append(ChatMessage(role="assistant", content=error_msg))
127
  return history, gr.MultimodalTextbox(value=None, interactive=False)
128
 
129
+ def _prepare_llm_messages(self, history: List) -> List[Dict[str, Any]]:
130
+ """Convert history (ChatMessage or dict) to LLM API format"""
131
  messages = []
132
 
133
+ # Convert history to LLM API format (text only for context)
134
  recent_history = history[-16:] if len(history) > 16 else history
135
  for msg in recent_history:
136
  # Handle both ChatMessage objects and dictionary format for backward compatibility
 
174
 
175
  return messages
176
 
177
+ def _call_anthropic_api(self, messages: List[Dict[str, Any]], user_files: List[str]) -> List[ChatMessage]:
178
+ """Call Anthropic API (existing implementation)"""
179
 
180
  # Check if we have MCP servers to use
181
  if not self.mcp_client.servers:
 
183
  else:
184
  return self._call_claude_with_mcp(messages, user_files)
185
 
186
+ def _call_hf_inference_api(self, messages: List[Dict[str, Any]], user_files: List[str]) -> List[ChatMessage]:
187
+ """Call HuggingFace Inference API with custom MCP implementation"""
188
+
189
+ # Run async call in sync context
190
+ def run_async():
191
+ loop = asyncio.new_event_loop()
192
+ asyncio.set_event_loop(loop)
193
+ try:
194
+ return loop.run_until_complete(
195
+ self.mcp_client.call_llm_with_mcp(messages, user_files)
196
+ )
197
+ finally:
198
+ loop.close()
199
+
200
+ try:
201
+ return run_async()
202
+ except Exception as e:
203
+ logger.error(f"HF Inference API error: {e}")
204
+ return [ChatMessage(role="assistant", content=f"❌ Error with HF Inference: {str(e)}")]
205
+
206
  def _call_claude_without_mcp(self, messages: List[Dict[str, Any]]) -> List[ChatMessage]:
207
  """Call Claude API without MCP servers"""
208
  logger.info("πŸ’¬ No MCP servers available, using regular Claude chat")
 
535
  - **Image Editing/Enhancement**: Use MCP image processing tools
536
  - **Image Generation**: Use MCP image generation tools
537
 
 
 
 
 
 
 
 
 
 
 
 
 
538
  IMPORTANT - GRADIO MEDIA DISPLAY:
539
  When MCP tools return media, end your response with "MEDIA_GENERATED: [URL]" where [URL] is the actual media URL.
540
 
 
 
 
 
 
 
541
  Current time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
542
  Available MCP servers: {list(self.mcp_client.servers.keys())}"""