feat(identify-words): 识别词——全局识别词(MP 语法)+ 作品识别词(季集换算),规则页「识别词」页签
- 新表 identify_words(0094):全局一块 + 每部作品一块原文,带版本与审计;episode_mapping_rule 转成文本行后删表
- 全局识别词移植 MP WordsMatcher(屏蔽 / 替换 / 集数偏移 / 替换+偏移 / {[tmdbid=…]}),所有按标题 / 文件名识别的地方解析前套用,命中的行记在解析结果上;保存后后台按改动行重新识别
- 作品识别词:S02 >> S01 EP+24 / S01E13 >> S00E01 / S01 @组 >> 忽略,解析器 + 打印器 + 编译;发布组繁简视为同一个
- 去掉规则自动停用:算出来对不上季表只待确认,要停用就注释掉那一行
- 集数待确认的采用 / 忽略与智能体 apply_rule 改为往作品识别词追加一行(带来历注释)
- 编辑器可视化 / 文本两种模式改同一份原文,保存前试算;作品页「集数映射」用同一个编辑器
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
12f8fc59c3
commit
63e94b308e
90 files changed
+6366
-2131
No files matched your search
@@ -7,9 +7,6 @@ import { CAPABILITY_CATALOG, type CapabilitySpec, type KnownCapabilityId } from
|
||||
import { Id, JsonObject, NonNegInt } from "./common.ts";
|
||||
import { MediaEntity, MediaKind } from "./content.ts";
|
||||
import {
|
||||
EpisodeMappingRuleSpec,
|
||||
EpisodeMappingRuleStatus,
|
||||
EpisodeMappingTableEntry,
|
||||
EpisodeReresolveResult,
|
||||
EpisodeResolutionMethod,
|
||||
EpisodeSpecialKind,
|
||||
@@ -17,14 +14,7 @@ import {
|
||||
EpisodeValidationState,
|
||||
} from "./episode-mapping.ts";
|
||||
import { AcquisitionPlan, DownloadStatus, DownloadTask, Task, TaskStatus } from "./execution.ts";
|
||||
import {
|
||||
EnrichmentStatus,
|
||||
EnrichSuggestion,
|
||||
EnrichUsage,
|
||||
EvidenceLevel,
|
||||
ExternalEntityType,
|
||||
ExternalIdentity,
|
||||
} from "./identity.ts";
|
||||
import { EnrichmentStatus, EnrichSuggestion, EnrichUsage, ExternalEntityType, ExternalIdentity } from "./identity.ts";
|
||||
import { OrganizeMetadataInput, OrganizeMetadataOutput } from "./local-metadata.ts";
|
||||
import { ServerMapping } from "./ops.ts";
|
||||
import { OrganizationAction, OrganizationRecord } from "./organization.ts";
|
||||
@@ -927,7 +917,7 @@ export const WebSearchTestResult = z.object({
|
||||
export type WebSearchTestResult = z.infer<typeof WebSearchTestResult>;
|
||||
|
||||
// ── episode_mapping.*:集数映射的智能体兜底(docs/plan/episode-resolution.md 批次 5) ──
|
||||
// inspect 给上下文包(有上限),simulate 试草稿规则,apply_rule 服务端强制先模拟、通过才写规则并重算。
|
||||
// inspect 给上下文包(有上限),simulate 试一行作品识别词,apply_rule 服务端强制先模拟、通过才把这一行写进作品识别词并重算。
|
||||
|
||||
const EpisodeRange = z.object({ start: z.number().int(), end: z.number().int() });
|
||||
const EpisodeSourceView = z.object({
|
||||
@@ -974,8 +964,6 @@ export const EpisodeMappingInspectOutput = z.object({
|
||||
status: DecisionStatus,
|
||||
title: z.string(),
|
||||
summary: z.string().nullable(),
|
||||
/** 算出越界被停用的规则 */
|
||||
failedRules: z.array(z.string()),
|
||||
})
|
||||
.nullable(),
|
||||
/** 事项内资源(没有事项时 = 这个范围里当前待确认的资源),最多 50 条 */
|
||||
@@ -994,25 +982,18 @@ export const EpisodeMappingInspectOutput = z.object({
|
||||
),
|
||||
latestSeason: z.number().int().nullable(),
|
||||
ended: z.boolean(),
|
||||
/** 这部作品的映射规则(含停用及原因);byAgent = 智能体写的 */
|
||||
rules: z.array(
|
||||
z.object({
|
||||
id: Id,
|
||||
season: z.number().int().nullable(),
|
||||
releaseGroup: z.string().nullable(),
|
||||
kind: z.enum(["expression", "table", "special"]),
|
||||
expression: z.string().nullable(),
|
||||
targetSeason: z.number().int().nullable(),
|
||||
tableEntries: z.array(EpisodeMappingTableEntry).nullable(),
|
||||
special: EpisodeSpecialKind.nullable(),
|
||||
status: EpisodeMappingRuleStatus,
|
||||
disabledReason: z.string().nullable(),
|
||||
evidenceLevel: EvidenceLevel,
|
||||
byAgent: z.boolean(),
|
||||
/** 智能体写规则时的理由 */
|
||||
reasons: z.array(z.string()),
|
||||
}),
|
||||
),
|
||||
/** 这部作品的作品识别词原文与逐行解析(注释掉的行是用户停用的,不要再写同范围的行) */
|
||||
words: z.object({
|
||||
text: z.string(),
|
||||
lines: z.array(
|
||||
z.object({
|
||||
line: z.number().int(),
|
||||
text: z.string(),
|
||||
kind: z.enum(["blank", "comment", "map", "table", "special"]),
|
||||
error: z.string().nullable(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
/** 确定性建议(按发布时间对播出日期,全部样本成立且唯一才有) */
|
||||
suggestion: EpisodeSuggestion.nullable(),
|
||||
truncated: z.object({ releases: z.boolean(), neighbors: z.boolean() }),
|
||||
@@ -1023,8 +1004,8 @@ export const EpisodeMappingSimulateInput = z.object({
|
||||
decisionId: Id.optional(),
|
||||
/** 不给 decisionId 时必填 */
|
||||
mediaEntityId: Id.optional(),
|
||||
/** 草稿规则(expression / table / special + 作用域) */
|
||||
rule: EpisodeMappingRuleSpec,
|
||||
/** 一行作品识别词,如 `S02 @ANi >> S01 EP+12`、`S01E13 >> S00E01`、`S03 @Grp >> 忽略` */
|
||||
line: z.string().trim().min(1).max(500),
|
||||
/** 理由:模拟通过时作为智能体建议留在事项上(后台调查没有写规则授权时) */
|
||||
reasons: z.array(z.string().trim().min(1).max(300)).max(10).optional(),
|
||||
});
|
||||
@@ -1061,7 +1042,8 @@ export const EpisodeSimulationSummary = z.object({
|
||||
});
|
||||
export type EpisodeSimulationSummary = z.infer<typeof EpisodeSimulationSummary>;
|
||||
export const EpisodeMappingSimulateOutput = z.object({
|
||||
rule: EpisodeMappingRuleSpec,
|
||||
/** 规范写法的那一行 */
|
||||
line: z.string(),
|
||||
summary: EpisodeSimulationSummary,
|
||||
/** 没通过的原因(通过时为空) */
|
||||
failures: z.array(z.string()),
|
||||
@@ -1074,14 +1056,16 @@ export const EpisodeMappingSimulateOutput = z.object({
|
||||
export const EpisodeMappingApplyRuleInput = z.object({
|
||||
/** 集数待确认事项 ID */
|
||||
decisionId: Id,
|
||||
/** 草稿规则;季 / 发布组不填时用事项的 */
|
||||
rule: EpisodeMappingRuleSpec,
|
||||
/** 为什么这样映射(依据),至少一条 */
|
||||
/** 一行作品识别词(写法同 simulate) */
|
||||
line: z.string().trim().min(1).max(500),
|
||||
/** 为什么这样映射(依据),至少一条;写进识别词时作为这一行上方的注释 */
|
||||
reasons: z.array(z.string().trim().min(1).max(300)).min(1).max(10),
|
||||
});
|
||||
export const EpisodeMappingApplyRuleOutput = z.object({
|
||||
ruleId: Id,
|
||||
evidenceLevel: EvidenceLevel,
|
||||
/** 追加进作品识别词的原文(注释 + 规则行) */
|
||||
appended: z.string(),
|
||||
/** 规则行在识别词里的行号 */
|
||||
lineNumber: z.number().int(),
|
||||
summary: EpisodeSimulationSummary,
|
||||
reresolve: EpisodeReresolveResult,
|
||||
/** 写入后事项的状态(资源都解决时已自动关闭) */
|
||||
|
||||
Reference in new issue
Block a user