Compare commits

...

1 Commits

Author SHA1 Message Date
hsafaei
6acabcf52d untill reason button 2026-02-01 09:04:29 +00:00
12 changed files with 1518 additions and 372 deletions

View File

@ -369,10 +369,11 @@ class Formatter:
self, self,
_input: Union[List[RuleRelation], str], _input: Union[List[RuleRelation], str],
header="نتایج اولیه مغایرت های احتمالی :\n", header="نتایج اولیه مغایرت های احتمالی :\n",
end_button:List=[],
): ):
if isinstance(_input, str): if isinstance(_input, str):
_input = self.form_law_chat(_input) _input = self.form_law_chat(_input)
return _input, [], [] return _input, [],
else: else:
chunks = [] chunks = []
buttons = [] buttons = []
@ -384,19 +385,20 @@ class Formatter:
groups[title].add(item.db_rule.section_id) groups[title].add(item.db_rule.section_id)
current = header current = header
for idx, (qanon_title, section_ids) in enumerate(groups.items(), start=1): for idx, (qanon_title, sections_data) in enumerate(groups.items(), start=1):
block_lines = [f"{self.number(idx)} در قانون {self.bold(qanon_title)}"] block_lines = [f"{self.number(idx)} در قانون {self.bold(qanon_title)}"]
sample_items_by_section = {} sample_items_by_section = {}
for item in _input: for item in _input:
if ( if (
item.db_rule.qanon_title == qanon_title item.db_rule.qanon_title == qanon_title
and item.db_rule.section_id in section_ids and item.db_rule.section_id in sections_data
): ):
sid = item.db_rule.section_id sid = item.db_rule.section_id
if sid not in sample_items_by_section: if sid not in sample_items_by_section:
sample_items_by_section[sid] = item sample_items_by_section[sid] = item
for sub_idx, section_id in enumerate(sorted(section_ids), start=1): for sub_idx, section_id in enumerate(sorted(sections_data), start=1):
item = sample_items_by_section[section_id] # representative item item = sample_items_by_section[section_id] # representative item
link = self.__make_link_qs(src=section_id) link = self.__make_link_qs(src=section_id)
@ -451,8 +453,92 @@ class Formatter:
for i in v: for i in v:
mapping_data[k].append(input_dict[i]) mapping_data[k].append(input_dict[i])
for i in end_button:
buttons.append(i)
return chunks, buttons, mapping_data return chunks, buttons, mapping_data
async def structed_form_subject_unity(
self,
_input: Union[List[RuleRelation], str],
header="نتایج بررسی وحدت موضوعی :\n",
end_button:List=[],
):
"""
خروجی به صورت ساختارمند :
[پیام-دکمه], ...
"""
if isinstance(_input, str):
_input = self.form_law_chat(_input)
return _input, [], []
else:
chunks_data = []
groups_data = defaultdict(set)
main_idx = 1
current = header
# گروه بندی بر اساس عنوان قانون
for item in _input:
qanon_id = item.db_rule.qanon_id
is_unity = item.subject_unity.has_subject_unity
if is_unity != 'no':
groups_data[qanon_id].add(
item
)
for _idx, (qanon_id, rule_data) in enumerate(groups_data.items(), start=1):
# for idx, (qanon_title, rule_data) in enumerate(groups.items(), start=1):
for _idx2, single_data in enumerate(rule_data, start=1):
if _idx2 == 1:
qanon_title = single_data.db_rule.qanon_title
block_lines = [self.bold(current)]
block_lines += [f" در قانون {self.bold(qanon_title)}"]
link = self.__make_link_qs(src=single_data.db_rule.section_id)
unity = single_data.subject_unity
if not unity:
block_lines.append("\t\t")
continue
if unity.has_subject_unity == "yes":
block_lines.append(f"توضیح {main_idx} بر اساس {link}:")
block_lines.append(f"\t{unity.reasoning or ''}")
elif unity.has_subject_unity == "yes_under_assumptions":
block_lines.append(f"توضیح {main_idx} بر اساس {link}:")
block_lines.append(f"\t{unity.reasoning or ''}")
block_lines.append("\tتوضیحات بیشتر (فرضیات لازم):")
block_lines.append(f"\t{unity.required_assumptions or ''}")
main_idx += 1
m_text = "\n".join(block_lines)
# Auto-chunk based on length
if len(m_text) > MAX_LEN:
# chunking m_text
pass
else:
print(f'structed_form_subject_unity; {len(m_text)}')
_button = [[
{
"text": f"بررسی مغایرت",
"callback_data": f"subject_unities:qq:{qanon_id}",
}
]]
# end_button
if _idx == len(groups_data):
m_button = _button + end_button
else:
m_button = _button
chunks_data.append([m_text, m_button])
print(f'structed_form_subject_unity')
return chunks_data, groups_data
async def form_rule_making( async def form_rule_making(
self, _input, header="گزاره های حقوقی زیر استخراج شد:\n\n", footer=None self, _input, header="گزاره های حقوقی زیر استخراج شد:\n\n", footer=None
): ):
@ -591,6 +677,35 @@ class Formatter:
return ["هیچ ماده مرتبطی یافت نشد!"] return ["هیچ ماده مرتبطی یافت نشد!"]
async def form2_ss_rules(self, _input: List[SemanticSearchP2P], header):
if len(_input) > 1:
chunks = []
main_id = 0
block = [header]
# -------- 1. group by qanon_id / qanon_title
groups_data = defaultdict(set)
for item in _input:
title = item.db_rule.qanon_title
groups_data[title].add(item)
for _idx, (qanon_title, sections_data) in enumerate(groups_data.items(), start=1):
main_id += 1
block += [f"{self.number(main_id)} در قانون {self.bold(qanon_title)}:"]
for _idx2, sec_data in enumerate(sections_data, start=1):
block +=[f"تشابه با گزاره های حقوقی: {self.bold(sec_data.db_rule.section_full_path)} {self.__make_link_qs(sec_data.db_rule.section_id)} یافت شد."]
if len("\n".join(block)) > self.max_len:
chunks.append("\n".join(block))
block=[header]
if block and "".join(block) != header:
chunks.append("\n".join(block))
return chunks
return ["هیچ ماده مرتبطی یافت نشد!"]
async def form_conflict_detection( async def form_conflict_detection(
self, _input: RuleRelation, header="نتیجه تشخیص مغایرت :\n" self, _input: RuleRelation, header="نتیجه تشخیص مغایرت :\n"
): ):
@ -601,7 +716,7 @@ class Formatter:
current += f"به صورت خلاصه {_input.conflict_detection.has_confict}\n" current += f"به صورت خلاصه {_input.conflict_detection.has_confict}\n"
current += f"توضیحات : {_input.conflict_detection.explanation_of_conflict}\n" current += f"توضیحات : {_input.conflict_detection.explanation_of_conflict}\n"
return current return [current]
async def form_conflict_type_detection( async def form_conflict_type_detection(
self, _input: RuleRelation, header="نتیجه تشخیص نوع مغایرت :\n" self, _input: RuleRelation, header="نتیجه تشخیص نوع مغایرت :\n"
@ -613,7 +728,7 @@ class Formatter:
current += f"به صورت خلاصه {_input.conflict_type_detection.conflict_type}\n" current += f"به صورت خلاصه {_input.conflict_type_detection.conflict_type}\n"
current += f"توضیحات : {_input.conflict_type_detection.explanation_of_type}\n" current += f"توضیحات : {_input.conflict_type_detection.explanation_of_type}\n"
return current return [current]
async def form_relation_identification( async def form_relation_identification(
self, _input: RuleRelation, header="نتیجه رابطه مغایرت :\n" self, _input: RuleRelation, header="نتیجه رابطه مغایرت :\n"
@ -625,25 +740,23 @@ class Formatter:
current += f"به صورت خلاصه {_input.relation_identification.relation_type}\n" current += f"به صورت خلاصه {_input.relation_identification.relation_type}\n"
current += f"توضیحات : {_input.relation_identification.reasoning}\n" current += f"توضیحات : {_input.relation_identification.reasoning}\n"
return current return [current]
async def form_evaluation( async def form_evaluation(
self, _input: Evaluation, header="نتیجه نهایی بررسی مغایرت :\n" self, _input: Evaluation, header="نتیجه نهایی بررسی مغایرت :\n"
): ):
current = header current = [header]
# ساخت لینک # ساخت لینک
# _link = self.__make_link_qs(src=_input.db_rule.section_id) # _link = self.__make_link_qs(src=_input.db_rule.section_id)
current += f"1. آیا ارزیابی وحدت موضوع صحیح است؟ {_input.is_subject_unity_assessment_correct}\n" current += [f"1. آیا ارزیابی وحدت موضوع صحیح است؟ {_input.is_subject_unity_assessment_correct}"]
current += f"2. آیا ارزیابی تشخیص نوع درست است ؟ {_input.is_conflict_detection_correct}\n" current += [f"2. آیا ارزیابی تشخیص نوع درست است ؟ {_input.is_conflict_detection_correct}"]
current += f"3. آیا ارزیابی نوع درست است ؟ {_input.is_conflict_type_detection_correct}\n" current += [f"3. آیا ارزیابی نوع درست است ؟ {_input.is_conflict_type_detection_correct}"]
current += ( current += [f"4. رابطه مغایرت چطور؟ {_input.is_relation_type_detection_correct}"]
f"4. رابطه مغایرت چطور؟ {_input.is_relation_type_detection_correct}\n" current += [f"5. نوع رابطه ؟ {_input.valid_relation_type}"]
) current += [f"6.توضیح بیشتر: {_input.comments}"]
current += f"5. نوع رابطه ؟ {_input.valid_relation_type}\n"
current += f"6.توضیح بیشتر: {_input.comments}\n"
return current return "\n".join(current)
async def from_law_writing_policy( async def from_law_writing_policy(
self, _input_dict: Dict, header: str self, _input_dict: Dict, header: str

View File

@ -30,7 +30,7 @@ class Operation:
url="new/semantic_search", url="new/semantic_search",
) )
return BMNewSemanticSearchOutput.parse_obj(result) return BMNewSemanticSearchOutput.model_validate(result)
async def stream_search_in_law( async def stream_search_in_law(
self, query: str, limit: int, rerank_model: str, embed_model: str self, query: str, limit: int, rerank_model: str, embed_model: str
@ -113,7 +113,7 @@ class Operation:
url="/single/semantic_search/run_chat", url="/single/semantic_search/run_chat",
) )
print(f"chat_in_law {result}") print(f"chat_in_law {result}")
return ChatLaw.parse_obj(result) return ChatLaw.model_validate(result)
async def title_repeated( async def title_repeated(
self, self,

View File

@ -1,19 +1,33 @@
################# modularity ################# Static-Ui-Controll
### import from external-package ### bottuns
# from fastapi import FastAPI, Request, HTTPException B_PREVIOUS = "⬅️ مرحله قبل"
# import requests, logging, asyncio, httpx, os, uuid, traceback, orjson, copy, uvicorn, time, re B_HOME = "🏠 خانه"
# from dotenv import load_dotenv B_10MORE = "بارگذاری نتایج بیشتر 10+"
# from pathlib import Path B_MORE_EFFORT = "بررسی عمیق تر"
# from time import sleep B_STOP_PROCCESS = "توقف عملیات در حال اجراء"
# from enum import Enum B_WAIT = "⌛ در حال پردازش درخواست شما هستم..."
# from typing import Dict B_CHOICE_SUMMARY = "نمایش به صورت خلاصه"
# from utils.base_model import RuleRelation B_CHOICE_FULL= "نمایش به صورت کامل"
### static-text-message/callback
"""
پیام های رزرو شده برای در نظر گرفتن بعنوان CALLBACK و دکمه های کیبورد
"""
MC_JOST_JO = "جستجو"
MC_GOFT_GO = "گفتگو"
MC_HOME = "بازگشت به خانه"
### State-Static-Messages
SM_CHOICE = """لطفا یک مورد را انتخاب کنید:""" #برای انتخاب بین چند دکمه
################################################# ### Core-Options
# پارامتر های کلی ## Delay-Time
################################################# D_TIME_CHAT = 0.05
D_TIME_UI_TEMP_CHAT = 0.4
## limit
REQUEST_FREEZE_LIMIT = 3
MAX_RAG_LIMIT = 100
BUSY_TEXT = "⏳ درخواست قبلی شما در حال پردازش هست، لطفا تا اتمام آن منتظر بمانید ⏳"
EFFORT = "low" EFFORT = "low"
MAX_LIMIT_RAG = 100 # بیشینه تعدادی که rag برمی گرداند MAX_LIMIT_RAG = 100 # بیشینه تعدادی که rag برمی گرداند
STEP_RAG = 10 # مقداری که هر مرحله rag اضافه میکند با فشردن نمایش بیشتر more STEP_RAG = 10 # مقداری که هر مرحله rag اضافه میکند با فشردن نمایش بیشتر more
@ -24,3 +38,4 @@ QQ_WEB_LINK = (
"https://majles.tavasi.ir/entity/navigation/view/qasection/" # آدرس صفحه qq ها "https://majles.tavasi.ir/entity/navigation/view/qasection/" # آدرس صفحه qq ها
) )
REF_TEXT = "«منبع»" # برای نمایش منبع REF_TEXT = "«منبع»" # برای نمایش منبع

271
inProcees_md.txt Normal file
View File

@ -0,0 +1,271 @@
result ==> # Flowchart: Bale-Bot Backend System
## Main Application Flow
```
┌─────────────────────────────────────┐
│ main.py │
└──────────┬────────────────────────┘
┌─────────────────────────────────────┐
│ Lifespan Manager (Startup) │
│ ┌─────────────────────────────┐ │
│ │ Load .env variables │ │
│ │ Validate required vars │ │
│ │ Initialize ElasticHelper │ │
│ │ Set webhook URL │ │
│ │ Initialize UserManager │ │
│ │ Initialize Formatter │ │
│ │ Initialize RequestManager │ │
│ │ Initialize Operation │ │
│ │ Initialize BaleBotCore │ │
│ └─────────────────────────────┘ │
└──────────┬────────────────────────┘
┌─────────────────────────────────────┐
│ Application Factory │
│ ┌─────────────────────────────┐ │
│ │ Create FastAPI app │ │
│ │ Add CORS middleware │ │
│ │ Add health routes (/, /ping)│ │
│ │ Include Bale router │ │
│ └─────────────────────────────┘ │
└──────────┬────────────────────────┘
┌─────────────────────────────────────┐
│ FastAPI App Running │
└─────────────────────────────────────┘
```
## Core Classes Flow
### 1. ElasticHelper Class
```
┌─────────────────────────────────────┐
│ ElasticHelper │
├─────────────────────────────────────┤
│ __init__(es_url, es_pass, es_user) │
│ ┌─────────────────────────────┐ │
│ │ Connect to Elasticsearch │ │
│ │ Retry connection 10 times │ │
│ └─────────────────────────────┘ │
│ │
│ search(**params) │
│ get_document(index, id) │
│ exist_document(index, id) │
│ update_index_doc(is_update, ...) │
└─────────────────────────────────────┘
```
### 2. Formatter Class
```
┌─────────────────────────────────────┐
│ Formatter │
├─────────────────────────────────────┤
│ __init__(max_len) │
│ ┌─────────────────────────────┐ │
│ │ Initialize formatting tools │ │
│ │ Number mapping │ │
│ └─────────────────────────────┘ │
│ │
│ __getattr__(name) │
│ _bold(text) │
│ _number(value) │
│ _pretier1(text) │
│ __make_link_qq(src) │
│ __make_link_qs(src) │
│ │
│ form_search_in_law_rules(...) │
│ form_search_in_law(...) │
│ form_law_chat(answer_text) │
│ form_title_repeated(...) │
│ form_chat(llm_text, header) │
│ form_llm_answer_chat(...) │
│ form_subject_unity(...) │
│ structed_form_subject_unity(...) │
│ form_rule_making(...) │
│ get_asl(_in) │
│ get_in_form_single(asl, ...) │
│ form_constitution(input) │
│ form_constitution_low(...) │
│ form_ss_rules(...) │
│ form2_ss_rules(...) │
│ form_conflict_detection(...) │
│ form_conflict_type_detection(...) │
│ form_relation_identification(...) │
│ form_evaluation(...) │
│ from_law_writing_policy(...) │
└─────────────────────────────────────┘
```
### 3. RequestManager Class
```
┌─────────────────────────────────────┐
│ RequestManager │
├─────────────────────────────────────┤
│ __init__(host_url) │
│ ┌─────────────────────────────┐ │
│ │ Set base URL │ │
│ │ Define task URLs │ │
│ └─────────────────────────────┘ │
│ │
│ get_result(payload, url, ...) │
│ ┌─────────────────────────────┐ │
│ │ Async HTTP POST request │ │
│ │ Handle timeouts/errors │ │
│ └─────────────────────────────┘ │
│ │
│ stream_result(url, payload) │
│ ┌─────────────────────────────┐ │
│ │ Stream HTTP POST response │ │
│ │ Yield JSON lines │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
```
### 4. Operation Class
```
┌─────────────────────────────────────┐
│ Operation │
├─────────────────────────────────────┤
│ __init__(request_manager) │
│ │
│ search_in_law(query, limit, ...) │
│ stream_search_in_law(...) │
│ stream_rule_making(...) │
│ stream_chat_in_law(...) │
│ stream_rule_semantic_search(...) │
│ chat_in_law(query, effort, ...) │
│ title_repeated(qanontitle, ...) │
│ talk(query) │
│ conflict_qanon_asasi_low(...) │
│ conflict_qanon_asasi_steps(...) │
│ stream_logical_chat_in_law(...) │
│ conflict_law_writing_policy(...) │
└─────────────────────────────────────┘
```
### 5. UserManager Class
```
┌─────────────────────────────────────┐
│ UserManager │
├─────────────────────────────────────┤
│ __init__() │
│ ┌─────────────────────────────┐ │
│ │ Load VIP usernames │ │
│ │ Load temporary data │ │
│ └─────────────────────────────┘ │
│ │
│ get_or_create(update) │
│ ┌─────────────────────────────┐ │
│ │ Extract user info │ │
│ │ Check VIP status │ │
│ │ Create/update user object │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
```
### 6. BaleBotCore Class
```
┌─────────────────────────────────────┐
│ BaleBotCore │
├─────────────────────────────────────┤
│ __init__(...) │
│ ┌─────────────────────────────┐ │
│ │ Initialize UI handler │ │
│ │ Setup components │ │
│ └─────────────────────────────┘ │
│ │
│ render_user_state(user) │
│ ┌─────────────────────────────┐ │
│ │ Get user state │ │
│ │ Call appropriate handler │ │
│ └─────────────────────────────┘ │
│ │
│ render_update(update) │
│ ┌─────────────────────────────┐ │
│ │ Process incoming updates │ │
│ │ Route to handlers │ │
│ └─────────────────────────────┘ │
│ │
│ handle_main(user) │
│ handle_search_in_law(user) │
│ handle_rule_making(user) │
│ handle_chat_in_law(user) │
│ handle_qanon_title_repeat(user) │
│ handle_talk(user) │
│ handle_logical_chat_in_law(user) │
│ handle_conflict_qanon_asasi(user) │
│ handle_conflict_law_writing_policy(user) │
│ handle_subject_unities_to_evalution(user) │
│ handle_summary_conflict_all_qavanin(user) │
│ handle_full_conflict_all_qavanin(user) │
│ handle_conflict_general_policy(user) │
│ handle_advanced_check_conflict(user) │
│ handle_stream_chat(user) │
│ handle_beta(user) │
│ │
│ save_to_db(user, data) │
└─────────────────────────────────────┘
```
### 7. BaleBotBase Class
```
┌─────────────────────────────────────┐
│ BaleBotBase │
├─────────────────────────────────────┤
│ __init__(send_msg_url, ...) │
│ │
│ delete_bale_message(chat_id, message_id) │
│ update_bale_message(user, text, buttons) │
│ serialize(obj) │
│ normalize_messages(...) │
│ send_message_helper(...) │
│ send_bale_message(...) │
└─────────────────────────────────────┘
```
### 8. BaleBotUI Class
```
┌─────────────────────────────────────┐
│ BaleBotUI │
├─────────────────────────────────────┤
│ __init__(delay_time, ...) │
│ ┌─────────────────────────────┐ │
│ │ Initialize heartbeat settings │ │
│ └─────────────────────────────┘ │
│ │
│ active(user) │
│ cancel(user) │
│ create(user, main_text, waiting_list) │
│ heartbeat_loop(user, waiting_list) │
└─────────────────────────────────────┘
```
### 9. StackManager Class
```
┌─────────────────────────────────────┐
│ StackManager │
├─────────────────────────────────────┤
│ push(output_pure_data, ...) │
│ last_item(user) │
│ get_last_item_metadata(user) │
│ prev_item(user) │
│ get(user, name) │
│ cleanup(user) │
│ set_runtime(user, index, runtime_ms) │
└─────────────────────────────────────┘
```
## Data Flow Between Components
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ FastAPI App │───▶│ BaleBotCore │───▶│ RequestManager │
└─────────────────┘ │ │ │ │
│ │ │ │
│ │ │ │

View File

@ -5,7 +5,7 @@ from core.core import ElasticHelper, Formatter, RequestManager
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from router.bale.bale import router as bale_router from router.bale.bale import router as bale_router
from router.bale.bale import initialize_webhook from router.bale.bale import initialize_webhook
from router.bale.bale_handle import BaleBot, UserManager from router.bale.bale_handle import BaleBotCore, UserManager
from core.operation import Operation from core.operation import Operation
from dotenv import load_dotenv from dotenv import load_dotenv
import os import os
@ -72,15 +72,17 @@ async def lifespan(app: FastAPI):
request_manager=app.state.request_manager, request_manager=app.state.request_manager,
) )
# بله بات # بله بات
bale_bot = BaleBot( bale_bot = BaleBotCore(
operation=app.state.operation, operation=app.state.operation,
user_manager=app.state.user_manager, user_manager=app.state.user_manager,
es_helper=app.state.es_helper, es_helper=app.state.es_helper,
es_index_name=app.state.es_index_name, es_index_name=app.state.es_index_name,
token=app.state.bale_token,
formatter= app.state.formatter, formatter= app.state.formatter,
back_end_url = BACK_END_URL, back_end_url = BACK_END_URL,
request_manager = app.state.request_manager, request_manager = app.state.request_manager,
send_message_url = f"https://tapi.bale.ai/bot{TOKEN}/sendMessage",
delete_message_url = f"https://tapi.bale.ai/bot{TOKEN}/deleteMessage",
update_message_url = f"https://tapi.bale.ai/bot{TOKEN}/editMessageText",
) )
app.state.bale_bot = bale_bot app.state.bale_bot = bale_bot
print("✅✅✅ Bale-Bot Initialized ✅✅✅") print("✅✅✅ Bale-Bot Initialized ✅✅✅")

View File

@ -9,7 +9,7 @@ Operation (logic layer)
└── return OperationResult └── return OperationResult
BaleBot (delivery / interface layer) BaleBotCore (delivery / interface layer)
├── دریافت user ├── دریافت user
├── صدا زدن Operation ├── صدا زدن Operation
@ -19,4 +19,83 @@ BaleBot (delivery / interface layer)
# Logic & Flow # Logic & Flow
Operation → منطق، پردازش، گرفتن دیتا، تصمیم‌گیری Operation → منطق، پردازش، گرفتن دیتا، تصمیم‌گیری
BaleBot → ورودی/خروجی، ارتباط با بله، فرمت پیام، دکمه‌ها، مدیریت state کاربر BaleBotCore → ورودی/خروجی، ارتباط با بله، فرمت پیام، دکمه‌ها، مدیریت state کاربر
# FlowChart
/
└── main.py
│ └── fast-api app
├── core
│ └── core.py
│ ├── class Formatter : فرمت دهی و مدیریت استایل ها و UI
│ ├── class RequestManager : درخواست ها و داده ها را از بک اند میگیرد در دو نوع async (chunk-chunk) و ساده
│ └── class ElasticHelper : مدیریت و ارتباط با الاستیک سرچ
├── router
│ └── bale
│ ├── bale.py
│ │ ├── func webhook : دریافت داده از بله
│ │ └── func initialize_webhook : شناساندن ربات به بله
│ ├── bale_handle.py
│ │ ├── class BaleBotBase : برای مدیریت پیام ها و دکمه ها و 3 url send, update, delet ارتباط با سرور بله
│ │ ├── class BaleBotUI : مدیریت پیام های موقتی
│ │ ├── class StackManager : مدیریت داده های کاربر در پشته یا stack
│ │ └── class BaleBotCore : ساختار ربات و انجام state ها
│ │ ├── func render_update : مسئول گرفتن داده از بله به دو صورت BaleStartMessage یا BaleCallbackQuery
│ │ ├── func render_user_state : وظیفه مدیریت و پاس دادن هر ورودی به بر اساس state به تابع موردنظر
│ │ ├── func handle_previous_message : دسترسی به پیام مرحله قبل (بزودی باید با stack هندل شود)
│ │ ├── func handle_main : صفحه اول - حذف کننده داده ها و ریست داده ها
│ │ ├── func handle_search_in_law :
│ │ ├── func handle_search_in_law_rules
│ │ ├── func handle_rule_making
│ │ ├── func handle_chat_in_law
│ │ ├── func handle_qanon_title_repeat
│ │ ├── func handle_logical_chat_in_law
│ │ ├── func handle_conflict_qanon_asasi
│ │ ├── func handle_conflict_law_writing_policy
│ │ ├── func handle_subject_unities_to_evalution
│ │ ├── func show_stack_data
│ │ ├── func handle_summary_conflict_all_qavanin
│ │ ├── func save_to_db
│ │ └──
# input-flow
User-Input
app → initialize_webhook → Bale-Server
webhook
BaleBotCore
└→ BaleBotBase
└→ BaleBotUI
└→ StackManager
└→ UserManager
└→ Operation

View File

@ -1,4 +1,3 @@
elasticsearch==8.13.2 elasticsearch==8.13.2
nltk nltk
pydantic pydantic
fast-api

View File

@ -1,7 +1,7 @@
# router.bale_bot.py # router.bale_bot.py
from fastapi import Depends, APIRouter, Request from fastapi import Depends, APIRouter, Request
import requests, traceback import requests, traceback
from router.bale.bale_handle import BaleBot, BaleUpdate from router.bale.bale_handle import BaleBotCore, BaleUpdate
from dependencies import _get_bale_token, _get_bale_bot from dependencies import _get_bale_token, _get_bale_bot
@ -20,7 +20,7 @@ chat_id
async def webhook( async def webhook(
request: Request, request: Request,
token: str = Depends(_get_bale_token), token: str = Depends(_get_bale_token),
bale_bot: BaleBot = Depends(_get_bale_bot), bale_bot: BaleBotCore = Depends(_get_bale_bot),
): ):
raw = await request.json() raw = await request.json()
# print(' webhook request ', raw) # print(' webhook request ', raw)

View File

@ -1,11 +1,17 @@
BACK_BUTTON = {"text": "⬅️ مرحله قبل", "callback_data": "workflow_back"} from core.static import *
HOME_BUTTON = {"text": "🏠 خانه", "callback_data": "main"}
MORE_LIMIT_BUTTON = {"text": "بارگذاری نتایج بیشتر 10+", "callback_data": "more_limit"} PREVIOUS_BUTTON = {"text": B_PREVIOUS, "callback_data": "previous_message"}
# MORE_EFFORT_BUTTON = {"text": "🧠 بررسی عمیق تر", "callback_data": "more_effort"} HOME_BUTTON = {"text": B_HOME, "callback_data": "main"}
MORE_EFFORT_BUTTON = {"text": "بررسی عمیق تر", "callback_data": "more_effort"} MORE_LIMIT_BUTTON = {"text": B_10MORE, "callback_data": "more_limit"}
MORE_EFFORT_BUTTON = {"text": B_MORE_EFFORT, "callback_data": "more_effort"}
STOP_PROCCESS = {"text":B_STOP_PROCCESS, "callback_data":"main"}
BUTTON_TEXT_TO_CALLBACK_LIST = [ BUTTON_TEXT_TO_CALLBACK_LIST = [
{"text": "جستجو"}, {"text": MC_JOST_JO},
{"text": "گفتگو"}, {"text": MC_GOFT_GO},
{"text": "بازگشت به خانه"}, {"text": MC_HOME},
] ]

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ from router.bale.bale_buttons import BUTTON_TEXT_TO_CALLBACK_LIST
import json import json
from typing import Optional, Callable, List, Any from typing import Optional, Callable, List, Any
from pydantic import BaseModel from pydantic import BaseModel
from time import time
class SingleSearchData(BaseModel): class SingleSearchData(BaseModel):
@ -11,6 +12,7 @@ class SingleSearchData(BaseModel):
id: str id: str
content: str content: str
class BMNewSemanticSearchOutput(BaseModel): class BMNewSemanticSearchOutput(BaseModel):
query: str query: str
result: List[SingleSearchData] result: List[SingleSearchData]
@ -32,6 +34,7 @@ class DbRule(BaseModel):
qanon_title: str qanon_title: str
state_etebar: str state_etebar: str
class InputRule(BaseModel): class InputRule(BaseModel):
rule_id: str rule_id: str
rule_content: str rule_content: str
@ -39,12 +42,23 @@ class InputRule(BaseModel):
section_id: str section_id: str
section_content: str section_content: str
class SemanticSearchP2P(BaseModel): class SemanticSearchP2P(BaseModel):
in_rule: InputRule in_rule: InputRule
db_rule: DbRule db_rule: DbRule
score: float = 0 score: float = 0
metadata: Dict metadata: Dict
def __eq__(self, other):
return (
isinstance(other, RuleRelation)
and self.db_rule.section_id == other.db_rule.section_id
)
def __hash__(self):
return hash(self.db_rule.section_id)
class BaleStartMessageForm(BaseModel): class BaleStartMessageForm(BaseModel):
id: int id: int
is_bot: bool = False is_bot: bool = False
@ -181,6 +195,8 @@ class RelationIdentification(BaseModel):
"تعارض مستقر", "تعارض مستقر",
"بدون تعارض", "بدون تعارض",
] ]
class Evaluation(BaseModel): class Evaluation(BaseModel):
is_subject_unity_assessment_correct: bool is_subject_unity_assessment_correct: bool
is_conflict_detection_correct: bool is_conflict_detection_correct: bool
@ -189,6 +205,7 @@ class Evaluation(BaseModel):
valid_relation_type: str valid_relation_type: str
comments: str comments: str
class SingleRuleRelation(BaseModel): class SingleRuleRelation(BaseModel):
rule_id: str rule_id: str
rule_content: str rule_content: str
@ -241,6 +258,16 @@ class RuleRelation(BaseModel):
# ----- relation-identification data # ----- relation-identification data
relation_identification: RelationIdentification | None = None relation_identification: RelationIdentification | None = None
def __eq__(self, other):
return (
isinstance(other, RuleRelation)
and self.db_rule.section_id == other.db_rule.section_id
)
def __hash__(self):
return hash(self.db_rule.section_id)
class StateDetail(BaseModel): class StateDetail(BaseModel):
state: str state: str
message: str message: str
@ -251,6 +278,39 @@ class StateDetail(BaseModel):
handler: str = None handler: str = None
allow_empty_input: bool = True allow_empty_input: bool = True
class BaleButton(BaseModel):
text: str
callback_data: str
class BaleMessage(BaseModel):
text: str
buttons: List[List[BaleButton]] = []
class PreviousMessage(BaseModel):
message: List | str
buttons: List[List[BaleButton]] = []
type: Literal["text", "chunked_text", "structured_text"]
class StackItem(BaseModel):
index: int
step_name: str
input_data: Any | int | None = (
None # اگر عدد بود یعنی داده از مرحله ایندکس قبلی امده
)
output_pure_data: Any
output_formed_data: Optional[PreviousMessage] = None
created_at: int = Field(default_factory=lambda: int(time()))
runtime_ms: float = -1
metadata: Dict[str, Any] = Field(default_factory=dict)
class BaleUser(BaseModel): class BaleUser(BaseModel):
uc_id: str uc_id: str
chat_id: int chat_id: int
@ -262,7 +322,8 @@ class BaleUser(BaseModel):
first_name: str = "" first_name: str = ""
last_name: str = "" last_name: str = ""
message_limit: int = 0 message_limit: int = 0
rule_relation: RuleRelation | None = None previous_message: PreviousMessage = None
rule_relation: RuleRelation | str | None = None
subject_unities: Dict = {} subject_unities: Dict = {}
# ---- defaults # ---- defaults
@ -287,10 +348,7 @@ class BaleUser(BaseModel):
# ---- memory # ---- memory
last_query: Dict[str, str] = {} # آخرین سوال کاربر last_query: Dict[str, str] = {} # آخرین سوال کاربر
last_result: Dict[str, Any] = {} # آخرین نتایج last_result: Dict[str, Any] = {} # آخرین نتایج
last_runtime: Dict[str, Any] = ( stack: List[StackItem] = [] # پشته برای داده های مرحله ای
{}
) # مثلا {"GP": {"effort": "medium", "limit": 20}} برای بقیه چیزها
stack: Dict[str, List] = {} # پشته برای داده های مرحله ای
class KeyboardItem(BaseModel): class KeyboardItem(BaseModel):
@ -326,4 +384,3 @@ class Step(BaseModel):
data_input: str data_input: str
data_output: str data_output: str
bot_output: List bot_output: List

View File

@ -1,10 +1,6 @@
from router.bale.base_model import StateDetail from router.bale.base_model import StateDetail
from core.static import *
from router.bale.bale_buttons import *
BUSY_TEXT = "⏳ درخواست قبلی شما در حال پردازش هست، لطفا تا اتمام آن منتظر بمانید ⏳"
class StateRegistry: class StateRegistry:
def __init__(self, states): def __init__(self, states):
@ -17,7 +13,6 @@ class StateRegistry:
return list(self._states.values()) return list(self._states.values())
STATE = [ STATE = [
StateDetail( StateDetail(
state="search_in_law", state="search_in_law",
@ -68,12 +63,35 @@ STATE = [
message="""لطفا متن قانونی مورد نظر برای بررسی مغایرت با سیاست های کلی نظام را وارد کنید :""", message="""لطفا متن قانونی مورد نظر برای بررسی مغایرت با سیاست های کلی نظام را وارد کنید :""",
handler="handle_conflict_general_policy", handler="handle_conflict_general_policy",
), ),
# StateDetail(
# state="choice_conflict_all_qavanin",
# button_text="بررسی مغایرت در تمام قوانین",
# end_buttons=[
# [{"text":B_CHOICE_SUMMARY,"callback_data":"summary_conflict_all_qavanin"}],
# [{"text":B_CHOICE_FULL,"callback_data":"full_conflict_all_qavanin"}],
# ],
# message=SM_CHOICE,
# ),
StateDetail( StateDetail(
state="conflict_all_qavanin", state="subject_unities_to_evalution",
button_text="بررسی مغایرت مرحله اول",
end_buttons=[],
message="""""",
handler="handle_subject_unities_to_evalution",
),
StateDetail(
state="full_conflict_all_qavanin",
button_text="بررسی مغایرت در تمام قوانین", button_text="بررسی مغایرت در تمام قوانین",
end_buttons=[], end_buttons=[],
message="""لطفا متن قانونی مورد نظر برای بررسی مغایرت در تمام قوانین جمهوری اسلامی ایران را وارد کنید :""", message="""لطفا متن قانونی مورد نظر برای بررسی مغایرت در تمام قوانین جمهوری اسلامی ایران را وارد کنید :""",
handler="handle_conflict_all_qavanin", handler="handle_full_conflict_all_qavanin",
),
StateDetail(
state="summary_conflict_all_qavanin",
button_text="بررسی مغایرت در تمام قوانین",
end_buttons=[],
message="""لطفا متن قانونی مورد نظر برای بررسی مغایرت در تمام قوانین جمهوری اسلامی ایران را وارد کنید :""",
handler="handle_summary_conflict_all_qavanin",
), ),
StateDetail( StateDetail(
state="qanon_title_repeat", state="qanon_title_repeat",
@ -106,6 +124,12 @@ STATE = [
button_text="در دست توسعه", button_text="در دست توسعه",
message="""این قسمت در دست توسعه قرار دارد.""", message="""این قسمت در دست توسعه قرار دارد.""",
), ),
StateDetail(
state="previous_message",
button_text="",
message="",
handler='handle_previous_message'
),
StateDetail( StateDetail(
state="about_us", state="about_us",
button_text="درباره ما ⚡", button_text="درباره ما ⚡",
@ -118,8 +142,10 @@ STATE = [
), ),
] ]
STATE_REGISTERY = StateRegistry(STATE) STATE_REGISTERY = StateRegistry(STATE)
STATE_CONFIG = {i.state: i for i in STATE} STATE_CONFIG = {i.state: i for i in STATE}
# MAIN_BUTTON = {i.state: i for i in STATE}
def build_buttons_form(button_form): def build_buttons_form(button_form):
@ -132,16 +158,16 @@ def build_buttons_form(button_form):
if not state: if not state:
continue continue
row_buttons.append({ row_buttons.append(
"text": state.button_text, {"text": state.button_text, "callback_data": state.state}
"callback_data": state.state )
})
if row_buttons: if row_buttons:
buttons.append(row_buttons) buttons.append(row_buttons)
return buttons return buttons
# Button-STYLE # Button-STYLE
main_button_form = [ main_button_form = [
["chat_in_law"], ["chat_in_law"],
@ -151,7 +177,7 @@ main_button_form = [
["conflict_law_writing_policy"], ["conflict_law_writing_policy"],
["conflict_qanon_asasi"], ["conflict_qanon_asasi"],
["conflict_general_policy"], ["conflict_general_policy"],
["conflict_all_qavanin"], ["summary_conflict_all_qavanin"],
["contact_us", "about_us", "beta"] ["contact_us", "about_us", "beta"],
] ]
MAIN_BUTTON = build_buttons_form(main_button_form) MAIN_BUTTON = build_buttons_form(main_button_form)