bd7635986a
Vue 前端 + FastAPI 后端,含部署脚本与词典数据。 Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
2.5 KiB
Python
84 lines
2.5 KiB
Python
"""词典导入共享工具。"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
from typing import Optional
|
||
|
||
from sqlalchemy.dialects.mysql import insert as mysql_insert
|
||
from sqlalchemy.orm import Session
|
||
|
||
from models import DictionaryEntry
|
||
|
||
_POS_PREFIX = re.compile(r"^[a-zA-Z]+\.\s*")
|
||
_TAG_PREFIX = re.compile(r"^\[[^\]]+\]\s*")
|
||
|
||
|
||
def clean_translation(text: str, max_len: int = 256) -> str:
|
||
if not text:
|
||
return ""
|
||
lines = [ln.strip() for ln in text.replace("\r", "").split("\n") if ln.strip()]
|
||
parts: list[str] = []
|
||
for ln in lines:
|
||
ln = _TAG_PREFIX.sub("", ln)
|
||
ln = _POS_PREFIX.sub("", ln)
|
||
if ln:
|
||
parts.append(ln)
|
||
result = ";".join(parts) if parts else text.strip()
|
||
return result[:max_len]
|
||
|
||
|
||
def normalize_row(raw: dict, source: Optional[str]) -> Optional[dict]:
|
||
lemma_en = (raw.get("lemma_en") or raw.get("en") or raw.get("word") or "").strip().lower()
|
||
zh = clean_translation(raw.get("zh") or raw.get("cn") or raw.get("translation") or "")
|
||
if not lemma_en or not zh:
|
||
return None
|
||
if len(lemma_en) > 128:
|
||
return None
|
||
phonetic = (raw.get("phonetic") or "").strip() or None
|
||
if phonetic and len(phonetic) > 128:
|
||
phonetic = phonetic[:128]
|
||
return {
|
||
"lemma_en": lemma_en,
|
||
"zh": zh,
|
||
"phonetic": phonetic,
|
||
"example_en": (raw.get("example_en") or "").strip() or None,
|
||
"example_cn": (raw.get("example_cn") or "").strip() or None,
|
||
"source": source or (raw.get("source") or "import"),
|
||
}
|
||
|
||
|
||
def upsert_batch(session: Session, rows: list[dict]) -> int:
|
||
if not rows:
|
||
return 0
|
||
stmt = mysql_insert(DictionaryEntry).values(rows)
|
||
stmt = stmt.on_duplicate_key_update(
|
||
zh=stmt.inserted.zh,
|
||
phonetic=stmt.inserted.phonetic,
|
||
example_en=stmt.inserted.example_en,
|
||
example_cn=stmt.inserted.example_cn,
|
||
source=stmt.inserted.source,
|
||
)
|
||
session.execute(stmt)
|
||
return len(rows)
|
||
|
||
|
||
def upsert_entries(session: Session, raw_rows: list[dict], source: Optional[str], batch_size: int = 2000) -> int:
|
||
batch: list[dict] = []
|
||
total = 0
|
||
for raw in raw_rows:
|
||
row = normalize_row(raw, source)
|
||
if not row:
|
||
continue
|
||
batch.append(row)
|
||
if len(batch) >= batch_size:
|
||
upsert_batch(session, batch)
|
||
session.commit()
|
||
total += len(batch)
|
||
batch.clear()
|
||
if batch:
|
||
upsert_batch(session, batch)
|
||
session.commit()
|
||
total += len(batch)
|
||
return total
|