chore: generic_prox ux

This commit is contained in:
jialin
2025-11-11 20:06:25 +08:00
parent 2d4ddea915
commit 7eedea8035
21 changed files with 274 additions and 83 deletions
-2
View File
@@ -83,6 +83,4 @@ const SegmentLine: React.FC<SegmentLineProps> = (props) => {
); );
}; };
SegmentLine.displayName = 'SegmentLine';
export default SegmentLine; export default SegmentLine;
+2
View File
@@ -6,3 +6,5 @@ export const DEFAULT_ENTER_PAGE = {
user: '/models/user-models', user: '/models/user-models',
login: '/login' login: '/login'
}; };
export const GPUSTACK_API_BASE_URL = 'v1';
+1 -1
View File
@@ -41,7 +41,7 @@ export default {
'clusters.create.addworker.tips': 'clusters.create.addworker.tips':
' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.', ' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.',
'clusters.create.addCommand.tips': 'clusters.create.addCommand.tips':
' On the Worker that needs to be added, run the following command to join it to the cluster.', 'On the Worker that needs to be added, run the following command to join it to the cluster.',
'clusters.create.register.tips': 'clusters.create.register.tips':
' On the Kubernetes cluster that needs to be added, run the following command to join its nodes to the cluster.', ' On the Kubernetes cluster that needs to be added, run the following command to join its nodes to the cluster.',
'cluster.create.checkEnv.tips': 'cluster.create.checkEnv.tips':
+5 -2
View File
@@ -246,7 +246,10 @@ export default {
'models.catalog.precision': 'Precision', 'models.catalog.precision': 'Precision',
'models.form.gpuPerReplica.tips': 'Enter a custom number', 'models.form.gpuPerReplica.tips': 'Enter a custom number',
'models.form.generic_proxy': 'Enable Generic Proxy', 'models.form.generic_proxy': 'Enable Generic Proxy',
'models.form.generic_proxy.tips': 'Enable Generic Proxy', 'models.form.generic_proxy.tips':
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
'models.form.generic_proxy.button': 'Generic Proxy', 'models.form.generic_proxy.button': 'Generic Proxy',
'models.accessControlModal.includeusers': 'Include Users' 'models.accessControlModal.includeusers': 'Include Users',
'models.table.genericProxy':
'Refer to the curl example below. The proxy forwards requests with the /model/proxy prefix to the corresponding model. You need to specify the model name either in the <span class="bold-text">X-GPUStack-Model</span> request header or in the "model" property of the JSON body.'
}; };
+2 -2
View File
@@ -41,7 +41,7 @@ export default {
'clusters.create.addworker.tips': 'clusters.create.addworker.tips':
' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.', ' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.',
'clusters.create.addCommand.tips': 'clusters.create.addCommand.tips':
' On the Worker that needs to be added, run the following command to join it to the cluster.', 'On the Worker that needs to be added, run the following command to join it to the cluster.',
'cluster.create.checkEnv.tips': 'cluster.create.checkEnv.tips':
'Use the following command to check if the environment is ready', 'Use the following command to check if the environment is ready',
'clusters.create.register.tips': 'clusters.create.register.tips':
@@ -101,7 +101,7 @@ export default {
// 37. 'clusters.create.noRegions': 'No regions available', // 37. 'clusters.create.noRegions': 'No regions available',
// 38. 'clusters.workerpool.batchSize.desc': 'Number of workers created simultaneously in the Worker pool', // 38. 'clusters.workerpool.batchSize.desc': 'Number of workers created simultaneously in the Worker pool',
// 39. 'clusters.create.addworker.tips': ' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.', // 39. 'clusters.create.addworker.tips': ' Please make sure the prerequisites for <a href={link} target="_blank">{label}</a> are met before executing the following command.',
// 40. 'clusters.create.addCommand.tips': ' On the Worker that needs to be added, run the following command to join it to the cluster.', // 40. 'clusters.create.addCommand.tips': 'On the Worker that needs to be added, run the following command to join it to the cluster.',
// 41. 'cluster.create.checkEnv.tips': 'Use the following command to check if the environment is ready', // 41. 'cluster.create.checkEnv.tips': 'Use the following command to check if the environment is ready',
// 42. 'clusters.create.register.tips': ' On the Kubernetes cluster that needs to be added, run the following command to join its nodes to the cluster.', // 42. 'clusters.create.register.tips': ' On the Kubernetes cluster that needs to be added, run the following command to join its nodes to the cluster.',
// 43. 'cluster.provider.comingsoon': 'Coming soon', // 43. 'cluster.provider.comingsoon': 'Coming soon',
+8 -4
View File
@@ -246,9 +246,12 @@ export default {
'models.catalog.precision': 'Precision', 'models.catalog.precision': 'Precision',
'models.form.gpuPerReplica.tips': 'Enter a custom number', 'models.form.gpuPerReplica.tips': 'Enter a custom number',
'models.form.generic_proxy': 'Enable Generic Proxy', 'models.form.generic_proxy': 'Enable Generic Proxy',
'models.form.generic_proxy.tips': 'Enable Generic Proxy', 'models.form.generic_proxy.tips':
'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
'models.form.generic_proxy.button': 'Generic Proxy', 'models.form.generic_proxy.button': 'Generic Proxy',
'models.accessControlModal.includeusers': 'Include Users' 'models.accessControlModal.includeusers': 'Include Users',
'models.table.genericProxy':
'Refer to the curl example below. The proxy forwards requests with the /model/proxy prefix to the corresponding model. You need to specify the model name either in the <span class="bold-text">X-GPUStack-Model</span> request header or in the "model" property of the JSON body.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
@@ -322,8 +325,9 @@ export default {
// 51. 'models.catalog.precision': 'Precision', // 51. 'models.catalog.precision': 'Precision',
// 52. 'models.form.gpuPerReplica.tips': 'Enter a custom number', // 52. 'models.form.gpuPerReplica.tips': 'Enter a custom number',
// 53. 'models.form.generic_proxy': 'Enable Generic Proxy', // 53. 'models.form.generic_proxy': 'Enable Generic Proxy',
// 54. 'models.form.generic_proxy.tips': 'Enable Generic Proxy', // 54. 'models.form.generic_proxy.tips': 'After enabling the generic proxy, you can access URI paths that do not follow the OpenAI API standard.',
// 55. 'models.form.generic_proxy.button': 'Generic Proxy', // 55. 'models.form.generic_proxy.button': 'Generic Proxy',
// 56. 'models.accessControlModal.includeusers': 'Include Users' // 56. 'models.accessControlModal.includeusers': 'Include Users',
// 57. 'models.table.genericProxy': 'Refer to the curl example below. The proxy forwards requests with the /model/proxy prefix to the corresponding model. You need to specify the model name either in the <span class="bold-text">X-GPUStack-Model</span> request header or in the "model" property of the JSON body.'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+4 -2
View File
@@ -249,9 +249,11 @@ export default {
'models.form.generic_proxy': 'Включить универсальный прокси', 'models.form.generic_proxy': 'Включить универсальный прокси',
'models.form.generic_proxy.tips': 'Включить универсальный прокси', 'models.form.generic_proxy.tips': 'Включить универсальный прокси',
'models.form.generic_proxy.button': 'Универсальный прокси', 'models.form.generic_proxy.button': 'Универсальный прокси',
'models.accessControlModal.includeusers': 'Включить пользователей' 'models.accessControlModal.includeusers': 'Включить пользователей',
'models.table.genericProxy':
'Refer to the curl example below. The proxy forwards requests with the /model/proxy prefix to the corresponding model. You need to specify the model name either in the <span class="bold-text">X-GPUStack-Model</span> request header or in the "model" property of the JSON body.'
}; };
// ========== To-Do: Translate Keys (Remove After Translation) ========== // ========== To-Do: Translate Keys (Remove After Translation) ==========
// 7. 'models.table.genericProxy': 'Refer to the curl example below. The proxy forwards requests with the /model/proxy prefix to the corresponding model. You need to specify the model name either in the <span class="bold-text">X-GPUStack-Model</span> request header or in the "model" property of the JSON body.'
// ========== End of To-Do List ========== // ========== End of To-Do List ==========
+5 -2
View File
@@ -233,7 +233,10 @@ export default {
'models.catalog.precision': '精度', 'models.catalog.precision': '精度',
'models.form.gpuPerReplica.tips': '输入自定义数值', 'models.form.gpuPerReplica.tips': '输入自定义数值',
'models.form.generic_proxy': '启用通用代理', 'models.form.generic_proxy': '启用通用代理',
'models.form.generic_proxy.tips': '启用通用代理', 'models.form.generic_proxy.tips':
'启用通用代理后可支持访问非 openai-API 标准的 URI 路径。',
'models.form.generic_proxy.button': '通用代理', 'models.form.generic_proxy.button': '通用代理',
'models.accessControlModal.includeusers': '显示用户' 'models.accessControlModal.includeusers': '显示用户',
'models.table.genericProxy':
'参考下面 curl 的方式,代理会将 /model/proxy 前缀的请求转发到对应的模型,需要在 <span class="bold-text">X-GPUStack-Model</span> 请求头或 JSON 请求体 "model" 属性设置模型名称。'
}; };
@@ -107,9 +107,6 @@ const AddWorkerStep: React.FC<AddModalProps> = ({
return ( return (
<Container> <Container>
<Title>
{intl.formatMessage({ id: 'clusters.create.supportedGpu' })}
</Title>
<SupportedGPUs <SupportedGPUs
onSelect={handleSelectProvider} onSelect={handleSelectProvider}
current={currentGPU} current={currentGPU}
@@ -58,6 +58,7 @@ import {
SourceType SourceType
} from '../config/types'; } from '../config/types';
import useFormInitialValues from '../hooks/use-form-initial-values'; import useFormInitialValues from '../hooks/use-form-initial-values';
import useGenericProxy from '../hooks/use-generic-proxy';
import useModelsColumns from '../hooks/use-models-columns'; import useModelsColumns from '../hooks/use-models-columns';
import AccessControlModal from './access-control-modal'; import AccessControlModal from './access-control-modal';
import APIAccessInfoModal from './api-access-info'; import APIAccessInfoModal from './api-access-info';
@@ -195,6 +196,8 @@ const Models: React.FC<ModelsProps> = ({
}); });
const modalRef = useRef<any>(null); const modalRef = useRef<any>(null);
const { GenericProxyModal, openProxyModal } = useGenericProxy();
useEffect(() => { useEffect(() => {
if (deleteIds?.length) { if (deleteIds?.length) {
rowSelection.removeSelectedKey(deleteIds); rowSelection.removeSelectedKey(deleteIds);
@@ -456,6 +459,10 @@ const Models: React.FC<ModelsProps> = ({
handleViewAPIInfo(row); handleViewAPIInfo(row);
} }
if (val === 'proxy') {
openProxyModal(row);
}
if (val === 'stop') { if (val === 'stop') {
modalRef.current?.show({ modalRef.current?.show({
content: 'models.instances', content: 'models.instances',
@@ -789,6 +796,7 @@ const Models: React.FC<ModelsProps> = ({
currentData={openAccessControlModal.currentData} currentData={openAccessControlModal.currentData}
action={openAccessControlModal.action} action={openAccessControlModal.action}
></AccessControlModal> ></AccessControlModal>
{GenericProxyModal}
</> </>
); );
}; };
+6 -5
View File
@@ -50,11 +50,11 @@ export const ActionList: ActionItem[] = [
key: 'chat', key: 'chat',
icon: icons.ExperimentOutlined icon: icons.ExperimentOutlined
}, },
// { {
// label: 'models.form.generic_proxy.button', label: 'models.form.generic_proxy.button',
// key: 'proxy', key: 'proxy',
// icon: icons.CaptivePortal icon: icons.CaptivePortal
// }, },
{ {
label: 'models.table.button.apiAccessInfo', label: 'models.table.button.apiAccessInfo',
key: 'api', key: 'api',
@@ -197,6 +197,7 @@ export const modelFileActions = [
export const categoryToPathMap: Record<string, string> = { export const categoryToPathMap: Record<string, string> = {
[modelCategoriesMap.llm]: '/playground/chat', [modelCategoriesMap.llm]: '/playground/chat',
[modelCategoriesMap.image]: '/playground/text-to-image',
[modelCategoriesMap.text_to_speech]: '/playground/speech?type=tts', [modelCategoriesMap.text_to_speech]: '/playground/speech?type=tts',
[modelCategoriesMap.speech_to_text]: '/playground/speech?type=stt', [modelCategoriesMap.speech_to_text]: '/playground/speech?type=stt',
[modelCategoriesMap.reranker]: '/playground/rerank', [modelCategoriesMap.reranker]: '/playground/rerank',
+1
View File
@@ -287,6 +287,7 @@ export const modelCategoriesMap = {
export const categoryOptions = [ export const categoryOptions = [
{ label: 'LLM', value: modelCategoriesMap.llm }, { label: 'LLM', value: modelCategoriesMap.llm },
{ label: 'Image', value: modelCategoriesMap.image },
{ label: 'Embedding', value: modelCategoriesMap.embedding }, { label: 'Embedding', value: modelCategoriesMap.embedding },
{ label: 'Reranker', value: modelCategoriesMap.reranker }, { label: 'Reranker', value: modelCategoriesMap.reranker },
{ label: 'Text-to-Speech', value: modelCategoriesMap.text_to_speech }, { label: 'Text-to-Speech', value: modelCategoriesMap.text_to_speech },
+2 -2
View File
@@ -133,7 +133,7 @@ const AdvanceConfig = () => {
})} })}
></CheckboxField> ></CheckboxField>
</Form.Item> </Form.Item>
{/* <Form.Item<FormData> <Form.Item<FormData>
name="generic_proxy" name="generic_proxy"
valuePropName="checked" valuePropName="checked"
style={{ marginBottom: 8 }} style={{ marginBottom: 8 }}
@@ -146,7 +146,7 @@ const AdvanceConfig = () => {
id: 'models.form.generic_proxy' id: 'models.form.generic_proxy'
})} })}
></CheckboxField> ></CheckboxField>
</Form.Item> */} </Form.Item>
</> </>
); );
}; };
+106 -28
View File
@@ -1,15 +1,62 @@
import ScrollerModal from '@/components/scroller-modal'; import ScrollerModal from '@/components/scroller-modal';
import CommandViewer from '@/pages/_components/command-viewer'; import CommandViewer from '@/pages/_components/command-viewer';
import { GPUSTACK_API, OPENAI_COMPATIBLE } from '@/pages/playground/apis'; import {
AUDIO_SPEECH_TO_TEXT_API,
AUDIO_TEXT_TO_SPEECH_API,
CHAT_API,
CREAT_IMAGE_API,
EMBEDDING_API,
MODEL_PROXY,
RERANKER_API
} from '@/pages/playground/apis';
import {
generateSpeechToTextCurlCode,
generateTextToSpeechCurlCode
} from '@/pages/playground/view-code/audio';
import { generateEmbeddingCurlCode } from '@/pages/playground/view-code/embedding';
import { generateImageCurlCode } from '@/pages/playground/view-code/image';
import { generateLLmCurlCode } from '@/pages/playground/view-code/llm';
import { generateRerankCurlCode } from '@/pages/playground/view-code/rerank';
import { formatCurlArgs } from '@/pages/playground/view-code/utils'; import { formatCurlArgs } from '@/pages/playground/view-code/utils';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { useState } from 'react'; import { useState } from 'react';
import { modelCategoriesMap } from '../config';
const API_MAP: Record<
string,
{ api: string; generateCurlCode: (args: any) => string }
> = {
[modelCategoriesMap.embedding]: {
api: EMBEDDING_API,
generateCurlCode: generateEmbeddingCurlCode
},
[modelCategoriesMap.llm]: {
api: CHAT_API,
generateCurlCode: generateLLmCurlCode
},
[modelCategoriesMap.image]: {
api: CREAT_IMAGE_API,
generateCurlCode: generateImageCurlCode
},
[modelCategoriesMap.text_to_speech]: {
api: AUDIO_TEXT_TO_SPEECH_API,
generateCurlCode: generateTextToSpeechCurlCode
},
[modelCategoriesMap.speech_to_text]: {
api: AUDIO_SPEECH_TO_TEXT_API,
generateCurlCode: generateSpeechToTextCurlCode
},
[modelCategoriesMap.reranker]: {
api: RERANKER_API,
generateCurlCode: generateRerankCurlCode
}
};
const langOptions = [{ label: 'Curl', value: 'bash' }]; const langOptions = [{ label: 'Curl', value: 'bash' }];
const generateCode = ({ api: url, parameters }: Record<string, any>) => { const generateCode = ({ api: url, parameters }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API); const api = '/model/proxy/v1/';
// ========================= Curl ========================= // ========================= Curl =========================
const curlCode = ` const curlCode = `
@@ -17,6 +64,8 @@ curl ${host}${api} \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\
${formatCurlArgs(parameters, false)}`.trim(); ${formatCurlArgs(parameters, false)}`.trim();
return curlCode;
}; };
const useGenericProxy = () => { const useGenericProxy = () => {
@@ -33,38 +82,67 @@ const useGenericProxy = () => {
}); });
}; };
const getModelCategory = (categories: string[]) => {
for (const [category, config] of Object.entries(API_MAP)) {
if (categories.includes(category)) {
return {
category,
api: `${MODEL_PROXY}${config.api}`,
generateCurlCode: config.generateCurlCode
};
}
}
return {
category: modelCategoriesMap.llm,
api: CHAT_API,
generateCurlCode: generateLLmCurlCode
};
};
const openProxyModal = (data?: any) => { const openProxyModal = (data?: any) => {
const { api, generateCurlCode } = getModelCategory(data?.categories || []);
setModalStatus({ setModalStatus({
open: true, open: true,
codeValue: data?.generic_proxy_command || '' codeValue: generateCurlCode({
api,
modelProxy: true,
parameters: {
model: data?.name || ''
}
})
}); });
}; };
const GenericProxyModal = () => { const GenericProxyModal = (
return ( <ScrollerModal
<ScrollerModal title={intl.formatMessage({
title={intl.formatMessage({ id: 'models.form.generic_proxy.button'
id: 'models.form.generic_title.button' })}
})} open={modalStatus.open}
open={modalStatus.open} centered={true}
centered={true} onCancel={onCancel}
onCancel={onCancel} destroyOnHidden={true}
destroyOnHidden={true} closeIcon={true}
closeIcon={true} maskClosable={false}
maskClosable={false} keyboard={false}
keyboard={false} width={700}
width={700} footer={false}
footer={false} >
> <div
<CommandViewer style={{ marginBottom: 8 }}
code={modalStatus.codeValue} dangerouslySetInnerHTML={{
copyText={modalStatus.codeValue} __html: intl.formatMessage({ id: 'models.table.genericProxy' })
options={langOptions} }}
defaultValue={'bash'} ></div>
></CommandViewer> <CommandViewer
</ScrollerModal> code={modalStatus.codeValue}
); copyText={modalStatus.codeValue}
}; options={langOptions}
defaultValue={'bash'}
></CommandViewer>
</ScrollerModal>
);
return { return {
GenericProxyModal, GenericProxyModal,
+4 -1
View File
@@ -1,8 +1,9 @@
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
import { request } from '@umijs/max'; import { request } from '@umijs/max';
export const OPENAI_COMPATIBLE = 'v1-openai'; export const OPENAI_COMPATIBLE = 'v1-openai';
export const GPUSTACK_API = 'v1'; export const GPUSTACK_API = GPUSTACK_API_BASE_URL;
export const CHAT_API = `/${OPENAI_COMPATIBLE}/chat/completions`; export const CHAT_API = `/${OPENAI_COMPATIBLE}/chat/completions`;
@@ -19,6 +20,8 @@ export const AUDIO_TEXT_TO_SPEECH_API = `/${OPENAI_COMPATIBLE}/audio/speech`;
export const AUDIO_SPEECH_TO_TEXT_API = `/${OPENAI_COMPATIBLE}/audio/transcriptions`; export const AUDIO_SPEECH_TO_TEXT_API = `/${OPENAI_COMPATIBLE}/audio/transcriptions`;
export const MODEL_PROXY = '/model/proxy';
export async function execChatCompletions(params: any) { export async function execChatCompletions(params: any) {
return request(`${CHAT_API}`, { return request(`${CHAT_API}`, {
method: 'POST', method: 'POST',
@@ -69,7 +69,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
width={600} width={600}
footer={null} footer={null}
> >
<div style={{ marginBottom: '10px' }}> <div style={{ marginBottom: '8px' }}>
{intl.formatMessage({ id: 'playground.viewcode.info' })} {intl.formatMessage({ id: 'playground.viewcode.info' })}
</div> </div>
<div> <div>
@@ -81,7 +81,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onChange={handleOnChangeLang} onChange={handleOnChangeLang}
></CommandViewer> ></CommandViewer>
<div <div
style={{ marginTop: 10, display: 'flex', alignItems: 'baseline' }} style={{ marginTop: 8, display: 'flex', alignItems: 'baseline' }}
> >
<BulbOutlined className="m-r-8" /> <BulbOutlined className="m-r-8" />
<span> <span>
+33 -4
View File
@@ -1,8 +1,9 @@
import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis'; import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis';
import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils'; import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils';
export const speechToTextCode = ({ export const generateSpeechToTextCurlCode = ({
api: url, api: url,
modelProxy,
parameters parameters
}: Record<string, any>) => { }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
@@ -13,12 +14,26 @@ export const speechToTextCode = ({
const curlCode = ` const curlCode = `
curl ${host}${api} \\ curl ${host}${api} \\
-H "Content-Type: multipart/form-data" \\ -H "Content-Type: multipart/form-data" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
-F file="@/path/to/file/audio.mp3;type=audio/mpeg" \\ -F file="@/path/to/file/audio.mp3;type=audio/mpeg" \\
${formatCurlArgs(parameters, true)}` ${formatCurlArgs(parameters, true)}`
.trim() .trim()
.replace(/\\$/g, ''); .replace(/\\$/g, '');
return curlCode;
};
export const speechToTextCode = ({
api: url,
parameters
}: Record<string, any>) => {
const host = window.location.origin;
// replace url OPENAI_COMPATIBLE with GPUSTACK
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl =========================
const curlCode = generateSpeechToTextCurlCode({ api: url, parameters });
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
from openai import OpenAI\n from openai import OpenAI\n
@@ -67,8 +82,9 @@ main();`.trim();
}; };
}; };
export const TextToSpeechCode = ({ export const generateTextToSpeechCurlCode = ({
api: url, api: url,
modelProxy,
parameters parameters
}: Record<string, any>) => { }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
@@ -78,9 +94,22 @@ export const TextToSpeechCode = ({
const curlCode = ` const curlCode = `
curl ${host}${api} \\ curl ${host}${api} \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
${formatCurlArgs(parameters, false)} \\\n--output output.${parameters.response_format}`.trim(); ${formatCurlArgs(parameters, false)} \\\n--output output.${parameters.response_format}`.trim();
return curlCode;
};
export const TextToSpeechCode = ({
api: url,
parameters
}: Record<string, any>) => {
const host = window.location.origin;
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl =========================
const curlCode = generateTextToSpeechCurlCode({ api: url, parameters });
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
from pathlib import Path from pathlib import Path
+16 -2
View File
@@ -1,8 +1,9 @@
import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis'; import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis';
import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils'; import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils';
export const generateEmbeddingCode = ({ export const generateEmbeddingCurlCode = ({
api: url, api: url,
modelProxy,
parameters parameters
}: Record<string, any>) => { }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
@@ -12,9 +13,22 @@ export const generateEmbeddingCode = ({
const curlCode = ` const curlCode = `
curl ${host}${api} \\ curl ${host}${api} \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
${formatCurlArgs(parameters, false)}`.trim(); ${formatCurlArgs(parameters, false)}`.trim();
return curlCode;
};
export const generateEmbeddingCode = ({
api: url,
parameters
}: Record<string, any>) => {
const host = window.location.origin;
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl =========================
const curlCode = generateEmbeddingCurlCode({ api: url, parameters });
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
from openai import OpenAI\n from openai import OpenAI\n
+38 -17
View File
@@ -2,6 +2,38 @@ import _ from 'lodash';
import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis'; import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis';
import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils'; import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils';
export const generateImageCurlCode = ({
api: url,
parameters,
modelProxy,
isFormdata = false,
edit = false
}: Record<string, any>) => {
const host = window.location.origin;
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl =========================
let curlCode = `
curl ${host}${api} \\
-H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
${formatCurlArgs(parameters, isFormdata)}`.trim();
if (edit) {
curlCode = `
curl ${host}${api} \\
-H "Content-Type: multipart/form-data" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
-F image="@image.png" \\
-F mask="@mask.png" \\
${formatCurlArgs(_.omit(parameters, ['mask', 'image']), isFormdata)}`
.trim()
.replace(/\\$/, '');
}
return curlCode;
};
export const generateImageCode = ({ export const generateImageCode = ({
api: url, api: url,
parameters, parameters,
@@ -12,23 +44,12 @@ export const generateImageCode = ({
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API); const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl ========================= // ========================= Curl =========================
let curlCode = ` let curlCode = generateImageCurlCode({
curl ${host}${api} \\ api: url,
-H "Content-Type: application/json" \\ parameters,
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ isFormdata,
${formatCurlArgs(parameters, isFormdata)}`.trim(); edit
});
if (edit) {
curlCode = `
curl ${host}${api} \\
-H "Content-Type: multipart/form-data" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\
-F image="@image.png" \\
-F mask="@mask.png" \\
${formatCurlArgs(_.omit(parameters, ['mask', 'image']), isFormdata)}`
.trim()
.replace(/\\$/, '');
}
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
+16 -2
View File
@@ -1,8 +1,9 @@
import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis'; import { GPUSTACK_API, OPENAI_COMPATIBLE } from '../apis';
import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils'; import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils';
export const generateLLMCode = ({ export const generateLLmCurlCode = ({
api: url, api: url,
modelProxy,
parameters parameters
}: Record<string, any>) => { }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
@@ -12,9 +13,22 @@ export const generateLLMCode = ({
const curlCode = ` const curlCode = `
curl ${host}${api} \\ curl ${host}${api} \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
${formatCurlArgs(parameters, false)}`.trim(); ${formatCurlArgs(parameters, false)}`.trim();
return curlCode;
};
export const generateLLMCode = ({
api: url,
parameters
}: Record<string, any>) => {
const host = window.location.origin;
const api = url.replace(OPENAI_COMPATIBLE, GPUSTACK_API);
// ========================= Curl =========================
const curlCode = generateLLmCurlCode({ api: url, parameters });
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
from openai import OpenAI\n from openai import OpenAI\n
+15 -2
View File
@@ -1,7 +1,8 @@
import { formatCurlArgs } from './utils'; import { formatCurlArgs } from './utils';
export const generateRerankCode = ({ export const generateRerankCurlCode = ({
api, api,
modelProxy,
parameters parameters
}: Record<string, any>) => { }: Record<string, any>) => {
const host = window.location.origin; const host = window.location.origin;
@@ -10,9 +11,21 @@ export const generateRerankCode = ({
const curlCode = ` const curlCode = `
curl ${host}${api} \\ curl ${host}${api} \\
-H "Content-Type: application/json" \\ -H "Content-Type: application/json" \\
-H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\ -H "Authorization: Bearer $\{YOUR_GPUSTACK_API_KEY}" \\${modelProxy ? `\n-H "X-GPUStack-Model: ${parameters.model}" \\` : ''}
${formatCurlArgs(parameters, false)}`.trim(); ${formatCurlArgs(parameters, false)}`.trim();
return curlCode;
};
export const generateRerankCode = ({
api,
parameters
}: Record<string, any>) => {
const host = window.location.origin;
// ========================= Curl =========================
const curlCode = generateRerankCurlCode({ api, parameters });
// ========================= Python ========================= // ========================= Python =========================
const pythonCode = ` const pythonCode = `
import requests\n import requests\n