Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pac
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tools
pac
Commits
06ae44f0
Commit
06ae44f0
authored
Aug 27, 2026
by
luoqi
Browse files
Options
Browse Files
Download
Plain Diff
merge: 含词大小写 + 补四词 → test
parents
a37e654e
66ed2e46
Pipeline
#3601
failed in 0 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
125 additions
and
5 deletions
+125
-5
apps/pac-service/data/_shared/dict/treatment-category-actual-rules.yaml
+21
-3
apps/pac-service/src/modules/sync/assembler/assembler-engine.ts
+8
-2
apps/pac-service/tests/keyword-case-and-terms.spec.ts
+96
-0
No files found.
apps/pac-service/data/_shared/dict/treatment-category-actual-rules.yaml
View file @
06ae44f0
...
@@ -23,7 +23,11 @@ keyword_mapping:
...
@@ -23,7 +23,11 @@ keyword_mapping:
# 修复/备牙/取模:收 C.10 治疗痕迹(修复后/修复术后/全瓷桥修复后/备牙后/重新取模后)。
# 修复/备牙/取模:收 C.10 治疗痕迹(修复后/修复术后/全瓷桥修复后/备牙后/重新取模后)。
# 排在 implant/endo/ortho/cosmetic 之后 → 种植修复→implant、根管…修复→endo 仍被前面抢走。
# 排在 implant/endo/ortho/cosmetic 之后 → 种植修复→implant、根管…修复→endo 仍被前面抢走。
# "嵌体修复"等 restorative 已由上方精确 enum 先命中,不受裸"修复"影响。
# "嵌体修复"等 restorative 已由上方精确 enum 先命中,不受裸"修复"影响。
-
{
value
:
prosthodontic
,
any
:
[
冠
,
桥
,
义齿
,
修复体
,
修复
,
备牙
,
取模
,
桩核
,
桩冠
,
戴牙
,
全瓷
,
烤瓷
,
重新粘接
]
}
# 加牙/活托(2026-08-27 过碧霞 TS0B006258 牙12;13;21):活动义齿在原基托上加牙 —— DW 实测
# 裸「加牙」58 条(50 带牙位)全部落 _default 被丢,患者整次修复在系统里不存在 → 误召缺失牙。
# 变体「活动义齿加牙/义齿加牙/取模加牙」已被 义齿/取模 收,只有裸词和「活托X」漏。
# 碰撞已验:「根管治疗加牙周治疗」含"加牙"但被上方 ② endodontic 的「根管」先吃,安全。
-
{
value
:
prosthodontic
,
any
:
[
冠
,
桥
,
义齿
,
修复体
,
修复
,
备牙
,
取模
,
桩核
,
桩冠
,
戴牙
,
全瓷
,
烤瓷
,
重新粘接
,
加牙
,
活托
]
}
# ⭐ 明确充填动作(充填/去腐/备洞/嵌体/垫底/补牙)压过 preventive:
# ⭐ 明确充填动作(充填/去腐/备洞/嵌体/垫底/补牙)压过 preventive:
# "去腐,备洞,...树脂充填,窝沟封闭"(dispose 散文)是补牙(restorative),不能因含"窝沟封闭"
# "去腐,备洞,...树脂充填,窝沟封闭"(dispose 散文)是补牙(restorative),不能因含"窝沟封闭"
# 被误判 preventive → 非 resolver → 误召(马思煦@46)。注:"开髓去腐"等根管语境已被上方 endodontic 先收。
# 被误判 preventive → 非 resolver → 误召(马思煦@46)。注:"开髓去腐"等根管语境已被上方 endodontic 先收。
...
@@ -33,11 +37,25 @@ keyword_mapping:
...
@@ -33,11 +37,25 @@ keyword_mapping:
# 材料弱词:放 preventive 后 —— "玻璃离子窝沟封闭" 已被上面 preventive 收;裸"树脂/玻璃离子"→ restorative
# 材料弱词:放 preventive 后 —— "玻璃离子窝沟封闭" 已被上面 preventive 收;裸"树脂/玻璃离子"→ restorative
-
{
value
:
restorative
,
any
:
[
树脂
,
玻璃离子
]
}
-
{
value
:
restorative
,
any
:
[
树脂
,
玻璃离子
]
}
# 牙周去裸"洁牙"(避开自由文本"清洁牙面"误命中);洁牙/全口洁牙等精确词由上方 enum_mapping 兜
# 牙周去裸"洁牙"(避开自由文本"清洁牙面"误命中);洁牙/全口洁牙等精确词由上方 enum_mapping 兜
-
{
value
:
periodontic
,
any
:
[
洁治
,
洗牙
,
龈上
,
龈下
,
刮治
,
牙周
,
喷砂
,
细洁
]
}
# SRP = scaling & root planing(龈下刮治+根面平整)的国际通用缩写,正是 perio_no_srp 子场景
# 要认的那个治疗。DW 实测 SRP 648 + 局部SRP 40 + SRP+冲洗上药 76,此前全部落 _default 被丢 ——
# 患者做完牙周基础治疗仍被召「牙周炎未做基础治疗」。含 SRP 的 DW 全量已扫,无非牙周语义。
-
{
value
:
periodontic
,
any
:
[
洁治
,
洗牙
,
龈上
,
龈下
,
刮治
,
牙周
,
喷砂
,
细洁
,
SRP
]
}
-
{
value
:
preventive
,
any
:
[
涂氟
,
防龋
,
OHI
,
口腔卫生宣教
]
}
-
{
value
:
preventive
,
any
:
[
涂氟
,
防龋
,
OHI
,
口腔卫生宣教
]
}
-
{
value
:
surgical
,
any
:
[
拔除
,
拔牙
,
切开
,
翻瓣
,
切除
,
系带
,
脓肿
,
囊肿
,
植骨
]
}
# 缝线:「拆线」已在宿主精确表(拆线→surgical,37,253 条正常落库),但措辞变体
# 「拆除缝线」699 条(665 带牙位)漏了 —— 同一临床动作。收「缝线」一并覆盖变体。
# 碰撞已验:「拆除」不含「拔除/切除」,不会被本行前面的词误命中。
-
{
value
:
surgical
,
any
:
[
拔除
,
拔牙
,
切开
,
翻瓣
,
切除
,
系带
,
脓肿
,
囊肿
,
植骨
,
缝线
]
}
-
{
value
:
pediatric
,
any
:
[
乳牙
,
儿童
,
年轻恒牙
]
}
-
{
value
:
pediatric
,
any
:
[
乳牙
,
儿童
,
年轻恒牙
]
}
# ⛔ 刻意不收(2026-08-27 评估过,别"顺手补全"):
# 冲洗 / 换药 / 上药(~3,500 条)—— **对症处置 ≠ 根治**。阻生牙冠周炎「冲洗上药」之后那颗牙
# 仍然要拔;归 surgical 会把 K01 阻生牙缺口消掉 = 该召的不召(少召不报错,最难发现)。
# 调磨(817)/ 试戴(213)—— 姑息调整 / 修复流程中途,都不代表问题已解决。
# ⚠️ 根因:本表的 category 同时被两处消费 —— ①治疗史完整性 ②resolver 判"缺口已解"。
# 对这几个词我们想要①不想要②,而现在只有一个旋钮,只能二选一(现选"都不要"=丢弃)。
# 要两全需在 category 之外再加一维"是否根治",那是更大的改动,不在本表解决。
# actual 语义:这些词开头的从句 = 本次没做(条件/未来/建议)→ 切段丢弃后再匹配。
# actual 语义:这些词开头的从句 = 本次没做(条件/未来/建议)→ 切段丢弃后再匹配。
# 例 "充填,必要时根管治疗" → 丢"必要时根管治疗" → "充填" → restorative(不误判成 endodontic)。
# 例 "充填,必要时根管治疗" → 丢"必要时根管治疗" → "充填" → restorative(不误判成 endodontic)。
keyword_strip_clauses
:
[
必要时
,
如需
,
择期
,
建议
,
推荐
,
考虑
,
若
]
# 若…=条件从句(若牙面脱矿,建议充填),非本次实际治疗
keyword_strip_clauses
:
[
必要时
,
如需
,
择期
,
建议
,
推荐
,
考虑
,
若
]
# 若…=条件从句(若牙面脱矿,建议充填),非本次实际治疗
apps/pac-service/src/modules/sync/assembler/assembler-engine.ts
View file @
06ae44f0
No preview for this file type
apps/pac-service/tests/keyword-case-and-terms.spec.ts
0 → 100644
View file @
06ae44f0
/**
* classifyByKeyword 大小写不敏感 + 2026-08-27 补的四个词(SRP / 加牙 / 活托 / 缝线)。
*
* 规则表按序裁决(首个命中即用),所以新词最大的风险不是"没命中",而是**抢了前面该赢的**。
* 下面每个新词都锁一条碰撞用例(生产 DW 里真实存在的串)。
*
* 跑:
* pnpm test -- keyword-case-and-terms
*/
import
*
as
fs
from
'node:fs'
;
import
*
as
path
from
'node:path'
;
import
*
as
yaml
from
'js-yaml'
;
import
{
classifyByKeyword
}
from
'../src/modules/sync/assembler/assembler-engine'
;
import
type
{
KeywordRule
}
from
'../src/modules/sync/assembler/assembler.schema'
;
/// 直接读生产字典,不在测试里抄一份(抄了必漂)
const
DICT
=
path
.
join
(
__dirname
,
'../data/_shared/dict/treatment-category-actual-rules.yaml'
);
const
doc
=
yaml
.
load
(
fs
.
readFileSync
(
DICT
,
'utf8'
))
as
{
keyword_mapping
:
{
category
:
KeywordRule
[]
};
keyword_strip_clauses
?:
string
[];
};
const
RULES
=
doc
.
keyword_mapping
.
category
;
const
STRIP
=
doc
.
keyword_strip_clauses
;
const
cat
=
(
s
:
string
)
=>
classifyByKeyword
(
s
,
RULES
,
STRIP
);
describe
(
'大小写不敏感'
,
()
=>
{
it
(
'RCT 大小写混写都归 endodontic(生产:RCT 3,122 落库 / rct 725 曾全丢)'
,
()
=>
{
for
(
const
s
of
[
'RCT'
,
'rct'
,
'Rct'
,
'rCT'
])
expect
(
cat
(
s
)).
toBe
(
'endodontic'
);
});
it
(
'复合串也不敏感'
,
()
=>
{
expect
(
cat
(
'rct+冠修复'
)).
toBe
(
'endodontic'
);
// 根管优先于冠
expect
(
cat
(
'局部srp'
)).
toBe
(
'periodontic'
);
});
it
(
'中文不受影响(toLowerCase 对中文恒等)'
,
()
=>
{
expect
(
cat
(
'根管治疗'
)).
toBe
(
'endodontic'
);
expect
(
cat
(
'全口龈上洁治'
)).
toBe
(
'periodontic'
);
});
});
describe
(
'SRP → periodontic'
,
()
=>
{
it
.
each
([
'SRP'
,
'局部SRP'
,
'SRP+冲洗上药'
])(
'%s'
,
(
s
)
=>
{
expect
(
cat
(
s
)).
toBe
(
'periodontic'
);
});
});
describe
(
'加牙 / 活托 → prosthodontic'
,
()
=>
{
it
.
each
([
'加牙'
,
'活托加牙'
,
'加牙后初戴'
,
'活托加牙后初戴'
])(
'%s'
,
(
s
)
=>
{
expect
(
cat
(
s
)).
toBe
(
'prosthodontic'
);
});
// ⛔ 碰撞:「加牙」是「加牙周治疗」的子串,必须让根管先赢
it
(
'「根管治疗加牙周治疗或酌情拔除」→ endodontic,不被加牙抢走'
,
()
=>
{
expect
(
cat
(
'根管治疗加牙周治疗或酌情拔除'
)).
toBe
(
'endodontic'
);
});
it
(
'已被旧词命中的变体行为不变'
,
()
=>
{
expect
(
cat
(
'活动义齿加牙'
)).
toBe
(
'prosthodontic'
);
// 义齿
expect
(
cat
(
'取模加牙'
)).
toBe
(
'prosthodontic'
);
// 取模
});
});
describe
(
'缝线 → surgical'
,
()
=>
{
it
.
each
([
'拆除缝线'
,
'拆除缝线,局部冲洗'
])(
'%s'
,
(
s
)
=>
{
expect
(
cat
(
s
)).
toBe
(
'surgical'
);
});
it
(
'种植拆线仍归 implant(种植优先)'
,
()
=>
{
expect
(
cat
(
'种植拆线'
)).
toBe
(
'implant'
);
});
});
describe
(
'⛔ 刻意不收的词仍然不命中(收了会误销召回)'
,
()
=>
{
it
.
each
([
'冲洗'
,
'换药'
,
'上药'
,
'调磨'
,
'试戴'
,
'观察'
,
'定期观察'
])(
'%s → undefined'
,
(
s
)
=>
{
expect
(
cat
(
s
)).
toBeUndefined
();
});
it
(
'「冲洗上药」不归 surgical —— 阻生牙冠周炎处置后那颗牙仍要拔'
,
()
=>
{
expect
(
cat
(
'冲洗上药'
)).
toBeUndefined
();
});
});
describe
(
'既有裁决顺序不被新词打乱'
,
()
=>
{
it
.
each
([
[
'种植二期'
,
'implant'
],
[
'根管治疗(磨牙)'
,
'endodontic'
],
[
'二期隐形矫正'
,
'orthodontic'
],
[
'冠修复(非美学区)'
,
'prosthodontic'
],
[
'非美学区树脂充填'
,
'restorative'
],
[
'玻璃离子窝沟封闭'
,
'preventive'
],
[
'牙拔除术(松动乳牙)'
,
'surgical'
],
])(
'%s → %s'
,
(
s
,
want
)
=>
{
expect
(
cat
(
s
)).
toBe
(
want
);
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment