Update chat_handler.py
Browse files- chat_handler.py +40 -32
chat_handler.py
CHANGED
|
@@ -75,7 +75,7 @@ class ChatHandler:
|
|
| 75 |
user_text = ""
|
| 76 |
user_files = []
|
| 77 |
uploaded_file_urls = [] # Store uploaded file URLs
|
| 78 |
-
self.file_url_mapping = {} #
|
| 79 |
|
| 80 |
try:
|
| 81 |
# Handle multimodal input - message is a dict with 'text' and 'files'
|
|
@@ -124,6 +124,7 @@ class ChatHandler:
|
|
| 124 |
uploaded_url = self._upload_file_to_gradio_server(file_path)
|
| 125 |
# Store the mapping
|
| 126 |
self.file_url_mapping[file_path] = uploaded_url
|
|
|
|
| 127 |
logger.info(f" ✅ Uploaded File URL: {uploaded_url}")
|
| 128 |
|
| 129 |
# Add to history with public URL
|
|
@@ -169,8 +170,8 @@ class ChatHandler:
|
|
| 169 |
return history, gr.MultimodalTextbox(value=None, interactive=False)
|
| 170 |
|
| 171 |
def _prepare_hf_messages(self, history: List, uploaded_file_urls: List[str] = None) -> List[Dict[str, Any]]:
|
| 172 |
-
"""Convert history (ChatMessage or dict) to
|
| 173 |
-
messages = []
|
| 174 |
|
| 175 |
# Get optimal context settings for current model/provider
|
| 176 |
if self.mcp_client.current_model and self.mcp_client.current_provider:
|
|
@@ -186,6 +187,7 @@ class ChatHandler:
|
|
| 186 |
# Convert history to HF API format (text only for context)
|
| 187 |
recent_history = history[-max_history:] if len(history) > max_history else history
|
| 188 |
|
|
|
|
| 189 |
for msg in recent_history:
|
| 190 |
# Handle both ChatMessage objects and dictionary format for backward compatibility
|
| 191 |
if hasattr(msg, 'role'): # ChatMessage object
|
|
@@ -197,39 +199,45 @@ class ChatHandler:
|
|
| 197 |
else:
|
| 198 |
continue # Skip invalid messages
|
| 199 |
|
| 200 |
-
if role
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
if isinstance(content, dict):
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
if file_path.startswith('http'):
|
| 208 |
-
# It's already a public URL
|
| 209 |
-
if AppConfig.is_image_file(file_path):
|
| 210 |
-
content = f"[User uploaded an image: {file_path}]"
|
| 211 |
-
elif AppConfig.is_audio_file(file_path):
|
| 212 |
-
content = f"[User uploaded an audio file: {file_path}]"
|
| 213 |
-
elif AppConfig.is_video_file(file_path):
|
| 214 |
-
content = f"[User uploaded a video file: {file_path}]"
|
| 215 |
-
else:
|
| 216 |
-
content = f"[User uploaded a file: {file_path}]"
|
| 217 |
-
else:
|
| 218 |
-
# Local path - mention it's not accessible to remote servers
|
| 219 |
-
content = f"[User uploaded a file (local path, not accessible to remote servers): {file_path}]"
|
| 220 |
else:
|
| 221 |
-
|
|
|
|
| 222 |
elif isinstance(content, (list, tuple)):
|
| 223 |
-
|
| 224 |
elif content is None:
|
| 225 |
-
|
| 226 |
else:
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
messages.
|
| 230 |
-
"
|
| 231 |
-
|
| 232 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
|
| 234 |
return messages
|
| 235 |
|
|
|
|
| 75 |
user_text = ""
|
| 76 |
user_files = []
|
| 77 |
uploaded_file_urls = [] # Store uploaded file URLs
|
| 78 |
+
self.file_url_mapping = {} # Map local paths to uploaded URLs
|
| 79 |
|
| 80 |
try:
|
| 81 |
# Handle multimodal input - message is a dict with 'text' and 'files'
|
|
|
|
| 124 |
uploaded_url = self._upload_file_to_gradio_server(file_path)
|
| 125 |
# Store the mapping
|
| 126 |
self.file_url_mapping[file_path] = uploaded_url
|
| 127 |
+
uploaded_file_urls.append(uploaded_url)
|
| 128 |
logger.info(f" ✅ Uploaded File URL: {uploaded_url}")
|
| 129 |
|
| 130 |
# Add to history with public URL
|
|
|
|
| 170 |
return history, gr.MultimodalTextbox(value=None, interactive=False)
|
| 171 |
|
| 172 |
def _prepare_hf_messages(self, history: List, uploaded_file_urls: List[str] = None) -> List[Dict[str, Any]]:
|
| 173 |
+
"""Convert history (ChatMessage or dict) to HF OpenAI-compatible format with multimodal support"""
|
| 174 |
+
messages: List[Dict[str, Any]] = []
|
| 175 |
|
| 176 |
# Get optimal context settings for current model/provider
|
| 177 |
if self.mcp_client.current_model and self.mcp_client.current_provider:
|
|
|
|
| 187 |
# Convert history to HF API format (text only for context)
|
| 188 |
recent_history = history[-max_history:] if len(history) > max_history else history
|
| 189 |
|
| 190 |
+
last_role = None
|
| 191 |
for msg in recent_history:
|
| 192 |
# Handle both ChatMessage objects and dictionary format for backward compatibility
|
| 193 |
if hasattr(msg, 'role'): # ChatMessage object
|
|
|
|
| 199 |
else:
|
| 200 |
continue # Skip invalid messages
|
| 201 |
|
| 202 |
+
if role == "user":
|
| 203 |
+
# Build multimodal user messages with parts
|
| 204 |
+
part = None
|
| 205 |
+
if isinstance(content, dict) and "path" in content:
|
| 206 |
+
file_path = content.get("path", "")
|
| 207 |
+
if isinstance(file_path, str) and file_path.startswith("http") and AppConfig.is_image_file(file_path):
|
| 208 |
+
part = {"type": "image_url", "image_url": {"url": file_path}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
else:
|
| 210 |
+
# Non-image or non-URL: fallback to text description
|
| 211 |
+
part = {"type": "text", "text": f"[File: {file_path}]"}
|
| 212 |
elif isinstance(content, (list, tuple)):
|
| 213 |
+
part = {"type": "text", "text": f"[List: {str(content)[:50]}...]"}
|
| 214 |
elif content is None:
|
| 215 |
+
part = {"type": "text", "text": "[Empty]"}
|
| 216 |
else:
|
| 217 |
+
part = {"type": "text", "text": str(content)}
|
| 218 |
+
|
| 219 |
+
if messages and last_role == "user" and isinstance(messages[-1].get("content"), list):
|
| 220 |
+
messages[-1]["content"].append(part)
|
| 221 |
+
elif messages and last_role == "user" and isinstance(messages[-1].get("content"), str):
|
| 222 |
+
# Convert existing string content to parts and append
|
| 223 |
+
existing_text = messages[-1]["content"]
|
| 224 |
+
messages[-1]["content"] = [{"type": "text", "text": existing_text}, part]
|
| 225 |
+
else:
|
| 226 |
+
messages.append({"role": "user", "content": [part]})
|
| 227 |
+
last_role = "user"
|
| 228 |
+
|
| 229 |
+
elif role == "assistant":
|
| 230 |
+
# Assistant content remains text for chat.completions API
|
| 231 |
+
if isinstance(content, dict):
|
| 232 |
+
text = f"[Object: {str(content)[:50]}...]"
|
| 233 |
+
elif isinstance(content, (list, tuple)):
|
| 234 |
+
text = f"[List: {str(content)[:50]}...]"
|
| 235 |
+
elif content is None:
|
| 236 |
+
text = "[Empty]"
|
| 237 |
+
else:
|
| 238 |
+
text = str(content)
|
| 239 |
+
messages.append({"role": "assistant", "content": text})
|
| 240 |
+
last_role = "assistant"
|
| 241 |
|
| 242 |
return messages
|
| 243 |
|