Initial commit: WordLoop 单词学习应用

Vue 前端 + FastAPI 后端,含部署脚本与词典数据。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
John
2026-06-04 14:30:53 -07:00
commit bd7635986a
66 changed files with 5495 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
"""词典导入共享工具。"""
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