| """CLI entry point for TermPrep."""
|
|
|
| import os
|
| import click
|
| from pathlib import Path
|
| from rich.console import Console
|
| from rich.table import Table
|
|
|
| from termprep.searcher import search_term
|
| from termprep.db import TermDB, list_termbases, init_termbase, delete_termbase
|
| from termprep.analyzer import analyze, analyze_file, get_summary
|
| from termprep.extractor import extract, extract_file, get_frequency_table
|
| from termprep.report import generate_report, save_report
|
| from termprep.pipeline import run_pipeline, format_pipeline_result
|
|
|
|
|
| _env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), ".env")
|
| if os.path.exists(_env_path):
|
| try:
|
| with open(_env_path, encoding="utf-8") as f:
|
| for line in f:
|
| line = line.strip()
|
| if line and not line.startswith("#") and "=" in line:
|
| key, _, val = line.partition("=")
|
| os.environ.setdefault(key.strip(), val.strip())
|
| except Exception:
|
| pass
|
|
|
| console = Console()
|
|
|
|
|
| @click.group()
|
| def main():
|
| """TermPrep - \u8bd1\u524d\u672f\u8bed\u51c6\u5907\u52a9\u624b"""
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| @click.argument("term")
|
| @click.option("--source", "-s", default="all", help="\u641c\u7d22\u6e90: local, web, all")
|
| @click.option("--limit", "-n", default=20, help="\u8fd4\u56de\u7ed3\u679c\u6570\u91cf")
|
| def search(term, source, limit):
|
| """\u641c\u7d22\u672f\u8bed\u53ca\u5173\u8054\u8bcd\u6c47\u3002"""
|
| results = search_term(term, source=source, limit=limit)
|
|
|
| table = Table(title=f"\u641c\u7d22\u7ed3\u679c: {term}")
|
| table.add_column("\u5173\u8054\u8bcd", style="cyan")
|
| table.add_column("\u7c7b\u578b", style="green")
|
| table.add_column("\u6765\u6e90", style="yellow")
|
| table.add_column("\u76f8\u5173\u5ea6", style="magenta")
|
|
|
| for r in results:
|
| table.add_row(r["word"], r["type"], r["source"], f"{r['score']:.2f}")
|
|
|
| console.print(table)
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| @click.argument("input_file")
|
| @click.option("--output", "-o", default="result.csv", help="\u8f93\u51fa\u6587\u4ef6")
|
| def batch(input_file, output):
|
| """\u6279\u91cf\u67e5\u8be2\u672f\u8bed\u3002"""
|
| with open(input_file, "r", encoding="utf-8") as f:
|
| terms = [line.strip() for line in f if line.strip()]
|
|
|
| results = []
|
| for term in terms:
|
| results.extend(search_term(term))
|
|
|
| import csv
|
| with open(output, "w", encoding="utf-8", newline="") as f:
|
| writer = csv.DictWriter(f, fieldnames=["query", "word", "type", "source", "score"])
|
| writer.writeheader()
|
| for r in results:
|
| writer.writerow(r)
|
|
|
| console.print(f"[green]OK[/green] \u5df2\u5bfc\u51fa {len(results)} \u6761\u7ed3\u679c\u5230 {output}")
|
|
|
|
|
|
|
|
|
|
|
| @main.command(name="analyze")
|
| @click.argument("file", required=False)
|
| @click.option("--text", "-t", default="", help="\u76f4\u63a5\u8f93\u5165\u6587\u672c\u5206\u6790")
|
| def _analyze(file, text):
|
| """\u9879\u76ee\u5206\u6790\uff1a\u8bed\u8a00\u68c0\u6d4b\u3001\u5b57\u6570\u7edf\u8ba1\u3001\u9886\u57df\u8bc6\u522b\u3002"""
|
| if file:
|
| result = analyze_file(file)
|
| elif text:
|
| result = analyze(text)
|
| else:
|
| console.print("[red]\u9519\u8bef:[/red] \u8bf7\u63d0\u4f9b\u6587\u4ef6\u8def\u5f84\u6216 --text \u53c2\u6570")
|
| return
|
| console.print(get_summary(result))
|
|
|
|
|
|
|
|
|
|
|
| @main.command(name="extract")
|
| @click.argument("file", required=False)
|
| @click.option("--text", "-t", default="", help="\u76f4\u63a5\u8f93\u5165\u6587\u672c\u63d0\u53d6")
|
| @click.option("--top", "-n", default=30, help="\u8fd4\u56de\u672f\u8bed\u6570\u91cf")
|
| def _extract(file, text, top):
|
| """\u672f\u8bed\u63d0\u53d6\uff1a\u9ad8\u9891\u8bcd\u3001N-gram\u3001\u4e13\u6709\u540d\u8bcd\u3002"""
|
| if file:
|
| terms = extract_file(file, top_n=top)
|
| elif text:
|
| terms = extract(text, top_n=top)
|
| else:
|
| console.print("[red]\u9519\u8bef:[/red] \u8bf7\u63d0\u4f9b\u6587\u4ef6\u8def\u5f84\u6216 --text \u53c2\u6570")
|
| return
|
| console.print(get_frequency_table(terms))
|
|
|
|
|
|
|
|
|
|
|
| @main.group()
|
| def db():
|
| """\u672c\u5730\u8bcd\u5e93\u7ba1\u7406\u3002"""
|
|
|
|
|
| @db.command("list")
|
| def db_list():
|
| """\u5217\u51fa\u6240\u6709\u672c\u5730\u8bcd\u5e93\u3002"""
|
| dbs = list_termbases()
|
| if not dbs:
|
| console.print("[yellow]\u6682\u65e0\u8bcd\u5e93\u3002\u4f7f\u7528 `termprep db init <name>` \u521b\u5efa\u3002[/yellow]")
|
| return
|
|
|
| table = Table(title="\u672c\u5730\u8bcd\u5e93")
|
| table.add_column("\u540d\u79f0", style="cyan")
|
| table.add_column("\u9886\u57df", style="green")
|
| table.add_column("\u8bed\u8a00", style="yellow")
|
| table.add_column("\u672f\u8bed\u6570", style="magenta")
|
| table.add_column("\u8def\u5f84")
|
|
|
| for d in dbs:
|
| table.add_row(
|
| d.name,
|
| d.domain or "-",
|
| d.lang or "-",
|
| str(d.total_terms),
|
| d.path,
|
| )
|
| console.print(table)
|
|
|
|
|
| @db.command("init")
|
| @click.argument("name")
|
| @click.option("--domain", "-d", default="", help="\u672f\u8bed\u5e93\u9886\u57df")
|
| def db_init(name, domain):
|
| """\u521b\u5efa\u65b0\u7684\u672c\u5730\u8bcd\u5e93\u3002"""
|
| try:
|
| tdb = init_termbase(name, domain=domain)
|
| console.print(f"[green]OK[/green] \u5df2\u521b\u5efa\u8bcd\u5e93: {tdb.db_path}")
|
| except FileExistsError as e:
|
| console.print(f"[red]\u9519\u8bef:[/red] {e}")
|
|
|
|
|
| @db.command("info")
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0 (\u9ed8\u8ba4: terms)")
|
| def db_info(db_name):
|
| """\u67e5\u770b\u5f53\u524d\u8bcd\u5e93\u7edf\u8ba1\u4fe1\u606f\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| stats = tdb.get_stats()
|
|
|
| console.print(f"[bold]\u8bcd\u5e93:[/bold] {stats['name']}")
|
| console.print(f"[bold]\u9886\u57df:[/bold] {stats.get('domain', '-')}")
|
| console.print(f"[bold]\u8def\u5f84:[/bold] {tdb.db_path}")
|
| console.print("")
|
| console.print(f"\u672f\u8bed\u603b\u6570: {stats['total_terms']}")
|
| console.print(f"\u5df2\u786e\u8ba4: {stats['confirmed']}")
|
| console.print(f"\u5173\u8054\u8bcd: {stats['associations']}")
|
| console.print("")
|
|
|
| if stats["by_domain"]:
|
| console.print("[bold]\u6309\u9886\u57df:[/bold]")
|
| for domain, count in stats["by_domain"].items():
|
| console.print(f" {domain or 'uncategorized'}: {count}")
|
|
|
| if stats["by_status"]:
|
| console.print("[bold]\u6309\u72b6\u6001:[/bold]")
|
| for status, count in stats["by_status"].items():
|
| console.print(f" {status}: {count}")
|
|
|
| if stats["recent"]:
|
| console.print("[bold]\u6700\u65b0\u6dfb\u52a0:[/bold]")
|
| for r in stats["recent"][:5]:
|
| console.print(f" {r['word']} -> {r['translation']} [{r['status']}]")
|
|
|
|
|
| @db.command("delete")
|
| @click.argument("name")
|
| def db_delete(name):
|
| """\u5220\u9664\u4e00\u4e2a\u8bcd\u5e93\u3002"""
|
| try:
|
| delete_termbase(name)
|
| console.print(f"[green]OK[/green] \u5df2\u5220\u9664\u8bcd\u5e93: {name}")
|
| except (FileNotFoundError, OSError) as e:
|
| console.print(f"[red]\u9519\u8bef:[/red] {e}")
|
|
|
|
|
| @db.command("merge")
|
| @click.argument("source_db")
|
| @click.option("--target", "-t", default=None, help="\u76ee\u6807\u8bcd\u5e93 (\u9ed8\u8ba4: terms)")
|
| @click.option("--no-dedup", is_flag=True, help="\u5141\u8bb8\u91cd\u590d\u672f\u8bed")
|
| def db_merge(source_db, target, no_dedup):
|
| """\u5408\u5e76\u53e6\u4e00\u4e2a\u8bcd\u5e93\u5230\u5f53\u524d\u8bcd\u5e93\u3002"""
|
| target_db = TermDB(db_name=target) if target else TermDB()
|
|
|
|
|
| from termprep.db import DB_DIR
|
| src_path = Path(source_db)
|
| if not src_path.exists():
|
| src_path = DB_DIR / (source_db if source_db.endswith(".db") else f"{source_db}.db")
|
| if not src_path.exists():
|
| console.print(f"[red]\u9519\u8bef:[/red] \u627e\u4e0d\u5230\u6e90\u8bcd\u5e93: {source_db}")
|
| return
|
|
|
| stats = target_db.merge(str(src_path), dedup=not no_dedup)
|
| console.print("[green]OK[/green] \u5408\u5e76\u5b8c\u6210:")
|
| console.print(f" \u65b0\u589e: {stats['added']}")
|
| console.print(f" \u8df3\u8fc7(\u91cd\u590d): {stats['skipped']}")
|
| console.print(f" \u6e90\u8bcd\u5e93\u603b\u6570: {stats['total_other']}")
|
|
|
|
|
|
|
|
|
|
|
| @db.command("import")
|
| @click.argument("csv_file")
|
| @click.option("--db", "db_name", default=None, help="\u76ee\u6807\u8bcd\u5e93\u540d\u79f0")
|
| @click.option("--no-dedup", is_flag=True, help="\u5141\u8bb8\u5bfc\u5165\u91cd\u590d\u672f\u8bed")
|
| def db_import(csv_file, db_name, no_dedup):
|
| """\u4ece CSV \u5bfc\u5165\u8bcd\u6c47\u5230\u8bcd\u5e93\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| count = tdb.import_csv(csv_file, dedup=not no_dedup)
|
| console.print(f"[green]OK[/green] \u5df2\u5bfc\u5165 {count} \u6761\u8bcd\u6c47")
|
|
|
|
|
| @db.command("export")
|
| @click.option("--output", "-o", default=None, help="\u8f93\u51fa\u6587\u4ef6\u8def\u5f84")
|
| @click.option("--format", "fmt", default="csv", help="\u683c\u5f0f: csv, xlsx, tbx, json")
|
| @click.option("--db", "db_name", default=None, help="\u6e90\u8bcd\u5e93\u540d\u79f0")
|
| @click.option("--status", default=None, help="\u6309\u72b6\u6001\u7b5b\u9009 (draft/confirmed/deprecated)")
|
| def db_export(output, fmt, db_name, status):
|
| """\u5bfc\u51fa\u8bcd\u5e93\u5230\u591a\u79cd\u683c\u5f0f\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
|
|
| if not output:
|
| output = f"{tdb.name}.{fmt}"
|
| if fmt == "xlsx":
|
| output = f"{tdb.name}.xlsx"
|
|
|
| fmt = fmt.lower()
|
| if fmt == "csv":
|
| from termprep.exporter import export_csv
|
| count = export_csv(tdb, output, status_filter=status)
|
| elif fmt == "xlsx":
|
| from termprep.exporter import export_xlsx
|
| count = export_xlsx(tdb, output, status_filter=status)
|
| elif fmt == "tbx":
|
| from termprep.exporter import export_tbx
|
| count = export_tbx(tdb, output, status_filter=status)
|
| elif fmt == "json":
|
| from termprep.exporter import export_json
|
| count = export_json(tdb, output, status_filter=status)
|
| else:
|
| console.print(f"[red]\u9519\u8bef:[/red] \u4e0d\u652f\u6301\u7684\u683c\u5f0f '{fmt}'. \u652f\u6301: csv, xlsx, tbx, json")
|
| return
|
|
|
| console.print(f"[green]OK[/green] \u5df2\u5bfc\u51fa {count} \u6761\u8bcd\u6c47\u5230 {output}")
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| @click.argument("file", required=False)
|
| @click.option("--text", "-t", default="", help="\u76f4\u63a5\u8f93\u5165\u6587\u672c")
|
| @click.option("--output", "-o", default="termprep-report.md", help="\u8f93\u51fa\u6587\u4ef6\u8def\u5f84")
|
| @click.option("--name", "project_name", default="Untitled", help="\u9879\u76ee\u540d\u79f0")
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| def report(file, text, output, project_name, db_name):
|
| """\u751f\u6210\u8bd1\u524d\u51c6\u5907\u62a5\u544a (Markdown)\u3002"""
|
|
|
| if file:
|
| analysis = analyze_file(file)
|
| elif text:
|
| analysis = analyze(text)
|
| else:
|
| console.print("[red]\u9519\u8bef:[/red] \u8bf7\u63d0\u4f9b\u6587\u4ef6\u8def\u5f84\u6216 --text \u53c2\u6570")
|
| return
|
|
|
|
|
| if file:
|
| terms = extract_file(file)
|
| else:
|
| terms = extract(text)
|
|
|
|
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| db_stats = tdb.get_stats()
|
|
|
| report_text = generate_report(
|
| analysis=analysis,
|
| terms=terms,
|
| db_stats=db_stats,
|
| project_name=project_name,
|
| source_file=file or "",
|
| )
|
| save_report(report_text, output)
|
| console.print(f"[green]OK[/green] \u62a5\u544a\u5df2\u751f\u6210: {output}")
|
| console.print("")
|
| console.print(report_text[:2000] + ("..." if len(report_text) > 2000 else ""))
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| def sources():
|
| """\u67e5\u770b\u53ef\u7528\u7684\u5728\u7ebf\u8bcd\u5178\u6e90\u3002"""
|
| from termprep.sources import get_available_sources
|
|
|
| srcs = get_available_sources()
|
| if not srcs:
|
| console.print("[yellow]\u6682\u65e0\u53ef\u7528\u7684\u5728\u7ebf\u8bcd\u5178\u6e90\u3002[/yellow]")
|
| console.print("\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf\u4ee5\u542f\u7528\uff1a")
|
| console.print(" TERMPREP_YOUDAO_KEY / TERMPREP_YOUDAO_SECRET")
|
| console.print(" TERMPREP_WEBSTER_KEY")
|
| return
|
|
|
| table = Table(title="\u53ef\u7528\u8bcd\u5178\u6e90")
|
| table.add_column("\u6e90\u540d\u79f0", style="cyan")
|
| table.add_column("\u72b6\u6001", style="green")
|
| table.add_column("\u8bf4\u660e")
|
|
|
| for src in srcs:
|
| status = "[green]OK \u5df2\u914d\u7f6e[/green]" if src.available else "[red]X \u672a\u914d\u7f6e[/red]"
|
| table.add_row(src.name, status, f"API key: {src.name}")
|
| console.print(table)
|
|
|
|
|
|
|
|
|
|
|
| @main.group()
|
| def term():
|
| """\u5355\u4e2a\u672f\u8bed\u7ba1\u7406\u3002"""
|
|
|
|
|
| @term.command("add")
|
| @click.argument("word")
|
| @click.option("--translation", "-t", default="", help="\u7ffb\u8bd1")
|
| @click.option("--type", "type_", default="", help="\u8bcd\u6027")
|
| @click.option("--domain", "-d", default="", help="\u9886\u57df")
|
| @click.option("--status", default="draft", help="\u72b6\u6001: draft, confirmed, deprecated")
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| def term_add(word, translation, type_, domain, status, db_name):
|
| """\u6dfb\u52a0\u4e00\u4e2a\u672f\u8bed\u5230\u8bcd\u5e93\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| tid = tdb.add_term(word, translation=translation, type_=type_,
|
| domain=domain, status=status)
|
| console.print(f"[green]OK[/green] \u5df2\u6dfb\u52a0\u672f\u8bed [id={tid}]: {word}")
|
|
|
|
|
| @term.command("delete")
|
| @click.argument("term_id", type=int)
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| def term_delete(term_id, db_name):
|
| """\u5220\u9664\u4e00\u4e2a\u672f\u8bed\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| tdb.delete_term(term_id)
|
| console.print(f"[green]OK[/green] \u5df2\u5220\u9664\u672f\u8bed id={term_id}")
|
|
|
|
|
| @term.command("update")
|
| @click.argument("term_id", type=int)
|
| @click.option("--translation", default=None, help="\u7ffb\u8bd1")
|
| @click.option("--status", default=None, help="\u72b6\u6001: draft, confirmed, deprecated")
|
| @click.option("--type", "type_", default=None, help="\u8bcd\u6027")
|
| @click.option("--domain", default=None, help="\u9886\u57df")
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| def term_update(term_id, translation, status, type_, domain, db_name):
|
| """\u66f4\u65b0\u4e00\u4e2a\u672f\u8bed\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| kwargs = {}
|
| if translation is not None:
|
| kwargs["translation"] = translation
|
| if status is not None:
|
| kwargs["status"] = status
|
| if type_ is not None:
|
| kwargs["type"] = type_
|
| if domain is not None:
|
| kwargs["domain"] = domain
|
| tdb.update_term(term_id, **kwargs)
|
| console.print(f"[green]OK[/green] \u5df2\u66f4\u65b0\u672f\u8bed id={term_id}")
|
|
|
|
|
| @term.command("search")
|
| @click.argument("query")
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| def term_search(query, db_name):
|
| """\u5728\u8bcd\u5e93\u4e2d\u641c\u7d22\u672f\u8bed\u3002"""
|
| tdb = TermDB(db_name=db_name) if db_name else TermDB()
|
| results = tdb.search_terms(query)
|
|
|
| if not results:
|
| console.print(f"[yellow]\u672a\u627e\u5230\u5339\u914d\u7684\u672f\u8bed: {query}[/yellow]")
|
| return
|
|
|
| table = Table(title=f"\u8bcd\u5e93\u641c\u7d22\u7ed3\u679c: {query}")
|
| table.add_column("ID", style="dim")
|
| table.add_column("\u672f\u8bed", style="cyan")
|
| table.add_column("\u7ffb\u8bd1", style="green")
|
| table.add_column("\u7c7b\u578b", style="yellow")
|
| table.add_column("\u9886\u57df", style="magenta")
|
| table.add_column("\u72b6\u6001")
|
|
|
| for r in results:
|
| table.add_row(
|
| str(r.get("id", "")),
|
| r.get("word", ""),
|
| r.get("translation", ""),
|
| r.get("type", ""),
|
| r.get("domain", ""),
|
| r.get("status", ""),
|
| )
|
| console.print(table)
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| @click.argument("file", required=False)
|
| @click.option("--text", "-t", default="", help="\u76f4\u63a5\u8f93\u5165\u6587\u672c")
|
| @click.option("--name", "project_name", default="Untitled", help="\u9879\u76ee\u540d\u79f0")
|
| @click.option("--top", default=20, help="\u63d0\u53d6\u672f\u8bed\u6570\u91cf", type=int)
|
| @click.option("--search", "search_limit", default=5, help="\u6bcf\u4e2a\u672f\u8bed\u641c\u7d22\u7ed3\u679c\u6570", type=int)
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| @click.option("--output", "-o", default="", help="\u62a5\u544a\u8f93\u51fa\u8def\u5f84")
|
| @click.option("--export", "export_fmt", default="", help="\u5bfc\u51fa\u683c\u5f0f (csv/xlsx/tbx/json, \u591a\u4e2a\u7528\u9017\u53f7\u5206\u9694)")
|
| @click.option("--notes", default="", help="\u9879\u76ee\u5907\u6ce8")
|
| @click.option("--ai", "use_ai", is_flag=True, help="\u542f\u7528 AI \u589e\u5f3a\u6a21\u5f0f\uff08\u9700\u914d\u7f6e API Key\uff09")
|
| @click.option("--ai-engine", default=None, help="AI \u5f15\u64ce\u540d\u79f0: ai, google, youdao")
|
| @click.option("--translate-mode", default="auto", help="\u7ffb\u8bd1\u6a21\u5f0f: auto | mixed | zh2en | en2zh")
|
| def pipeline(file, text, project_name, top, search_limit, db_name, output, export_fmt, notes, use_ai, ai_engine, translate_mode):
|
| """\u5168\u81ea\u52a8\u8bd1\u524d\u51c6\u5907\u6d41\u6c34\u7ebf: \u5206\u6790 -> \u63d0\u53d6 -> \u641c\u7d22 -> \u8bcd\u5e93 -> \u62a5\u544a -> \u5bfc\u51fa\u3002"""
|
| if not file and not text:
|
| console.print("[red]\u9519\u8bef:[/red] \u8bf7\u63d0\u4f9b\u6587\u4ef6\u8def\u5f84\u6216 --text \u53c2\u6570")
|
| return
|
|
|
| export_formats = [f.strip() for f in export_fmt.split(",") if f.strip()] if export_fmt else None
|
|
|
| with console.status("[bold green]\u8fd0\u884c\u8bd1\u524d\u51c6\u5907\u6d41\u6c34\u7ebf...[/bold green]"):
|
| result = run_pipeline(
|
| file_path=file,
|
| text=text or None,
|
| project_name=project_name,
|
| top_n=top,
|
| search_limit=search_limit,
|
| db_name=db_name,
|
| report_output=output,
|
| export_formats=export_formats,
|
| notes=notes,
|
| use_ai=use_ai,
|
| ai_engine=ai_engine,
|
| translate_mode=translate_mode,
|
| )
|
|
|
| console.print(format_pipeline_result(result))
|
|
|
|
|
| if result.ai_used:
|
| console.print("\n[green]\u2713[/green] AI \u589e\u5f3a\u6a21\u5f0f\u5df2\u542f\u7528")
|
| if result.glossary_json:
|
| json_path = f"{project_name}-glossary.json"
|
| try:
|
| with open(json_path, "w", encoding="utf-8") as f:
|
| f.write(result.glossary_json)
|
| console.print(f"[green]\u2713[/green] \u6807\u51c6\u5316 Glossary JSON \u5df2\u5bfc\u51fa: {json_path}")
|
| except Exception:
|
| pass
|
| else:
|
| console.print("\n[yellow]![/yellow] \u4f7f\u7528\u514d\u8d39\u6a21\u5f0f\uff08Google Translate + Youdao\uff09\n\u63d0\u793a: \u914d\u7f6e TERMPREP_AI_API_KEY \u53ef\u542f\u7528 AI \u589e\u5f3a")
|
|
|
|
|
|
|
|
|
|
|
| @main.command(name="ai-pipeline")
|
| @click.argument("file", required=False)
|
| @click.option("--text", "-t", default="", help="\u76f4\u63a5\u8f93\u5165\u6587\u672c")
|
| @click.option("--name", "project_name", default="Untitled", help="\u9879\u76ee\u540d\u79f0")
|
| @click.option("--top", default=20, help="\u63d0\u53d6\u672f\u8bed\u6570\u91cf", type=int)
|
| @click.option("--db", "db_name", default=None, help="\u8bcd\u5e93\u540d\u79f0")
|
| @click.option("--output", "-o", default="", help="\u62a5\u544a\u8f93\u51fa\u8def\u5f84")
|
| @click.option("--export", "export_fmt", default="", help="\u5bfc\u51fa\u683c\u5f0f")
|
| @click.option("--engine", default=None, help="AI \u5f15\u64ce\u540d\u79f0")
|
| @click.option("--translate-mode", default="auto", help="\u7ffb\u8bd1\u6a21\u5f0f: auto | mixed | zh2en | en2zh")
|
| def ai_pipeline(file, text, project_name, top, db_name, output, export_fmt, engine, translate_mode):
|
| """AI \u589e\u5f3a\u6d41\u6c34\u7ebf\u5feb\u6377\u547d\u4ee4\uff08\u7b49\u4ef7\u4e8e pipeline --ai\uff09\u3002"""
|
| if not file and not text:
|
| console.print("[red]\u9519\u8bef:[/red] \u8bf7\u63d0\u4f9b\u6587\u4ef6\u8def\u5f84\u6216 --text \u53c2\u6570")
|
| return
|
| export_formats = [f.strip() for f in export_fmt.split(",") if f.strip()] if export_fmt else None
|
| with console.status("[bold green]AI \u589e\u5f3a\u6d41\u6c34\u7ebf\u8fd0\u884c\u4e2d...[/bold green]"):
|
| result = run_pipeline(
|
| file_path=file, text=text or None, project_name=project_name,
|
| top_n=top, db_name=db_name, report_output=output,
|
| export_formats=export_formats, use_ai=True, ai_engine=engine,
|
| translate_mode=translate_mode,
|
| )
|
| console.print(format_pipeline_result(result))
|
| if result.glossary_json:
|
| console.print(f"\n[green]\u2713[/green] Glossary JSON \u5df2\u5bfc\u51fa\u81f3 {project_name}-glossary.json")
|
|
|
|
|
|
|
|
|
|
|
| @main.command()
|
| @click.option("--port", "-p", default=8672, help="\u7aef\u53e3\u53f7", type=int)
|
| @click.option("--host", default="127.0.0.1", help="\u7ed1\u5b9a\u5730\u5740")
|
| def web(host, port):
|
| """\u542f\u52a8 TermPrep Web \u754c\u9762\u3002"""
|
| from termprep.web import start_server
|
| start_server(host=host, port=port)
|
|
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|