feat: add image_make controls to admin
This commit is contained in:
@@ -12,6 +12,7 @@ type PluginDraft = {
|
||||
provider: string;
|
||||
llmProviderKeyId: string;
|
||||
llmModel: string;
|
||||
purposes: Record<string, boolean>;
|
||||
};
|
||||
|
||||
function draftFromPlugin(plugin: AssetPluginConfig): PluginDraft {
|
||||
@@ -20,6 +21,7 @@ function draftFromPlugin(plugin: AssetPluginConfig): PluginDraft {
|
||||
provider: plugin.provider ?? '',
|
||||
llmProviderKeyId: plugin.llmProviderKeyId ?? '',
|
||||
llmModel: plugin.llmModel ?? '',
|
||||
purposes: { ...(plugin.purposes ?? {}) },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,6 +63,16 @@ export function AssetGatewayPage() {
|
||||
setDrafts((current) => ({ ...current, [pluginId]: { ...current[pluginId], ...patch } }));
|
||||
};
|
||||
|
||||
const updatePurpose = (pluginId: string, purposeId: string, enabled: boolean) => {
|
||||
setDrafts((current) => ({
|
||||
...current,
|
||||
[pluginId]: {
|
||||
...current[pluginId],
|
||||
purposes: { ...(current[pluginId]?.purposes ?? {}), [purposeId]: enabled },
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const saveGlobal = async (enabled: boolean) => {
|
||||
setBusy('global'); setMessage(null); setError(null);
|
||||
try {
|
||||
@@ -81,6 +93,7 @@ export function AssetGatewayPage() {
|
||||
provider: draft.provider || null,
|
||||
llmProviderKeyId: draft.llmProviderKeyId || null,
|
||||
llmModel: draft.llmModel || null,
|
||||
purposes: draft.purposes,
|
||||
});
|
||||
setConfig(result.config);
|
||||
setDrafts(Object.fromEntries(result.config.plugins.map((item) => [item.pluginId, draftFromPlugin(item)])));
|
||||
@@ -126,11 +139,21 @@ export function AssetGatewayPage() {
|
||||
</label>
|
||||
</div>
|
||||
<div className="asset-plugin-fields">
|
||||
<label>运行 Provider<select value={draft.provider} onChange={(event) => updateDraft(plugin.pluginId, { provider: event.target.value })} disabled={!draft.enabled}>
|
||||
<label>运行 Provider<select value={draft.provider} onChange={(event) => {
|
||||
const provider = event.target.value;
|
||||
updateDraft(plugin.pluginId, {
|
||||
provider,
|
||||
...(provider === 'image_make' ? { llmProviderKeyId: '', llmModel: '' } : {}),
|
||||
});
|
||||
}} disabled={!draft.enabled}>
|
||||
<option value="">选择 Provider</option>
|
||||
{plugin.providers.map((provider) => <option key={provider} value={provider}>{provider}</option>)}
|
||||
</select></label>
|
||||
{plugin.supportsLlm ? <>
|
||||
{plugin.pluginId === 'asset-generate' && draft.provider === 'image_make' ? (
|
||||
<div className="asset-image-make-note">
|
||||
image_make 独立管理本地模型,不读取统一模型中心密钥。
|
||||
</div>
|
||||
) : plugin.supportsLlm ? <>
|
||||
<label>专属 LLM<select value={draft.llmProviderKeyId} onChange={(event) => updateDraft(plugin.pluginId, { llmProviderKeyId: event.target.value, llmModel: '' })} disabled={!draft.enabled}>
|
||||
<option value="">不使用 LLM</option>
|
||||
{activeKeys.map((key) => <option key={key.id} value={key.id}>{key.name}</option>)}
|
||||
@@ -140,6 +163,24 @@ export function AssetGatewayPage() {
|
||||
{selectedKey?.models.map((model) => <option key={model} value={model}>{model}</option>)}
|
||||
</select></label>
|
||||
</> : <div className="asset-no-llm">确定性处理 · 不调用 LLM</div>}
|
||||
{plugin.pluginId === 'asset-generate' && plugin.purposeCatalog?.length ? (
|
||||
<fieldset className="asset-purpose-fieldset" disabled={!draft.enabled || draft.provider !== 'image_make'}>
|
||||
<legend>image_make 生效范围</legend>
|
||||
<div className="asset-purpose-grid">
|
||||
{plugin.purposeCatalog.map((purpose) => (
|
||||
<label key={purpose.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={Boolean(draft.purposes[purpose.id])}
|
||||
onChange={(event) => updatePurpose(plugin.pluginId, purpose.id, event.target.checked)}
|
||||
/>
|
||||
<span>{purpose.label}<small>{purpose.presetId}</small></span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
<p>信息流缩略图仍由 MindSpace 从封面源图派生,不会重复调用生图模型。</p>
|
||||
</fieldset>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="asset-plugin-footer"><span className={`asset-status ${draft.enabled ? 'is-on' : ''}`}>{draft.enabled ? '待保存为启用' : '默认安全关闭'}</span><button type="button" className="send-btn" disabled={busy === plugin.pluginId} onClick={() => void savePlugin(plugin)}>{busy === plugin.pluginId ? '保存中…' : '保存配置'}</button></div>
|
||||
</section>;
|
||||
|
||||
@@ -307,6 +307,7 @@ export async function updateAssetPluginConfig(
|
||||
provider?: string | null;
|
||||
llmProviderKeyId?: string | null;
|
||||
llmModel?: string | null;
|
||||
purposes?: Record<string, boolean>;
|
||||
},
|
||||
): Promise<{ ok: boolean; config: AssetGatewayConfig }> {
|
||||
return portalFetch(`/admin-api/asset-gateway/plugins/${encodeURIComponent(pluginId)}`, {
|
||||
|
||||
@@ -1080,6 +1080,60 @@ body,
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.asset-image-make-note,
|
||||
.asset-no-llm {
|
||||
padding: 9px 10px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: rgba(132, 110, 255, .1);
|
||||
color: var(--color-text-muted);
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.asset-purpose-fieldset {
|
||||
min-width: 0;
|
||||
margin: 2px 0 0;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.asset-purpose-fieldset legend {
|
||||
padding: 0 5px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.asset-purpose-fieldset > p {
|
||||
margin: 8px 0 0;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 10px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.asset-purpose-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.asset-purpose-grid label {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 7px;
|
||||
padding: 7px;
|
||||
border-radius: var(--radius-xs);
|
||||
background: rgba(255, 255, 255, .035);
|
||||
}
|
||||
|
||||
.asset-purpose-grid small {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 9px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.asset-plugin-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -208,6 +208,12 @@ export type AssetPluginConfig = {
|
||||
llmProviderId: string | null;
|
||||
llmModel: string | null;
|
||||
updatedAt: number | null;
|
||||
purposes?: Record<string, boolean>;
|
||||
purposeCatalog?: Array<{
|
||||
id: string;
|
||||
label: string;
|
||||
presetId: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type AssetGatewayConfig = {
|
||||
|
||||
Reference in New Issue
Block a user