feat(组件): 模型选择器支持 Gemini 图片模型
- 新增 Gemini 图片模型卡片配置 - 添加 gemini 模型类型检测逻辑 - 实现 Gemini 模型选择和高亮显示 - 添加模型类型切换提示信息
This commit is contained in:
parent
81e437d0b4
commit
6a70b236b6
@ -48,8 +48,18 @@ const CODEX_MODEL_CARDS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Gemini 图片模型卡片配置
|
||||||
|
const GEMINI_MODEL_CARDS = [
|
||||||
|
{
|
||||||
|
id: 'gemini-3-pro-image-preview',
|
||||||
|
name: 'Gemini 图片',
|
||||||
|
description: '文生图',
|
||||||
|
modelIdPattern: 'gemini',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
// 模型类型
|
// 模型类型
|
||||||
type ModelType = 'claude' | 'codex';
|
type ModelType = 'claude' | 'codex' | 'gemini';
|
||||||
|
|
||||||
interface ModelCardSelectorProps {
|
interface ModelCardSelectorProps {
|
||||||
value: string;
|
value: string;
|
||||||
@ -73,6 +83,9 @@ export function ModelCardSelector({
|
|||||||
if (modelId.startsWith('gpt-') && modelId.includes('codex')) {
|
if (modelId.startsWith('gpt-') && modelId.includes('codex')) {
|
||||||
return 'codex';
|
return 'codex';
|
||||||
}
|
}
|
||||||
|
if (modelId.includes('gemini') || modelId.includes('imagen')) {
|
||||||
|
return 'gemini';
|
||||||
|
}
|
||||||
return 'claude';
|
return 'claude';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,9 +120,22 @@ export function ModelCardSelector({
|
|||||||
return model?.modelId || cardId;
|
return model?.modelId || cardId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 根据当前选中的模型ID判断选中的卡片(Gemini)
|
||||||
|
const getSelectedGeminiCard = (modelId: string): string | null => {
|
||||||
|
const matchedCard = GEMINI_MODEL_CARDS.find((card) => modelId.includes(card.modelIdPattern));
|
||||||
|
return matchedCard?.id || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据卡片类型找到对应的实际模型ID(Gemini)
|
||||||
|
const findGeminiModelIdByCard = (cardId: string): string => {
|
||||||
|
const model = models.find((m) => m.modelId === cardId);
|
||||||
|
return model?.modelId || cardId;
|
||||||
|
};
|
||||||
|
|
||||||
const currentModelType = getModelType(value);
|
const currentModelType = getModelType(value);
|
||||||
const selectedClaudeCard = getSelectedClaudeCard(value);
|
const selectedClaudeCard = getSelectedClaudeCard(value);
|
||||||
const selectedCodexCard = getSelectedCodexCard(value);
|
const selectedCodexCard = getSelectedCodexCard(value);
|
||||||
|
const selectedGeminiCard = getSelectedGeminiCard(value);
|
||||||
|
|
||||||
// 处理模型选择
|
// 处理模型选择
|
||||||
const handleModelSelect = (modelId: string, modelType: ModelType) => {
|
const handleModelSelect = (modelId: string, modelType: ModelType) => {
|
||||||
@ -137,6 +163,9 @@ export function ModelCardSelector({
|
|||||||
// 检查是否有 Codex 模型可用
|
// 检查是否有 Codex 模型可用
|
||||||
const hasCodexModels = models.some(m => m.modelType === 'codex' || (m.modelId.startsWith('gpt-') && m.modelId.includes('codex')));
|
const hasCodexModels = models.some(m => m.modelType === 'codex' || (m.modelId.startsWith('gpt-') && m.modelId.includes('codex')));
|
||||||
|
|
||||||
|
// 检查是否有 Gemini 模型可用
|
||||||
|
const hasGeminiModels = models.some(m => m.modelType === 'gemini' || m.modelId.includes('gemini') || m.modelId.includes('imagen'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* 模型切换提示 */}
|
{/* 模型切换提示 */}
|
||||||
@ -148,6 +177,8 @@ export function ModelCardSelector({
|
|||||||
<p className="text-amber-600 dark:text-amber-300 mt-1">
|
<p className="text-amber-600 dark:text-amber-300 mt-1">
|
||||||
{currentModelType === 'codex'
|
{currentModelType === 'codex'
|
||||||
? 'Codex 模型不支持思考模式(Thinking),但支持工具调用。'
|
? 'Codex 模型不支持思考模式(Thinking),但支持工具调用。'
|
||||||
|
: currentModelType === 'gemini'
|
||||||
|
? 'Gemini 图片模型专注于图片生成,不支持思考模式和工具调用。'
|
||||||
: 'Claude 模型支持思考模式和工具调用。'}
|
: 'Claude 模型支持思考模式和工具调用。'}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -271,6 +302,70 @@ export function ModelCardSelector({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Gemini 图片模型组 */}
|
||||||
|
{hasGeminiModels && (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-[var(--color-text-tertiary)] mb-3 flex items-center gap-2">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-blue-500"></span>
|
||||||
|
Gemini 图片模型
|
||||||
|
<span className="text-[10px] px-1.5 py-0.5 rounded bg-blue-100 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400">
|
||||||
|
Google
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
{GEMINI_MODEL_CARDS.map((card) => {
|
||||||
|
const isSelected = selectedGeminiCard === card.id;
|
||||||
|
// 检查该模型是否在可用模型列表中
|
||||||
|
const isAvailable = models.some(m => m.modelId === card.id || m.modelId.includes(card.modelIdPattern));
|
||||||
|
|
||||||
|
if (!isAvailable) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={card.id}
|
||||||
|
onClick={() => {
|
||||||
|
const newModelId = findGeminiModelIdByCard(card.id);
|
||||||
|
handleModelSelect(newModelId, 'gemini');
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
className={cn(
|
||||||
|
'flex flex-col items-center justify-center',
|
||||||
|
'w-[120px] h-[72px] rounded-md',
|
||||||
|
'border-2 transition-all duration-200',
|
||||||
|
'focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500',
|
||||||
|
isSelected
|
||||||
|
? 'bg-blue-50 dark:bg-blue-900/20 border-blue-500'
|
||||||
|
: 'bg-[var(--color-bg-tertiary)] border-transparent hover:border-blue-300 dark:hover:border-blue-700',
|
||||||
|
disabled && 'opacity-50 cursor-not-allowed'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'text-sm font-semibold',
|
||||||
|
isSelected
|
||||||
|
? 'text-blue-600 dark:text-blue-400'
|
||||||
|
: 'text-[var(--color-text-primary)]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{card.name}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'text-xs mt-1',
|
||||||
|
isSelected
|
||||||
|
? 'text-blue-500 dark:text-blue-400'
|
||||||
|
: 'text-[var(--color-text-tertiary)]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{card.description}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user