diff --git a/web/src/components/table/model-pricing/modal/ModelDetailSideSheet.jsx b/web/src/components/table/model-pricing/modal/ModelDetailSideSheet.jsx index 6542137..c23e9f8 100644 --- a/web/src/components/table/model-pricing/modal/ModelDetailSideSheet.jsx +++ b/web/src/components/table/model-pricing/modal/ModelDetailSideSheet.jsx @@ -26,6 +26,7 @@ import ModelHeader from './components/ModelHeader'; import ModelBasicInfo from './components/ModelBasicInfo'; import ModelEndpoints from './components/ModelEndpoints'; import ModelPricingTable from './components/ModelPricingTable'; +import ModelCodeSnippet from './components/ModelCodeSnippet'; const { Text } = Typography; @@ -99,6 +100,7 @@ const ModelDetailSideSheet = ({ autoGroups={autoGroups} t={t} /> + )} diff --git a/web/src/components/table/model-pricing/modal/components/ModelCodeSnippet.jsx b/web/src/components/table/model-pricing/modal/components/ModelCodeSnippet.jsx new file mode 100644 index 0000000..cad1549 --- /dev/null +++ b/web/src/components/table/model-pricing/modal/components/ModelCodeSnippet.jsx @@ -0,0 +1,232 @@ +/* +Copyright (C) 2025 QuantumNous + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . + +For commercial licensing, please contact support@quantumnous.com +*/ + +import React, { useState, useMemo, useContext } from 'react'; +import { + Card, + Avatar, + Typography, + RadioGroup, + Radio, + TextArea, + Button, +} from '@douyinfe/semi-ui'; +import { IconCode } from '@douyinfe/semi-icons'; +import { copy, showSuccess, showInfo } from '../../../../../helpers'; +import { StatusContext } from '../../../../../context/Status'; + +const { Text } = Typography; + +const LANG_OPTIONS = [ + { value: 'python', label: 'Python' }, + { value: 'java', label: 'Java' }, + { value: 'go', label: 'Go' }, + { value: 'shell', label: 'Shell' }, +]; + +// 四种语言的调用示例代码模板,使用 __MODEL_NAME__ 与 __BASE_URL__ 作为占位符 +const getDefaultCodeByLang = () => ({ + python: ` +from openai import OpenAI + +client = OpenAI( + api_key="", + base_url="__BASE_URL__" +) + +response = client.chat.completions.create( + model="__MODEL_NAME__", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Hello, how are you?"} + ], + max_tokens=128000, + temperature=0.7 +) + +print(response.choices[0].message.content) + `, + java: ` +import com.openai.OpenAI; +import com.openai.models.*; + +OpenAI client = new OpenAI("", "__BASE_URL__"); + +ChatCompletionRequest request = ChatCompletionRequest.builder() + .model("__MODEL_NAME__") + .messages(Arrays.asList( + new ChatMessage("system", "You are a helpful assistant."), + new ChatMessage("user", "Hello, how are you?") + )) + .maxTokens(1000) + .temperature(0.7) + .build(); + +ChatCompletion response = client.chatCompletions().create(request); +System.out.println(response.getChoices().get(0).getMessage().getContent()); + `, + go: ` +package main + +import ( + "context" + "fmt" + "github.com/openai/openai-go" +) + +func main() { + client := openai.NewClient("", "__BASE_URL__") + + messages := []openai.ChatMessage{ + {Role: "system", Content: "You are a helpful assistant."}, + {Role: "user", Content: "Hello, how are you?"}, + } + + response, err := client.ChatCompletions.Create(context.Background(), openai.ChatCompletionRequest{ + Model: "__MODEL_NAME__", + Messages: messages, + MaxTokens: 128000, + Temperature: 0.7, + }) + + if err != nil { + panic(err) + } + + fmt.Println(response.Choices[0].Message.Content) +} + `, + shell: ` +#!/bin/bash + +API_KEY="" +MODEL_ID="__MODEL_NAME__" +BASE_URL="__BASE_URL__" + +curl -X POST "$BASE_URL/v1/chat/completions" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $API_KEY" \ + -d '{ + "model": "'$MODEL_ID'", + "messages": [ + { + "role": "system", + "content": "You are a helpful assistant." + }, + { + "role": "user", + "content": "Hello, how are you?" + } + ], + "max_tokens": 128000, + "temperature": 0.7 + }' + `, +}); + +const PLACEHOLDER_MODEL = '__MODEL_NAME__'; +const PLACEHOLDER_BASE_URL = '__BASE_URL__'; + +const ModelCodeSnippet = ({ modelData, t }) => { + const [statusState] = useContext(StatusContext); + const serverAddress = + statusState?.status?.server_address || (typeof window !== 'undefined' ? window.location.origin : ''); + const [lang, setLang] = useState('python'); + const codeByLang = useMemo(() => { + const templates = getDefaultCodeByLang(); + const modelName = modelData?.model_name || ''; + const baseUrl = serverAddress || ''; + return Object.fromEntries( + Object.entries(templates).map(([key, code]) => { + let result = code.replaceAll(PLACEHOLDER_BASE_URL, baseUrl); + result = result.replaceAll(PLACEHOLDER_MODEL, modelName); + return [key, result]; + }), + ); + }, [modelData?.model_name, serverAddress]); + + const currentCode = codeByLang[lang] || ''; + + const handleCopy = async () => { + if (!currentCode || currentCode.trim() === '') { + showInfo(t('当前语言暂无示例代码')); + return; + } + const ok = await copy(currentCode); + if (ok) { + showSuccess(t('已复制到剪切板')); + } + }; + + return ( + +
+ + + +
+ {t('调用示例')} +
+ {t('使用 OpenAI 兼容接口调用该模型的示例代码')} +
+
+
+ +
+ + {t('选择语言')} + + setLang(e.target.value)} + direction='horizontal' + > + {LANG_OPTIONS.map((opt) => ( + + {opt.label} + + ))} + +
+ +
+