Back to skills
extension
Category: Data & AnalyticsNo API key required

一键解析名片字段

Use when building high-accuracy paste/OCR contact extraction (name, phone, email, company) with confidence scoring, or when the user asks for 精准名片解析、 粘贴解析优化、备注拆字段增强、OCR 名片纠错、比 paste-card-parse 更准的解析。 Prefer this over paste-card-parse for production entry forms.

personAuthor: user_f1b049dahubcommunity

Precise Card Parse(精准名片解析 · 增强版)

相对 paste-card-parse 的升级版:同样支持粘贴文本 / 图片 OCR,但采用
清洗 → 行分类 → 标签提取 → 候选打分 → 冲突消解 管线,提升准确率与效率,并输出置信度。

目标字段:姓名、电话、邮箱、公司(可选职位、地址)。

何时启用(优先于旧 Skill)

  • 生产录入、智能录入、线索落库前的结构化
  • 用户要求「更准 / 更完整 / 更高效率」的名片解析
  • OCR 噪声多、带「手机:」「邮箱:」标签、单行备注混排

旧 Skill paste-card-parse 仅作入门;新实现对齐本 Skill

硬约束

  1. 单次扫描优先:正文只遍历行/token 一遍完成分类与候选收集(O(n)),禁止对全文反复跑多套无关正则。
  2. 标签优先于启发式:出现「姓名/手机/电话/邮箱/公司/单位」等标签时,标签值置信度最高。
  3. 每字段可多候选,只输出最优 + confidence:禁止静默拼接脏字符串。
  4. 清洗必做:零宽字符、全角、杂空白(可复用 cleanPasteText)。
  5. 图片:OCR → 纠错 → 同一解析器;OCR 空文必须失败提示。
  6. 填表默认 fill-empty;成功反馈含命中字段与低置信警告。
  7. 正则无全局状态污染;手机/邮箱用局部字面量。
  8. 与仓库 parseContactText 共存时:封装为 parseCardPrecise,可内部先调旧函数作 baseline,再以本管线结果覆盖高置信字段。

标准工作流

Precise Card Parse
- [ ] cleanPasteText(或等价预处理)
- [ ] 实现 lineClassify + extractByLabel
- [ ] 收集候选 → score → pickBest → ParsedCardPrecise
- [ ] OCR 路径:ocr → fixOcrNoise → 同上
- [ ] apply + emitParseSignal(含低置信提示)
- [ ] 用 fixtures 回归(见 reference)

管线总览

raw / OCR text
    │
    ▼
 clean (全角/零宽/换行)
    │
    ▼
 split lines + soft-split(;|;|空格分隔标签段)
    │
    ▼
 classify each segment  ──► label | phone | email | company | title | name_cand | noise
    │
    ▼
 extractByLabel(最高优先级)
    │
    ▼
 score candidates(规则分)
    │
    ▼
 pickBest + conflict resolve
    │
    ▼
 ParsedCardPrecise { fields, confidence, hitFields, warnings }

Step 1:增强输出模型

export type CardFieldKey = 'name' | 'phone' | 'email' | 'company' | 'title' | 'address';

export type FieldHit = {
  value: string;
  confidence: number; // 0~1
  evidence: 'label' | 'pattern' | 'heuristic' | 'ocr-fix';
};

export type ParsedCardPrecise = {
  name: string;
  phone: string;
  email: string;
  company: string;
  title: string;
  address: string;
  raw: string;
  cleaned: string;
  source: 'text' | 'image';
  fields: Partial<Record<CardFieldKey, FieldHit>>;
  hitFields: CardFieldKey[];
  warnings: string[]; // 如「姓名置信度偏低」
};

Step 2:清洗(效率:一遍字符串替换)

优先复用 src/utils/localCrmTools/pasteClean.tscleanPasteText
额外建议:统一中文冒号 :(便于标签解析);去掉首尾引号。

Step 3:标签提取(准确率关键)

const LABEL_MAP: Array<{ keys: string[]; field: CardFieldKey }> = [
  { keys: ['姓名', '名字', '联系人', 'name'], field: 'name' },
  { keys: ['手机', '电话', '联系电话', 'mobile', 'tel', 'phone'], field: 'phone' },
  { keys: ['邮箱', '邮件', 'email', 'mail'], field: 'email' },
  { keys: ['公司', '单位', '企业', '机构', 'company'], field: 'company' },
  { keys: ['职位', '职务', 'title'], field: 'title' },
  { keys: ['地址', 'addr', 'address'], field: 'address' },
];

// 匹配:^标签\s*[::]\s*(.+)$
// confidence: 0.92 ~ 0.98

同一字段多标签命中时取更长且更像该字段的值(电话需通过 normalizePhone 校验)。

Step 4:无标签启发式(打分,勿盲取)

| 字段 | 高分信号 | 降分 / 排除 | |------|----------|-------------| | phone | 11 位 1[3-9]…;标签附近 | 连续年份、订单号过长数字 | | email | 含 @ 且域名合法 | 缺 . 的残缺串 | | company | 后缀 有限公司/股份/集团/研究所;长度 6–40 | 纯职位词、纯姓名 | | name | 2–4 汉字;或「姓+职位」拆分 | 落在公司行内的子串;含「公司」 | | title | 词表命中且行短 | 整行即公司名 |

姓名防误吸(比旧版重要):

  1. 已判定为 company 的行,禁止再当 name
  2. 禁止用「全文第一个 2–4 汉字」若该匹配落在公司名内部
  3. 优先独立行 / 标签值 /「X经理」去职位后剩余

公司防误吸:

  1. 关键词命中后仍要 scoreCompany:后缀权重大于「科技/投资」孤词
  2. 多候选取 score 最高,而非单纯最长(避免把整段备注当公司)

Step 5:OCR 噪声轻纠(图片路径)

在解析前对 OCR 文做低成本替换(仅高把握):

| 噪声 | 处理 | |------|------| | 邮箱中空格 name @ xx.com | 去 @ 两侧空格 | | 常见 l/I/1 混在域名 | 仅当原串不像邮箱、修正后像邮箱时采用 | | 全角 @ | 转半角 | | 手机号中间杂 . | 按手机模式抽取时忽略分隔符 |

纠错成功的字段 evidence: 'ocr-fix',confidence 略降(如 0.8)。

Step 6:冲突消解与效率

function pickBest(cands: FieldHit[]): FieldHit | undefined {
  return cands.slice().sort((a, b) => b.confidence - a.confidence)[0];
}
  • 电话:手机优先于座机;多个手机取标签命中或全文首次合法号
  • 邮箱:多个取标签或顶级域名更常见者
  • warnings:任一输出字段 confidence < 0.65 时推入警告
  • 早停:清洗后为空直接返回;已标签凑齐 name+phone+email+company 可跳过重度启发式(仍可轻量补 title)

Step 7:填表与反馈

function emitParseSignal(card: ParsedCardPrecise) {
  const hit = card.hitFields.join('/'); // 映射中文后再 Toast
  if (!card.hitFields.length) {
    ElMessage.warning('未识别到有效字段');
    return;
  }
  const low = card.warnings.length ? `;注意:${card.warnings[0]}` : '';
  ElMessage.success(`解析成功:${hit}${low}`);
}

与旧实现迁移

| 项目 | paste-card-parse | precise-card-parse(本 Skill) | |------|------------------|--------------------------------| | 策略 | 单次正则 + 最长公司行 | 标签 + 打分 + 消解 | | 输出 | 平坦字符串 | 带 confidence / warnings | | 姓名 | 易误吸公司内汉字 | 显式排除公司行 | | 效率 | 多次全文 match | 一行分类为主 | | OCR | 直解析 | 纠错后再解析 |

新页面直接按本 Skill 实现;旧页可渐进把 parseContactText 包进 parseCardPrecise

反模式

| 禁止 | 原因 | |------|------| | 只用最长含「科技」的行当公司 | 备注整段误判 | | 全文第一个 2–4 汉字当姓名 | 从公司名切开「上海」等 | | 每字段各扫一遍超大正则库 | 浪费、难维护 | | 忽略标签行 | 准确率上限被锁死 | | 低置信仍 success 且无 warnings | 脏数据入库 |

Agent 交付检查

  • [ ] 带标签备注样例:四要素全中且 confidence≥0.9
  • [ ] 无标签混排样例:电话+邮箱稳定
  • [ ] 公司名内不含被拆出的伪姓名
  • [ ] OCR 空格邮箱可修好或给出 warning
  • [ ] fixtures 中样例通过(见 reference)
  • [ ] 反馈含命中字段;低置信有提示

附加资源