refactor: replace antd with shadcn/ui

This commit is contained in:
Junyan Qin
2025-05-07 18:06:44 +08:00
parent f5cee8b6b5
commit d2fb0dd749
28 changed files with 2907 additions and 225 deletions

View File

@@ -1,12 +1,8 @@
* {
margin: 0;
padding: 0;
}
:root {
/* 适用于 Firefox 的滚动条 */
scrollbar-color: rgba(0, 0, 0, 0.2) transparent; /* 滑块颜色 + 轨道颜色 */
scrollbar-width: thin; /* auto | thin | none */
scrollbar-width: thin; /* auto | thin | none */ --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.141 0.005 285.823); --card: oklch(1 0 0); --card-foreground: oklch(0.141 0.005 285.823); --popover: oklch(1 0 0); --popover-foreground: oklch(0.141 0.005 285.823); --primary: oklch(0.21 0.006 285.885); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.967 0.001 286.375); --secondary-foreground: oklch(0.21 0.006 285.885); --muted: oklch(0.967 0.001 286.375); --muted-foreground: oklch(0.552 0.016 285.938); --accent: oklch(0.967 0.001 286.375); --accent-foreground: oklch(0.21 0.006 285.885); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.92 0.004 286.32); --input: oklch(0.92 0.004 286.32); --ring: oklch(0.705 0.015 286.067); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.141 0.005 285.823); --sidebar-primary: oklch(0.21 0.006 285.885); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.967 0.001 286.375); --sidebar-accent-foreground: oklch(0.21 0.006 285.885); --sidebar-border: oklch(0.92 0.004 286.32); --sidebar-ring: oklch(0.705 0.015 286.067);
}
/* WebKit 内核浏览器定制 */
@@ -35,3 +31,90 @@
-ms-overflow-style: -ms-autohiding-scrollbar; /* 自动隐藏滚动条 */
}
}
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.21 0.006 285.885);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.21 0.006 285.885);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.92 0.004 286.32);
--primary-foreground: oklch(0.21 0.006 285.885);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.552 0.016 285.938);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.21 0.006 285.885);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.274 0.006 286.033);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.552 0.016 285.938);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}

View File

@@ -28,7 +28,7 @@
.basicInfoContainer {
display: flex;
flex-direction: column;
gap: 0.6rem;
gap: 0.2rem;
}
.basicInfoNameContainer {

View File

@@ -3,12 +3,6 @@
height: 100%;
}
.modalContainer {
width: 100%;
/*height: calc(100vh - 200px);*/
margin-top: 20px;
}
.modelListContainer {
align-self: flex-start;
justify-self: flex-start;

View File

@@ -19,6 +19,7 @@
flex-direction: row;
gap: 0.8rem;
user-select: none;
/* background-color: aqua; */
}
.iconImage {
@@ -31,7 +32,7 @@
.basicInfoContainer {
display: flex;
flex-direction: column;
gap: 0.6rem;
gap: 0.2rem;
}
.basicInfoText {

View File

@@ -1,5 +1,6 @@
import styles from './LLMCard.module.css';
import { LLMCardVO } from '@/app/home/models/component/llm-card/LLMCardVO';
import { Button } from '@/components/ui/button';
function checkAbilityBadges(abilities: string[]) {

View File

@@ -1,12 +1,69 @@
import styles from '@/app/home/models/LLMConfig.module.css';
import { Button, Form, Input, Select, SelectProps, Space, Modal } from 'antd';
import { SelectProps } from 'antd';
import { ICreateLLMField } from '@/app/home/models/ICreateLLMField';
import { useEffect, useState } from 'react';
import { IChooseRequesterEntity } from '@/app/home/models/component/llm-form/ChooseAdapterEntity';
import { IChooseRequesterEntity } from '@/app/home/models/component/llm-form/ChooseRequesterEntity';
import { httpClient } from '@/app/infra/http/HttpClient';
import { LLMModel } from '@/app/infra/api/api-types';
import { UUID } from 'uuidjs';
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogFooter,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Checkbox } from "@/components/ui/checkbox"
const extraArgSchema = z.object({
key: z.string().min(1, { message: '键名不能为空' }),
type: z.enum(['string', 'number', 'boolean']),
value: z.string(),
}).superRefine((data, ctx) => {
if (data.type === 'number' && isNaN(Number(data.value))) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "必须是有效的数字",
path: ['value'],
});
}
if (data.type === 'boolean' && data.value !== 'true' && data.value !== 'false') {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "必须是 true 或 false",
path: ['value'],
});
}
});
const formSchema = z.object({
name: z.string().min(1, { message: '模型名称不能为空' }),
model_provider: z.string().min(1, { message: '模型供应商不能为空' }),
url: z.string().min(1, { message: '请求URL不能为空' }),
api_key: z.string().min(1, { message: 'API Key不能为空' }),
abilities: z.array(z.string()),
extra_args: z.array(extraArgSchema).optional(),
})
export default function LLMForm({
editMode,
initLLMId,
@@ -16,40 +73,97 @@ export default function LLMForm({
}: {
editMode: boolean;
initLLMId?: string;
onFormSubmit: (value: ICreateLLMField) => void;
onFormCancel: (value: ICreateLLMField) => void;
onFormSubmit: (value: z.infer<typeof formSchema>) => void;
onFormCancel: () => void;
onLLMDeleted: () => void;
}) {
const [form] = Form.useForm<ICreateLLMField>();
const extraOptions: SelectProps['options'] = [];
const [initValue] = useState<ICreateLLMField>();
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
name: '',
model_provider: '',
url: '',
api_key: '',
abilities: [],
extra_args: [],
},
});
const [extraArgs, setExtraArgs] = useState<{key: string, type: 'string' | 'number' | 'boolean', value: string}[]>([]);
const [showDeleteConfirmModal, setShowDeleteConfirmModal] = useState(false);
const abilityOptions: SelectProps['options'] = [
{
label: '视觉能力',
value: 'vision',
},
{
label: '函数调用',
value: 'func_call',
},
{
label: '图像识别',
value: 'vision',
},
];
const [requesterNameList, setRequesterNameList] = useState<
IChooseRequesterEntity[]
>([]);
const [requesterDefaultURLList, setRequesterDefaultURLList] = useState<
string[]
>([]);
useEffect(() => {
initLLMModelFormComponent();
if (editMode && initLLMId) {
getLLMConfig(initLLMId).then((val) => {
form.setFieldsValue(val);
form.setValue('name', val.name);
form.setValue('model_provider', val.model_provider);
form.setValue('url', val.url);
form.setValue('api_key', val.api_key);
form.setValue('abilities', val.abilities as ("vision" | "func_call")[]);
// 转换extra_args为新格式
if(val.extra_args) {
const args = val.extra_args.map(arg => {
const [key, value] = arg.split(':');
let type: 'string' | 'number' | 'boolean' = 'string';
if(!isNaN(Number(value))) {
type = 'number';
} else if(value === 'true' || value === 'false') {
type = 'boolean';
}
return {
key,
type,
value
};
});
setExtraArgs(args);
form.setValue('extra_args', args);
}
});
} else {
form.resetFields();
form.reset();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const addExtraArg = () => {
setExtraArgs([...extraArgs, {key: '', type: 'string', value: ''}]);
};
const updateExtraArg = (index: number, field: 'key' | 'type' | 'value', value: string) => {
const newArgs = [...extraArgs];
newArgs[index] = {
...newArgs[index],
[field]: value
};
setExtraArgs(newArgs);
form.setValue('extra_args', newArgs);
};
const removeExtraArg = (index: number) => {
const newArgs = extraArgs.filter((_, i) => i !== index);
setExtraArgs(newArgs);
form.setValue('extra_args', newArgs);
};
async function initLLMModelFormComponent() {
const requesterNameList = await httpClient.getProviderRequesters();
setRequesterNameList(
@@ -60,6 +174,17 @@ export default function LLMForm({
};
}),
);
setRequesterDefaultURLList(
requesterNameList.requesters.map((item) => {
const config = item.spec.config;
for (let i = 0; i < config.length; i++) {
if (config[i].name == 'base_url') {
return config[i].default;
}
}
return '';
}),
);
}
async function getLLMConfig(id: string): Promise<ICreateLLMField> {
@@ -75,42 +200,35 @@ export default function LLMForm({
model_provider: llmModel.model.requester,
url: llmModel.model.requester_config?.base_url,
api_key: llmModel.model.api_keys[0],
abilities: llmModel.model.abilities,
abilities: llmModel.model.abilities || [],
extra_args: fakeExtraArgs,
};
}
function handleFormSubmit(value: ICreateLLMField) {
function handleFormSubmit(value: z.infer<typeof formSchema>) {
if (editMode) {
// 暂不支持更改模型
// onSaveEdit(value)
} else {
onCreateLLM(value);
}
form.resetFields();
form.reset();
}
// function onSaveEdit(value: ICreateLLMField) {
// const requestParam: LLMModel = {
// uuid: UUID.generate(),
// name: value.name,
// description: "",
// requester: value.model_provider,
// requester_config: {
// "base_url": value.url,
// "timeout": 120
// },
// extra_args: value.extra_args,
// api_keys: [value.api_key],
// abilities: value.abilities,
// // created_at: 'Sun Apr 27 2025 21:56:35 GMT+0800',
// // updated_at: 'Sun Apr 27 2025 21:56:35 GMT+0800',
// };
// httpClient.createProviderLLMModel(requestParam).then(r => console.log(r))
// }
function onCreateLLM(value: ICreateLLMField) {
function onCreateLLM(value: z.infer<typeof formSchema>) {
console.log('create llm', value);
// 转换extra_args为对象格式
const extraArgsObj: Record<string, any> = {};
value.extra_args?.forEach(arg => {
if(arg.type === 'number') {
extraArgsObj[arg.key] = Number(arg.value);
} else if(arg.type === 'boolean') {
extraArgsObj[arg.key] = arg.value === 'true';
} else {
extraArgsObj[arg.key] = arg.value;
}
});
const requestParam: LLMModel = {
uuid: UUID.generate(),
name: value.name,
@@ -120,18 +238,16 @@ export default function LLMForm({
base_url: value.url,
timeout: 120,
},
extra_args: value.extra_args,
extra_args: extraArgsObj,
api_keys: [value.api_key],
abilities: value.abilities,
// created_at: 'Sun Apr 27 2025 21:56:35 GMT+0800',
// updated_at: 'Sun Apr 27 2025 21:56:35 GMT+0800',
};
httpClient.createProviderLLMModel(requestParam).then(() => {
onFormSubmit(value);
});
}
function handleAbilitiesChange() {}
function handleAbilitiesChange() { }
function deleteModel() {
if (initLLMId) {
@@ -143,145 +259,221 @@ export default function LLMForm({
return (
<div className={styles.modalContainer}>
<Modal
open={showDeleteConfirmModal}
title={'删除确认'}
onCancel={() => setShowDeleteConfirmModal(false)}
footer={
<div
style={{
width: '170px',
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
}}
>
<Button
danger
onClick={() => {
deleteModel();
setShowDeleteConfirmModal(false);
}}
>
</Button>
<Button
onClick={() => {
setShowDeleteConfirmModal(false);
}}
>
<Dialog open={showDeleteConfirmModal} onOpenChange={setShowDeleteConfirmModal}>
<DialogContent>
<DialogHeader>
<DialogTitle></DialogTitle>
</DialogHeader>
<DialogDescription>
</DialogDescription>
<DialogFooter>
<Button variant="outline" onClick={() => setShowDeleteConfirmModal(false)}>
</Button>
<Button variant="destructive" onClick={() => {
deleteModel();
setShowDeleteConfirmModal(false);
}}>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Form {...form}>
<form onSubmit={form.handleSubmit(handleFormSubmit)} className="space-y-8">
<div className="space-y-4">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel><span className="text-red-500">*</span></FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
<FormDescription>
</FormDescription>
</FormItem>
)}
/>
<FormField
control={form.control}
name="model_provider"
render={({ field }) => (
<FormItem>
<FormLabel><span className="text-red-500">*</span></FormLabel>
<FormControl>
<Select onValueChange={(value) => {
field.onChange(value);
const index = requesterNameList.findIndex(item => item.value === value);
if(index !== -1) {
form.setValue('url', requesterDefaultURLList[index]);
}
}} value={field.value}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="选择模型供应商" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{requesterNameList.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="url"
render={({ field }) => (
<FormItem>
<FormLabel>URL<span className="text-red-500">*</span></FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="api_key"
render={({ field }) => (
<FormItem>
<FormLabel>API Key<span className="text-red-500">*</span></FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="abilities"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<div className="mb-0">
<FormDescription>
</FormDescription>
</div>
{abilityOptions.map((item) => (
<FormField
key={item.value}
control={form.control}
name="abilities"
render={({ field }) => {
return (
<FormItem
key={item.value}
className="flex flex-row items-start space-x-1 space-y-0"
>
<FormControl>
<Checkbox
checked={Array.isArray(field.value) && field.value?.includes(item.value)}
onCheckedChange={(checked) => {
return checked
? field.onChange([...(field.value || []), item.value])
: field.onChange(
field.value?.filter(
(value) => value !== item.value
)
)
}}
/>
</FormControl>
<FormLabel className="font-normal">
{item.label}
</FormLabel>
</FormItem>
)
}}
/>
))}
<FormMessage />
</FormItem>
)}
/>
<FormItem>
<FormLabel></FormLabel>
<div className="space-y-2">
{extraArgs.map((arg, index) => (
<div key={index} className="flex gap-2">
<Input
placeholder="键名"
value={arg.key}
onChange={(e) => updateExtraArg(index, 'key', e.target.value)}
/>
<Select
value={arg.type}
onValueChange={(value) => updateExtraArg(index, 'type', value)}
>
<SelectTrigger className="w-[120px]">
<SelectValue placeholder="类型" />
</SelectTrigger>
<SelectContent>
<SelectItem value="string"></SelectItem>
<SelectItem value="number"></SelectItem>
<SelectItem value="boolean"></SelectItem>
</SelectContent>
</Select>
<Input
placeholder="值"
value={arg.value}
onChange={(e) => updateExtraArg(index, 'value', e.target.value)}
/>
<button
type="button"
className="p-2 hover:bg-gray-100 rounded"
onClick={() => removeExtraArg(index)}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-5 h-5 text-red-500">
<path d="M7 4V2H17V4H22V6H20V21C20 21.5523 19.5523 22 19 22H5C4.44772 22 4 21.5523 4 21V6H2V4H7ZM6 6V20H18V6H6ZM9 9H11V17H9V9ZM13 9H15V17H13V9Z"></path>
</svg>
</button>
</div>
))}
<Button type="button" variant="outline" onClick={addExtraArg}>
</Button>
</div>
<FormDescription>
max_tokens, temperature, top_p
</FormDescription>
<FormMessage />
</FormItem>
</div>
}
>
</Modal>
<Form
form={form}
labelCol={{ span: 4 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
initialValues={{
...initValue,
}}
onFinish={handleFormSubmit}
clearOnDestroy={true}
disabled={editMode}
>
<Form.Item<ICreateLLMField>
label={'模型名称'}
name={'name'}
rules={[{ required: true, message: '该项为必填项哦~' }]}
>
<Input
placeholder={'为自己的大模型取个好听的名字~'}
style={{ width: 260 }}
></Input>
</Form.Item>
<Form.Item<ICreateLLMField>
label={'模型供应商'}
name={'model_provider'}
rules={[{ required: true, message: '该项为必填项哦~' }]}
>
<Select
style={{ width: 120 }}
onChange={() => {}}
options={requesterNameList}
/>
</Form.Item>
<Form.Item<ICreateLLMField>
label={'请求URL'}
name={'url'}
rules={[{ required: true, message: '该项为必填项哦~' }]}
>
<Input
placeholder="请求地址一般是API提供商提供的URL"
style={{ width: 500 }}
></Input>
</Form.Item>
<Form.Item<ICreateLLMField>
label={'API Key'}
name={'api_key'}
rules={[{ required: true, message: '该项为必填项哦~' }]}
>
<Input placeholder="你的API Key" style={{ width: 500 }}></Input>
</Form.Item>
<Form.Item<ICreateLLMField> label={'开启能力'} name={'abilities'}>
<Select
mode="tags"
style={{ width: 500 }}
placeholder="选择模型能力,输入回车可自定义能力"
onChange={handleAbilitiesChange}
options={abilityOptions}
/>
</Form.Item>
<Form.Item<ICreateLLMField> label={'其他参数'} name={'extra_args'}>
<Select
mode="tags"
style={{ width: 500 }}
placeholder="输入后回车可自定义其他参数,例 key:value"
onChange={handleAbilitiesChange}
options={extraOptions}
/>
</Form.Item>
<Form.Item wrapperCol={{ offset: 4, span: 14 }}>
<Space>
<DialogFooter>
{!editMode && (
<Button type="primary" htmlType="submit">
</Button>
<Button type="submit"></Button>
)}
{editMode && (
<Button
color="danger"
variant="solid"
onClick={() => {
setShowDeleteConfirmModal(true);
}}
disabled={false}
>
<Button type="button" variant="destructive" onClick={() => setShowDeleteConfirmModal(true)}>
</Button>
)}
<Button
htmlType="button"
onClick={() => {
onFormCancel(form.getFieldsValue());
}}
disabled={false}
>
<Button type="button" onClick={() => onFormCancel()}>
</Button>
</Space>
</Form.Item>
</DialogFooter>
</form>
</Form>
</div>
);
}

View File

@@ -4,12 +4,20 @@ import { useState, useEffect } from 'react';
import { LLMCardVO } from '@/app/home/models/component/llm-card/LLMCardVO';
import styles from './LLMConfig.module.css';
import EmptyAndCreateComponent from '@/app/home/components/empty-and-create-component/EmptyAndCreateComponent';
import { Modal } from 'antd';
import LLMCard from '@/app/home/models/component/llm-card/LLMCard';
import LLMForm from '@/app/home/models/component/llm-form/LLMForm';
import CreateCardComponent from '@/app/infra/basic-component/create-card-component/CreateCardComponent';
import { httpClient } from '@/app/infra/http/HttpClient';
import { LLMModel } from '@/app/infra/api/api-types';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
export default function LLMConfigPage() {
const [cardList, setCardList] = useState<LLMCardVO[]>([]);
@@ -41,7 +49,7 @@ export default function LLMConfigPage() {
name: model.name,
providerLabel: requesterNameList.find((item) => item.value === model.requester)?.label || model.requester.substring(0, 10),
baseURL: model.requester_config?.base_url,
abilities: model.abilities,
abilities: model.abilities || [],
});
});
console.log('get llmModelList', llmModelList);
@@ -67,32 +75,30 @@ export default function LLMConfigPage() {
return (
<div className={styles.configPageContainer}>
<Modal
title={isEditForm ? '预览模型' : '创建模型'}
centered
open={modalOpen}
destroyOnClose={true}
onOk={() => setModalOpen(false)}
onCancel={() => setModalOpen(false)}
width={700}
footer={null}
>
<LLMForm
editMode={isEditForm}
initLLMId={nowSelectedLLM?.id}
onFormSubmit={() => {
setModalOpen(false);
getLLMModelList();
}}
onFormCancel={() => {
setModalOpen(false);
}}
onLLMDeleted={() => {
setModalOpen(false);
getLLMModelList();
}}
/>
</Modal>
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
<DialogContent className="w-[700px] p-6">
<DialogHeader>
<DialogTitle>{isEditForm ? '预览模型' : '创建模型'}</DialogTitle>
</DialogHeader>
<LLMForm
editMode={isEditForm}
initLLMId={nowSelectedLLM?.id}
onFormSubmit={() => {
setModalOpen(false);
getLLMModelList();
}}
onFormCancel={() => {
setModalOpen(false);
}}
onLLMDeleted={() => {
setModalOpen(false);
getLLMModelList();
}}
/>
</DialogContent>
</Dialog>
{cardList.length > 0 && (
<div className={`${styles.modelListContainer}`}>

View File

@@ -1,5 +1,6 @@
import styles from './pipelineCard.module.css';
import { PipelineCardVO } from '@/app/home/pipelines/components/pipeline-card/PipelineCardVO';
import { Button } from '@/components/ui/button';
export default function PipelineCard({
cardVO,

View File

@@ -8,6 +8,7 @@ import { PipelineCardVO } from '@/app/home/pipelines/components/pipeline-card/Pi
import PipelineCard from '@/app/home/pipelines/components/pipeline-card/PipelineCard';
import { PipelineFormEntity } from '@/app/home/pipelines/components/pipeline-form/PipelineFormEntity';
import styles from './pipelineConfig.module.css';
import { Button } from '@/components/ui/button';
export default function PluginConfigPage() {
const [modalOpen, setModalOpen] = useState<boolean>(false);
@@ -72,6 +73,7 @@ export default function PluginConfigPage() {
return (
<div className={styles.configPageContainer}>
<Modal
title={isEditForm ? '编辑流水线' : '创建流水线'}
centered

View File

@@ -46,9 +46,9 @@ export interface LLMModel {
base_url: string;
timeout: number;
};
extra_args: object;
extra_args?: object;
api_keys: string[];
abilities: string[];
abilities?: string[];
// created_at: string;
// updated_at: string;
}