基于 skill-template 脚手架开发,包含: - payroll_config(费率配置,可编辑)+ payslip_snapshots(解析历史,只读)2 张业务表 - 全国默认 + 北上广 4 套费率(社保/公积金/个税起征点/7 级税率表) - 5 个业务 Action:calculate-payslip-simple / calculate-payslip-full / explain-term / view-config / edit-config - 个税累计预扣法计算,支持多月历史累加 - 20 个薪资名词库(社保/公积金/个税/全勤/加班费等) - 完整市场文档(README/TUTORIAL/DEMO/CHANGELOG) - 296 测试全部通过
96 lines
2.8 KiB
Python
96 lines
2.8 KiB
Python
"""名词解释服务。
|
||
|
||
从 assets/glossary.json 读取词条,按 key/display/category 查询。
|
||
不做 LLM 生成,纯静态数据查询。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
from typing import Any, Optional
|
||
|
||
from util.constants import SKILL_SLUG
|
||
from util.logging_config import get_skill_logger
|
||
from util.runtime_paths import get_skill_root
|
||
|
||
log = get_skill_logger()
|
||
|
||
|
||
def _load_glossary() -> list[dict[str, Any]]:
|
||
"""从 assets/glossary.json 加载全部词条。"""
|
||
glossary_path = get_skill_root() / "assets" / "glossary.json"
|
||
try:
|
||
with open(glossary_path, "r", encoding="utf-8") as f:
|
||
data = json.load(f)
|
||
terms = data.get("terms", []) if isinstance(data, dict) else []
|
||
return terms if isinstance(terms, list) else []
|
||
except (FileNotFoundError, json.JSONDecodeError, OSError):
|
||
return []
|
||
|
||
|
||
def explain_term(term: str) -> dict[str, Any]:
|
||
"""查询单个名词解释。
|
||
|
||
支持按 key(精确)或 display(包含)匹配。
|
||
未命中返回结构化空(ok=True, found=False)。
|
||
"""
|
||
log.info("glossary_explain term=%s", term)
|
||
terms = _load_glossary()
|
||
term_lower = (term or "").strip().lower()
|
||
|
||
hit: Optional[dict[str, Any]] = None
|
||
for t in terms:
|
||
if str(t.get("key", "")).lower() == term_lower:
|
||
hit = t
|
||
break
|
||
if term_lower in str(t.get("display", "")).lower():
|
||
hit = t
|
||
break
|
||
|
||
if hit is None:
|
||
return {
|
||
"ok": True,
|
||
"skill": SKILL_SLUG,
|
||
"found": False,
|
||
"term": term,
|
||
"explanation": None,
|
||
"suggestions": [str(t.get("display", "")) for t in terms[:5]],
|
||
}
|
||
|
||
return {
|
||
"ok": True,
|
||
"skill": SKILL_SLUG,
|
||
"found": True,
|
||
"term": term,
|
||
"key": hit.get("key"),
|
||
"display": hit.get("display"),
|
||
"category": hit.get("category"),
|
||
"explanation": hit.get("explanation"),
|
||
"example": hit.get("example"),
|
||
}
|
||
|
||
|
||
def list_terms(category: str | None = None) -> dict[str, Any]:
|
||
"""列出全部或按分类的词条。"""
|
||
terms = _load_glossary()
|
||
if category:
|
||
filtered = [t for t in terms if str(t.get("category", "")).lower() == category.lower()]
|
||
else:
|
||
filtered = terms
|
||
return {
|
||
"ok": True,
|
||
"skill": SKILL_SLUG,
|
||
"count": len(filtered),
|
||
"categories": sorted({str(t.get("category", "")) for t in terms}),
|
||
"terms": [
|
||
{
|
||
"key": t.get("key"),
|
||
"display": t.get("display"),
|
||
"category": t.get("category"),
|
||
"explanation": t.get("explanation"),
|
||
"example": t.get("example"),
|
||
}
|
||
for t in filtered
|
||
],
|
||
}
|