diff --git a/config/routes.ts b/config/routes.ts index 6640dfc8..ba629a4b 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -79,10 +79,10 @@ export default [ title: 'Video', path: '/playground/video', key: 'video', - icon: 'icon-video', - hideInMenu: true, - selectedIcon: 'icon-video-filled', - defaultIcon: 'icon-video', + icon: 'icon-video-outline', + hideInMenu: false, + selectedIcon: 'icon-video-filled02', + defaultIcon: 'icon-video-outline', component: './playground/video' } ] diff --git a/src/components/icon-font/index.tsx b/src/components/icon-font/index.tsx index 90249bc8..987b95d8 100644 --- a/src/components/icon-font/index.tsx +++ b/src/components/icon-font/index.tsx @@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons'; // import './iconfont/iconfont.js'; const IconFont = createFromIconfontCN({ - scriptUrl: '//at.alicdn.com/t/c/font_4613488_h1excejg8p8.js' + scriptUrl: '//at.alicdn.com/t/c/font_4613488_xson4g41d39.js' }); export default IconFont; diff --git a/src/components/logs-viewer/styles/logs-list.less b/src/components/logs-viewer/styles/logs-list.less index a5c55135..2c4eb669 100644 --- a/src/components/logs-viewer/styles/logs-list.less +++ b/src/components/logs-viewer/styles/logs-list.less @@ -1,7 +1,8 @@ .logs-wrap { background-color: var(--color-logs-bg); border-radius: var(--border-radius-mini); - font-family: monospace, Menlo, Courier, 'Courier New', Consolas, Monaco, + font-family: + monospace, Menlo, Courier, 'Courier New', Consolas, Monaco, 'Liberation Mono' !important; .content { @@ -35,7 +36,7 @@ } color: var(--color-logs-text); - font-size: var(--font-size-small); + font-size: 12px; line-height: 22px; white-space: pre-wrap; background-color: var(--color-logs-bg); diff --git a/src/components/status-tag/index.less b/src/components/status-tag/index.less index 3b20bf52..90628479 100644 --- a/src/components/status-tag/index.less +++ b/src/components/status-tag/index.less @@ -3,7 +3,7 @@ display: flex; justify-content: center; align-items: center; - padding: 2px 10px; + padding-inline: 7px; border-radius: 20px; min-width: 76px; width: max-content; @@ -16,7 +16,7 @@ display: flex; align-items: center; height: 20px; - gap: 5px; + gap: 4px; &.err { cursor: default; diff --git a/src/global.less b/src/global.less index 3c15b98d..cb46db4b 100644 --- a/src/global.less +++ b/src/global.less @@ -212,6 +212,7 @@ body { // set for the non-form item .ant-input-outlined, .ant-input-affix-wrapper, + .ant-select, .ant-picker { height: 40px; } diff --git a/src/locales/en-US/playground.ts b/src/locales/en-US/playground.ts index e99fe002..752dd7f4 100644 --- a/src/locales/en-US/playground.ts +++ b/src/locales/en-US/playground.ts @@ -161,5 +161,6 @@ export default { 'playground.uploadImage.url.invalid': 'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.', 'playground.uploadImage.url.holder': 'Enter an image URL', - 'playground.uploadImage.url.button': 'Add Image from URL' + 'playground.uploadImage.url.button': 'Add Image from URL', + 'playground.params.duration': 'Duration (seconds)' }; diff --git a/src/locales/ja-JP/playground.ts b/src/locales/ja-JP/playground.ts index 4e0e8d7c..dfad350f 100644 --- a/src/locales/ja-JP/playground.ts +++ b/src/locales/ja-JP/playground.ts @@ -164,7 +164,8 @@ export default { 'playground.uploadImage.url.invalid': 'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.', 'playground.uploadImage.url.holder': 'Enter an image URL', - 'playground.uploadImage.url.button': 'Add Image from URL' + 'playground.uploadImage.url.button': 'Add Image from URL', + 'playground.params.duration': 'Duration (seconds)' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== @@ -173,5 +174,6 @@ export default { // 3. 'playground.uploadfile.sizeError': 'File size exceeds the limit. Maximum allowed: {size}.' // 4. 'playground.uploadImage.url.invalid': 'Please enter a direct image URL(e.g. https://.../image.png). Press ESC to cancel.', // 5. 'playground.uploadImage.url.holder': 'Enter an image URL' -// 6. 'playground.uploadImage.url.button': 'Add Image from URL' +// 6. 'playground.uploadImage.url.button': 'Add Image from URL', +// 7. 'playground.params.duration': 'Duration (seconds)' // ========== End of To-Do List ========== diff --git a/src/locales/ru-RU/playground.ts b/src/locales/ru-RU/playground.ts index c7dfecdd..2a4dfbde 100644 --- a/src/locales/ru-RU/playground.ts +++ b/src/locales/ru-RU/playground.ts @@ -158,11 +158,13 @@ export default { 'playground.uploadImage.url.invalid': 'Please enter a direct image URL (e.g. https://.../image.png). Press ESC to cancel.', 'playground.uploadImage.url.holder': 'Enter an image URL', - 'playground.uploadImage.url.button': 'Add Image from URL' + 'playground.uploadImage.url.button': 'Add Image from URL', + 'playground.params.duration': 'Duration (seconds)' }; // ========== To-Do: Translate Keys (Remove After Translation) ========== // 1. 'playground.uploadImage.url.invalid': 'Please enter a direct image URL(e.g. https://.../image.png). Press ESC to cancel.', // 2. 'playground.uploadImage.url.holder': 'Enter an image URL', -// 3. 'playground.uploadImage.url.button': 'Add Image from URL' +// 3. 'playground.uploadImage.url.button': 'Add Image from URL', +// 4. 'playground.params.duration': 'Duration (seconds)' // ========== End of To-Do List ========== diff --git a/src/locales/zh-CN/playground.ts b/src/locales/zh-CN/playground.ts index d8f32e5a..0588da49 100644 --- a/src/locales/zh-CN/playground.ts +++ b/src/locales/zh-CN/playground.ts @@ -154,5 +154,6 @@ export default { 'playground.uploadImage.url.invalid': '请输入直接的图片链接(例如:https://…/image.png)。按 ESC 可取消。', 'playground.uploadImage.url.holder': '请输入图片链接', - 'playground.uploadImage.url.button': '从链接添加图片' + 'playground.uploadImage.url.button': '从链接添加图片', + 'playground.params.duration': '时长 (秒)' }; diff --git a/src/pages/cluster-management/cluster-detail.tsx b/src/pages/cluster-management/cluster-detail.tsx index dddeaa22..a27c9b83 100644 --- a/src/pages/cluster-management/cluster-detail.tsx +++ b/src/pages/cluster-management/cluster-detail.tsx @@ -44,7 +44,7 @@ const ClusterDetailModal = () => { items={[ { key: 'workers', - label: `Workers (${clusterDetailData?.workers ?? 0})`, + label: `Workers`, icon: , children: ( { }, { key: 'deployments', - label: `Deployments (${clusterDetailData?.models ?? 0})`, + label: `Deployments`, icon: , children: }, { key: 'gpus', - label: `GPUs (${clusterDetailData?.gpus ?? 0})`, + label: `GPUs`, icon: , children: } diff --git a/src/pages/llmodels/forms/advance-config.tsx b/src/pages/llmodels/forms/advance-config.tsx index 071f8824..70d8765e 100644 --- a/src/pages/llmodels/forms/advance-config.tsx +++ b/src/pages/llmodels/forms/advance-config.tsx @@ -1,7 +1,6 @@ import LabelSelector from '@/components/label-selector'; import CheckboxField from '@/components/seal-form/checkbox-field'; import SealSelect from '@/components/seal-form/seal-select'; -import SealSlider from '@/components/seal-form/seal-slider'; import { useIntl } from '@umijs/max'; import { Form } from 'antd'; import _ from 'lodash'; @@ -68,36 +67,6 @@ const AdvanceConfig = () => { options={modelCategories} > - {!isGGUF && modelContextData?.native && ( - name="max_context_len"> - - - )} name="env"> = forwardRef((props, ref) => { const viewCodeContent = useMemo(() => { return generateCode({ api: CREATE_VIDEO_API, + isFormdata: true, parameters: { ...finalParameters, prompt: currentPrompt @@ -170,22 +170,34 @@ const GroundVideo: React.FC = forwardRef((props, ref) => { > <>
- + {videoList.length > 0 && ( +
+ + +
+ )} {!videoList.length && (
diff --git a/src/pages/playground/config/params-config.ts b/src/pages/playground/config/params-config.ts index 31d4f704..8303727c 100644 --- a/src/pages/playground/config/params-config.ts +++ b/src/pages/playground/config/params-config.ts @@ -1,6 +1,6 @@ import { ParamsSchema } from './types'; -export interface ImageSizeItem { +export interface SizeOption { label: string; value: string; width: number; @@ -504,7 +504,7 @@ export const ImageAdvancedParamsConfig: ParamsSchema[] = [ } ]; -export const ImageCustomSizeConfig: ParamsSchema[] = [ +export const CustomSizeConfig: ParamsSchema[] = [ { type: 'Slider', name: 'width', diff --git a/src/pages/playground/config/video-parameters.ts b/src/pages/playground/config/video-parameters.ts index dabe2a8e..7d9bf349 100644 --- a/src/pages/playground/config/video-parameters.ts +++ b/src/pages/playground/config/video-parameters.ts @@ -1,7 +1,7 @@ -import { ImageSizeItem } from './params-config'; +import { SizeOption } from './params-config'; import { ParamsSchema } from './types'; -export const videoSizeOptions: ImageSizeItem[] = [ +export const videoSizeOptions: SizeOption[] = [ { label: '720x1280', value: '720x1280', width: 720, height: 1280 }, { label: '1280x720', value: '1280x720', width: 1280, height: 720 }, { label: '1024x1792', value: '1024x1792', width: 1024, height: 1792 }, diff --git a/src/pages/playground/hooks/use-init-meta.ts b/src/pages/playground/hooks/use-init-meta.ts index d4e714af..b1d07cfc 100644 --- a/src/pages/playground/hooks/use-init-meta.ts +++ b/src/pages/playground/hooks/use-init-meta.ts @@ -1,11 +1,11 @@ import useOverlayScroller from '@/hooks/use-overlay-scroller'; import { + CustomSizeConfig, ImageCountConfig, - ImageCustomSizeConfig, ImageSizeConfig, - ImageSizeItem, ImageconstExtraConfig, ImageAdvancedParamsConfig as ImgAdvancedParamsConfig, + SizeOption, imageSizeOptions as imageSizeList } from '@/pages/playground/config/params-config'; import { generateRandomNumber } from '@/utils'; @@ -210,9 +210,9 @@ export const useInitImageMeta = ( const [searchParams] = useSearchParams(); const [modelMeta, setModelMeta] = useState({}); const [isOpenaiCompatible, setIsOpenaiCompatible] = useState(false); - const [imageSizeOptions, setImageSizeOptions] = React.useState< - ImageSizeItem[] - >([]); + const [imageSizeOptions, setImageSizeOptions] = React.useState( + [] + ); const [basicParamsConfig, setBasicParamsConfig] = React.useState< ParamsSchema[] >([...ImageCountConfig, ...ImageSizeConfig]); @@ -275,7 +275,7 @@ export const useInitImageMeta = ( const generateImageParamsConfig = ( currentModel: any, - sizeOptions: ImageSizeItem[] + sizeOptions: SizeOption[] ) => { if (sizeOptions.length) { const sizeConfig = ImageSizeConfig.map((item) => { @@ -290,18 +290,16 @@ export const useInitImageMeta = ( return [...ImageCountConfig, ...sizeConfig]; } const { max_height, max_width } = currentModel.meta || {}; - const customSizeConfig = _.cloneDeep(ImageCustomSizeConfig).map( - (item: any) => { - const max = item.name === 'height' ? max_height : max_width; - return { - ...item, - attrs: { - ...item.attrs, - max: max || item.attrs.max - } - }; - } - ); + const customSizeConfig = _.cloneDeep(CustomSizeConfig).map((item: any) => { + const max = item.name === 'height' ? max_height : max_width; + return { + ...item, + attrs: { + ...item.attrs, + max: max || item.attrs.max + } + }; + }); return [...ImageCountConfig, ...customSizeConfig]; }; @@ -334,7 +332,7 @@ export const useInitImageMeta = ( if (values.size === 'custom') { return [ ...basicParamsConfig, - ...ImageCustomSizeConfig, + ...CustomSizeConfig, ...(values.isOpenaiCompatible ? ImageconstExtraConfig : ImageAdvancedParamsConfig) @@ -437,7 +435,7 @@ export const useInitImageMeta = ( if (changeValues.size && changeValues.size === 'custom') { setParamsConfig([ ...basicParamsConfig, - ...ImageCustomSizeConfig, + ...CustomSizeConfig, ...(!isOpenaiCompatible ? ImageAdvancedParamsConfig : ImageconstExtraConfig) @@ -515,7 +513,7 @@ export const useInitImageMeta = ( imgInitialValues, ImageCountConfig, ImageSizeConfig, - ImageCustomSizeConfig, + CustomSizeConfig, ImageconstExtraConfig }; }; diff --git a/src/pages/playground/hooks/use-init-video-meta.ts b/src/pages/playground/hooks/use-init-video-meta.ts index 47b0f383..ee810d4e 100644 --- a/src/pages/playground/hooks/use-init-video-meta.ts +++ b/src/pages/playground/hooks/use-init-video-meta.ts @@ -1,6 +1,6 @@ import { - ImageCustomSizeConfig, - ImageSizeItem + CustomSizeConfig, + SizeOption } from '@/pages/playground/config/params-config'; import { generateRandomNumber } from '@/utils'; import { useSearchParams } from '@umijs/max'; @@ -43,9 +43,9 @@ export const useInitVideoMeta = ( const [searchParams] = useSearchParams(); const [modelMeta, setModelMeta] = useState({}); const [isOpenaiCompatible, setIsOpenaiCompatible] = useState(false); - const [videoSizeOptions, setVideoSizeOptions] = React.useState< - ImageSizeItem[] - >([]); + const [videoSizeOptions, setVideoSizeOptions] = React.useState( + [] + ); const [basicParamsConfig, setBasicParamsConfig] = React.useState< ParamsSchema[] >([...videoParamsConfig]); @@ -107,7 +107,7 @@ export const useInitVideoMeta = ( const generateParamsConfig = ( currentModel: any, - sizeOptions: ImageSizeItem[] + sizeOptions: SizeOption[] ) => { if (sizeOptions.length) { const sizeConfig = videoParamsConfig.map((item) => { @@ -120,18 +120,16 @@ export const useInitVideoMeta = ( } const { max_height, max_width } = currentModel.meta || {}; // generate custom size config - const customSizeConfig = _.cloneDeep(ImageCustomSizeConfig).map( - (item: any) => { - const max = item.name === 'height' ? max_height : max_width; - return { - ...item, - attrs: { - ...item.attrs, - max: max || item.attrs.max - } - }; - } - ); + const customSizeConfig = _.cloneDeep(CustomSizeConfig).map((item: any) => { + const max = item.name === 'height' ? max_height : max_width; + return { + ...item, + attrs: { + ...item.attrs, + max: max || item.attrs.max + } + }; + }); return [...customSizeConfig]; }; @@ -163,7 +161,7 @@ export const useInitVideoMeta = ( if (values.size === 'custom') { return [ ...basicParamsConfig, - ...ImageCustomSizeConfig, + ...CustomSizeConfig, ...(values.isOpenaiCompatible ? videoExtraConfig : videoAdvancedParamsConfig) @@ -266,7 +264,7 @@ export const useInitVideoMeta = ( if (changeValues.size && changeValues.size === 'custom') { setParamsConfig([ ...basicParamsConfig, - ...ImageCustomSizeConfig, + ...CustomSizeConfig, ...(!isOpenaiCompatible ? videoAdvancedParamsConfig : videoExtraConfig) @@ -342,7 +340,7 @@ export const useInitVideoMeta = ( videoAdvancedDefaultValues, videoAdvancedParamsConfig, videoInitialValues, - ImageCustomSizeConfig, + CustomSizeConfig, videoExtraConfig }; }; diff --git a/src/pages/playground/hooks/use-text-video.ts b/src/pages/playground/hooks/use-text-video.ts index 6f45f65a..6b265b92 100644 --- a/src/pages/playground/hooks/use-text-video.ts +++ b/src/pages/playground/hooks/use-text-video.ts @@ -13,10 +13,6 @@ export default function useTextVideo(props: any) { const [videoList, setVideoList] = useState< { dataUrl: string; - height: number | string; - width: string | number; - maxHeight: string | number; - maxWidth: string | number; uid: number; span?: number; loading?: boolean; @@ -47,29 +43,6 @@ export default function useTextVideo(props: any) { return requestIdRef.current; }; - const removeBase64Suffix = (str: string, suffix: string) => { - return str.endsWith(suffix) ? str.slice(0, -suffix.length) : str; - }; - - const setImageSize = (parameters: any) => { - let size: Record = { - span: 12 - }; - if (parameters.n === 1) { - size.span = 24; - } - if (parameters.n === 2) { - size.span = 12; - } - if (parameters.n === 3) { - size.span = 12; - } - if (parameters.n === 4) { - size.span = 12; - } - return size; - }; - const setMessageId = () => { messageId.current = messageId.current + 1; return messageId.current; @@ -91,31 +64,21 @@ export default function useTextVideo(props: any) { requestToken.current?.abort?.('cancel'); requestToken.current = new AbortController(); const currentRequestId = updateRequestId(); - const size: any = setImageSize(parameters); setLoading(true); setMessageId(); setTokenResult(null); - const imgSize = _.split(parameters.size, 'x').map((item: string) => - _.toNumber(item) - ); + const newList = [ + { + dataUrl: '', + progress: 0, + loading: true, + preview: false, + uid: setMessageId() + } + ]; - let newImageList = Array(parameters.n) - .fill({}) - .map((item, index: number) => { - return { - dataUrl: 'data:image/png;base64,', - ...size, - progress: 0, - height: imgSize[1], - width: imgSize[0], - loading: true, - progressType: 'dashboard', - preview: false, - uid: setMessageId() - }; - }); - setVideoList(newImageList); + setVideoList(newList); const result = await createVideo({ data: parameters, @@ -145,28 +108,15 @@ export default function useTextVideo(props: any) { return; } - result?.data?.forEach((item: any, index: number) => { - const imgItem = newImageList[index]; + newList[0] = { + ...newList[0], + dataUrl: result?.id, + loading: false, + progress: 100 + }; - if (item.b64_json) { - imgItem.dataUrl = `data:image/png;base64,${item.b64_json}`; - } - - newImageList[index] = { - dataUrl: imgItem.dataUrl, - height: imgSize[1], - width: imgSize[0], - maxHeight: `${imgSize[1]}px`, - maxWidth: `${imgSize[0]}px`, - uid: imgItem.uid, - span: imgItem.span, - loading: false, - preview: true, - progress: 100 - }; - }); - console.log('newImageList:', newImageList); - setVideoList([...newImageList]); + console.log('newList:', newList); + setVideoList([...newList]); } catch (error) { console.log('error:', error); updateRequestId(); diff --git a/src/pages/playground/video.tsx b/src/pages/playground/video.tsx index b3b907b5..42561325 100644 --- a/src/pages/playground/video.tsx +++ b/src/pages/playground/video.tsx @@ -17,32 +17,30 @@ import './style/play-ground.less'; const PlaygroundRerank: React.FC = () => { const intl = useIntl(); - const groundRerankerRef = useRef(null); - const [rerankerModelList, setRerankerModelList] = useState< - Global.BaseOption[] - >([]); + const groundVideoRef = useRef(null); + const [modelList, setModelList] = useState[]>([]); const [loaded, setLoaded] = useState(false); useCollapseLayout({ handler: () => { - groundRerankerRef.current?.setCollapse?.(); + groundVideoRef.current?.setCollapse?.(); }, - triggeredRef: groundRerankerRef.current + triggeredRef: groundVideoRef.current }); const handleViewCode = useMemoizedFn(() => { - groundRerankerRef.current?.viewCode?.(); + groundVideoRef.current?.viewCode?.(); }); const handleToggleCollapse = useMemoizedFn(() => { - groundRerankerRef.current?.setCollapse?.(); + groundVideoRef.current?.setCollapse?.(); }); useEffect(() => { - const getModelListByReranker = async () => { + const getModelList = async () => { try { const params = { - categories: modelCategoriesMap.reranker, + categories: modelCategoriesMap.llm, with_meta: true }; const res = await queryModelsList(params); @@ -61,10 +59,8 @@ const PlaygroundRerank: React.FC = () => { }; const fetchData = async () => { try { - const [rerankerModelList] = await Promise.all([ - getModelListByReranker() - ]); - setRerankerModelList(rerankerModelList); + const [modelList] = await Promise.all([getModelList()]); + setModelList(modelList); } catch (error) { setLoaded(true); } @@ -75,7 +71,7 @@ const PlaygroundRerank: React.FC = () => { useHotkeys( HotKeys.RIGHT.join(','), () => { - groundRerankerRef.current?.setCollapse?.(); + groundVideoRef.current?.setCollapse?.(); }, { preventDefault: true @@ -103,8 +99,8 @@ const PlaygroundRerank: React.FC = () => {
diff --git a/src/pages/playground/view-code/video.ts b/src/pages/playground/view-code/video.ts index 4aa6ff83..1319054c 100644 --- a/src/pages/playground/view-code/video.ts +++ b/src/pages/playground/view-code/video.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; -import { MODEL_PROXY } from '../apis'; -import { fomatNodeJsParams, formatCurlArgs } from './utils'; +import { MODEL_PROXY, OPENAI_COMPATIBLE } from '../apis'; +import { fomatNodeJsParams, formatCurlArgs, formatPyParams } from './utils'; export const generateCurlCode = ({ api: url, @@ -13,23 +13,14 @@ export const generateCurlCode = ({ const api = modelProxy ? `${MODEL_PROXY}/\${YOUR_API_PATH}` : url; // ========================= 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 = ` + const 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(/\\$/, ''); - } + .trim() + .replace(/\\$/, ''); return curlCode; }; @@ -37,8 +28,7 @@ ${formatCurlArgs(_.omit(parameters, ['mask', 'image']), isFormdata)}` export const generateCode = ({ api: url, parameters, - isFormdata = false, - edit = false + isFormdata = false }: Record) => { const host = window.location.origin; const api = url; @@ -47,36 +37,39 @@ export const generateCode = ({ let curlCode = generateCurlCode({ api: url, parameters, - isFormdata, - edit + isFormdata }); // ========================= Python ========================= const pythonCode = ` -import requests\n -url="${host}${api}" -headers = { - "Content-type": "application/json", - "Authorization": "Bearer $\{YOUR_GPUSTACK_API_KEY}" -} -data = ${JSON.stringify(parameters, null, 2).replace(/null/g, 'None')}\n -response = requests.post(url, headers=headers, json=data) -print(response.json()['data']['object'])`.trim(); +from openai import OpenAI\n +client = OpenAI( + base_url="${host}/${OPENAI_COMPATIBLE}", + api_key="YOUR_GPUSTACK_API_KEY" +) + +video = client.videos.create(\n${formatPyParams({ ...parameters })})\n +print(video.id)`.trim(); // ========================= Node.js ========================= + const params = fomatNodeJsParams({ + ...parameters + }); + const nodeJsCode = ` -const axios = require('axios'); +const OpenAI = require("openai"); -const url = "${host}${api}"; -const headers = { - "Content-type": "application/json", - "Authorization": "Bearer $\{YOUR_GPUSTACK_API_KEY}" -}; -const data = ${fomatNodeJsParams(parameters)}; +const openai = new OpenAI({ + "apiKey": "YOUR_GPUSTACK_API_KEY", + "baseURL": "${host}/${OPENAI_COMPATIBLE}" +}); -axios.post(url, data, { headers }).then((response) => { - console.log(response.data.object); -});`.trim(); +async function main() { + const params = ${params}; + const video = await openai.videos.create(params); + console.log(video.id); +} +main();`.trim(); return { curlCode,