Spaces:
Sleeping
Sleeping
Refactor webhook handling and AI call flow
Browse filesAvoid duplicate message persistence, streamline Telegram webhook processing, and run Hugging Face completion calls through an executor-based async wrapper.
Made-with: Cursor
- ai_service.py +19 -58
- telegram_handlers.py +29 -50
ai_service.py
CHANGED
|
@@ -48,70 +48,31 @@ TOOLS = [
|
|
| 48 |
}
|
| 49 |
]
|
| 50 |
|
| 51 |
-
async def get_ai_response(user_query: str, telegram_id: int
|
| 52 |
-
|
| 53 |
-
return "عذراً، خدمة الذكاء الاصطناعي غير متوفرة حالياً."
|
| 54 |
-
|
| 55 |
-
print(f"User query: {user_query}")
|
| 56 |
conversation_history = []
|
| 57 |
-
if
|
| 58 |
-
db_manager.save_message(telegram_id, user_query, "user")
|
| 59 |
-
# جلب آخر 6 رسائل لتوفير السياق للموديل
|
| 60 |
raw_history = db_manager.get_history(telegram_id, limit=6)
|
| 61 |
for msg in raw_history:
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
|
| 66 |
-
|
| 67 |
messages = [{"role": "system", "content": PROMPT}] + conversation_history
|
| 68 |
-
|
| 69 |
-
print(f"getting response from Messages: {messages}")
|
| 70 |
-
response = hf_client.chat.completions.create(
|
| 71 |
-
model=MODEL_NAME,
|
| 72 |
-
messages=messages,
|
| 73 |
-
tools=TOOLS,
|
| 74 |
-
tool_choice="auto",
|
| 75 |
-
temperature=0.1
|
| 76 |
-
)
|
| 77 |
-
|
| 78 |
-
response_message = response.choices[0].message
|
| 79 |
-
tool_calls = getattr(response_message, 'tool_calls', None)
|
| 80 |
-
|
| 81 |
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
messages.append(response_message)
|
| 93 |
-
messages.append({
|
| 94 |
-
"role": "tool",
|
| 95 |
-
"tool_call_id": tool_call.id,
|
| 96 |
-
"name": "search_bank_knowledge",
|
| 97 |
-
"content": extracted_context
|
| 98 |
-
})
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
final_response = hf_client.chat.completions.create(
|
| 102 |
-
model=MODEL_NAME,
|
| 103 |
messages=messages,
|
| 104 |
-
temperature=0.
|
|
|
|
| 105 |
)
|
| 106 |
-
ai_final_content = final_response.choices[0].message.content
|
| 107 |
-
else:
|
| 108 |
-
print(f"response_message: {response_message}")
|
| 109 |
-
ai_final_content = response_message.content
|
| 110 |
-
|
| 111 |
-
print(f"ai_final_content: {ai_final_content}")
|
| 112 |
-
cleaned_response = clean_ai_response(ai_final_content)
|
| 113 |
-
|
| 114 |
-
if telegram_id and db_manager:
|
| 115 |
-
db_manager.save_message(telegram_id, cleaned_response, "assistant")
|
| 116 |
|
| 117 |
-
|
|
|
|
|
|
| 48 |
}
|
| 49 |
]
|
| 50 |
|
| 51 |
+
async def get_ai_response(user_query: str, telegram_id: int):
|
| 52 |
+
# جلب التاريخ من قاعدة البيانات فقط (بدون إعادة حفظ الرسالة الحالية)
|
|
|
|
|
|
|
|
|
|
| 53 |
conversation_history = []
|
| 54 |
+
if db_manager:
|
|
|
|
|
|
|
| 55 |
raw_history = db_manager.get_history(telegram_id, limit=6)
|
| 56 |
for msg in raw_history:
|
| 57 |
+
# تأكد أن المحتوى ليس فارغاً
|
| 58 |
+
if msg.get('content'):
|
| 59 |
+
conversation_history.append({"role": msg['role'], "content": msg['content']})
|
| 60 |
|
| 61 |
+
# بناء الرسائل
|
| 62 |
messages = [{"role": "system", "content": PROMPT}] + conversation_history
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
# إذا كان hf_client متزامن، يفضل تشغيله هكذا لتجنب التوقف:
|
| 65 |
+
import asyncio
|
| 66 |
+
loop = asyncio.get_event_loop()
|
| 67 |
+
|
| 68 |
+
# تنفيذ طلب الموديل
|
| 69 |
+
def call_hf():
|
| 70 |
+
return hf_client.chat.completions.create(
|
| 71 |
+
model=HF_MODEL,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
messages=messages,
|
| 73 |
+
temperature=0.1,
|
| 74 |
+
max_tokens=800
|
| 75 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
+
completion = await loop.run_in_executor(None, call_hf)
|
| 78 |
+
return clean_ai_response(completion.choices[0].message.content)
|
telegram_handlers.py
CHANGED
|
@@ -20,64 +20,43 @@ class WebhookData(BaseModel):
|
|
| 20 |
|
| 21 |
async def telegram_webhook(data: WebhookData):
|
| 22 |
try:
|
| 23 |
-
if data.message:
|
| 24 |
-
|
| 25 |
-
user_text = data.message.text
|
| 26 |
-
|
| 27 |
-
# Extract user info
|
| 28 |
-
username = data.message.chat.username
|
| 29 |
-
first_name = data.message.chat.first_name
|
| 30 |
-
last_name = data.message.chat.last_name
|
| 31 |
|
| 32 |
-
if user_text:
|
| 33 |
-
# Save user message to database if available
|
| 34 |
-
if db_manager:
|
| 35 |
-
db_manager.save_message(telegram_id, user_text, "user")
|
| 36 |
-
db_manager.create_or_update_user(telegram_id, username, first_name, last_name)
|
| 37 |
-
|
| 38 |
-
# Get the intelligent response with conversation history
|
| 39 |
-
ai_answer = await get_ai_response(user_text, telegram_id)
|
| 40 |
-
|
| 41 |
-
# Save assistant response to database if available
|
| 42 |
-
if db_manager:
|
| 43 |
-
db_manager.save_message(telegram_id, ai_answer, "assistant")
|
| 44 |
-
|
| 45 |
-
# Send back to Telegram if TELEGRAM_URL is available
|
| 46 |
-
if TELEGRAM_URL:
|
| 47 |
-
async with httpx.AsyncClient(verify=False) as client:
|
| 48 |
-
await client.post(
|
| 49 |
-
TELEGRAM_URL,
|
| 50 |
-
headers={"Host": "api.telegram.org"},
|
| 51 |
-
json={
|
| 52 |
-
"chat_id": telegram_id,
|
| 53 |
-
"text": ai_answer,
|
| 54 |
-
"parse_mode": "Markdown"
|
| 55 |
-
}
|
| 56 |
-
)
|
| 57 |
-
|
| 58 |
-
return {"status": "ok"}
|
| 59 |
-
except Exception as e:
|
| 60 |
-
return {"status": "error", "message": str(e)}
|
| 61 |
-
|
| 62 |
-
async def test_webhook(data: WebhookData):
|
| 63 |
-
try:
|
| 64 |
-
if not data.message:
|
| 65 |
-
return {"error": "Missing 'message' field in request"}
|
| 66 |
-
|
| 67 |
telegram_id = data.message.chat.id
|
| 68 |
user_text = data.message.text
|
| 69 |
|
| 70 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
if db_manager:
|
|
|
|
| 72 |
db_manager.save_message(telegram_id, user_text, "user")
|
| 73 |
|
| 74 |
-
#
|
| 75 |
-
|
| 76 |
|
| 77 |
-
#
|
| 78 |
if db_manager:
|
| 79 |
-
db_manager.save_message(telegram_id,
|
| 80 |
|
| 81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
except Exception as e:
|
| 83 |
-
|
|
|
|
|
|
| 20 |
|
| 21 |
async def telegram_webhook(data: WebhookData):
|
| 22 |
try:
|
| 23 |
+
if not data.message or not data.message.text:
|
| 24 |
+
return {"status": "ok"}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
telegram_id = data.message.chat.id
|
| 27 |
user_text = data.message.text
|
| 28 |
|
| 29 |
+
# معلومات المستخدم
|
| 30 |
+
username = data.message.chat.username
|
| 31 |
+
first_name = data.message.chat.first_name
|
| 32 |
+
|
| 33 |
+
print(f"--- Processing message from {first_name} ---")
|
| 34 |
+
|
| 35 |
+
# 1. تحديث بيانات المستخدم وحفظ رسالته (مرة واحدة فقط هنا)
|
| 36 |
if db_manager:
|
| 37 |
+
db_manager.create_or_update_user(telegram_id, username, first_name, data.message.chat.last_name)
|
| 38 |
db_manager.save_message(telegram_id, user_text, "user")
|
| 39 |
|
| 40 |
+
# 2. جلب الرد (تأكد من إزالة حفظ الرسالة المتكرر داخل get_ai_response)
|
| 41 |
+
ai_answer = await get_ai_response(user_text, telegram_id)
|
| 42 |
|
| 43 |
+
# 3. حفظ رد البوت
|
| 44 |
if db_manager:
|
| 45 |
+
db_manager.save_message(telegram_id, ai_answer, "assistant")
|
| 46 |
|
| 47 |
+
# 4. الإرسال لتليجرام (تم تنظيفه من الهيدرز الزائدة)
|
| 48 |
+
if TELEGRAM_URL:
|
| 49 |
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
| 50 |
+
payload = {
|
| 51 |
+
"chat_id": telegram_id,
|
| 52 |
+
"text": ai_answer,
|
| 53 |
+
"parse_mode": "Markdown"
|
| 54 |
+
}
|
| 55 |
+
# حذفنا Host Header و verify=False (إلا لو كنت متأكداً من حاجتك لها)
|
| 56 |
+
response = await client.post(TELEGRAM_URL, json=payload)
|
| 57 |
+
print(f"Telegram response status: {response.status_code}")
|
| 58 |
+
|
| 59 |
+
return {"status": "ok"}
|
| 60 |
except Exception as e:
|
| 61 |
+
print(f"Error in webhook: {str(e)}")
|
| 62 |
+
return {"status": "error", "message": str(e)}
|