Files

1 line
7.5 KiB
JSON
Raw Permalink 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.
{"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"}}}}