diff --git a/nanoclaude/routers/synology.py b/nanoclaude/routers/synology.py index 2c347f0..7dd8610 100644 --- a/nanoclaude/routers/synology.py +++ b/nanoclaude/routers/synology.py @@ -69,7 +69,7 @@ async def synology_webhook(request: Request): logger.info("Synology job %s from %s: %s", job.id, username, text[:50]) # "처리 중" 메시지 먼저 전송 (typing 느낌) - await send_to_synology("🤔 생각 중...") + await send_to_synology("🤔 생각 중...", raw=True) # 파이프라인 시작 (비동기) await jq_module.job_queue.submit(job) diff --git a/nanoclaude/services/synology_sender.py b/nanoclaude/services/synology_sender.py index 88195a5..d74472b 100644 --- a/nanoclaude/services/synology_sender.py +++ b/nanoclaude/services/synology_sender.py @@ -4,6 +4,7 @@ from __future__ import annotations import json import logging +import re import httpx @@ -12,12 +13,24 @@ from config import settings logger = logging.getLogger(__name__) -async def send_to_synology(text: str) -> bool: - """Incoming webhook URL로 메시지 전송. 성공 시 True.""" +def _strip_markdown(text: str) -> str: + """마크다운 문법 제거 — Synology Chat은 렌더링 안 됨.""" + text = re.sub(r'\*\*(.+?)\*\*', r'\1', text) # **bold** + text = re.sub(r'\*(.+?)\*', r'\1', text) # *italic* + text = re.sub(r'`(.+?)`', r'\1', text) # `code` + text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE) # ### headers + text = re.sub(r'^\s*[-*]\s+', '• ', text, flags=re.MULTILINE) # - list → • + return text + + +async def send_to_synology(text: str, *, raw: bool = False) -> bool: + """Incoming webhook URL로 메시지 전송. raw=True면 마크다운 제거 안 함.""" if not settings.synology_incoming_url: logger.warning("Synology incoming URL not configured") return False + if not raw: + text = _strip_markdown(text) payload = json.dumps({"text": text}, ensure_ascii=False) try: diff --git a/nanoclaude/services/worker.py b/nanoclaude/services/worker.py index dbad67f..a764abe 100644 --- a/nanoclaude/services/worker.py +++ b/nanoclaude/services/worker.py @@ -163,7 +163,7 @@ async def run(job: Job) -> None: if job.callback != "synology": await state_stream.push(job.id, "rewrite", {"content": rewritten_message}) else: - await send_to_synology("📝 더 깊이 살펴볼게요...") + await send_to_synology("📝 더 깊이 살펴볼게요...", raw=True) if job.status == JobStatus.cancelled: return @@ -241,7 +241,7 @@ async def run(job: Job) -> None: await state_stream.push(job.id, "error", {"message": "내부 오류가 발생했습니다."}) if job.callback == "synology": try: - await send_to_synology("⚠️ 처리 중 오류가 발생했습니다. 다시 시도해주세요.") + await send_to_synology("⚠️ 처리 중 오류가 발생했습니다. 다시 시도해주세요.", raw=True) except Exception: pass try: