Merge remote-tracking branch 'origin/CODEX' into main_laptop_1
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""원문 Markdown 검색과 Gemini 설명. 실무문서는 어떤 경로에서도 읽지 않는다."""
|
||||
"""지식DB Markdown 검색과 Gemini 설명. 제외 폴더는 읽지 않는다."""
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -12,7 +12,8 @@ from pydantic import BaseModel, Field
|
||||
from common_util.common_util_auth import verify_session
|
||||
|
||||
router = APIRouter(prefix="/knowledge-chat", tags=["B01_KnowledgeChat"])
|
||||
ORIGINAL = Path(__file__).resolve().parents[1] / "resources" / "knowledge" / "original"
|
||||
KNOWLEDGE = Path(__file__).resolve().parents[1] / "resources" / "knowledge"
|
||||
EXCLUDED = ("실무문서", "stmate", "다산소프트")
|
||||
MODEL = "gemini-3.8-flash"
|
||||
|
||||
|
||||
@@ -21,24 +22,26 @@ class ChatRequest(BaseModel):
|
||||
|
||||
|
||||
def _allowed(path: Path) -> bool:
|
||||
return path.suffix.lower() == ".md" and "실무문서" not in path.relative_to(ORIGINAL).parts
|
||||
return path.suffix.lower() == ".md" and not any(
|
||||
excluded in part.casefold()
|
||||
for part in path.relative_to(KNOWLEDGE).parts
|
||||
for excluded in EXCLUDED
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _sections() -> list[tuple[str, str]]:
|
||||
sections = []
|
||||
for path in ORIGINAL.rglob("*.md"):
|
||||
for path in KNOWLEDGE.rglob("*.md"):
|
||||
if not _allowed(path):
|
||||
continue
|
||||
relative = path.relative_to(ORIGINAL).as_posix()
|
||||
if path.name in {"CHANGELOG.md", "_index.md"} or path.name.startswith("_"):
|
||||
continue
|
||||
relative = path.relative_to(KNOWLEDGE).as_posix()
|
||||
content = path.read_text(encoding="utf-8", errors="replace")
|
||||
for part in re.split(r"(?=^#{1,4} )", content, flags=re.MULTILINE):
|
||||
part = part.strip()
|
||||
for start in range(0, len(part), 1800):
|
||||
snippet = part[start : start + 1800].strip()
|
||||
if len(snippet) >= 40:
|
||||
if snippet:
|
||||
sections.append((relative, snippet))
|
||||
return sections
|
||||
|
||||
|
||||
@@ -3,14 +3,23 @@ import asyncio
|
||||
from B01_Dashboard import B01_Dashboard_Knowledge_Chat as chat
|
||||
|
||||
|
||||
def test_chat_excludes_practice_documents_from_gemini(monkeypatch, tmp_path):
|
||||
public = tmp_path / "법률"
|
||||
private = tmp_path / "실무문서"
|
||||
public.mkdir()
|
||||
def test_chat_searches_all_knowledge_markdown_except_excluded_folders(monkeypatch, tmp_path):
|
||||
public = tmp_path / "original" / "법률"
|
||||
guide = tmp_path / "technical_info"
|
||||
private = tmp_path / "original" / "실무문서"
|
||||
stmate = tmp_path / "original" / "원가계산" / "STmate"
|
||||
dasan = tmp_path / "original" / "원가계산" / "다산소프트"
|
||||
public.mkdir(parents=True)
|
||||
guide.mkdir()
|
||||
private.mkdir()
|
||||
stmate.mkdir(parents=True)
|
||||
dasan.mkdir()
|
||||
(public / "현행.md").write_text("# 임도 기준\n" + "임도 설치 기준 내용 " * 10, encoding="utf-8")
|
||||
(guide / "_검토.md").write_text("# 임도 기준\n기술정보 안내 " * 10, encoding="utf-8")
|
||||
(private / "사례.md").write_text("# 임도 기준\n비공개 사례 " * 10, encoding="utf-8")
|
||||
monkeypatch.setattr(chat, "ORIGINAL", tmp_path)
|
||||
(stmate / "자료.md").write_text("# 임도 기준\nSTmate 자료 " * 10, encoding="utf-8")
|
||||
(dasan / "자료.md").write_text("# 임도 기준\n다산소프트 자료 " * 10, encoding="utf-8")
|
||||
monkeypatch.setattr(chat, "KNOWLEDGE", tmp_path)
|
||||
monkeypatch.setenv("GEMINI_API_KEY", "test-key")
|
||||
chat._sections.cache_clear()
|
||||
sent = {}
|
||||
@@ -39,7 +48,10 @@ def test_chat_excludes_practice_documents_from_gemini(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(chat.httpx, "AsyncClient", Client)
|
||||
result = asyncio.run(chat.ask_knowledge_chat(chat.ChatRequest(question="임도 기준"), {}))
|
||||
assert result["answer"] == "설명 [1]"
|
||||
assert result["sources"][0]["path"] == "법률/현행.md"
|
||||
paths = {source["path"] for source in result["sources"]}
|
||||
assert paths == {"original/법률/현행.md", "technical_info/_검토.md"}
|
||||
assert "실무문서" not in sent["prompt"]
|
||||
assert "비공개 사례" not in sent["prompt"]
|
||||
assert "STmate" not in sent["prompt"]
|
||||
assert "다산소프트" not in sent["prompt"]
|
||||
chat._sections.cache_clear()
|
||||
|
||||
Reference in New Issue
Block a user