nahj engine

This commit is contained in:
ajokar 2026-05-12 12:53:07 +00:00
parent d21fa4d2c5
commit 61df642a34

View File

@ -0,0 +1,309 @@
import json
from fastapi import FastAPI, Request
from pydantic import BaseModel
import requests
import logging
import uvicorn
import random
import time
import nahj_engine as nahj_chat
import data_model as dm
# ===========================
# پیکربندی اولیه
# ===========================
TOKEN = "602738113:OcVhjcsXqvE6D9FUytdoMZ096DPKYIUwnrk"
API_URL = f"https://tapi.bale.ai/bot{TOKEN}/"
# راه‌اندازی لاگر
logging.basicConfig(
filename="./bale_bot/bot.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
# ===========================
# define import model class
# ===========================
class Message(BaseModel):
chat: dict
text: str | None = None
class Update(BaseModel):
message: Message | None = None
async def get_latest_req_id(self):
latest_request = dm.get_last_request()
latest_req_id = latest_request['update_id']
if not latest_req_id:
latest_req_id = 0
return latest_req_id + 1
async def save_entery(self, update_item):
is_active = True
answer = ''
message = update_item['message']
fromm = message['from']
chat = message['chat']
username, first_name, last_name = '','',''
if 'username' in fromm:
username = fromm['username']
if 'first_name' in fromm:
first_name = fromm['first_name']
if 'last_name' in fromm:
last_name = fromm['last_name']
try:
dm.insert_request(update_item['update_id'],username,message['text'], answer, message['message_id'],fromm['id'],fromm['is_bot'],message['date'],chat['id'],chat['type'],first_name,last_name, is_active)
except:
return update_item['update_id']
return update_item['update_id']
async def update_request(self, update_id, answer):
dm.update_request(update_id= update_id, answer= answer)
async def split_text_into_chunks(self, text, max_length=4000):
"""
تقسیم یک متن به چانکهای حداکثر max_length کاراکتری، بدون خراب کردن معنا با رعایت انتهای جملهها.
:param text: متن ورودی
:param max_length: حداکثر طول هر چانک (پیشفرض 4000)
:return: لیستی از چانکهای متن
"""
chunks = [] # لیستی برای ذخیره چانک‌ها
start = 0 # شروع متن برای هر چانک
while start < len(text):
# اگر متن باقی‌مانده کوتاه‌تر از max_length باشد، کل آن را اضافه کنید
if len(text) - start <= max_length:
chunks.append(text[start:])
break
# پیدا کردن نقطه پایانی چانک (حداکثر تا max_length کاراکتر جلو بروید)
end = start + max_length
# اگر در وسط یک جمله هستیم، به عقب برگردید تا انتهای جمله پیدا شود
while end > start and text[end - 1] not in '.!?':
end -= 1
# اگر هیچ انتهای جمله پیدا نشد، متن را تا max_length ببرید
if end == start:
end = start + max_length
# اضافه کردن چانک به لیست
chunks.append(text[start:end])
# شروع چانک بعدی
start = end
return chunks
async def save_chat_data(self,query, answer, first_name, username):
chat_data = f'''username: {username}\nfirstname: {first_name}\nquery: {query}\nanswer:{answer}\n+ + + + + + + + + + + + + + + + + + + + \n+ + + + + + + + + + + + + + + + + + + + \n\n'''
# # should write in DATABASE
with open('./bale_bot/chat-data.txt', 'a+', encoding='utf-8') as file:
file.write(chat_data)
async def handle_update(self, update_reqs: dict):
print(f"handle update ...")
data = update_reqs
if "message" not in data:
return
message = data["message"]
chat_id = message["chat"]["id"]
text = message.get("text", "").strip()
fromm = message['from']
# first_name = fromm['first_name']
# username = fromm['username']
logging.info(f"Received message from {chat_id}: {text}")
keyboard = {
"keyboard": [["جستجو","پرسش","پرسش عمیق"]],# ,"شبکه معنایی"
"resize_keyboard": True,
"one_time_keyboard": True
}
if text == "/start":
reply = "سلام، من دستیار هوشمند نهج‌البلاغه هستم. لطفا یکی از گزینه‌های زیر را انتخاب نمائید ..."
await self.send_message(chat_id, reply, keyboard)
return
elif text == "پرسش":
# حذف نوع درخواست قبلی کاربر
self.user_states.pop(chat_id, None)
# ایجاد وضعیت پرسش برای کاربر جاری
self.user_states[chat_id] = "simple_question"
reply = "لطفا متن «پرسش» را وارد نمائید ..."
await self.send_message(chat_id, reply, keyboard)
return
elif text == "جستجو":
# حذف نوع درخواست قبلی کاربر
self.user_states.pop(chat_id, None)
# ایجاد وضعیت جستجو برای کاربر جاری
self.user_states[chat_id] = "search"
reply = "لطفا متن موردنظر جهت «جستجو» را وارد نمائید ..."
await self.send_message(chat_id, reply, keyboard)
return
elif text == "شبکه معنایی":
# حذف نوع درخواست قبلی کاربر
self.user_states.pop(chat_id, None)
# ایجاد وضعیت شبکه معنایی برای کاربر جاری
self.user_states[chat_id] = "semantic-network"
reply = "لطفا کلمه موردنظر جهت ترسیم «شبکه معنایی» را وارد نمائید ..."
await self.send_message(chat_id, reply, keyboard)
return
elif text == "پرسش عمیق":
# حذف نوع درخواست قبلی کاربر
self.user_states.pop(chat_id, None)
# ایجاد وضعیت پرسش برای کاربر جاری
self.user_states[chat_id] = "deep_question"
reply = "لطفا متن «پرسش عمیق» را وارد نمائید ..."
await self.send_message(chat_id, reply, keyboard)
return
# elif text == "/help":
# reply = (
# "دستورهای موجود:\n"
# "/start - شروع ربات\n"
# "/chat - گفت‌گو با دستیار هوشمند نهج البلاغه\n"
# "/status - وضعیت ربات"
# )
# self.send_message(chat_id, reply)
elif text == "ربات":
reply = "ربات فعال است ✅"
await self.send_message(chat_id, reply, keyboard)
return
elif self.user_states.get(chat_id) == "semantic-network":
await self.send_message(chat_id, f"⏳ در حال ایجاد شبکه معنایی برای کلمه «{text}» ...")
reply = 'با عرض پوزش؛ این امکان، در حال حاضر در دسترس نیست'
elif self.user_states.get(chat_id) == "search":
await self.send_message(chat_id, f"⏳ در حال جستجو برای «{text}» ...")
answer = nahj_chat.bale_search(text)
if answer:
reply = answer
else:
reply = 'خطا در تولید پاسخ!'
elif self.user_states.get(chat_id) == "simple_question":
await self.send_message(chat_id, f"⏳ در حال آماده‌سازی پاسخ به «{text}» ...")
answer = nahj_chat.bale_chat(text)
if answer:
reply = answer
else:
reply = 'خطا در تولید پاسخ!'
elif self.user_states.get(chat_id) == "deep_question":
await self.send_message(chat_id, f"⏳ در حال آماده‌سازی پاسخ به «{text}» ...")
# answer = nahj_chat.bale_chat(text)
final_result = await nahj_chat.bale_complex_chat(text)
if final_result:
sub_questions = 'سوالات جزئی مرتبط با سوال کاربر:\n'
for i, q in enumerate(final_result.get('sub_qa'),1):
sub_questions += f'{i}. {q.get("question")}\n'
sub_qa_text = ''
for i, qa in enumerate(final_result.get('sub_qa'),1):
sub_qa_text += f'{i}. {qa.get("question")}\n{qa.get("answer")}\n\n'
# reply_content = f'''سوال اصلی: {text}\n\n{sub_questions}\n\n* * * * *سوالات جزئی:\n{sub_qa_text.strip()}\n\nپاسخ نهائی:\n{final_result.get('final_answer',0)}'''
reply_content = f'''{final_result.get('final_answer',0)}'''
reply = reply_content.strip()
else:
reply = 'خطا در تولید پاسخ!'
else:
reply = "لطفا یکی از گزینه‌های زیر را انتخاب نمائید"
await self.send_message(chat_id, reply, keyboard)
return
reply_len = len(reply.split())
print(f"len answer: {reply_len}")
print(f"ready for next ...")
print('+'*20)
print('+'*20)
reply_chuncs = []
reply_chuncs = await self.split_text_into_chunks(reply)
for i, paragraph in enumerate(reply_chuncs):
await self.send_message(chat_id, paragraph, keyboard)
# await self.save_chat_data(text, reply, first_name, username)
return reply
# ===========================
# ساخت اپلیکیشن FastAPI
# ===========================
app = FastAPI()
@app.post("/chat")
async def chat(request: Request):
"""
دریافت مستقیم آبجکت ورودی به صورت JSON
"""
# دریافت بدنه درخواست
body = await request.json()
# دسترسی به فیلدها
user_input = body.get("message")
metadata = body.get("metadata", {})
# update_id = await save_entery(item)
update_id = random.randint(1, 10)
answer = nahj_chat.bale_chat(user_input)
if not answer:
reply = 'خطا در تولید پاسخ!'
if answer:
await update_request(update_id, answer)
# برگرداندن آبجکت خروجی (خودکار به JSON تبدیل می‌شود)
return {
"output": answer,
"status": "ok",
"input_received": user_input
}
print(f'%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
print(f'!!! NAHJ-RUNNER IS READY !!!')
print(f'%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
# ===========================
# (local execution)
# ===========================
# if __name__ == "__main__":
# import asyncio
# result = asyncio.run(chat())
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8010)
# uvicorn.run(
# "nahj_engine_general_runner:app",
# host="0.0.0.0",
# port=8010,
# reload=True, # فعال بودن reload برای دیباگ مفید است
# log_level="debug"
# )
# uvicorn nahj_engine_general_runner:app --reload --host 0.0.0.0 --port 8010