agent-Specialization/static/src/stores/model.ts

128 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineStore } from 'pinia';
export type ModelKey = string;
export interface ModelOption {
key: ModelKey;
label: string;
description: string;
visible?: boolean;
multimodal?: string;
supportsImage?: boolean;
supportsVideo?: boolean;
contextWindow?: number | null;
maxOutputTokens?: number | null;
fastOnly: boolean;
supportsThinking: boolean;
deepOnly?: boolean;
}
interface ModelState {
currentModelKey: ModelKey;
models: ModelOption[];
}
export const useModelStore = defineStore('model', {
state: (): ModelState => ({
currentModelKey: 'kimi-k2.5',
models: [
{
key: 'kimi-k2.5',
label: 'Kimi-k2.5',
description: '新版 Kimi支持图文 & 思考开关',
multimodal: 'image,video',
supportsImage: true,
supportsVideo: true,
fastOnly: false,
supportsThinking: true
},
{
key: 'kimi',
label: 'Kimi-k2',
description: '综合能力较强',
fastOnly: false,
supportsThinking: true
},
{
key: 'deepseek',
label: 'Deepseek-V3.2',
description: '数学能力较强',
fastOnly: false,
supportsThinking: true
},
{
key: 'qwen3-vl-plus',
label: 'Qwen3.5',
description: '图文视频多模态 + 深度思考',
multimodal: 'image,video',
supportsImage: true,
supportsVideo: true,
fastOnly: false,
supportsThinking: true
},
{
key: 'minimax-m2.5',
label: 'MiniMax-M2.5',
description: '仅深度思考,超长上下文',
fastOnly: false,
supportsThinking: true,
deepOnly: true
}
]
}),
getters: {
currentModel(state): ModelOption {
return state.models.find((m) => m.key === state.currentModelKey) || state.models[0];
}
},
actions: {
setModels(models: ModelOption[]) {
if (!Array.isArray(models) || !models.length) return;
this.models = models;
const exists = this.models.some((m) => m.key === this.currentModelKey);
if (!exists && this.models[0]) {
this.currentModelKey = this.models[0].key;
}
},
setModel(key: ModelKey) {
if (this.currentModelKey === key) return;
const exists = this.models.some((m) => m.key === key);
if (exists) {
this.currentModelKey = key;
}
},
async fetchModels() {
const resp = await fetch('/api/v1/models', { cache: 'no-store' });
const data = await resp.json();
if (!resp.ok || !data?.success || !Array.isArray(data.items)) {
throw new Error(data?.error || '加载模型列表失败');
}
const mapped: ModelOption[] = data.items
.filter((item: any) => item && item.model_key)
.map((item: any) => {
const multimodal = String(item.multimodal || 'none');
const supportsImage = multimodal === 'image' || multimodal === 'image,video';
const supportsVideo = multimodal === 'video' || multimodal === 'image,video';
return {
key: String(item.model_key),
label: String(item.name || item.model_key),
description: String(item.description || ''),
visible: item.visible !== false,
multimodal,
supportsImage,
supportsVideo,
contextWindow: typeof item.context_window === 'number' ? item.context_window : null,
maxOutputTokens:
typeof item.max_output_tokens === 'number' ? item.max_output_tokens : null,
fastOnly: !!item.fast_only,
supportsThinking: !!item.supports_thinking,
deepOnly: !!item.deep_only
};
});
if (mapped.length) {
this.setModels(mapped);
}
}
}
});