feat: KOC 资源导入后自动爬取主页资料并调用 LLM 打标签
- 新增 structured_text_process 打标客户端(文本构造、标签解析清洗、MCP 调用) - 写库后后台打标(tagUntaggedAccounts),单条新增 / 批量导入 / 每日补全三个入口统一 - 标签只补空,UPDATE 带 tags 为空守卫,不覆盖已有标签 - 新增 AI_TAGGING_TOOL 配置项(留空关闭),更新配置示例与文档 - 新增 16 个打标测试用例,全量 131 个测试通过
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import {
|
||||
generateAccountTagsFromMcp,
|
||||
resolveXhsPublicAccountDetails,
|
||||
resolveAccountProfileFromMcp,
|
||||
resolveProfileDetailsFromMcp,
|
||||
type AccountTaggingEnv,
|
||||
type CollectionMcpConfig,
|
||||
} from "./mcp-collection-client";
|
||||
import { getRuntimeEnv } from "./runtime-env";
|
||||
import { hashText } from "./mvp-db";
|
||||
import type { DatabaseClient } from "./database";
|
||||
|
||||
@@ -260,6 +263,7 @@ export async function backfillAccountProfiles(
|
||||
mcpConfig: CollectionMcpConfig,
|
||||
limit = 10,
|
||||
) {
|
||||
const taggingEnv: AccountTaggingEnv = getRuntimeEnv();
|
||||
const rows = await db
|
||||
.prepare(
|
||||
`SELECT
|
||||
@@ -334,6 +338,7 @@ export async function backfillAccountProfiles(
|
||||
const isDemoAccount = row.platform_uid?.startsWith("xhs-");
|
||||
let attemptedThisRow = false;
|
||||
let publicProfileUpdated = false;
|
||||
let tagsUpdated = false;
|
||||
if (
|
||||
row.platform === "小红书" &&
|
||||
!isDemoAccount &&
|
||||
@@ -341,7 +346,8 @@ export async function backfillAccountProfiles(
|
||||
(!row.public_account_id ||
|
||||
Number(row.followers ?? 0) === 0 ||
|
||||
!row.gender ||
|
||||
!row.bio)
|
||||
!row.bio ||
|
||||
!row.tags?.trim())
|
||||
) {
|
||||
attempted += 1;
|
||||
attemptedThisRow = true;
|
||||
@@ -402,6 +408,39 @@ export async function backfillAccountProfiles(
|
||||
.run();
|
||||
publicProfileUpdated = true;
|
||||
}
|
||||
if (
|
||||
row.account_id &&
|
||||
!row.tags?.trim() &&
|
||||
(details.bio ||
|
||||
details.providerTags.length > 0 ||
|
||||
details.recentNoteTitles.length > 0)
|
||||
) {
|
||||
const tags = await generateAccountTagsFromMcp(
|
||||
{
|
||||
platform: "小红书",
|
||||
nickname: row.nickname || details.nickname || "",
|
||||
bio: details.bio,
|
||||
gender: details.gender,
|
||||
ipLocation: details.ipLocation ?? "",
|
||||
followers: details.followers,
|
||||
providerTags: details.providerTags,
|
||||
recentNoteTitles: details.recentNoteTitles,
|
||||
},
|
||||
mcpConfig,
|
||||
taggingEnv,
|
||||
).catch(() => []);
|
||||
if (tags.length > 0) {
|
||||
await db
|
||||
.prepare(
|
||||
`UPDATE accounts
|
||||
SET tags = CASE WHEN ? != '' THEN ? ELSE tags END
|
||||
WHERE id = ?`,
|
||||
)
|
||||
.bind(tags.join(","), tags.join(","), row.account_id)
|
||||
.run();
|
||||
tagsUpdated = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
(details.redId || row.public_account_id) &&
|
||||
Number(details.followers ?? row.followers ?? 0) > 0
|
||||
@@ -410,7 +449,7 @@ export async function backfillAccountProfiles(
|
||||
continue;
|
||||
}
|
||||
if (attempted >= Math.max(1, Math.min(25, limit))) {
|
||||
if (publicProfileUpdated) updated += 1;
|
||||
if (publicProfileUpdated || tagsUpdated) updated += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -430,7 +469,7 @@ export async function backfillAccountProfiles(
|
||||
row.platform_uid?.startsWith("pending-") ||
|
||||
Boolean(noteId && row.platform_uid === noteId));
|
||||
if (!needsEnrichment || !row.publish_url) {
|
||||
if (publicProfileUpdated) updated += 1;
|
||||
if (publicProfileUpdated || tagsUpdated) updated += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -443,9 +482,9 @@ export async function backfillAccountProfiles(
|
||||
row.nickname || "待识别账号",
|
||||
mcpConfig,
|
||||
);
|
||||
if (result.updated || publicProfileUpdated) updated += 1;
|
||||
if (result.updated || publicProfileUpdated || tagsUpdated) updated += 1;
|
||||
} catch {
|
||||
if (publicProfileUpdated) updated += 1;
|
||||
if (publicProfileUpdated || tagsUpdated) updated += 1;
|
||||
else failed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user