edit nahj general runner and some changes

This commit is contained in:
ajokar 2026-05-16 14:29:40 +00:00
parent 31da2788a3
commit a1375a0956
3 changed files with 156 additions and 180 deletions

View File

@ -1,5 +1,5 @@
# nahj engine
# nahj engine started ...
print('nahj engine started ...')
import json
import os
import numpy as np
@ -693,14 +693,24 @@ def bale_chat(query):
print(f'len messages SIMPLE question: {len(messages)}')
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
return llm_answer
result = {
"output" : llm_answer,
"status" : 'OK',
"similarity_result" : retrived_sections_list,
"reference_ids" : [],
}
return result
# uvicorn src.app:app --reload
if __name__ == "__main__":
# query = 'در قانون حمایت از خانواده و جوانی جمعیت چه خدماتی در نظر گرفته شده است؟'
while True:
query = input('enter your qustion:')
# query = input('enter your qustion:')
query = "انسان در فتنه باید چگونه رفتار کند؟"
if query == '':
# should write in DATABASE
with open('./nahj-answer/chat-leader.txt', 'r', encoding='utf-8') as file:
@ -714,8 +724,9 @@ if __name__ == "__main__":
print(f'retrive duration: {(end_retrive - start).total_seconds()}')
# prompt = f'برای پرسش "{query}" از میان متن های "{result_passages}" .پاسخ مناسب را استخراج کن. پاسخ از زبان رهبر انقلاب اسلامی -حضرت آیت الله خامنه‌ای- بیان می شود. پاسخ به صورت تحلیلی باشد و ابعاد مختلف پرسش را در نظر بگیرد. پاسخ تولید شده، باید متن های مرتبط با پرسش را به صورت علمی بازنویسی کند. برای هر بخش از متن که در تولید پاسخ استفاده می کنی، عنوان آن بخش و تاریخ را نیز حتما در متن اضافه کن. درصورتی که مطلبی مرتبط با پرسش در متن پیدا نشد، فقط پاسخ بده: "متاسفانه در منابع، پاسخی پیدا نشد!"'
prompt = f'''برای پرسش "{query}" از میان بیانات رهبر معظم انقلاب، پاسخ مناسب را استخراج کن. پاسخ به صورت تحلیلی باشد و ابعاد مختلف پرسش را در نظر بگیرد. پاسخ تولید شده، باید محتوای بیانات مرتبط با پرسش را به صورت علمی بازنویسی کند. برای هر بخش از بیانات که در تولید پاسخ استفاده می کنی، عنوان آن و تاریخ را نیز در پاسخ اضافه کن. بیانات رهبر معظم انقلاب اسلامی: "{result_passages}"'''
# prompt = f'''برای پرسش "{query}" از میان بیانات رهبر معظم انقلاب، پاسخ مناسب را استخراج کن. پاسخ به صورت تحلیلی باشد و ابعاد مختلف پرسش را در نظر بگیرد. پاسخ تولید شده، باید محتوای بیانات مرتبط با پرسش را به صورت علمی بازنویسی کند. برای هر بخش از بیانات که در تولید پاسخ استفاده می کنی، عنوان آن و تاریخ را نیز در پاسخ اضافه کن. بیانات رهبر معظم انقلاب اسلامی: "{result_passages}"'''
prompt = f'''برای پرسش "{query}" از میان متن های زیر که از نهج‌البلاغه استخراج شده است، پاسخ مناسب را استخراج کن. متن خروجی «بدون مارک داون» و «بدون استایل» باشد. برای هر کدام از بخش‌ها که در تولید پاسخ استفاده می کنی، عنوان آن بخش را نیز در پاسخ اضافه کن. متن‌های مرتبط از کتاب نهج‌البلاغه "{related_paragraphs.strip()}"'''
llm_answer = llm_request(prompt)# "deepseek-reasoner"
print('-'*40)

View File

@ -1,5 +1,9 @@
"""
این سرویس، هسته اصلی نهج البلاغه را اجرا می کند
"""
import json
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import requests
import logging
@ -8,6 +12,7 @@ import random
import time
import nahj_engine as nahj_chat
import data_model as dm
from typing import Optional, Dict
# ===========================
# پیکربندی اولیه
# ===========================
@ -25,14 +30,13 @@ logging.basicConfig(
# define import model class
# ===========================
class Message(BaseModel):
chat: dict
text: str | None = None
user_query: str
class Update(BaseModel):
message: Message | None = None
async def get_latest_req_id(self):
async def get_latest_req_id():
latest_request = dm.get_last_request()
latest_req_id = latest_request['update_id']
@ -41,7 +45,7 @@ async def get_latest_req_id(self):
return latest_req_id + 1
async def save_entery(self, update_item):
async def save_entery(update_item):
is_active = True
answer = ''
message = update_item['message']
@ -61,11 +65,11 @@ async def save_entery(self, update_item):
return update_item['update_id']
async def update_request(self, update_id, answer):
async def update_request(update_id, answer):
dm.update_request(update_id= update_id, answer= answer)
async def split_text_into_chunks(self, text, max_length=4000):
async def split_text_into_chunks(text, max_length=4000):
"""
تقسیم یک متن به چانکهای حداکثر max_length کاراکتری، بدون خراب کردن معنا با رعایت انتهای جملهها.
@ -99,190 +103,67 @@ async def split_text_into_chunks(self, text, max_length=4000):
return chunks
async def save_chat_data(self,query, answer, first_name, username):
async def save_chat_data(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.add_middleware(
CORSMiddleware,
allow_origins=["*"], # یا دامنه فرانت‌اند
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.post("/chat")
async def chat(request: Request):
async def chat(request: Message):
"""
دریافت مستقیم آبجکت ورودی به صورت JSON
"""
# دریافت بدنه درخواست
body = await request.json()
body = dict(request)
user_query = body.get('user_query')
# دسترسی به فیلدها
user_input = body.get("message")
metadata = body.get("metadata", {})
# 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)
answer = nahj_chat.bale_chat(user_query)
if not answer:
reply = 'خطا در تولید پاسخ!'
answer['output'] = 'خطا در تولید پاسخ!'
answer['status'] = 'Failed'
answer['similarity_result'] = []
answer['reference_ids'] = []
if answer:
await update_request(update_id, answer)
try:
await update_request(update_id = update_id, answer = answer['output'])
except:
pass
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
retrived_sections_list = answer['similarity_result']
print(type(retrived_sections_list))
print(retrived_sections_list)
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
# برگرداندن آبجکت خروجی (خودکار به JSON تبدیل می‌شود)
return {
"output": answer,
"status": "ok",
"input_received": user_input
}
return answer
print(f'%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
print(f'!!! NAHJ-RUNNER IS READY !!!')
@ -297,7 +178,8 @@ print(f'%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
# result = asyncio.run(chat())
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8010)
pass
# uvicorn.run(app, host="127.0.0.1", port=8010)
# uvicorn.run(
# "nahj_engine_general_runner:app",
# host="0.0.0.0",
@ -306,4 +188,5 @@ if __name__ == "__main__":
# log_level="debug"
# )
# uvicorn nahj_engine_general_runner:app --reload --host 0.0.0.0 --port 8010
# uvicorn nahj_engine_general_runner:app --reload --host 0.0.0.0 --port 8010
# uvicorn main:app --reload --host 0.0.0.0 --port 8000 >> runs llm for pajoohesh

View File

@ -201,7 +201,27 @@ async def single_async_item(
reasoning_effort=reasoning_effort,
extra_body={"priority": priority},
)
response = await asyncio.wait_for(coro, timeout=timeout)
# response = await asyncio.wait_for(coro, timeout=timeout)
response = await asyncio.wait_for(
client.chat.completions.parse(
model=model_name,
messages=messages,
temperature=temperature,
top_p=top_p,
max_tokens=max_token,
stop=stop,
response_format=output_schema,
reasoning_effort=reasoning_effort,
extra_body={"priority": priority},
),
timeout=timeout
)
print('----------------------------------------------------')
print('----------------------------------------------------')
print(response)
print('----------------------------------------------------')
print('----------------------------------------------------')
if print_logs:
print(f"parse response ---- {response}")
@ -319,11 +339,73 @@ async def main():
print(f'all_paragraphs: {all_paragraphs}')
print('---------------------------------------------')
async def oss_test():
item = {}
item['assistant_prompt'] = "تو یک دستیار خبره در زمینه تدوین متون علمی هستی"
item['system_prompt'] = "پاسخ ها فقط باید علمی باشند و سبک نگارش طنز، سرگرمی، ادبی،احساسی و ... قابل قبول نیست."
item['user_prompt'] = "ابعاد مختلف علوم اجتماعی محاسباتی کدام است؟"
def process_item(
item:dict,
output_schema:BaseModel,
model_name:str="gpt-oss-120b",
api_url:str="http://172.16.29.102:8001/v1/",
api_key:str="EMPTY",
temperature:float=0.1,
top_p:float=1,
reasoning_effort:str="medium",
max_token:int=1024,
priority:int=1,
):
try:
client = OpenAI(
base_url=api_url,
api_key=api_key,
)
messages = [
{"role": "user", "content": item["user_prompt"]},
]
if item.get("system_prompt"):
messages.append({"role": "system", "content": item["system_prompt"]})
if item.get("assistant_prompt"):
messages.append(
{"role": "assistant", "content": item["assistant_prompt"]}
)
response = client.chat.completions.parse(
model=model_name,
messages=messages,
temperature=temperature,
top_p=top_p,
reasoning_effort=reasoning_effort,
max_tokens=max_token,
stop=None,
response_format=output_schema,
extra_body={"priority": priority},
)
parsed = (
response.choices[0].message.parsed
if response and response.choices and response.choices[0].message.parsed
else {"raw_text": str(response)}
)
parsed = output_schema.model_validate(parsed)
item["llm_output"] = dict(parsed.model_dump())
return item, 200
except Exception as e:
print(f"⚠️ Error __process_item {item['id']}: {traceback.print_exc()}")
return None, 400
# res = process_item(
# item={"user_prompt":"سلام خوبی"},
# output_schema=Result,
# )
async def oss_test(SYSTEM_PROMPT,USER_PROMPT,Dictt):
item['system_prompt'] = SYSTEM_PROMPT
item['user_prompt'] = f"{USER_PROMPT}\n{Dictt}"
# item = {}
# item['assistant_prompt'] = "تو یک دستیار خبره در زمینه تدوین متون علمی هستی"
# item['system_prompt'] = "پاسخ ها فقط باید علمی باشند و سبک نگارش طنز، سرگرمی، ادبی،احساسی و ... قابل قبول نیست. پاسخ فقط به زبان فارسی باشد و فقط اصطلاحات علمی را در صورت نیاز به زبان انگلیسی بیاور."
# item['user_prompt'] = "ابعاد مختلف علوم اجتماعی محاسباتی کدام است؟"
response = await single_async_item(
api_url="http://2.188.15.102:8001/v1/",
api_key="EMPTY",
@ -338,10 +420,10 @@ async def oss_test():
max_token=None,
return_reason=True,
return_used_token=True,
timeout=300
timeout=1000
)
print(response['llm_output'])
pass
return response['llm_output']
if __name__ == "__main__":