Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from common import ROOT, read_yaml_mapping
|
||||
|
||||
|
||||
DEFAULT_PROFILES = ROOT / "plugins" / "1c" / "rag" / "profiles.yaml"
|
||||
DEFAULT_PROFILE = "auto"
|
||||
|
||||
PROFILE_KEYWORDS = {
|
||||
"metadata": [
|
||||
"метадан",
|
||||
"реквизит",
|
||||
"табличн",
|
||||
"справочник",
|
||||
"документ",
|
||||
"регистр",
|
||||
"форма",
|
||||
"объект",
|
||||
"конфигурац",
|
||||
],
|
||||
"bsl": [
|
||||
"bsl",
|
||||
"бсл",
|
||||
"код",
|
||||
"процедур",
|
||||
"функц",
|
||||
"модул",
|
||||
"ошибк",
|
||||
"переменн",
|
||||
"конецесли",
|
||||
"передзаписью",
|
||||
],
|
||||
"query": [
|
||||
"запрос",
|
||||
"выбрать",
|
||||
"срез",
|
||||
"остатк",
|
||||
"read-only",
|
||||
"readonly",
|
||||
"sql",
|
||||
],
|
||||
"safe-change": [
|
||||
"измен",
|
||||
"переимен",
|
||||
"production",
|
||||
"прод",
|
||||
"резерв",
|
||||
"backup",
|
||||
"соглас",
|
||||
"безопас",
|
||||
"удалить",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def load_rag_profiles(path: Path = DEFAULT_PROFILES) -> dict[str, dict[str, Any]]:
|
||||
data = read_yaml_mapping(path)
|
||||
profiles = data.get("profiles")
|
||||
if not isinstance(profiles, dict):
|
||||
raise ValueError(f"{path} must contain a profiles mapping")
|
||||
return {str(name): dict(value or {}) for name, value in profiles.items()}
|
||||
|
||||
|
||||
def get_rag_profile(name: str | None, path: Path = DEFAULT_PROFILES) -> dict[str, Any]:
|
||||
profiles = load_rag_profiles(path)
|
||||
profile_name = name or DEFAULT_PROFILE
|
||||
if profile_name not in profiles:
|
||||
available = ", ".join(sorted(profiles))
|
||||
raise ValueError(f"Unknown RAG profile `{profile_name}`. Available: {available}")
|
||||
profile = profiles[profile_name]
|
||||
profile["id"] = profile_name
|
||||
profile.setdefault("source_types", [])
|
||||
profile.setdefault("limit", 4)
|
||||
profile.setdefault("candidate_limit", 40)
|
||||
profile.setdefault("min_score", 0.0)
|
||||
profile.setdefault("max_context_chars", 12000)
|
||||
profile.setdefault("dedupe_by_document", False)
|
||||
return profile
|
||||
|
||||
|
||||
def detect_rag_profile(question: str) -> str:
|
||||
text = question.lower().replace("ё", "е")
|
||||
scores = {
|
||||
profile: sum(1 for keyword in keywords if keyword in text)
|
||||
for profile, keywords in PROFILE_KEYWORDS.items()
|
||||
}
|
||||
best_profile, best_score = max(scores.items(), key=lambda item: item[1])
|
||||
return best_profile if best_score > 0 else "general"
|
||||
|
||||
|
||||
def resolve_rag_profile(name: str | None, question: str, path: Path = DEFAULT_PROFILES) -> dict[str, Any]:
|
||||
profile_name = name or DEFAULT_PROFILE
|
||||
if profile_name == "auto":
|
||||
profile_name = detect_rag_profile(question)
|
||||
return get_rag_profile(profile_name, path)
|
||||
|
||||
|
||||
def list_rag_profiles(path: Path = DEFAULT_PROFILES) -> list[dict[str, Any]]:
|
||||
return [get_rag_profile(name, path) for name in sorted(load_rag_profiles(path))]
|
||||
Reference in New Issue
Block a user