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:
1 parent
d282212a6b
commit
4480fc346d
212 files changed
+741
-715
No files matched your search
@@ -50,17 +50,17 @@ const RISK: Record<RiskLevel, { label: string; tone: StatusTone }> = {
|
||||
|
||||
const AUTH: Record<CapabilityAuthState, { label: string; tone: StatusTone; hint: string }> = {
|
||||
read_only: { label: "无需授权", tone: "neutral", hint: "只读或预览,不落变更,Key 有对应 scope 即可调用" },
|
||||
granted: { label: "有持续授权", tone: "success", hint: "Agent、MCP、API Key 调用按持续授权放行" },
|
||||
granted: { label: "有持续授权", tone: "success", hint: "智能体、MCP、API Key 调用按持续授权放行" },
|
||||
needs_approval: {
|
||||
label: "需审批",
|
||||
tone: "warning",
|
||||
hint: "没有覆盖它的持续授权,Agent、MCP、API Key 调用需要单次审批",
|
||||
hint: "没有覆盖它的持续授权,智能体、MCP、API Key 调用需要单次审批",
|
||||
},
|
||||
agent_only: { label: "仅 Agent 会话", tone: "neutral", hint: "只在 Agent 会话内可用,不经 MCP 暴露" },
|
||||
agent_only: { label: "仅智能体会话", tone: "neutral", hint: "只在智能体会话内可用,不经 MCP 暴露" },
|
||||
};
|
||||
|
||||
export const CALLER_LABEL: Record<CapabilityCaller, string> = {
|
||||
agent: "内置 Agent",
|
||||
agent: "内置智能体",
|
||||
mcp: "MCP",
|
||||
rest: "REST",
|
||||
other: "其他",
|
||||
@@ -86,7 +86,7 @@ function McpServerBlock() {
|
||||
section="agent"
|
||||
anchor="mcp"
|
||||
title="MCP 服务端"
|
||||
description="外部 Agent 用 API Key 经 MCP 调用同一套能力。授权、审计、幂等与控制台一致,有副作用的工具没有持续授权或单次审批时被拒绝。"
|
||||
description="外部智能体用 API Key 经 MCP 调用同一套能力。授权、审计、幂等与控制台一致,有副作用的工具没有持续授权或单次审批时被拒绝。"
|
||||
>
|
||||
{status.isPending ? (
|
||||
<LoadingState rows={3} />
|
||||
@@ -318,13 +318,13 @@ function CapabilitiesBlock() {
|
||||
section="agent"
|
||||
anchor="capabilities"
|
||||
title="能力清单"
|
||||
description="Agent、MCP、REST 共用这些能力。调用数与失败率为最近 7 天,含被拒绝的调用。"
|
||||
description="智能体、MCP、REST 共用这些能力。调用数与失败率为最近 7 天,含被拒绝的调用。"
|
||||
plain
|
||||
>
|
||||
{automationOff ? (
|
||||
<p className="mb-3 rounded-lg border border-warning/30 bg-warning/10 px-3 py-2 text-caption text-warning">
|
||||
{tools.data?.readOnlyReconcile ? "只读对账模式" : "自动化总开关已关闭"}
|
||||
:执行类能力对 Agent、MCP、API Key 一律拒绝,持续授权暂不生效。
|
||||
:执行类能力对智能体、MCP、API Key 一律拒绝,持续授权暂不生效。
|
||||
</p>
|
||||
) : null}
|
||||
<DataTable
|
||||
|
||||
@@ -14,7 +14,7 @@ export const WEBSEARCH_CARD: CardSpec = {
|
||||
anchor: "websearch",
|
||||
title: "网页搜索",
|
||||
description:
|
||||
"开启后 Agent 可以用 web.search 搜索站外公开信息,用 web.fetch 读取搜索结果里的网页。结果和正文按不可信数据交给模型,web.fetch 不能读内网地址和结果以外的链接。",
|
||||
"开启后智能体可以用 web.search 搜索站外公开信息,用 web.fetch 读取搜索结果里的网页。结果和正文按不可信数据交给模型,web.fetch 不能读内网地址和结果以外的链接。",
|
||||
fields: [
|
||||
{
|
||||
name: "agent.webSearch.provider",
|
||||
@@ -63,7 +63,7 @@ export const WEBSEARCH_CARD: CardSpec = {
|
||||
name: "agent.webSearch.maxResults",
|
||||
label: "每次条数",
|
||||
kind: "number",
|
||||
hint: "1–10,Agent 可以要更少",
|
||||
hint: "1–10,智能体可以要更少",
|
||||
visible: (v) => v["agent.webSearch.provider"] !== "none",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -85,7 +85,7 @@ const BUDGET_CARD: CardSpec = {
|
||||
const INVESTIGATE_CARD: CardSpec = {
|
||||
anchor: "investigate",
|
||||
title: "自动调查",
|
||||
description: "待处理事项(识别有歧义、下载失败等)创建时,自动发起一次有界调查。",
|
||||
description: "待处理事项(没识别出作品、下载失败等)创建时,自动发起一次有界调查。",
|
||||
fields: [
|
||||
{ name: "agent.autoInvestigate", label: "自动调查", kind: "switch", wide: true },
|
||||
{
|
||||
@@ -155,7 +155,7 @@ const ADVANCED_CARD: CardSpec = {
|
||||
name: "agent.optionsTimeoutSec",
|
||||
label: "方案选择等待(秒)",
|
||||
kind: "number",
|
||||
hint: "Agent 给出方案后等你选择的最长时间",
|
||||
hint: "智能体给出方案后等你选择的最长时间",
|
||||
},
|
||||
{
|
||||
name: "agent.optionsTimeoutAction",
|
||||
@@ -163,7 +163,7 @@ const ADVANCED_CARD: CardSpec = {
|
||||
kind: "select",
|
||||
options: [
|
||||
{ value: "recommended", label: "自动选推荐项" },
|
||||
{ value: "stop", label: "不选,Agent 收尾" },
|
||||
{ value: "stop", label: "不选,智能体收尾" },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -184,7 +184,7 @@ const ADVANCED_CARD: CardSpec = {
|
||||
name: "agent.fakeScript",
|
||||
label: "fake 脚本(JSON)",
|
||||
kind: "textarea",
|
||||
hint: "只对 fake 上游生效,留空用内置演示脚本;格式见 docs/runbook/agent.md",
|
||||
hint: "只对 fake 模型服务生效,留空用内置演示脚本;格式见 docs/runbook/agent.md",
|
||||
},
|
||||
],
|
||||
fromSettings: (s) => ({
|
||||
|
||||
@@ -16,7 +16,7 @@ const GiB = 1024 ** 3;
|
||||
const CACHE_CARD: CardSpec = {
|
||||
anchor: "cache",
|
||||
title: "缓存水位",
|
||||
description: "缓存卷使用率到硬阈值时停止新增下载并暂停纳管任务;降到恢复水位以下只恢复因阈值暂停的任务。",
|
||||
description: "缓存卷使用率到硬阈值时停止新增下载并暂停本工具的下载任务;降到恢复水位以下只恢复因阈值暂停的任务。",
|
||||
fields: [
|
||||
{ name: "cache.hardThresholdPercent", label: "硬阈值(%)", kind: "number" },
|
||||
{ name: "cache.resumePercent", label: "恢复水位(%)", kind: "number", hint: "低于硬阈值" },
|
||||
@@ -115,7 +115,7 @@ const STORAGE_BUDGET_CARD: CardSpec = {
|
||||
gbField("pgDataWarnGb", "数据库告警线", "不高于数据库预算"),
|
||||
gbField("imagesGb", "图片缓存容量"),
|
||||
gbField("backupsGb", "备份目录预算"),
|
||||
gbField("sessionsEvidenceGb", "Agent 会话与截图证据预算"),
|
||||
gbField("sessionsEvidenceGb", "智能体会话与截图证据预算"),
|
||||
],
|
||||
fromSettings: (s) => Object.fromEntries(BUDGET_KEYS.map((k) => [`storage.budgets.${k}`, n(s.storage.budgets[k])])),
|
||||
toPatch: (v) => ({ storage: { budgets: pick(v, "storage.budgets", BUDGET_KEYS) } }),
|
||||
@@ -136,17 +136,17 @@ const STORAGE_RETENTION_CARD: CardSpec = {
|
||||
title: "流水数据保留",
|
||||
description: "到期由定时清理任务分批删除。单位天,心跳为小时。",
|
||||
fields: [
|
||||
dayField("retentionDays", "observation", "Feed 观察"),
|
||||
dayField("retentionDays", "observation", "RSS 抓取记录"),
|
||||
dayField("retentionDays", "sseEvent", "实时事件"),
|
||||
dayField("retentionDays", "heartbeatHours", "进程心跳(小时)"),
|
||||
dayField("retentionDays", "taskRun", "任务运行记录"),
|
||||
dayField("retentionDays", "agentEvent", "Agent 会话事件", "只删已结束的会话"),
|
||||
dayField("retentionDays", "agentEvent", "智能体会话事件", "只删已结束的会话"),
|
||||
dayField("retentionDays", "audit", "审计日志", "能力调用审计除外"),
|
||||
dayField("retentionDays", "capabilityStats", "能力调用统计"),
|
||||
dayField(
|
||||
"retentionDays",
|
||||
"identityPoolArchive",
|
||||
"待识别池归档",
|
||||
"未识别资源归档",
|
||||
"未命中的条目这么久没有新证据就归档,仍可手动指定",
|
||||
),
|
||||
],
|
||||
|
||||
@@ -97,7 +97,7 @@ export function BrowserProvidersBlock() {
|
||||
section="sites"
|
||||
anchor="browser"
|
||||
title="浏览器服务"
|
||||
description="原站视图和 Agent 打开站点网页用的 camofox-browser。部署自带的一台由环境变量登记(camofox-env)。"
|
||||
description="原站视图和智能体打开站点网页用的 camofox-browser。部署自带的一台由环境变量登记(camofox-env)。"
|
||||
plain
|
||||
>
|
||||
<ResourceSection<BrowserProviderView>
|
||||
|
||||
@@ -257,9 +257,8 @@ export function LibraryRootsTable() {
|
||||
<ResourceSection<LibraryRoot>
|
||||
hooks={{ list, create, update, remove } as never}
|
||||
config={{
|
||||
noun: "库根",
|
||||
description:
|
||||
"登记或改路径时会在目录里写哨兵文件 .uhd-root,据此判断库根是否在线;目录不存在或不可写时无法保存。",
|
||||
noun: "媒体库目录",
|
||||
description: "保存时会在目录里放一个标记文件,用来判断目录是否挂载;目录不存在或不可写时无法保存。",
|
||||
deleteHint: "只删除登记,磁盘上的文件不动。",
|
||||
columns: [
|
||||
{
|
||||
@@ -286,7 +285,7 @@ export function LibraryRootsTable() {
|
||||
},
|
||||
{ key: "health", header: "在线", cell: (r) => <Health status={r.healthStatus} at={r.lastHealthAt} /> },
|
||||
],
|
||||
rowActions: (r) => <TestButton label="检查哨兵" pending={test.isPending} run={() => test.mutateAsync(r.id)} />,
|
||||
rowActions: (r) => <TestButton label="检查目录" pending={test.isPending} run={() => test.mutateAsync(r.id)} />,
|
||||
fields: [
|
||||
{ name: "name", label: "名称", kind: "text", required: true, placeholder: "例如:电影库" },
|
||||
{ name: "mediaKind", label: "内容类型", kind: "select", options: MEDIA_KIND },
|
||||
|
||||
@@ -42,7 +42,7 @@ const ORGANIZE_CARD: CardSpec = {
|
||||
export function LibrarySection() {
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-8">
|
||||
<SettingsBlock section="library" anchor="roots" title="库根" plain>
|
||||
<SettingsBlock section="library" anchor="roots" title="媒体库目录" plain>
|
||||
<LibraryRootsTable />
|
||||
</SettingsBlock>
|
||||
<SettingsGate>{(s) => <SettingsCard section="library" spec={ORGANIZE_CARD} settings={s} />}</SettingsGate>
|
||||
|
||||
@@ -203,7 +203,7 @@ const IDENTITY_CARD: CardSpec = {
|
||||
anchor: "identity",
|
||||
title: "资源识别",
|
||||
description:
|
||||
"缺省只在资源命中订阅或本地作品别名、新作品收录规则前置条件通过、你手动识别或搜索时查 TMDB;其余进待识别池,不进待处理。",
|
||||
"缺省只在资源命中订阅或本地作品别名、新作品收录规则前置条件通过、你手动识别或搜索时查 TMDB;其余进未识别资源,不进待处理。",
|
||||
fields: [
|
||||
{
|
||||
name: "identity.eagerTmdbLookup",
|
||||
@@ -216,7 +216,7 @@ const IDENTITY_CARD: CardSpec = {
|
||||
name: "identity.autoEnrich",
|
||||
label: "TMDB 查不到时自动补全元数据",
|
||||
kind: "switch",
|
||||
hint: "资源命中订阅或新作品收录规则、TMDB 却没有结果时,自动搜索网页出一份补全建议(每条资源一次,不建作品)。每次约 1–2 次网页搜索、最多读 3 个网页、1 次 Agent 上游调用",
|
||||
hint: "资源命中订阅或新作品收录规则、TMDB 却没有结果时,自动搜索网页出一份补全建议(每条资源一次,不建作品)。每次约 1–2 次网页搜索、最多读 3 个网页、1 次 模型服务调用",
|
||||
wide: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -120,7 +120,7 @@ function RootNaming() {
|
||||
<SettingsBlock
|
||||
section="library"
|
||||
anchor="naming-roots"
|
||||
title="库根命名覆盖"
|
||||
title="媒体库目录命名覆盖"
|
||||
description="按类型覆盖全局模板;留空的类型沿用全局。"
|
||||
>
|
||||
{roots.isPending ? (
|
||||
@@ -128,12 +128,12 @@ function RootNaming() {
|
||||
) : roots.isError ? (
|
||||
<ErrorState plain error={roots.error} onRetry={() => roots.refetch()} />
|
||||
) : !root ? (
|
||||
<p className="text-caption text-muted-foreground">还没有库根。先在上方「库根」添加。</p>
|
||||
<p className="text-caption text-muted-foreground">还没有媒体库目录。先在上方「媒体库目录」添加。</p>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Select value={root.id} onValueChange={setRootId}>
|
||||
<SelectTrigger size="sm" aria-label="库根" className="max-w-full min-w-48">
|
||||
<SelectTrigger size="sm" aria-label="媒体库目录" className="max-w-full min-w-48">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent position="popper">
|
||||
@@ -177,7 +177,7 @@ function RootNamingEditor({ root }: { root: LibraryRoot }) {
|
||||
try {
|
||||
await save.mutateAsync({ id: root.id, naming: body });
|
||||
setDraft({ ...(body ?? {}) });
|
||||
toast.success(body ? "库根命名覆盖已保存" : "已清除库根命名覆盖");
|
||||
toast.success(body ? "媒体库目录命名覆盖已保存" : "已清除媒体库目录命名覆盖");
|
||||
} catch (err) {
|
||||
const split = splitNamingErrors(errorMessage(err));
|
||||
if (split) setErrors(split);
|
||||
@@ -190,7 +190,7 @@ function RootNamingEditor({ root }: { root: LibraryRoot }) {
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{KINDS.map((k) => (
|
||||
<StatusBadge key={k} tone={saved[k] ? "success" : "neutral"}>
|
||||
{NAMING_KIND_LABEL[k]}:{saved[k] ? "库根覆盖" : "沿用全局"}
|
||||
{NAMING_KIND_LABEL[k]}:{saved[k] ? "媒体库目录覆盖" : "沿用全局"}
|
||||
</StatusBadge>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -104,7 +104,7 @@ export function PathMappingsPanel({
|
||||
<p className="truncate">{m.remotePrefix}</p>
|
||||
<p className="truncate text-muted-foreground">→ {m.localPrefix}</p>
|
||||
{rootName(m.libraryRootId) ? (
|
||||
<p className="font-sans text-muted-foreground">库根:{rootName(m.libraryRootId)}</p>
|
||||
<p className="font-sans text-muted-foreground">媒体库目录:{rootName(m.libraryRootId)}</p>
|
||||
) : null}
|
||||
</div>
|
||||
<StatusBadge tone={h.tone}>{h.label}</StatusBadge>
|
||||
@@ -175,7 +175,7 @@ export function PathMappingsPanel({
|
||||
disabled={create.isPending}
|
||||
/>
|
||||
<FieldControl
|
||||
spec={{ name: "libraryRootId", label: "关联库根", kind: "select", options: rootOpts }}
|
||||
spec={{ name: "libraryRootId", label: "关联媒体库目录", kind: "select", options: rootOpts }}
|
||||
value={v.libraryRootId}
|
||||
onChange={(x) => setV((s) => ({ ...s, libraryRootId: x }))}
|
||||
disabled={create.isPending}
|
||||
|
||||
@@ -22,7 +22,7 @@ const SOURCE_TEXT: Record<string, string> = { "stored credential": "已存凭证
|
||||
|
||||
/** 上游返回的多是英文原文:先给一句怎么办,原文留作排查 */
|
||||
const ERROR_HINT: Record<string, string> = {
|
||||
network: "连不上上游,检查 Base URL、端口和网络",
|
||||
network: "连不上模型服务,检查 Base URL、端口和网络",
|
||||
auth: "凭证被拒,检查 API Key 或重新订阅登录",
|
||||
model: "模型不可用,换一个模型 id",
|
||||
};
|
||||
|
||||
@@ -49,13 +49,13 @@ export function PiUpstreamsBlock() {
|
||||
<SettingsBlock
|
||||
section="agent"
|
||||
anchor="upstream"
|
||||
title="上游"
|
||||
description="没指定上游的运行用默认上游。密钥和登录凭证保存后不回显。"
|
||||
title="模型服务"
|
||||
description="没指定模型服务的运行用默认模型服务。密钥和登录凭证保存后不回显。"
|
||||
plain
|
||||
actions={
|
||||
<Button size="sm" onClick={() => setWizard(true)}>
|
||||
<Plus />
|
||||
新建上游
|
||||
新建模型服务
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
@@ -66,7 +66,7 @@ export function PiUpstreamsBlock() {
|
||||
error={list.error}
|
||||
onRetry={() => list.refetch()}
|
||||
onRowClick={(r) => setOpenId(r.id)}
|
||||
empty={{ title: "还没有上游" }}
|
||||
empty={{ title: "还没有模型服务" }}
|
||||
columns={[
|
||||
{
|
||||
key: "name",
|
||||
@@ -181,7 +181,7 @@ function UpstreamDrawer({
|
||||
const makeDefault = async () => {
|
||||
const model = v.model.trim();
|
||||
if (!model) {
|
||||
setErrors((e) => ({ ...e, defaultModel: "设为默认上游前先选默认模型" }));
|
||||
setErrors((e) => ({ ...e, defaultModel: "设为默认模型服务前先选默认模型" }));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -189,7 +189,7 @@ function UpstreamDrawer({
|
||||
id: upstream.id,
|
||||
body: { makeDefault: true, ...(model !== (upstream.defaultModel ?? "") ? { defaultModel: model } : {}) },
|
||||
});
|
||||
toast.success(`${upstream.name}已设为默认上游`);
|
||||
toast.success(`${upstream.name}已设为默认模型服务`);
|
||||
} catch (err) {
|
||||
toast.error(errorMessage(err, "设置失败"));
|
||||
}
|
||||
@@ -204,7 +204,7 @@ function UpstreamDrawer({
|
||||
description={
|
||||
<span className="flex flex-wrap items-center gap-2">
|
||||
<UpstreamStatusBadge u={upstream} />
|
||||
{upstream.isDefault ? <StatusBadge tone="success">默认上游</StatusBadge> : null}
|
||||
{upstream.isDefault ? <StatusBadge tone="success">默认模型服务</StatusBadge> : null}
|
||||
<span>
|
||||
{provider?.name ?? upstream.provider} · {AUTH_LABEL[upstream.authKind]}
|
||||
</span>
|
||||
@@ -402,11 +402,13 @@ function UpstreamDrawer({
|
||||
<ConfirmDialog
|
||||
open={deleting}
|
||||
onOpenChange={setDeleting}
|
||||
title={`删除上游「${upstream.name}」?`}
|
||||
title={`删除模型服务「${upstream.name}」?`}
|
||||
description={
|
||||
upstream.isDefault ? "它是默认上游,删除后没有默认上游;凭证一并删除,无法恢复。" : "凭证一并删除,无法恢复。"
|
||||
upstream.isDefault
|
||||
? "它是默认模型服务,删除后没有默认模型服务;凭证一并删除,无法恢复。"
|
||||
: "凭证一并删除,无法恢复。"
|
||||
}
|
||||
confirmLabel="删除上游"
|
||||
confirmLabel="删除模型服务"
|
||||
destructive
|
||||
onConfirm={async () => {
|
||||
try {
|
||||
|
||||
@@ -60,9 +60,9 @@ export function PiUpstreamWizard({ open, onClose }: { open: boolean; onClose: ()
|
||||
|
||||
const title =
|
||||
step === "provider"
|
||||
? "新建 Agent 上游"
|
||||
? "新建模型服务"
|
||||
: step === "config"
|
||||
? `新建上游 · ${provider?.name ?? ""}`
|
||||
? `新建模型服务 · ${provider?.name ?? ""}`
|
||||
: (created?.name ?? "");
|
||||
const description =
|
||||
step === "provider"
|
||||
@@ -70,8 +70,8 @@ export function PiUpstreamWizard({ open, onClose }: { open: boolean; onClose: ()
|
||||
: step === "config"
|
||||
? "第 2 步,共 3 步:凭证与模型"
|
||||
: created?.authKind === "oauth"
|
||||
? "第 3 步,共 3 步:登录并测试。上游已创建。"
|
||||
: "第 3 步,共 3 步:测试。上游已创建。";
|
||||
? "第 3 步,共 3 步:登录并测试。模型服务已创建。"
|
||||
: "第 3 步,共 3 步:测试。模型服务已创建。";
|
||||
|
||||
return (
|
||||
<DetailSheet open={open} onOpenChange={(o) => !o && close()} title={title} description={description} width="lg">
|
||||
@@ -413,7 +413,7 @@ function VerifyStep({
|
||||
|
||||
const finish = async () => {
|
||||
if (makeDefault && !model.trim()) {
|
||||
setModelError("设为默认上游前先选默认模型");
|
||||
setModelError("设为默认模型服务前先选默认模型");
|
||||
return;
|
||||
}
|
||||
const body = {
|
||||
@@ -422,7 +422,7 @@ function VerifyStep({
|
||||
};
|
||||
try {
|
||||
if (Object.keys(body).length) await update.mutateAsync({ id: upstream.id, body });
|
||||
if (makeDefault && !upstream.isDefault) toast.success(`${upstream.name}已设为默认上游`);
|
||||
if (makeDefault && !upstream.isDefault) toast.success(`${upstream.name}已设为默认模型服务`);
|
||||
onDone();
|
||||
} catch (err) {
|
||||
toast.error(errorMessage(err, "保存失败"));
|
||||
@@ -476,7 +476,7 @@ function VerifyStep({
|
||||
onCheckedChange={setMakeDefault}
|
||||
disabled={upstream.isDefault}
|
||||
/>
|
||||
{upstream.isDefault ? "已是默认上游" : "设为默认上游"}
|
||||
{upstream.isDefault ? "已是默认模型服务" : "设为默认模型服务"}
|
||||
</label>
|
||||
<Button onClick={finish} disabled={update.isPending}>
|
||||
{update.isPending ? <LoaderCircle className="animate-spin" /> : null}
|
||||
|
||||
@@ -23,15 +23,15 @@ const DEFAULTS_CARD: CardSpec = {
|
||||
{ name: "sites.defaultRateLimit.concurrency", label: "并发", kind: "number", hint: "同一站点同时进行的请求" },
|
||||
{
|
||||
name: "sites.defaultSnapshotIntervalSec",
|
||||
label: "快照周期(分钟)",
|
||||
label: "抓取周期(分钟)",
|
||||
kind: "number",
|
||||
hint: "站点开了定时快照但没设周期时使用;5–10080",
|
||||
hint: "站点开了定时抓取但没设周期时使用;5–10080",
|
||||
},
|
||||
{
|
||||
name: "sites.defaultSnapshotMaxPages",
|
||||
label: "快照页数",
|
||||
label: "抓取页数",
|
||||
kind: "number",
|
||||
hint: "定时和手动快照最多抓几页列表;站点定义更少时按站点;1–20",
|
||||
hint: "定时和手动抓取最多抓几页列表;站点定义更少时按站点;1–20",
|
||||
},
|
||||
{
|
||||
name: "sites.defaultHealthCheckIntervalSec",
|
||||
|
||||
Reference in new issue
Block a user