diff --git a/services/ai.py b/services/ai.py index debd982..86915f3 100644 --- a/services/ai.py +++ b/services/ai.py @@ -2,13 +2,14 @@ import httpx from typing import List from services.config import ConfigCenter + async def describe_image_base64(base64_image: str, detail: str = "high") -> str: """ 传入base64图片和文本提示,返回图片描述文本。 """ - OAI_API_URL = await ConfigCenter.get("AI_API_URL", "https://api.siliconflow.cn/v1/chat/completions") - VISION_MODEL = await ConfigCenter.get("AI_VISION_MODEL", "Qwen/Qwen2.5-VL-32B-Instruct") - API_KEY = await ConfigCenter.get("AI_API_KEY", "") + OAI_API_URL = await ConfigCenter.get("AI_VISION_API_URL") + VISION_MODEL = await ConfigCenter.get("AI_VISION_MODEL") + API_KEY = await ConfigCenter.get("AI_VISION_API_KEY") payload = { "model": VISION_MODEL, "messages": [ @@ -42,13 +43,14 @@ async def describe_image_base64(base64_image: str, detail: str = "high") -> str: except Exception as e: return f"请求失败: {str(e)}" + async def get_text_embedding(text: str) -> List[float]: """ 传入文本,返回嵌入向量。 """ - OAI_API_URL = await ConfigCenter.get("AI_API_URL", "https://api.siliconflow.cn/v1/chat/completions") - EMBED_MODEL = await ConfigCenter.get("AI_EMBED_MODEL", "Qwen/Qwen3-Embedding-8B") - API_KEY = await ConfigCenter.get("AI_API_KEY", "") + OAI_API_URL = await ConfigCenter.get("AI_EMBED_API_URL") + EMBED_MODEL = await ConfigCenter.get("AI_EMBED_MODEL") + API_KEY = await ConfigCenter.get("AI_EMBED_API_KEY") payload = { "model": EMBED_MODEL, "input": text @@ -58,7 +60,11 @@ async def get_text_embedding(text: str) -> List[float]: "Content-Type": "application/json" } async with httpx.AsyncClient() as client: - resp = await client.post(OAI_API_URL.replace("chat/completions", "embeddings"), headers=headers, json=payload) + if OAI_API_URL.endswith("chat/completions"): + url = OAI_API_URL.replace("chat/completions", "embeddings") + else: + url = OAI_API_URL + resp = await client.post(url, headers=headers, json=payload) resp.raise_for_status() result = resp.json() return result["data"][0]["embedding"] diff --git a/web/src/pages/SystemSettingsPage/SystemSettingsPage.tsx b/web/src/pages/SystemSettingsPage/SystemSettingsPage.tsx index e1842a5..ee82332 100644 --- a/web/src/pages/SystemSettingsPage/SystemSettingsPage.tsx +++ b/web/src/pages/SystemSettingsPage/SystemSettingsPage.tsx @@ -1,4 +1,4 @@ -import { Form, Input, Button, message, Tabs, Space } from 'antd'; +import { Form, Input, Button, message, Tabs, Space, Card } from 'antd'; import { useEffect, useState } from 'react'; import PageCard from '../../components/PageCard'; import { getAllConfig, setConfig } from '../../api/config'; @@ -11,16 +11,23 @@ const APP_CONFIG_KEYS = [ { key: 'SERVER_URL', label: '服务端URL', default: API_BASE_URL }, ]; -const AI_CONFIG_KEYS = [ - { key: 'AI_API_URL', label: 'AI API地址' }, - { key: 'AI_VISION_MODEL', label: '视觉模型' }, - { key: 'AI_EMBED_MODEL', label: '嵌入模型' }, - { key: 'AI_API_KEY', label: 'API Key' }, +const VISION_CONFIG_KEYS = [ + { key: 'AI_VISION_API_URL', label: '视觉模型 API 地址' }, + { key: 'AI_VISION_MODEL', label: '视觉模型', default: 'Qwen/Qwen2.5-VL-32B-Instruct' }, + { key: 'AI_VISION_API_KEY', label: '视觉模型 API Key' }, ]; +const EMBED_CONFIG_KEYS = [ + { key: 'AI_EMBED_API_URL', label: '嵌入模型 API 地址' }, + { key: 'AI_EMBED_MODEL', label: '嵌入模型', default: 'Qwen/Qwen3-Embedding-8B' }, + { key: 'AI_EMBED_API_KEY', label: '嵌入模型 API Key' }, +]; + +const ALL_AI_KEYS = [...VISION_CONFIG_KEYS, ...EMBED_CONFIG_KEYS]; + export default function SystemSettingsPage() { const [loading, setLoading] = useState(false); - const [config, setConfigState] = useState | null>(null); + const [config, setConfigState] = useState | null>(null); const [activeTab, setActiveTab] = useState('app'); useEffect(() => { @@ -41,14 +48,13 @@ export default function SystemSettingsPage() { setLoading(false); }; - // 加载中时不渲染表单 if (!config) { return
加载中...
; } return ( {APP_CONFIG_KEYS.map(({ key, label }) => ( @@ -100,18 +106,27 @@ export default function SystemSettingsPage() {
[key, config[key] ?? ''])), + ...Object.fromEntries(ALL_AI_KEYS.map(({ key, default: def }) => [key, config[key] ?? def ?? ''])), }} onFinish={handleSave} style={{ marginTop: 24 }} - key={JSON.stringify(config)} // 强制表单重置 + key={JSON.stringify(config)} > - {AI_CONFIG_KEYS.map(({ key, label }) => ( - - - - ))} - + + {VISION_CONFIG_KEYS.map(({ key, label }) => ( + + + + ))} + + + {EMBED_CONFIG_KEYS.map(({ key, label }) => ( + + + + ))} + +