feat: DEVONthink 제거 + 모닝 브리핑 추가

- DEVONthink 의존성 제거 → kb_writer 전환 (news_digest, inbox_processor, mail pipeline)
- devonthink_bridge.py, plist 삭제
- morning_briefing.py 신규 (매일 07:30, 일정·메일·보고·뉴스 → Synology Chat)
- intent_service.py 분류기 프롬프트 개선 + 키워드 fallback
- migrate-v5.sql (news_digest_log kb_path 컬럼)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-19 14:12:38 +09:00
parent fd8925637d
commit 782caf5130
15 changed files with 479 additions and 240 deletions

View File

@@ -20,7 +20,7 @@ GPU_OLLAMA_URL = os.getenv("GPU_OLLAMA_URL", "http://192.168.1.186:11434")
LOCAL_OLLAMA_URL = os.getenv("LOCAL_OLLAMA_URL", "http://127.0.0.1:11434")
QDRANT_URL = os.getenv("QDRANT_URL", "http://127.0.0.1:6333")
SYNOLOGY_CHAT_WEBHOOK_URL = os.getenv("SYNOLOGY_CHAT_WEBHOOK_URL", "")
DEVONTHINK_BRIDGE_URL = os.getenv("DEVONTHINK_BRIDGE_URL", "http://127.0.0.1:8093")
KB_WRITER_URL = os.getenv("KB_WRITER_URL", "http://127.0.0.1:8095")
# Postgres 연결 (직접 접속)
PG_HOST = os.getenv("PG_HOST", "127.0.0.1")
@@ -179,21 +179,24 @@ def embed_to_qdrant(text: str) -> str | None:
return None
def save_to_devonthink(title: str, content: str) -> str | None:
"""DEVONthink에 저장."""
def save_to_kb(title: str, content: str) -> str | None:
"""kb_writer에 저장."""
try:
resp = httpx.post(
f"{DEVONTHINK_BRIDGE_URL}/save",
f"{KB_WRITER_URL}/save",
json={
"title": title,
"content": content,
"type": "markdown",
"type": "news",
"tags": ["news", "digest"],
"username": "news-digest",
"source": "karakeep",
"topic": "news",
},
timeout=10,
)
data = resp.json()
return data.get("uuid") if data.get("success") else None
return data.get("path") if data.get("success") else None
except Exception:
return None
@@ -258,7 +261,7 @@ def main():
emb_text = f"{result['title_ko']} {result['summary_ko']}"
qdrant_id = embed_to_qdrant(emb_text)
dt_uuid = save_to_devonthink(
kb_path = save_to_kb(
result["title_ko"],
f"**원문**: {bm['url']}\n**출처**: {bm.get('source', '')}\n\n{result['summary_ko']}",
)
@@ -268,9 +271,9 @@ def main():
try:
with conn.cursor() as cur:
cur.execute(
"INSERT INTO news_digest_log (article_url,source,original_lang,title_ko,summary_ko,qdrant_id,devonthink_uuid) "
"INSERT INTO news_digest_log (article_url,source,original_lang,title_ko,summary_ko,qdrant_id,kb_path) "
"VALUES (%s,%s,%s,%s,%s,%s,%s) ON CONFLICT (article_url) DO NOTHING",
(bm["url"], bm.get("source", ""), lang, result["title_ko"], result["summary_ko"], qdrant_id, dt_uuid),
(bm["url"], bm.get("source", ""), lang, result["title_ko"], result["summary_ko"], qdrant_id, kb_path),
)
conn.commit()
except Exception as e: