refactor(copy): 术语统一——收录版本、模型服务、智能体等(DEAI-2)

- 版本目标 → 收录版本(前后端用户可见字符串、能力描述、给模型的提示)
- Agent 上游 / 上游 → 模型服务;界面上的 Agent / Agent 会话 → 智能体 / 智能体会话
- 身份歧义 / 识别有歧义 / 无法确定作品 → 没识别出作品;待识别(池) → 未识别
- 建档 → 加入媒体库;资产 → 文件;库根 → 媒体库目录;纳管 → 本工具 / 外部任务;
  哨兵 → 标记文件 / 检查目录;站点快照 → 抓取;Feed / RSS 订阅 / 来源健康 → RSS
- 代码标识符、API 字段名、迁移文件不改;glossary.md 同步;smoke 选择器跟随

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 20:35:43 +08:00
1 parent d282212a6b
commit 4480fc346d
212 files changed
+741 -715

No files matched your search

@@ -383,7 +383,7 @@ export function MergeDialog({
<DialogHeader>
<DialogTitle>合并作品</DialogTitle>
<DialogDescription>
「{entity.title}」会标为已合并,旧 ID 跳转到目标作品,订阅、资产和历史记录一并转过去。合并错了可以再修订。
「{entity.title}」会标为已合并,旧 ID 跳转到目标作品,订阅、文件和历史记录一并转过去。合并错了可以再修订。
</DialogDescription>
</DialogHeader>
<EntityPicker value={target} onChange={setTarget} excludeId={entity.id} />
@@ -392,7 +392,7 @@ export function MergeDialog({
id="merge-reason"
value={reason}
onChange={(e) => setReason(e.target.value)}
placeholder="重复建档"
placeholder="重复添加"
/>
</FormField>
<DialogFooter>
@@ -68,7 +68,7 @@ function FieldRow({ k, s, enrichmentId }: { k: EnrichFieldName; s: Suggestion; e
{k !== "posterUrl" ? <p className="text-sm break-words text-foreground">{String(v.value)}</p> : null}
<div className="flex flex-wrap items-center gap-1.5">
<Chip>{EVIDENCE_LEVEL[v.evidenceLevel] ?? v.evidenceLevel}</Chip>
{v.verbatim ? null : <Chip>Agent 归纳</Chip>}
{v.verbatim ? null : <Chip>智能体归纳</Chip>}
<SourceLink url={v.sourceUrl} />
</div>
</div>
@@ -142,7 +142,7 @@ export function EnrichSection({ item }: { item: IdentityPoolItem }) {
{out.notice}
{" · "}
{out.cached ? "7 天内的缓存结果" : `搜索 ${out.usage.searchCalls} 次,读取网页 ${out.usage.fetchCalls} 次`}
{s ? ` · ${s.extractor === "model" ? `Agent 抽取${s.model ? `(${s.model})` : ""}` : "规则抽取"}` : ""}
{s ? ` · ${s.extractor === "model" ? `智能体抽取${s.model ? `(${s.model})` : ""}` : "规则抽取"}` : ""}
{` · 今日 ${out.budget.usedToday}/${out.budget.dailyLimit}`}
</p>
{out.error ? <p className="text-caption text-warning">{out.error}</p> : null}
@@ -23,7 +23,7 @@ const ACTION: Record<IdentityRevision["action"], string> = {
locked: "加人工锁",
unlocked: "解除人工锁",
};
const ACTOR: Record<string, string> = { user: "用户", agent: "Agent", system: "系统", api_key: "API Key" };
const ACTOR: Record<string, string> = { user: "用户", agent: "智能体", system: "系统", api_key: "API Key" };
export const identityRef = (i: Pick<ExternalIdentity, "provider" | "entityType" | "externalId">) =>
`${i.provider}:${i.entityType}:${i.externalId}`;
@@ -76,7 +76,7 @@ function CandidateRow({ c, index }: { c: PoolCandidate; index: number }) {
<ExternalLink className="h-3 w-3" />
</Link>
) : (
<span className="text-meta text-muted-foreground">本地未建档</span>
<span className="text-meta text-muted-foreground">不在媒体库</span>
)}
</div>
{c.evidence.length ? (
@@ -148,7 +148,7 @@ export function PoolTab() {
selectedKey={openId}
empty={{
icon: SearchX,
title: filtered ? "没有符合条件的待识别资源" : "没有待识别资源",
title: filtered ? "没有符合条件的未识别资源" : "没有未识别资源",
description: "未命中订阅、证据不足或冲突的资源会出现在这里;新增相近别名时自动重试,也可手动指定。",
}}
hasMore={pool.hasNextPage}
@@ -249,7 +249,7 @@ export function ExternalTab() {
empty={{
icon: Fingerprint,
title: "没有外部身份",
description: "没有外部身份的作品也能建档入库。",
description: "没有外部编号的作品也能入库。",
}}
hasMore={list.hasNextPage}
onLoadMore={() => list.fetchNextPage()}
+10 -10
View File
@@ -34,7 +34,7 @@ export const MEDIA_KIND: Record<MediaKind, string> = {
};
export const ENTITY_STATUS: Record<MediaEntityStatus, ToneLabel> = {
provisional: { label: "临时建档", tone: "warning" },
provisional: { label: "临时作品", tone: "warning" },
active: { label: "正常", tone: "success" },
merged: { label: "已合并", tone: "neutral" },
archived: { label: "已归档", tone: "neutral" },
@@ -132,8 +132,8 @@ export const CANDIDATE_DECISION: Record<string, ToneLabel> = {
};
export const DECISION_KIND: Record<DecisionKind, string> = {
identity_ambiguous: "身份歧义",
identity_unresolved: "待识别",
identity_ambiguous: "没识别出作品",
identity_unresolved: "未识别",
download_stalled: "下载无进展",
download_failed: "下载失败",
path_conflict: "路径冲突",
@@ -146,7 +146,7 @@ export const DECISION_KIND: Record<DecisionKind, string> = {
export const DECISION_STATUS: Record<DecisionStatus, ToneLabel> = {
open: { label: "待处理", tone: "warning" },
investigating: { label: "Agent 调查中", tone: "neutral" },
investigating: { label: "智能体调查中", tone: "neutral" },
awaiting_user: { label: "等你决定", tone: "warning" },
resolved: { label: "已处理", tone: "success" },
dismissed: { label: "已忽略", tone: "neutral" },
@@ -168,7 +168,7 @@ export const POOL_REASON: Record<IdentityCandidateReason, ToneLabel> = {
};
export const POOL_STATUS: Record<string, ToneLabel> = {
pending: { label: "待识别", tone: "warning" },
pending: { label: "未识别", tone: "warning" },
resolved: { label: "已识别", tone: "success" },
dismissed: { label: "已忽略", tone: "neutral" },
archived: { label: "已归档", tone: "neutral" },
@@ -178,13 +178,13 @@ export const PREF_KIND: Record<PreferenceKind, { label: string; hint: string }>
soft: { label: "软偏好", hint: "影响排序,不排除" },
hard: { label: "硬规则", hint: "命中即排除" },
version: { label: "版本偏好", hint: "同一作品内选哪种版本" },
target: { label: "版本目标", hint: "为作品新建一个版本目标" },
target: { label: "收录版本", hint: "为作品新建一个收录版本" },
};
export const PREF_ORIGIN: Record<PreferenceOrigin, string> = {
manual: "手动",
conversation: "对话确认",
agent_inferred: "Agent 推断",
agent_inferred: "智能体推断",
};
export const PREF_STATUS: Record<PreferenceStatus, ToneLabel> = {
@@ -219,12 +219,12 @@ export const SUB_STATUS: Record<SubscriptionStatus, ToneLabel> = {
completed: { label: "已完成", tone: "neutral" },
cancelled: { label: "已取消", tone: "neutral" },
};
export const SUB_ORIGIN: Record<string, string> = { user: "用户", agent: "Agent", policy: "策略", import: "导入" };
export const SUB_ORIGIN: Record<string, string> = { user: "用户", agent: "智能体", policy: "策略", import: "导入" };
export const METADATA_SOURCE: Record<string, string> = {
tmdb: "TMDB",
user: "人工",
agent: "Agent",
agent: "智能体",
nfo: "NFO",
site: "站点",
import: "导入",
@@ -316,7 +316,7 @@ export const opts = <K extends string>(rec: Record<K, string | { label: string }
return { value, label: typeof v === "string" ? v : v.label };
});
/** 版本目标 / 候选的原因串(如 `blocked:no_main_video`、`deferred:slot_busy;inflight:<id>`)→ 中文;不认识的原样显示 */
/** 收录版本 / 候选的原因串(如 `blocked:no_main_video`、`deferred:slot_busy;inflight:<id>`)→ 中文;不认识的原样显示 */
const SLOT_REASON: Record<string, string> = {
"blocked:no_main_video": "没有可入库的主视频",
"deferred:slot_busy": "已有计划在途,等它结束再评估",
@@ -108,7 +108,7 @@ export function PreferenceFormDialog({
<DialogTitle>{tag ? "编辑偏好" : "添加偏好"}</DialogTitle>
<DialogDescription>
{tag
? "修改作用范围或规则会留下旧语义的抑制记录,Agent 不会按旧证据加回。"
? "修改作用范围或规则会留下旧语义的抑制记录,智能体不会按旧证据加回。"
: "手动添加等同对话确认。之前取消过的偏好,重新添加会解除抑制。"}
</DialogDescription>
</DialogHeader>
@@ -39,7 +39,7 @@ export function SlotCard({
{slot.requireDistinctAsset ? (
<Chip>
<Link2 className="h-3 w-3" />
需不同物理资产{slot.distinctGroup ? ` · ${slot.distinctGroup}` : ""}
需独立文件{slot.distinctGroup ? ` · ${slot.distinctGroup}` : ""}
</Chip>
) : null}
<span className="ml-auto text-meta text-muted-foreground tabular-nums">r{slot.revision}</span>
@@ -72,7 +72,7 @@ export function SlotCard({
<dd className="text-caption text-foreground">{summarizeCompletion(slot.completion)}</dd>
</div>
<div className="min-w-0 sm:col-span-2">
<dt className="mb-1 text-meta text-muted-foreground">当前资产</dt>
<dt className="mb-1 text-meta text-muted-foreground">当前文件</dt>
<dd className="text-caption break-words text-foreground">{currentAsset ?? "无"}</dd>
</div>
</dl>
@@ -353,8 +353,8 @@ function RulesSummary({ rules, valid }: { rules: AcquisitionPolicyRules | undefi
return (
<div className="space-y-2 text-caption">
<div>
<span className="text-muted-foreground">默认版本目标 </span>
<ChipList items={(rules.defaultSlots ?? []).map(tplLine)} empty="无(订阅没有版本目标时不自动创建)" />
<span className="text-muted-foreground">默认收录版本 </span>
<ChipList items={(rules.defaultSlots ?? []).map(tplLine)} empty="无(订阅没有收录版本时不自动创建)" />
</div>
<div>
<span className="text-muted-foreground">新作品收录 </span>
@@ -718,7 +718,7 @@ function PolicyEditorSheet({
</DetailSection>
<DetailSection
title="默认版本目标模板"
title="默认收录版本模板"
actions={
<Button
variant="ghost"
@@ -730,7 +730,7 @@ function PolicyEditorSheet({
</Button>
}
>
<p className="mb-2 text-meta text-muted-foreground">订阅的作品没有版本目标时,按这些模板创建。</p>
<p className="mb-2 text-meta text-muted-foreground">订阅的作品没有收录版本时,按这些模板创建。</p>
<TemplateList list={d.defaultSlots} onChange={(v) => set("defaultSlots", v)} errors={errors} />
</DetailSection>
@@ -768,7 +768,7 @@ function PolicyEditorSheet({
</FormField>
</div>
<div className="flex items-center justify-between gap-2">
<p className="text-meta text-muted-foreground">新作品的版本目标模板</p>
<p className="text-meta text-muted-foreground">新作品的收录版本模板</p>
<Button
variant="ghost"
size="xs"
@@ -51,10 +51,10 @@ export function SlotsPanel({
return (
<div className="space-y-3">
<div className="flex flex-wrap items-center justify-between gap-2">
<p className="text-meta text-muted-foreground">每个版本目标单独判定和升级。这里只改规则。</p>
<p className="text-meta text-muted-foreground">每个收录版本单独判定和升级。这里只改规则。</p>
<Button variant="outline" size="sm" onClick={() => setEditing("new")}>
<Plus />
新建版本目标
新建收录版本
</Button>
</div>
{q.isPending ? (
@@ -65,7 +65,7 @@ export function SlotsPanel({
<EmptyState
plain
icon={Target}
title="还没有版本目标"
title="还没有收录版本"
description="没有时按已发布收录策略的默认模板创建,也可以手动新建。"
className="py-8"
/>
@@ -140,7 +140,7 @@ function SlotEditorSheet({
const errs: Record<string, string> = {};
if (!meta.success) for (const i of meta.error.issues) errs[String(i.path[0])] ??= i.message;
if (!rules.ok) Object.assign(errs, rules.errors);
if (requireDistinct && !distinctGroup.trim()) errs.distinctGroup = "要求不同物理资产时须填写分组";
if (requireDistinct && !distinctGroup.trim()) errs.distinctGroup = "要求独立文件时须填写分组";
setErrors(errs);
if (Object.keys(errs).length || !meta.success || !rules.ok) return;
const common = {
@@ -178,7 +178,7 @@ function SlotEditorSheet({
open
onOpenChange={(o) => !o && !pending && onClose()}
width="lg"
title={slot ? `编辑版本目标 ${slot.name}` : "新建版本目标"}
title={slot ? `编辑收录版本 ${slot.name}` : "新建收录版本"}
description={
slot ? `当前 r${slot.revision}。保存时若已被修改,会提示刷新。` : "不满足硬条件的资源不收;软偏好决定先收哪个。"
}
@@ -225,10 +225,10 @@ function SlotEditorSheet({
</div>
<div className="flex items-center justify-between gap-3 rounded-lg border border-border px-3 py-2">
<div className="min-w-0">
<p className="text-caption font-medium text-foreground">要求不同物理资产</p>
<p className="text-caption font-medium text-foreground">要求独立文件</p>
<p className="text-meta text-muted-foreground">同一个文件不能同时满足两个目标</p>
</div>
<Switch checked={requireDistinct} onCheckedChange={setRequireDistinct} aria-label="要求不同物理资产" />
<Switch checked={requireDistinct} onCheckedChange={setRequireDistinct} aria-label="要求独立文件" />
</div>
<SlotRulesEditor value={draft} onChange={setDraft} errors={errors} />
</DetailSheet>