You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
53 lines
1.9 KiB
Python
53 lines
1.9 KiB
Python
# backend/app/connectors/knowledge/clipper.py — 웹 클리퍼 / Markdown 노트 임포트(로컬 우선)
|
|
import hashlib
|
|
from datetime import UTC, datetime
|
|
|
|
from sqlmodel import Session
|
|
|
|
from ..base import BaseConnector, NormalizedRecord, RawRecord
|
|
from .normalize import normalize_knowledge, upsert_knowledge
|
|
|
|
|
|
class ClipperConnector(BaseConnector):
|
|
domain = "knowledge"
|
|
entity_type = "knowledge_item"
|
|
|
|
def fetch(self, session: Session, *, full: bool = False):
|
|
for p in getattr(self, "_items", []):
|
|
yield RawRecord(
|
|
external_id=p["id"],
|
|
payload=p,
|
|
etag=p.get("title", ""),
|
|
external_updated_at=datetime.now(UTC),
|
|
)
|
|
|
|
def normalize(self, raw: RawRecord) -> NormalizedRecord:
|
|
return normalize_knowledge(self.account, raw, provider="clipper")
|
|
|
|
def write(self, session: Session, norm: NormalizedRecord):
|
|
return upsert_knowledge(session, norm)
|
|
|
|
def event_for(self, norm, entity_id):
|
|
return "knowledge.ingested"
|
|
|
|
def import_bytes(self, session: Session, content: bytes, filename: str = "") -> dict:
|
|
text = content.decode("utf-8", "ignore")
|
|
title = next((ln.lstrip("# ").strip() for ln in text.split("\n") if ln.strip()), filename)
|
|
self._items = [
|
|
{
|
|
"id": "clip-" + hashlib.sha1(text.encode()).hexdigest()[:12],
|
|
"type": "article",
|
|
"title": title or "스크랩",
|
|
"src": filename or "웹 클리퍼",
|
|
"excerpt": text[:280],
|
|
}
|
|
]
|
|
res = self.sync(session, full=True)
|
|
return {
|
|
"entity_type": "knowledge_item",
|
|
"imported": res.upserted,
|
|
"skipped": res.skipped,
|
|
"errors": res.errors,
|
|
"detail": f"{filename or '스크랩'} · 지식 {res.upserted}건 적재",
|
|
}
|