AI UPDATE

This commit is contained in:
2026-03-22 03:08:27 +03:30
parent 3ee14ca977
commit d977a583c6
37 changed files with 3525 additions and 263 deletions
+66 -25
View File
@@ -4,7 +4,7 @@
import logging
from pathlib import Path
from .config import load_rag_config, RAGConfig
from .config import load_rag_config, RAGConfig, get_service_config, ServiceConfig
from .api_provider import get_chat_client
from .retrieve import search_with_query
from .user_data import build_user_soil_text, build_user_weather_text
@@ -43,6 +43,16 @@ def _load_kb_tone(kb_name: str, config: RAGConfig | None = None) -> str:
return ""
def _load_service_tone(service: ServiceConfig, config: RAGConfig | None = None) -> str:
cfg = config or load_rag_config()
if service.tone_file:
base = Path(__file__).resolve().parent.parent
tone_path = base / service.tone_file
if tone_path.exists():
return tone_path.read_text(encoding="utf-8").strip()
return _load_kb_tone(service.knowledge_base, cfg)
def _detect_kb_intent(query: str) -> str:
"""تشخیص ساده نوع پایگاه دانش مورد نیاز از روی متن سوال."""
q = query.lower()
@@ -59,10 +69,11 @@ def _detect_kb_intent(query: str) -> str:
def build_rag_context(
query: str,
sensor_uuid: str,
sensor_uuid: str | None = None,
config: RAGConfig | None = None,
limit: int = 8,
kb_name: str | None = None,
service_id: str | None = None,
) -> str:
"""
ساخت context برای LLM: دیتای فعلی خاک کاربر + متن‌های مرتبط از RAG.
@@ -76,24 +87,34 @@ def build_rag_context(
len(query or ""),
)
parts: list[str] = []
cfg = config or load_rag_config()
service = get_service_config(service_id, cfg) if service_id else None
include_user_embeddings = service.use_user_embeddings if service else True
resolved_kb_name = kb_name or (service.knowledge_base if service else None)
user_soil = build_user_soil_text(sensor_uuid)
if user_soil and user_soil.strip():
parts.append("[داده‌های فعلی خاک شما]\n" + user_soil.strip())
logger.debug("Included user soil section sensor_uuid=%s", sensor_uuid)
else:
logger.info("No user soil data found sensor_uuid=%s", sensor_uuid)
if include_user_embeddings and sensor_uuid:
user_soil = build_user_soil_text(sensor_uuid)
if user_soil and user_soil.strip():
parts.append("[داده‌های فعلی خاک شما]\n" + user_soil.strip())
logger.debug("Included user soil section sensor_uuid=%s", sensor_uuid)
else:
logger.info("No user soil data found sensor_uuid=%s", sensor_uuid)
weather_text = build_user_weather_text(sensor_uuid)
if weather_text and weather_text.strip():
parts.append("[پیش‌بینی هواشناسی]\n" + weather_text.strip())
logger.debug("Included weather section sensor_uuid=%s", sensor_uuid)
else:
logger.info("No weather data found sensor_uuid=%s", sensor_uuid)
weather_text = build_user_weather_text(sensor_uuid)
if weather_text and weather_text.strip():
parts.append("[پیش‌بینی هواشناسی]\n" + weather_text.strip())
logger.debug("Included weather section sensor_uuid=%s", sensor_uuid)
else:
logger.info("No weather data found sensor_uuid=%s", sensor_uuid)
results = search_with_query(
query, sensor_uuid=sensor_uuid, limit=limit, config=config,
kb_name=kb_name,
query,
sensor_uuid=sensor_uuid,
limit=limit,
config=cfg,
kb_name=resolved_kb_name,
service_id=service_id,
use_user_embeddings=include_user_embeddings,
)
if results:
logger.info("Retrieved RAG results count=%s sensor_uuid=%s", len(results), sensor_uuid)
@@ -109,11 +130,12 @@ def build_rag_context(
def chat_rag_stream(
query: str,
sensor_uuid: str,
sensor_uuid: str | None = None,
config: RAGConfig | None = None,
limit: int = 5,
system_override: str | None = None,
kb_name: str | None = None,
service_id: str | None = None,
):
logger.info(
"chat_rag_stream started sensor_uuid=%s kb_name=%s limit=%s query_len=%s",
@@ -137,24 +159,43 @@ def chat_rag_stream(
تک‌تک deltaهای content به‌صورت رشته
"""
cfg = config or load_rag_config()
client = get_chat_client(cfg)
model = cfg.llm.model
logger.debug("Loaded RAG config with model=%s", model)
resolved_service_id = service_id or kb_name or _detect_kb_intent(query)
service = get_service_config(resolved_service_id, cfg)
service_llm_config = service.llm
service_cfg = RAGConfig(
embedding=cfg.embedding,
qdrant=cfg.qdrant,
chunking=cfg.chunking,
llm=service_llm_config,
knowledge_bases=cfg.knowledge_bases,
services=cfg.services,
chromadb=cfg.chromadb,
)
client = get_chat_client(service_cfg)
model = service_llm_config.model
logger.debug("Loaded service config service_id=%s model=%s", resolved_service_id, model)
detected_kb = kb_name or _detect_kb_intent(query)
logger.info("Using knowledge base=%s", detected_kb)
detected_kb = kb_name or service.knowledge_base
logger.info("Using knowledge base=%s for service_id=%s", detected_kb, resolved_service_id)
context = build_rag_context(
query, sensor_uuid, config=cfg, limit=limit, kb_name=detected_kb,
query,
sensor_uuid,
config=cfg,
limit=limit,
kb_name=detected_kb,
service_id=resolved_service_id,
)
logger.debug("Built context length=%s", len(context))
if system_override is not None:
system_content = system_override
else:
tone = _load_kb_tone(detected_kb, cfg)
tone = _load_service_tone(service, cfg)
if not tone:
tone = _load_tone(cfg)
system_parts = [tone] if tone else []
if service.system_prompt:
system_parts.append(service.system_prompt)
system_parts.append(
"با استفاده از بخش «داده‌های فعلی خاک شما» و «متن‌های مرجع» زیر به سوال کاربر پاسخ بده. "
"برای سوالاتی درباره خاک کاربر (مثل pH، رطوبت، NPK) حتماً از داده‌های فعلی استفاده کن. "
@@ -169,7 +210,7 @@ def chat_rag_stream(
{"role": "system", "content": system_content},
{"role": "user", "content": query},
]
logger.info("Prepared messages for model=%s message=%s", model,messages)
logger.info("Prepared messages for model=%s service_id=%s", model, resolved_service_id)
stream = client.chat.completions.create(
model=model,