Spaces:
Sleeping
Sleeping
Commit
·
c29cfbe
1
Parent(s):
d7efb13
Revert lại bản UI cũ
Browse files
app.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
"""
|
| 2 |
Chainlit UI for AI Agent with Login/Registration and Image Support
|
| 3 |
-
Fixed version with proper timeout handling
|
| 4 |
"""
|
| 5 |
|
| 6 |
import chainlit as cl
|
|
@@ -8,68 +7,25 @@ import requests
|
|
| 8 |
from typing import Optional, Dict
|
| 9 |
import json
|
| 10 |
import os
|
| 11 |
-
import asyncio
|
| 12 |
from image_captioning import image_captioning
|
| 13 |
|
| 14 |
# API Configuration
|
| 15 |
API_BASE_URL = os.getenv("API_BASE_URL")
|
| 16 |
|
| 17 |
-
# Timeout configurations
|
| 18 |
-
API_TIMEOUT = 180 # 3 minutes for API calls
|
| 19 |
-
IMAGE_PROCESSING_TIMEOUT =150 # 2.5 minutes for image processing
|
| 20 |
-
|
| 21 |
# ============================================
|
| 22 |
# API HELPER FUNCTIONS
|
| 23 |
# ============================================
|
| 24 |
|
| 25 |
-
def check_user_exists(user_id: str) ->
|
| 26 |
-
"""Check if user exists in the system
|
| 27 |
try:
|
| 28 |
-
|
| 29 |
-
print(f"[DEBUG] Checking user exists at: {url}")
|
| 30 |
-
|
| 31 |
-
response = requests.get(url, timeout=10)
|
| 32 |
-
print(f"[DEBUG] Response status: {response.status_code}")
|
| 33 |
-
print(f"[DEBUG] Response body: {response.text}")
|
| 34 |
-
|
| 35 |
if response.status_code == 200:
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
print(f"[DEBUG] User exists: {exists}, Full data: {data}")
|
| 39 |
-
return {
|
| 40 |
-
"success": True,
|
| 41 |
-
"exists": exists,
|
| 42 |
-
"user_id": data.get("user_id", user_id),
|
| 43 |
-
"message": data.get("message", "")
|
| 44 |
-
}
|
| 45 |
-
else:
|
| 46 |
-
print(f"[ERROR] Unexpected status code: {response.status_code}")
|
| 47 |
-
return {
|
| 48 |
-
"success": False,
|
| 49 |
-
"exists": False,
|
| 50 |
-
"error": f"API returned status {response.status_code}"
|
| 51 |
-
}
|
| 52 |
-
except requests.exceptions.Timeout:
|
| 53 |
-
print(f"[ERROR] Timeout when checking user: {user_id}")
|
| 54 |
-
return {
|
| 55 |
-
"success": False,
|
| 56 |
-
"exists": False,
|
| 57 |
-
"error": "Timeout - API không phản hồi"
|
| 58 |
-
}
|
| 59 |
-
except requests.exceptions.ConnectionError as e:
|
| 60 |
-
print(f"[ERROR] Connection error: {e}")
|
| 61 |
-
return {
|
| 62 |
-
"success": False,
|
| 63 |
-
"exists": False,
|
| 64 |
-
"error": f"Lỗi kết nối: {str(e)}"
|
| 65 |
-
}
|
| 66 |
except Exception as e:
|
| 67 |
-
print(f"
|
| 68 |
-
return
|
| 69 |
-
"success": False,
|
| 70 |
-
"exists": False,
|
| 71 |
-
"error": f"Lỗi: {str(e)}"
|
| 72 |
-
}
|
| 73 |
|
| 74 |
|
| 75 |
def register_user(user_id: str) -> Dict:
|
|
@@ -77,8 +33,7 @@ def register_user(user_id: str) -> Dict:
|
|
| 77 |
try:
|
| 78 |
response = requests.post(
|
| 79 |
f"{API_BASE_URL}/register",
|
| 80 |
-
json={"user_id": user_id}
|
| 81 |
-
timeout=10
|
| 82 |
)
|
| 83 |
if response.status_code == 201:
|
| 84 |
return {"success": True, "message": response.json().get("message", "Đăng ký thành công!")}
|
|
@@ -89,20 +44,14 @@ def register_user(user_id: str) -> Dict:
|
|
| 89 |
return {"success": False, "message": f"Lỗi kết nối: {str(e)}"}
|
| 90 |
|
| 91 |
|
| 92 |
-
|
| 93 |
-
"""Send chat message to API
|
| 94 |
try:
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
lambda: requests.post(
|
| 100 |
-
f"{API_BASE_URL}/chat",
|
| 101 |
-
json={"query": query, "user_id": user_id},
|
| 102 |
-
timeout=API_TIMEOUT
|
| 103 |
-
)
|
| 104 |
)
|
| 105 |
-
|
| 106 |
if response.status_code == 200:
|
| 107 |
data = response.json()
|
| 108 |
return {
|
|
@@ -114,8 +63,6 @@ async def send_chat_message_async(query: str, user_id: str) -> Dict:
|
|
| 114 |
error_msg = response.json().get("detail", "Lỗi xử lý câu hỏi")
|
| 115 |
return {"success": False, "message": error_msg}
|
| 116 |
|
| 117 |
-
except asyncio.TimeoutError:
|
| 118 |
-
return {"success": False, "message": "⏱️ Request timeout! Vui lòng thử lại."}
|
| 119 |
except requests.exceptions.Timeout:
|
| 120 |
return {"success": False, "message": "⏱️ Server đang khởi động (cold start), vui lòng thử lại sau 30 giây!"}
|
| 121 |
except Exception as e:
|
|
@@ -126,18 +73,11 @@ async def send_chat_message_async(query: str, user_id: str) -> Dict:
|
|
| 126 |
# IMAGE PROCESSING
|
| 127 |
# ============================================
|
| 128 |
|
| 129 |
-
async def
|
| 130 |
-
"""Process image and return caption
|
| 131 |
try:
|
| 132 |
-
|
| 133 |
-
loop = asyncio.get_event_loop()
|
| 134 |
-
caption = await asyncio.wait_for(
|
| 135 |
-
loop.run_in_executor(None, image_captioning, image_path),
|
| 136 |
-
timeout=IMAGE_PROCESSING_TIMEOUT
|
| 137 |
-
)
|
| 138 |
return caption
|
| 139 |
-
except asyncio.TimeoutError:
|
| 140 |
-
return "(⏱️ Timeout khi xử lý ảnh - ảnh quá phức tạp hoặc lỗi xử lý)"
|
| 141 |
except Exception as e:
|
| 142 |
return f"(Lỗi khi xử lý ảnh: {str(e)})"
|
| 143 |
|
|
@@ -211,7 +151,7 @@ async def main(message: cl.Message):
|
|
| 211 |
user_id = cl.user_session.get("user_id")
|
| 212 |
awaiting_auth = cl.user_session.get("awaiting_auth", True)
|
| 213 |
|
| 214 |
-
content = message.content.strip()
|
| 215 |
|
| 216 |
# Handle authentication commands
|
| 217 |
if content.startswith("/"):
|
|
@@ -239,21 +179,28 @@ async def process_chat_message_with_image(message: cl.Message, user_id: str):
|
|
| 239 |
|
| 240 |
# If there are images, process them
|
| 241 |
if images:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
image_captions = []
|
| 243 |
|
| 244 |
-
for
|
| 245 |
try:
|
| 246 |
# Get image path
|
| 247 |
image_path = img.path
|
| 248 |
|
| 249 |
-
# Process image and get caption
|
| 250 |
-
caption = await
|
| 251 |
-
image_captions.append(
|
| 252 |
|
| 253 |
except Exception as e:
|
| 254 |
-
error_caption = f"
|
| 255 |
image_captions.append(error_caption)
|
| 256 |
|
|
|
|
|
|
|
|
|
|
| 257 |
# Concatenate all captions
|
| 258 |
combined_captions = "\n\n".join(image_captions)
|
| 259 |
|
|
@@ -299,39 +246,14 @@ async def handle_command(command: str):
|
|
| 299 |
loading_msg = cl.Message(content="🔍 Đang kiểm tra tài khoản...", author="Kumiko")
|
| 300 |
await loading_msg.send()
|
| 301 |
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
loop = asyncio.get_event_loop()
|
| 305 |
-
result = await loop.run_in_executor(None, check_user_exists, user_id)
|
| 306 |
-
|
| 307 |
-
print(f"[DEBUG] Login check result: {result}")
|
| 308 |
-
|
| 309 |
await loading_msg.remove()
|
| 310 |
-
|
| 311 |
-
|
| 312 |
-
if not result.get("success", False):
|
| 313 |
-
await cl.Message(
|
| 314 |
-
content=f"❌ Lỗi kiểm tra tài khoản: {result.get('error', 'Unknown error')}\n\n💡 API URL: `{API_BASE_URL}`",
|
| 315 |
-
author="Kumiko"
|
| 316 |
-
).send()
|
| 317 |
-
return
|
| 318 |
-
|
| 319 |
-
# Check if user exists
|
| 320 |
-
if result.get("exists", False):
|
| 321 |
-
confirmed_user_id = result.get("user_id", user_id)
|
| 322 |
-
print(f"[DEBUG] Login successful for user: {confirmed_user_id}")
|
| 323 |
-
await show_chat_interface(confirmed_user_id)
|
| 324 |
-
else:
|
| 325 |
-
await cl.Message(
|
| 326 |
-
content=f"❌ User ID `{user_id}` không tồn tại!\n\nVui lòng đăng ký bằng: `/register {user_id}`",
|
| 327 |
-
author="Kumiko"
|
| 328 |
-
).send()
|
| 329 |
-
|
| 330 |
-
except Exception as e:
|
| 331 |
-
print(f"[ERROR] Exception in login: {type(e).__name__} - {e}")
|
| 332 |
await loading_msg.remove()
|
| 333 |
await cl.Message(
|
| 334 |
-
content=f"❌
|
| 335 |
author="Kumiko"
|
| 336 |
).send()
|
| 337 |
|
|
@@ -351,10 +273,8 @@ async def handle_command(command: str):
|
|
| 351 |
loading_msg = cl.Message(content="📝 Đang đăng ký tài khoản...", author="Kumiko")
|
| 352 |
await loading_msg.send()
|
| 353 |
|
| 354 |
-
# Register user
|
| 355 |
-
|
| 356 |
-
result = await loop.run_in_executor(None, register_user, user_id)
|
| 357 |
-
|
| 358 |
await loading_msg.remove()
|
| 359 |
|
| 360 |
if result["success"]:
|
|
@@ -399,44 +319,43 @@ Hệ thống sẽ trả lời và cung cấp tài liệu tham khảo.
|
|
| 399 |
|
| 400 |
async def process_chat_message(query: str, user_id: str):
|
| 401 |
"""Process chat message and display response"""
|
| 402 |
-
#
|
| 403 |
-
|
| 404 |
-
await
|
| 405 |
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
await msg.update()
|
| 440 |
|
| 441 |
|
| 442 |
@cl.action_callback("show_references")
|
|
|
|
| 1 |
"""
|
| 2 |
Chainlit UI for AI Agent with Login/Registration and Image Support
|
|
|
|
| 3 |
"""
|
| 4 |
|
| 5 |
import chainlit as cl
|
|
|
|
| 7 |
from typing import Optional, Dict
|
| 8 |
import json
|
| 9 |
import os
|
|
|
|
| 10 |
from image_captioning import image_captioning
|
| 11 |
|
| 12 |
# API Configuration
|
| 13 |
API_BASE_URL = os.getenv("API_BASE_URL")
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
# ============================================
|
| 16 |
# API HELPER FUNCTIONS
|
| 17 |
# ============================================
|
| 18 |
|
| 19 |
+
def check_user_exists(user_id: str) -> bool:
|
| 20 |
+
"""Check if user exists in the system"""
|
| 21 |
try:
|
| 22 |
+
response = requests.get(f"{API_BASE_URL}/user-exists/{user_id}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
if response.status_code == 200:
|
| 24 |
+
return response.json().get("exists", False)
|
| 25 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
except Exception as e:
|
| 27 |
+
print(f"Error checking user: {e}")
|
| 28 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
def register_user(user_id: str) -> Dict:
|
|
|
|
| 33 |
try:
|
| 34 |
response = requests.post(
|
| 35 |
f"{API_BASE_URL}/register",
|
| 36 |
+
json={"user_id": user_id}
|
|
|
|
| 37 |
)
|
| 38 |
if response.status_code == 201:
|
| 39 |
return {"success": True, "message": response.json().get("message", "Đăng ký thành công!")}
|
|
|
|
| 44 |
return {"success": False, "message": f"Lỗi kết nối: {str(e)}"}
|
| 45 |
|
| 46 |
|
| 47 |
+
def send_chat_message(query: str, user_id: str) -> Dict:
|
| 48 |
+
"""Send chat message to API"""
|
| 49 |
try:
|
| 50 |
+
response = requests.post(
|
| 51 |
+
f"{API_BASE_URL}/chat",
|
| 52 |
+
json={"query": query, "user_id": user_id},
|
| 53 |
+
timeout=120
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
)
|
|
|
|
| 55 |
if response.status_code == 200:
|
| 56 |
data = response.json()
|
| 57 |
return {
|
|
|
|
| 63 |
error_msg = response.json().get("detail", "Lỗi xử lý câu hỏi")
|
| 64 |
return {"success": False, "message": error_msg}
|
| 65 |
|
|
|
|
|
|
|
| 66 |
except requests.exceptions.Timeout:
|
| 67 |
return {"success": False, "message": "⏱️ Server đang khởi động (cold start), vui lòng thử lại sau 30 giây!"}
|
| 68 |
except Exception as e:
|
|
|
|
| 73 |
# IMAGE PROCESSING
|
| 74 |
# ============================================
|
| 75 |
|
| 76 |
+
async def process_image(image_path: str) -> str:
|
| 77 |
+
"""Process image and return caption"""
|
| 78 |
try:
|
| 79 |
+
caption = image_captioning(image_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
return caption
|
|
|
|
|
|
|
| 81 |
except Exception as e:
|
| 82 |
return f"(Lỗi khi xử lý ảnh: {str(e)})"
|
| 83 |
|
|
|
|
| 151 |
user_id = cl.user_session.get("user_id")
|
| 152 |
awaiting_auth = cl.user_session.get("awaiting_auth", True)
|
| 153 |
|
| 154 |
+
content = message.content.strip()
|
| 155 |
|
| 156 |
# Handle authentication commands
|
| 157 |
if content.startswith("/"):
|
|
|
|
| 179 |
|
| 180 |
# If there are images, process them
|
| 181 |
if images:
|
| 182 |
+
# Show processing message
|
| 183 |
+
processing_msg = cl.Message(content="🖼️ Đang xử lý ảnh...", author="Kumiko")
|
| 184 |
+
await processing_msg.send()
|
| 185 |
+
|
| 186 |
image_captions = []
|
| 187 |
|
| 188 |
+
for img in images:
|
| 189 |
try:
|
| 190 |
# Get image path
|
| 191 |
image_path = img.path
|
| 192 |
|
| 193 |
+
# Process image and get caption
|
| 194 |
+
caption = await process_image(image_path)
|
| 195 |
+
image_captions.append(caption)
|
| 196 |
|
| 197 |
except Exception as e:
|
| 198 |
+
error_caption = f"(Lỗi khi xử lý ảnh: {str(e)})"
|
| 199 |
image_captions.append(error_caption)
|
| 200 |
|
| 201 |
+
# Remove processing message
|
| 202 |
+
await processing_msg.remove()
|
| 203 |
+
|
| 204 |
# Concatenate all captions
|
| 205 |
combined_captions = "\n\n".join(image_captions)
|
| 206 |
|
|
|
|
| 246 |
loading_msg = cl.Message(content="🔍 Đang kiểm tra tài khoản...", author="Kumiko")
|
| 247 |
await loading_msg.send()
|
| 248 |
|
| 249 |
+
# Check if user exists
|
| 250 |
+
if check_user_exists(user_id):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
await loading_msg.remove()
|
| 252 |
+
await show_chat_interface(user_id)
|
| 253 |
+
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
await loading_msg.remove()
|
| 255 |
await cl.Message(
|
| 256 |
+
content=f"❌ User ID `{user_id}` không tồn tại!\n\nVui lòng đăng ký bằng: `/register {user_id}`",
|
| 257 |
author="Kumiko"
|
| 258 |
).send()
|
| 259 |
|
|
|
|
| 273 |
loading_msg = cl.Message(content="📝 Đang đăng ký tài khoản...", author="Kumiko")
|
| 274 |
await loading_msg.send()
|
| 275 |
|
| 276 |
+
# Register user
|
| 277 |
+
result = register_user(user_id)
|
|
|
|
|
|
|
| 278 |
await loading_msg.remove()
|
| 279 |
|
| 280 |
if result["success"]:
|
|
|
|
| 319 |
|
| 320 |
async def process_chat_message(query: str, user_id: str):
|
| 321 |
"""Process chat message and display response"""
|
| 322 |
+
# Show thinking message
|
| 323 |
+
thinking_msg = cl.Message(content="🤔 Đang suy nghĩ...", author="Kumiko")
|
| 324 |
+
await thinking_msg.send()
|
| 325 |
|
| 326 |
+
# Send request to API
|
| 327 |
+
result = send_chat_message(query, user_id)
|
| 328 |
+
|
| 329 |
+
# Remove thinking message
|
| 330 |
+
await thinking_msg.remove()
|
| 331 |
+
|
| 332 |
+
if not result["success"]:
|
| 333 |
+
await cl.Message(content=f"❌ Lỗi: {result['message']}", author="Kumiko").send()
|
| 334 |
+
return
|
| 335 |
+
|
| 336 |
+
answer = result["answer"]
|
| 337 |
+
references = result["references"]
|
| 338 |
+
|
| 339 |
+
# Store references in session for the button
|
| 340 |
+
cl.user_session.set("last_references", references)
|
| 341 |
+
|
| 342 |
+
# Create message with action button
|
| 343 |
+
actions = [
|
| 344 |
+
cl.Action(
|
| 345 |
+
name="show_references",
|
| 346 |
+
value="show",
|
| 347 |
+
label="𝄢 Tài liệu tham khảo",
|
| 348 |
+
description="Xem các nguồn tham khảo",
|
| 349 |
+
payload={"references": references}
|
| 350 |
+
)
|
| 351 |
+
]
|
| 352 |
+
|
| 353 |
+
# Send answer with reference button
|
| 354 |
+
await cl.Message(
|
| 355 |
+
content=answer,
|
| 356 |
+
actions=actions,
|
| 357 |
+
author="Kumiko"
|
| 358 |
+
).send()
|
|
|
|
| 359 |
|
| 360 |
|
| 361 |
@cl.action_callback("show_references")
|