1 line
7.5 KiB
JSON
1 line
7.5 KiB
JSON
{"repo": "andershsueh/rednotes-mate", "files": {"aionui/src/renderer/pages/settings/components/EditModeModal.tsx": {"2c793177d791de7d36a4f3fbdd7064afe67f334e": {"t": 1785595471.7158642, "n": 7132, "h": "6d8e7b1ccd7f1a52", "c": "import type { IProvider } from '@/common/storage';\nimport ModalHOC from '@/renderer/utils/ModalHOC';\nimport { Form, Input } from '@arco-design/web-react';\nimport React, { useEffect, useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport AionModal from '@/renderer/components/base/AionModal';\nimport { LinkCloud } from '@icon-park/react';\n\n// Provider Logo imports\nimport GeminiLogo from '@/renderer/assets/logos/gemini.svg';\nimport OpenAILogo from '@/renderer/assets/logos/openai.svg';\nimport AnthropicLogo from '@/renderer/assets/logos/anthropic.svg';\nimport DeepSeekLogo from '@/renderer/assets/logos/deepseek.svg';\nimport OpenRouterLogo from '@/renderer/assets/logos/openrouter.svg';\nimport SiliconFlowLogo from '@/renderer/assets/logos/siliconflow.svg';\nimport QwenLogo from '@/renderer/assets/logos/qwen.svg';\nimport KimiLogo from '@/renderer/assets/logos/kimi.svg';\nimport ZhipuLogo from '@/renderer/assets/logos/zhipu.svg';\nimport XaiLogo from '@/renderer/assets/logos/xai.svg';\nimport VolcengineLogo from '@/renderer/assets/logos/volcengine.svg';\nimport BaiduLogo from '@/renderer/assets/logos/baidu.svg';\nimport TencentLogo from '@/renderer/assets/logos/tencent.svg';\nimport LingyiLogo from '@/renderer/assets/logos/lingyiwanwu.svg';\nimport PoeLogo from '@/renderer/assets/logos/poe.svg';\nimport ModelScopeLogo from '@/renderer/assets/logos/modelscope.svg';\nimport InfiniAILogo from '@/renderer/assets/logos/infiniai.svg';\nimport CtyunLogo from '@/renderer/assets/logos/ctyun.svg';\nimport StepFunLogo from '@/renderer/assets/logos/stepfun.svg';\n\n/**\n * 供应商配置(包含名称、URL、Logo)\n * Provider config (includes name, URL, logo)\n */\nconst PROVIDER_CONFIGS = [\n { name: 'Gemini', url: '', logo: GeminiLogo, platform: 'gemini' },\n { name: 'Gemini (Vertex AI)', url: '', logo: GeminiLogo, platform: 'gemini-vertex-ai' },\n { name: 'OpenAI', url: 'https://api.openai.com/v1', logo: OpenAILogo },\n { name: 'Anthropic', url: 'https://api.anthropic.com/v1', logo: AnthropicLogo },\n { name: 'DeepSeek', url: 'https://api.deepseek.com', logo: DeepSeekLogo },\n { name: 'OpenRouter', url: 'https://openrouter.ai/api/v1', logo: OpenRouterLogo },\n { name: 'SiliconFlow', url: 'https://api.siliconflow.cn/v1', logo: SiliconFlowLogo },\n { name: 'Dashscope', url: 'https://dashscope.aliyuncs.com/compatible-mode/v1', logo: QwenLogo },\n { name: 'Moonshot', url: 'https://api.moonshot.cn/v1', logo: KimiLogo },\n { name: 'Zhipu', url: 'https://open.bigmodel.cn/api/paas/v4', logo: ZhipuLogo },\n { name: 'xAI', url: 'https://api.x.ai/v1', logo: XaiLogo },\n { name: 'Ark', url: 'https://ark.cn-beijing.volces.com/api/v3', logo: VolcengineLogo },\n { name: 'Qianfan', url: 'https://qianfan.baidubce.com/v2', logo: BaiduLogo },\n { name: 'Hunyuan', url: 'https://api.hunyuan.cloud.tencent.com/v1', logo: TencentLogo },\n { name: 'Lingyi', url: 'https://api.lingyiwanwu.com/v1', logo: LingyiLogo },\n { name: 'Poe', url: 'https://api.poe.com/v1', logo: PoeLogo },\n { name: 'ModelScope', url: 'https://api-inference.modelscope.cn/v1', logo: ModelScopeLogo },\n { name: 'InfiniAI', url: 'https://cloud.infini-ai.com/maas/v1', logo: InfiniAILogo },\n { name: 'Ctyun', url: 'https://wishub-x1.ctyun.cn/v1', logo: CtyunLogo },\n { name: 'StepFun', url: 'https://api.stepfun.com/v1', logo: StepFunLogo },\n];\n\n/**\n * 根据名称或 URL 获取供应商 Logo\n * Get provider logo by name or URL\n */\nconst getProviderLogo = (name?: string, baseUrl?: string, platform?: string): string | null => {\n if (!name && !baseUrl && !platform) return null;\n\n // 优先按 platform 匹配(Gemini 系列)\n if (platform) {\n const byPlatform = PROVIDER_CONFIGS.find((p) => p.platform === platform);\n if (byPlatform) return byPlatform.logo;\n }\n\n // 按名称精确匹配\n const byName = PROVIDER_CONFIGS.find((p) => p.name === name);\n if (byName) return byName.logo;\n\n // 按名称模糊匹配(忽略大小写)\n const byNameLower = PROVIDER_CONFIGS.find((p) => p.name.toLowerCase() === name?.toLowerCase());\n if (byNameLower) return byNameLower.logo;\n\n // 按 URL 匹配\n if (baseUrl) {\n const byUrl = PROVIDER_CONFIGS.find((p) => p.url && baseUrl.includes(p.url.replace('https://', '').split('/')[0]));\n if (byUrl) return byUrl.logo;\n }\n\n return null;\n};\n\n/**\n * 供应商 Logo 组件\n * Provider Logo Component\n */\nconst ProviderLogo: React.FC<{ logo: string | null; name: string; size?: number }> = ({ logo, name, size = 20 }) => {\n if (logo) {\n return <img src={logo} alt={name} className='object-contain shrink-0' style={{ width: size, height: size }} />;\n }\n return <LinkCloud theme='outline' size={size} className='text-t-secondary flex shrink-0' />;\n};\n\nconst EditModeModal = ModalHOC<{ data?: IProvider; onChange(data: IProvider): void }>(({ modalProps, modalCtrl, ...props }) => {\n const { t } = useTranslation();\n const { data } = props;\n const [form] = Form.useForm();\n\n // 获取供应商 Logo / Get provider logo\n const providerLogo = useMemo(() => {\n return getProviderLogo(data?.name, data?.baseUrl, data?.platform);\n }, [data?.name, data?.baseUrl, data?.platform]);\n\n useEffect(() => {\n if (data) {\n form.setFieldsValue(data);\n }\n }, [data]);\n\n return (\n <AionModal\n visible={modalProps.visible}\n onCancel={modalCtrl.close}\n header={{ title: t('settings.editModel'), showClose: true }}\n style={{ minHeight: '400px', maxHeight: '90vh', borderRadius: 16 }}\n contentStyle={{ background: 'var(--bg-1)', borderRadius: 16, padding: '20px 24px 16px', overflow: 'auto' }}\n onOk={async () => {\n const values = await form.validate();\n props.onChange({ ...(data || {}), ...values });\n modalCtrl.close();\n }}\n okText={t('common.save')}\n cancelText={t('common.cancel')}\n >\n <div className='py-20px'>\n <Form form={form} layout='vertical'>\n {/* 模型供应商名称(可编辑,带 Logo)/ Model Provider name (editable, with Logo) */}\n <Form.Item\n label={\n <div className='flex items-center gap-6px'>\n <ProviderLogo logo={providerLogo} name={data?.name || ''} size={16} />\n <span>{t('settings.modelProvider')}</span>\n </div>\n }\n field='name'\n required\n rules={[{ required: true }]}\n >\n <Input placeholder={t('settings.modelProvider')} />\n </Form.Item>\n\n {/* Base URL - 仅 Gemini 平台显示(用于自定义代理)/ Base URL - only for Gemini platform (for custom proxy) */}\n <Form.Item label={t('settings.baseUrl')} required={data?.platform !== 'gemini' && data?.platform !== 'gemini-vertex-ai'} rules={[{ required: data?.platform !== 'gemini' && data?.platform !== 'gemini-vertex-ai' }]} field={'baseUrl'} disabled>\n <Input></Input>\n </Form.Item>\n\n <Form.Item label={t('settings.apiKey')} required rules={[{ required: true }]} field={'apiKey'} extra={<div className='text-11px text-t-secondary mt-2'>💡 {t('settings.multiApiKeyEditTip')}</div>}>\n <Input.TextArea rows={4} placeholder={t('settings.apiKeyPlaceholder')} />\n </Form.Item>\n </Form>\n </div>\n </AionModal>\n );\n});\n\nexport default EditModeModal;\n"}}}} |