126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
import { Select } from '../components/ui';
|
||
import type { PretrainedInitialization, PretrainedSource } from './types';
|
||
import { pretrainedSelectionError } from './pretrainedSelection';
|
||
import { PretrainedUpload, type PretrainedUploadConnection } from './PretrainedUpload';
|
||
|
||
export function PretrainedIdentity({ source }: { source?: PretrainedInitialization }) {
|
||
if (!source)
|
||
return <p className="text-xs text-text-tertiary">初始化:随机新策略(未选择基础策略)</p>;
|
||
return (
|
||
<div className="break-all text-xs text-text-secondary" aria-label="基础策略身份">
|
||
<p>
|
||
初始化:{source.label} · {source.manifest.artifacts.checkpoint.name}
|
||
</p>
|
||
<details className="domain-details">
|
||
<summary>来源与校验详情</summary>
|
||
<p>checkpoint SHA256:{source.manifest.artifacts.checkpoint.sha256}</p>
|
||
{source.manifest.artifacts.upload ? (
|
||
<>
|
||
<p>
|
||
上传格式:{source.manifest.sourceFormat} · 原文件:{source.label}
|
||
</p>
|
||
<p>原文件 SHA256:{source.manifest.artifacts.upload.sha256}</p>
|
||
<p>
|
||
模板:{source.manifest.contract}
|
||
(用户确认缺失的物理语义);继承actor权重,非完整resume。
|
||
</p>
|
||
{source.manifest.sourceFormat === 'onnx' && (
|
||
<p>
|
||
ONNX统计count合成:
|
||
{source.manifest.derived_fields?.normalizer_count?.value ?? '未知'};
|
||
探索std使用新训练默认,critic/optimizer重新初始化。
|
||
</p>
|
||
)}
|
||
</>
|
||
) : (
|
||
<p>ONNX SHA256:{source.manifest.artifacts.onnx?.sha256 ?? '未知'}</p>
|
||
)}
|
||
</details>
|
||
<p>
|
||
来源迭代 {source.manifest.source_iteration ?? '未知'}
|
||
;新训练从0开始,critic/optimizer重新初始化;同trial续训保留自身checkpoint。
|
||
</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export function PretrainedSourceSelect({
|
||
sources = [],
|
||
taskId,
|
||
value,
|
||
onChange,
|
||
disabled = false,
|
||
upload,
|
||
}: {
|
||
sources?: PretrainedSource[];
|
||
taskId: string;
|
||
value: string;
|
||
onChange(value: string): void;
|
||
disabled?: boolean;
|
||
upload?: PretrainedUploadConnection;
|
||
}) {
|
||
const selected = sources.find((source) => source.id === value);
|
||
const selectionError = pretrainedSelectionError(sources, taskId, value);
|
||
return (
|
||
<div className="space-y-1">
|
||
<label className="block text-xs text-text-secondary">
|
||
基础策略
|
||
<Select
|
||
aria-label="基础策略"
|
||
className="w-full"
|
||
value={value}
|
||
disabled={disabled}
|
||
onChange={(event) => onChange(event.target.value)}
|
||
>
|
||
<option value="">不选择(随机初始化)</option>
|
||
{value && !selected && (
|
||
<option value={value} disabled>
|
||
所选基础策略已失效({value})
|
||
</option>
|
||
)}
|
||
{sources.map((source) => (
|
||
<option
|
||
key={source.id}
|
||
value={source.id}
|
||
disabled={!source.ready || !source.compatibleTasks.includes(taskId)}
|
||
>
|
||
{source.label}
|
||
{!source.ready
|
||
? '(验证失败)'
|
||
: !source.compatibleTasks.includes(taskId)
|
||
? '(任务不兼容)'
|
||
: '(已验证)'}
|
||
</option>
|
||
))}
|
||
</Select>
|
||
</label>
|
||
{upload && (
|
||
<PretrainedUpload
|
||
key={JSON.stringify([upload.endpoint, upload.token, upload.revision, taskId])}
|
||
connection={upload}
|
||
disabled={disabled}
|
||
/>
|
||
)}
|
||
{!sources.length && <p className="text-xs text-text-secondary">尚无基础策略</p>}
|
||
{sources
|
||
.filter((source) => source.error)
|
||
.map((source) => (
|
||
<p role="alert" key={source.id}>
|
||
{source.label}:{source.error}
|
||
</p>
|
||
))}
|
||
{selected && (
|
||
<p className="text-xs">
|
||
兼容:{selected.compatibleTasks.join(' / ')};观测 {selected.observationSizes?.join('/')}{' '}
|
||
→ 12动作。只继承actor权重,新训练从0开始。
|
||
</p>
|
||
)}
|
||
{selectionError ? (
|
||
<p role="alert">{selectionError}</p>
|
||
) : (
|
||
<PretrainedIdentity source={selected?.initialization} />
|
||
)}
|
||
</div>
|
||
);
|
||
}
|