Skip to content

Commit 534053b

Browse files
committed
fix: remove keyword-based tag extraction, use AI auto-tag only
- extractTagsFromOrganization → no-op (keyword matching too imprecise) - Tags now solely from Gemini auto-tag cron (industry/location/expertise/seniority) - Migration 0051: backfill legacy tag data (category/normalized_value)
1 parent ef4f7ee commit 534053b

4 files changed

Lines changed: 39 additions & 50 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-- Migration 0051: Backfill auto_keyword tags missing category/normalized_value
2+
-- 修復 extractTagsFromOrganization 寫入的 tag 缺少 category/raw_value/normalized_value
3+
4+
UPDATE card_tags
5+
SET category = 'keyword',
6+
raw_value = tag,
7+
normalized_value = tag
8+
WHERE tag_source = 'auto_keyword'
9+
AND category IS NULL;
10+
11+
-- 修復英文 key → 中文可讀標籤
12+
UPDATE card_tags SET tag = '政府機關', raw_value = '政府機關', normalized_value = '政府機關' WHERE tag = 'government' AND tag_source = 'auto_keyword';
13+
UPDATE card_tags SET tag = '企業法人', raw_value = '企業法人', normalized_value = '企業法人' WHERE tag = 'listed' AND tag_source = 'auto_keyword';
14+
UPDATE card_tags SET tag = '新創公司', raw_value = '新創公司', normalized_value = '新創公司' WHERE tag = 'startup' AND tag_source = 'auto_keyword';
15+
UPDATE card_tags SET tag = '非營利組織', raw_value = '非營利組織', normalized_value = '非營利組織' WHERE tag = 'ngo' AND tag_source = 'auto_keyword';
16+
17+
-- tag_stats 也需要更新
18+
UPDATE tag_stats SET tag = '政府機關' WHERE tag = 'government';
19+
UPDATE tag_stats SET tag = '企業法人' WHERE tag = 'listed';
20+
UPDATE tag_stats SET tag = '新創公司' WHERE tag = 'startup';
21+
UPDATE tag_stats SET tag = '非營利組織' WHERE tag = 'ngo';
22+
23+
-- 回滾方案(註解)
24+
-- UPDATE card_tags SET tag = 'government', raw_value = 'government', normalized_value = 'government' WHERE tag = '政府機關' AND tag_source = 'auto_keyword';
25+
-- UPDATE card_tags SET tag = 'listed', raw_value = 'listed', normalized_value = 'listed' WHERE tag = '企業法人' AND tag_source = 'auto_keyword';
26+
-- UPDATE card_tags SET tag = 'startup', raw_value = 'startup', normalized_value = 'startup' WHERE tag = '新創公司' AND tag_source = 'auto_keyword';
27+
-- UPDATE card_tags SET tag = 'ngo', raw_value = 'ngo', normalized_value = 'ngo' WHERE tag = '非營利組織' AND tag_source = 'auto_keyword';

workers/src/handlers/mcp/tools.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,9 +354,9 @@ export async function toolSaveReceivedCard(
354354
if (tags.length > 0) {
355355
const tagStatements = tags.map(tag =>
356356
env.DB.prepare(`
357-
INSERT OR IGNORE INTO card_tags (card_uuid, tag, tag_source, created_at)
358-
VALUES (?, ?, 'auto_keyword', ?)
359-
`).bind(cardUuid, tag, now)
357+
INSERT OR IGNORE INTO card_tags (card_uuid, tag, category, raw_value, normalized_value, tag_source, created_at)
358+
VALUES (?, ?, 'keyword', ?, ?, 'auto_keyword', ?)
359+
`).bind(cardUuid, tag, tag, tag, now)
360360
);
361361
await env.DB.batch(tagStatements);
362362

workers/src/handlers/user/received-cards/crud.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,9 @@ export async function handleSaveCard(request: Request, env: Env, ctx: ExecutionC
232232
for (const tag of tags) {
233233
statements.push(
234234
env.DB.prepare(`
235-
INSERT OR IGNORE INTO card_tags (card_uuid, tag, tag_source, created_at)
236-
VALUES (?, ?, 'auto_keyword', ?)
237-
`).bind(cardUuid, tag, now)
235+
INSERT OR IGNORE INTO card_tags (card_uuid, tag, category, raw_value, normalized_value, tag_source, created_at)
236+
VALUES (?, ?, 'keyword', ?, ?, 'auto_keyword', ?)
237+
`).bind(cardUuid, tag, tag, tag, now)
238238
);
239239
}
240240
await env.DB.batch(statements);

workers/src/utils/tags.ts

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,14 @@
11
/**
22
* Tag Extraction Utilities
33
*
4-
* BDD Spec: Tag Extraction Logic
5-
* Automatically extracts tags from business card data based on organization field
4+
* Organization-based keyword tagging removed (2026-06-23):
5+
* Keyword matching was too imprecise. AI auto-tagging (Gemini) via
6+
* auto-tag-cards cron provides accurate industry/location/seniority/expertise.
67
*/
78

89
/**
9-
* Company type keywords for tag extraction
10-
* Each type maps to an array of keywords to match
10+
* @deprecated No-op. Kept for backward compatibility with callers.
1111
*/
12-
const COMPANY_TYPE_KEYWORDS = {
13-
government: ['政府', '部會', '機關', '局', '署', '處'],
14-
listed: ['股份有限公司', '有限公司', 'Co., Ltd.', 'Inc.'],
15-
startup: ['新創', '創業', 'Startup'],
16-
ngo: ['基金會', '協會', '學會', '公會']
17-
};
18-
19-
/**
20-
* Extract tags from organization field
21-
*
22-
* @param organization - The organization field from business card
23-
* @returns Array of matched tags
24-
*
25-
* @example
26-
* extractTagsFromOrganization("數位發展部") // ["government"]
27-
* extractTagsFromOrganization("台積電股份有限公司") // ["listed"]
28-
* extractTagsFromOrganization("AI 新創科技") // ["startup"]
29-
* extractTagsFromOrganization("台灣人工智慧協會") // ["ngo"]
30-
* extractTagsFromOrganization(null) // []
31-
*/
32-
export function extractTagsFromOrganization(organization: string | null | undefined): string[] {
33-
// Handle null, undefined, or empty string
34-
if (!organization) {
35-
return [];
36-
}
37-
38-
const tags = new Set<string>();
39-
const lowerOrg = organization.toLowerCase();
40-
41-
// Iterate through each company type and its keywords
42-
for (const [type, keywords] of Object.entries(COMPANY_TYPE_KEYWORDS)) {
43-
for (const keyword of keywords) {
44-
if (lowerOrg.includes(keyword.toLowerCase())) {
45-
tags.add(type);
46-
break; // Each type should only be added once
47-
}
48-
}
49-
}
50-
51-
return Array.from(tags);
12+
export function extractTagsFromOrganization(_organization: string | null | undefined): string[] {
13+
return [];
5214
}

0 commit comments

Comments
 (0)