251 lines
7.7 KiB
Python
Executable File
251 lines
7.7 KiB
Python
Executable File
from fastapi import APIRouter, Request
|
|
from fastapi.responses import JSONResponse
|
|
import time, os, traceback
|
|
from .base_model import Query, LLMOutput, LLMInput, Title
|
|
from .ai_data_parser import AsyncCore
|
|
from .chatbot_handler import (
|
|
InitHybridRetrieverReranker,
|
|
format_answer_bale,
|
|
get_user_prompt2,
|
|
get_user_prompt3,
|
|
load_faiss_index,
|
|
get_in_form,chunked_simple_text
|
|
)
|
|
from .static import (
|
|
EMBED_MODEL_PATH,
|
|
FAISS_INDEX_PATH,
|
|
FAISS_METADATA_PATH,
|
|
LLM_URL,
|
|
SYSTEM_PROMPT_FINALL,
|
|
RERANKER_MODEL_PATH,
|
|
LLM_ERROR,
|
|
MODEL_KEY,
|
|
MODEL_NAME,
|
|
OUTPUT_PATH_LLM,
|
|
REASONING_EFFORT,
|
|
TASK_NAME,
|
|
LLM_TIME_OUT,
|
|
MAX_TOKEN,
|
|
SYSTEM_PROPMT2,
|
|
)
|
|
|
|
|
|
# ################################################## Global-params
|
|
router = APIRouter(tags=["ragchat"])
|
|
# # settings= get_settings()
|
|
|
|
|
|
METADATA_DICT, FAISS_INDEX = load_faiss_index(
|
|
index_path=FAISS_INDEX_PATH, metadata_path=FAISS_METADATA_PATH
|
|
)
|
|
|
|
RAG = InitHybridRetrieverReranker(
|
|
embeder_path=EMBED_MODEL_PATH,
|
|
reranker_path=RERANKER_MODEL_PATH,
|
|
dict_content=METADATA_DICT,
|
|
faiss_index=FAISS_INDEX,
|
|
dense_alpha=0.6,
|
|
device="cuda",
|
|
)
|
|
|
|
RUNNER_PROMPT = AsyncCore(
|
|
model_name=MODEL_NAME,
|
|
api_url=LLM_URL,
|
|
output_path=OUTPUT_PATH_LLM,
|
|
task_name=TASK_NAME,
|
|
output_schema=LLMOutput,
|
|
reasoning_effort=REASONING_EFFORT,
|
|
ai_code_version=MODEL_KEY,
|
|
request_timeout=LLM_TIME_OUT,
|
|
max_token=MAX_TOKEN,
|
|
save_number=1,
|
|
)
|
|
|
|
from pydantic import BaseModel
|
|
|
|
SYS_PROMPT = """
|
|
شما یک ربات متخصص حقوقی و قانونی هستید به نام «قانونیار».
|
|
هویت شما: یک وکیل باتجربه، دقیق، مودب و مشتاق کمککردن به افراد در فهم مسائل حقوقی.
|
|
|
|
در این مرحله، وظیفه شما «تشخیص نوع پیام» است؛ اما باید یک دلیل کوتاه (answer) بدهید
|
|
که لحنش لحن یک وکیل کارکشته و حامی باشد.
|
|
|
|
برچسب خروجی فقط یکی از این موارد است:
|
|
- legal_question
|
|
- greeting
|
|
- other
|
|
|
|
تعریفها:
|
|
1. legal_question: هر پرسش یا متن مرتبط با قوانین، مقررات، دادگاه، وکالت، قرارداد، مالیات، ارث، نکاح و طلاق، شکایت، چک، سفته، ثبت شرکت، حقوق کار و هر موضوع مشابه.
|
|
2. greeting: پیامهای غیرحقوقی شامل سلام، معرفی، احوالپرسی، تشکر، خداحافظی.
|
|
3. other: پیامهایی که خارج از دو دسته بالا قرار میگیرند.
|
|
|
|
نکات مهم:
|
|
- answer باید بسیار کوتاه باشد (حداکثر دو خط).
|
|
- اگر پیام حتی کمی رنگوبوی حقوقی داشته باشد، answer را به سمت توضیح حقوقی ببرید.
|
|
- در حالت greeting با لحن رسمی و دوستانه یک وکیل پاسخ بدهید.
|
|
- در حالت other، در عین محترمانهگفتن اینکه پیام حقوقی نیست، سعی کنید یک زاویهٔ حقوقی احتمالی مطرح کنید تا راه کمک باز بماند.
|
|
|
|
خروجی شما حتماً باید شامل دو فیلد باشد:
|
|
label: یکی از سه برچسب
|
|
answer: توضیح کوتاه، دوستانه، مودب و با لحن یک وکیل حامی
|
|
|
|
خروجی فقط JSON باشد.
|
|
"""
|
|
|
|
|
|
ASSIST_PROMPT = """
|
|
### Example 1:
|
|
input:
|
|
"عین کلی"
|
|
output:
|
|
{
|
|
"label": "legal_question",
|
|
"answer": "موضوع شما به یکی از مفاهیم مهم حقوق مدنی مربوط میشود و با کمال میل راهنماییتان میکنم."
|
|
}
|
|
|
|
### Example 2:
|
|
input:
|
|
"طرز تهیه ماست"
|
|
output:
|
|
{
|
|
"label":"other",
|
|
"answer":"موضوع شما ماهیت حقوقی ندارد، اما اگر دغدغهتان مرتبط با استاندارد یا مسئولیت تولید باشد میتوانم به شما کمک کنم، می شود سوال خود را بهتر و کامل تر بپرسید؟ میخواهم دقیق بدانم چه قسمتی از موارد حقوقی تولید ماست رو میخواهید بدونید"
|
|
}
|
|
|
|
### Example 3:
|
|
input:
|
|
"سلام، تو کی هستی؟"
|
|
output:
|
|
{
|
|
"label":"greeting",
|
|
"answer":"سلام و ارادت؛ من قانونیار هستم، وکیل همراه شما برای هر پرسش حقوقی."
|
|
}
|
|
"""
|
|
|
|
class ChatOutput(BaseModel):
|
|
label: str
|
|
answer: str | None = None
|
|
|
|
RUNNER_CHAT = AsyncCore(
|
|
model_name=MODEL_NAME,
|
|
api_url=LLM_URL,
|
|
output_path="/home2/rag_qa_chat2/data/_temp/",
|
|
task_name="type-of-chat",
|
|
output_schema=ChatOutput,
|
|
reasoning_effort="low",
|
|
ai_code_version=MODEL_KEY,
|
|
request_timeout=LLM_TIME_OUT,
|
|
max_token=256,
|
|
save_number=1,
|
|
top_p=0.8,
|
|
temperature=0.5
|
|
)
|
|
|
|
# legal_question
|
|
# greeting
|
|
# other
|
|
|
|
# label
|
|
# reasoning
|
|
async def chat_bot_run(query):
|
|
try:
|
|
s0 = time.time()
|
|
print(f'query {query}')
|
|
type_, _ = await RUNNER_CHAT.single_simple_async_proccess_item(
|
|
item={
|
|
"user_prompt": query,
|
|
"system_prompt": SYS_PROMPT,
|
|
"assistant_prompt":ASSIST_PROMPT
|
|
}
|
|
)
|
|
type_chat = type_.get('label', None)
|
|
answer = type_['answer']
|
|
s = time.time()
|
|
print(f'type_llm {type_} {s-s0}\'s Toke')
|
|
if type_chat != "legal_question":
|
|
return chunked_simple_text(answer)
|
|
|
|
sections_dict = await RAG.search_base(
|
|
query,
|
|
final_k=10,
|
|
topk_dense=100,
|
|
topk_sparse=100,
|
|
pre_rerank_k=100,
|
|
)
|
|
e = time.time()
|
|
# input_data = LLMInput(query=query, knowledge=sections_dict)
|
|
# prompt = get_user_prompt2(input_data)
|
|
prompt = get_user_prompt3(query=query, knowledge_json=sections_dict)
|
|
|
|
llm_answer, _ = await RUNNER_PROMPT.single_simple_async_proccess_item(
|
|
item={"user_prompt": prompt, "system_prompt": SYSTEM_PROPMT2},
|
|
)
|
|
ee = time.time()
|
|
finall = format_answer_bale(
|
|
answer_text=llm_answer["text"], sources=llm_answer["source"]
|
|
)
|
|
eee = time.time()
|
|
print(f"Rag = {e-s}", f"llm_answer = {ee-e}", f"Format = {eee-ee}", sep="\n")
|
|
return finall
|
|
except:
|
|
traceback.print_exc()
|
|
|
|
|
|
class RagInput(BaseModel):
|
|
query: str
|
|
limit:int = 10
|
|
|
|
class RagOutput (BaseModel):
|
|
finall_form: str
|
|
duration: int
|
|
ids: List[str]
|
|
|
|
async def rag_run(input:RagInput):
|
|
try:
|
|
|
|
s = time.time()
|
|
sections_dict = await RAG.search_base(
|
|
query=input.query,
|
|
final_k=input.limit,
|
|
topk_dense=100,
|
|
topk_sparse=100,
|
|
pre_rerank_k=100,
|
|
)
|
|
e = time.time()
|
|
finall = get_in_form(title=input.query, sections=sections_dict)
|
|
ee = time.time()
|
|
print(f"Rag = {e-s}", f"Form = {ee-e}", sep="\n")
|
|
finall = RagOutput(
|
|
|
|
)
|
|
return finall
|
|
except:
|
|
traceback.print_exc()
|
|
|
|
|
|
@router.post("/run_chat")
|
|
async def run_chat(payload: Query, request: Request):
|
|
s = time.time()
|
|
try:
|
|
answer = await chat_bot_run(payload.query)
|
|
except:
|
|
print(f"chat_bot_run FAIL!")
|
|
answer = LLM_ERROR
|
|
e = time.time()
|
|
print(f"Total Time {e-s:.2f}'s")
|
|
return JSONResponse({"result": answer}, status_code=201)
|
|
|
|
|
|
@router.post("/run_rag")
|
|
async def run_chat(payload: Query, request: Request):
|
|
s = time.time()
|
|
try:
|
|
answer = await rag_run(payload.query)
|
|
except:
|
|
print(f"chat_bot_run FAIL!")
|
|
answer = LLM_ERROR
|
|
e = time.time()
|
|
print(f"Total Time {e-s:.2f}'s")
|
|
return JSONResponse({"result": answer}, status_code=201)
|