/** * 本地模型列表组件 * * 显示用户的本地模型列表,仅支持查看和使用 * 需求: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7 */ import React, { useState, useEffect } from 'react'; import { Server, Loader2, AlertCircle, X, Copy, CheckCircle2, Code } from 'lucide-react'; import { localModelApi, LocalModel } from '../services/localModelApi'; import { useToast } from '../contexts/NotificationContext'; import { copyToClipboard } from '../utils/clipboard'; interface LocalModelListProps { onUseModel?: (modelId: string) => void; } const LocalModelList: React.FC = ({ onUseModel }) => { const { showToast } = useToast(); const [models, setModels] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [apiExampleModel, setApiExampleModel] = useState(null); const [copied, setCopied] = useState(null); const loadModels = async () => { setLoading(true); setError(null); try { const data = await localModelApi.getLocalModels(); setModels(data); } catch (err: any) { setError(err.message || '加载失败'); } finally { setLoading(false); } }; useEffect(() => { loadModels(); }, []); const handleShowApiExample = (model: LocalModel) => { setApiExampleModel(model); }; const handleCopy = async (text: string, key: string) => { await copyToClipboard(text); setCopied(key); setTimeout(() => setCopied(null), 2000); }; const getApiBaseUrl = () => { const baseUrl = import.meta.env.VITE_API_BASE_URL || window.location.origin; return `${baseUrl}/api/v1`; }; const getModelId = (model: LocalModel) => `local:${model.id}`; const generateCurlExample = (model: LocalModel) => { const modelId = getModelId(model); if (model.category === 4) { // 文生图 return `curl ${getApiBaseUrl()}/images/generations \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "prompt": "a beautiful sunset over the ocean", "n": 1, "size": "1024x1024" }'`; } else if (model.category === 6) { // 图生图 return `curl ${getApiBaseUrl()}/images/edits \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -F "model=${modelId}" \\ -F "prompt=make it look like a painting" \\ -F "image=@/path/to/your/image.png"`; } else if (model.category === 2) { // TTS return `curl ${getApiBaseUrl()}/audio/speech \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "input": "你好,世界", "voice": "alloy" }' --output speech.mp3`; } else if (model.category === 3) { // STT return `curl ${getApiBaseUrl()}/audio/transcriptions \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -F "model=${modelId}" \\ -F "file=@/path/to/audio.mp3"`; } else if (model.category === 5) { // 视频生成 return `curl ${getApiBaseUrl()}/videos/generations \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "prompt": "a beautiful sunset timelapse", "size": "720P" }'`; } else if (model.category === 7) { // 向量嵌入 return `curl ${getApiBaseUrl()}/embeddings \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "input": "Hello, this is a test." }'`; } else if (model.category === 8) { // 重排序 return `curl ${getApiBaseUrl()}/rerank \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "query": "什么是机器学习?", "documents": [ "机器学习是人工智能的一个分支。", "深度学习使用神经网络。", "Python是一种编程语言。" ], "top_n": 2 }'`; } else { // LLM / 多模态 return `curl ${getApiBaseUrl()}/chat/completions \\ -H "Content-Type: application/json" \\ -H "Authorization: Bearer YOUR_API_KEY" \\ -d '{ "model": "${modelId}", "messages": [ {"role": "user", "content": "你好"} ] }'`; } }; const generatePythonExample = (model: LocalModel) => { const modelId = getModelId(model); if (model.category === 4) { return `from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="${getApiBaseUrl()}" ) response = client.images.generate( model="${modelId}", prompt="a beautiful sunset over the ocean", n=1, size="1024x1024" ) print(response.data[0].url)`; } else if (model.category === 6) { return `from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="${getApiBaseUrl()}" ) with open("/path/to/your/image.png", "rb") as f: response = client.images.edit( model="${modelId}", image=f, prompt="make it look like a painting" ) print(response.data[0].url)`; } else if (model.category === 2) { return `from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="${getApiBaseUrl()}" ) response = client.audio.speech.create( model="${modelId}", voice="alloy", input="你好,世界" ) response.stream_to_file("speech.mp3")`; } else if (model.category === 3) { return `from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="${getApiBaseUrl()}" ) with open("/path/to/audio.mp3", "rb") as f: transcript = client.audio.transcriptions.create( model="${modelId}", file=f ) print(transcript.text)`; } else if (model.category === 5) { return `import requests response = requests.post( "${getApiBaseUrl()}/videos/generations", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, json={ "model": "${modelId}", "prompt": "a beautiful sunset timelapse", "size": "720P" } ) print(response.json()["data"][0]["url"])`; } else if (model.category === 7) { return `import requests response = requests.post( "${getApiBaseUrl()}/embeddings", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, json={ "model": "${modelId}", "input": "Hello, this is a test." } ) embeddings = response.json()["data"] print(f"向量维度: {len(embeddings[0]['embedding'])}")`; } else if (model.category === 8) { return `import requests response = requests.post( "${getApiBaseUrl()}/rerank", headers={ "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" }, json={ "model": "${modelId}", "query": "什么是机器学习?", "documents": [ "机器学习是人工智能的一个分支。", "深度学习使用神经网络。", "Python是一种编程语言。" ], "top_n": 2 } ) result = response.json() for item in result["data"]: print(f"分数: {item['relevance_score']:.4f} - {item['document']}")`; } else { return `from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="${getApiBaseUrl()}" ) response = client.chat.completions.create( model="${modelId}", messages=[ {"role": "user", "content": "你好"} ] ) print(response.choices[0].message.content)`; } }; const generateJsExample = (model: LocalModel) => { const modelId = getModelId(model); if (model.category === 4) { return `const response = await fetch("${getApiBaseUrl()}/images/generations", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }, body: JSON.stringify({ model: "${modelId}", prompt: "a beautiful sunset over the ocean", n: 1, size: "1024x1024" }) }); const data = await response.json(); console.log(data.data[0].url);`; } else if (model.category === 6) { return `const formData = new FormData(); formData.append("model", "${modelId}"); formData.append("prompt", "make it look like a painting"); formData.append("image", imageFile); // File object const response = await fetch("${getApiBaseUrl()}/images/edits", { method: "POST", headers: { "Authorization": "Bearer YOUR_API_KEY" }, body: formData }); const data = await response.json(); console.log(data.data[0].url);`; } else if (model.category === 5) { return `const response = await fetch("${getApiBaseUrl()}/videos/generations", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }, body: JSON.stringify({ model: "${modelId}", prompt: "a beautiful sunset timelapse", size: "720P" }) }); const data = await response.json(); console.log(data.data[0].url);`; } else if (model.category === 7) { return `const response = await fetch("${getApiBaseUrl()}/embeddings", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }, body: JSON.stringify({ model: "${modelId}", input: "Hello, this is a test." }) }); const data = await response.json(); console.log(\`向量维度: \${data.data[0].embedding.length}\`);`; } else if (model.category === 8) { return `const response = await fetch("${getApiBaseUrl()}/rerank", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }, body: JSON.stringify({ model: "${modelId}", query: "什么是机器学习?", documents: [ "机器学习是人工智能的一个分支。", "深度学习使用神经网络。", "Python是一种编程语言。" ], top_n: 2 }) }); const data = await response.json(); data.data.forEach(item => { console.log(\`分数: \${item.relevance_score.toFixed(4)} - \${item.document}\`); });`; } else { return `const response = await fetch("${getApiBaseUrl()}/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }, body: JSON.stringify({ model: "${modelId}", messages: [ { role: "user", content: "你好" } ] }) }); const data = await response.json(); console.log(data.choices[0].message.content);`; } }; if (loading) { return (
加载中...
); } if (error) { return (

{error}

); } return (
{/* 私域模型列表 */} {/* 模型列表 */} {models.length === 0 ? (

暂无私域模型

请联系管理员添加私域模型

) : (
{models.map((model) => (

{model.name}

私域模型 {model.supplier && ( {model.supplier} )}
模型ID: local:{model.id}
{model.supplier && (
调用格式: {model.supplier}/{model.name}
)}
{model.base_url}
{model.has_api_key ? '已配置API Key' : '无需认证'} {new Date(model.created_at).toLocaleDateString()}
{onUseModel && ( )}
))}
)} {/* API调用示例模态框 */} {apiExampleModel && (

API调用示例

模型: {apiExampleModel.name}

{/* 调用方式说明 */}

📌 模型调用方式

方式1 - 精确ID(推荐): local:{apiExampleModel.id}
{apiExampleModel.supplier && (
方式2 - 提供商/名称: {apiExampleModel.supplier}/{apiExampleModel.name}
)}
方式3 - 仅名称: {apiExampleModel.name} (如有同名模型,将使用最新创建的)
{/* 提示信息 */}

提示:请先在「开放平台」页面创建本地私钥(访问本地模型),然后将下方示例中的 YOUR_API_KEY 替换为您的实际API Key。

{/* cURL示例 */}

cURL

                  {generateCurlExample(apiExampleModel)}
                
{/* Python示例 */}

Python (OpenAI SDK)

                  {generatePythonExample(apiExampleModel)}
                
{/* JavaScript示例 */}

JavaScript (Fetch)

                  {generateJsExample(apiExampleModel)}
                

API端点: {getApiBaseUrl()}/{ apiExampleModel.category === 4 ? 'images/generations' : apiExampleModel.category === 6 ? 'images/edits' : apiExampleModel.category === 2 ? 'audio/speech' : apiExampleModel.category === 3 ? 'audio/transcriptions' : apiExampleModel.category === 5 ? 'videos/generations' : apiExampleModel.category === 7 ? 'embeddings' : apiExampleModel.category === 8 ? 'rerank' : 'chat/completions' }

)}
); }; export default LocalModelList;