diff --git a/app/components/chat.tsx b/app/components/chat.tsx index b983799d1..812a6ff62 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -688,10 +688,48 @@ export function ChatActions(props: { {showProviderSelector && ( ({ - title: name, - value: value, - }))} + items={Object.entries(ServiceProvider) + .filter(([_, value]) => { + const accessStore = useAccessStore.getState(); + switch (value) { + case ServiceProvider.OpenAI: + return true; // 始终保留OpenAI选项,即使没有配置API密钥 + case ServiceProvider.Azure: + return accessStore.isValidAzure(); + case ServiceProvider.Google: + return accessStore.isValidGoogle(); + case ServiceProvider.Anthropic: + return accessStore.isValidAnthropic(); + case ServiceProvider.Baidu: + return accessStore.isValidBaidu(); + case ServiceProvider.ByteDance: + return accessStore.isValidByteDance(); + case ServiceProvider.Alibaba: + return accessStore.isValidAlibaba(); + case ServiceProvider.Tencent: + return accessStore.isValidTencent(); + case ServiceProvider.Moonshot: + return accessStore.isValidMoonshot(); + case ServiceProvider.Iflytek: + return accessStore.isValidIflytek(); + case ServiceProvider.DeepSeek: + return accessStore.isValidDeepSeek(); + case ServiceProvider.XAI: + return accessStore.isValidXAI(); + case ServiceProvider.ChatGLM: + return accessStore.isValidChatGLM(); + case ServiceProvider.SiliconFlow: + return accessStore.isValidSiliconFlow(); + case ServiceProvider.Stability: + return true; // 假设不需要验证 + default: + return false; + } + }) + .map(([name, value]) => ({ + title: name, + value: value, + }))} onClose={() => setShowProviderSelector(false)} onSelection={(s) => { if (s.length === 0) return; @@ -717,7 +755,11 @@ export function ChatActions(props: { m.provider?.providerName === currentProviderName) + .filter( + (m) => + m.available && + m.provider?.providerName === currentProviderName, + ) .map((m) => ({ title: m.displayName, value: `${m.name}@${m?.provider?.providerName}`, diff --git a/app/components/model-config.tsx b/app/components/model-config.tsx index 8b089e4de..51ad480a5 100644 --- a/app/components/model-config.tsx +++ b/app/components/model-config.tsx @@ -1,5 +1,6 @@ import { ServiceProvider } from "@/app/constant"; import { ModalConfigValidator, ModelConfig } from "../store"; +import { useAccessStore } from "../store"; import Locale from "../locales"; import { InputRange } from "./input-range"; @@ -13,6 +14,46 @@ export function ModelConfigList(props: { updateConfig: (updater: (config: ModelConfig) => void) => void; }) { const allModels = useAllModels(); + const accessStore = useAccessStore(); + + // 过滤未配置API密钥的服务提供商 + const validProviders = Object.entries(ServiceProvider).filter(([_, v]) => { + switch (v) { + case ServiceProvider.OpenAI: + return true; // 始终保留OpenAI选项,即使没有配置API密钥 + case ServiceProvider.Azure: + return accessStore.isValidAzure(); + case ServiceProvider.Google: + return accessStore.isValidGoogle(); + case ServiceProvider.Anthropic: + return accessStore.isValidAnthropic(); + case ServiceProvider.Baidu: + return accessStore.isValidBaidu(); + case ServiceProvider.ByteDance: + return accessStore.isValidByteDance(); + case ServiceProvider.Alibaba: + return accessStore.isValidAlibaba(); + case ServiceProvider.Tencent: + return accessStore.isValidTencent(); + case ServiceProvider.Moonshot: + return accessStore.isValidMoonshot(); + case ServiceProvider.Iflytek: + return accessStore.isValidIflytek(); + case ServiceProvider.DeepSeek: + return accessStore.isValidDeepSeek(); + case ServiceProvider.XAI: + return accessStore.isValidXAI(); + case ServiceProvider.ChatGLM: + return accessStore.isValidChatGLM(); + case ServiceProvider.SiliconFlow: + return accessStore.isValidSiliconFlow(); + case ServiceProvider.Stability: + return true; // 假设不需要验证或其他处理 + default: + return false; + } + }); + const filteredModels = allModels.filter( (v) => v.available && @@ -42,7 +83,7 @@ export function ModelConfigList(props: { }); }} > - {Object.entries(ServiceProvider).map(([k, v]) => ( + {validProviders.map(([k, v]) => ( @@ -288,7 +329,7 @@ export function ModelConfigList(props: { }); }} > - {Object.entries(ServiceProvider).map(([k, v]) => ( + {validProviders.map(([k, v]) => ( diff --git a/app/components/realtime-chat/realtime-config.tsx b/app/components/realtime-chat/realtime-config.tsx index 08809afda..2db0481be 100644 --- a/app/components/realtime-chat/realtime-config.tsx +++ b/app/components/realtime-chat/realtime-config.tsx @@ -6,8 +6,10 @@ import { ListItem, Select, PasswordInput } from "@/app/components/ui-lib"; import { InputRange } from "@/app/components/input-range"; import { Voice } from "rt-client"; import { ServiceProvider } from "@/app/constant"; +import { useAccessStore } from "@/app/store"; -const providers = [ServiceProvider.OpenAI, ServiceProvider.Azure]; +// 只支持OpenAI和Azure +const allProviders = [ServiceProvider.OpenAI, ServiceProvider.Azure]; const models = ["gpt-4o-realtime-preview-2024-10-01"]; @@ -17,6 +19,20 @@ export function RealtimeConfigList(props: { realtimeConfig: RealtimeConfig; updateConfig: (updater: (config: RealtimeConfig) => void) => void; }) { + const accessStore = useAccessStore(); + + // 根据API密钥配置过滤服务提供商 + const providers = allProviders.filter((provider) => { + switch (provider) { + case ServiceProvider.OpenAI: + return true; // 始终保留OpenAI选项,即使没有配置API密钥 + case ServiceProvider.Azure: + return accessStore.isValidAzure(); + default: + return false; + } + }); + const azureConfigComponent = props.realtimeConfig.provider === ServiceProvider.Azure && ( <>