chore: rename web_ui dir to web

This commit is contained in:
Junyan Qin
2025-04-28 21:41:03 +08:00
parent 5c74bb41c9
commit 2eaac168dc
81 changed files with 0 additions and 1 deletions

View File

@@ -0,0 +1,8 @@
export interface ICreateLLMField {
name: string;
model_provider: string;
url: string;
api_key: string;
abilities: string[];
extra_args: string[];
}

View File

@@ -0,0 +1,90 @@
.configPageContainer {
width: 100%;
height: 100%;
}
.modalContainer {
width: 100%;
/*height: calc(100vh - 200px);*/
margin-top: 20px;
}
.modelListContainer {
align-self: flex-start;
justify-self: flex-start;
width: calc(100% - 60px);
margin: auto;
display: grid;
grid-template-rows: repeat(auto-fill, minmax(220px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
gap: 15px;
justify-items: center;
align-items: center;
}
.emptyContainer {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.cardContainer {
width: 360px;
height: 200px;
background-color: #FFF;
border-radius: 9px;
box-shadow: rgba(0, 0, 0, 0.4) 0 1px 1px -1px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-evenly;
}
.iconBasicInfoContainer {
width: 300px;
height: 100px;
margin-left: 20px;
display: flex;
flex-direction: row;
}
.icon {
width: 90px;
height: 90px;
border-radius: 5px;
font-size: 40px;
line-height: 90px;
text-align: center;
color: #ffffff;
background: rgba(96, 149, 209, 0.31);
border: 1px solid rgba(96, 149, 209, 0.31);
}
.basicInfoContainer {
width: 200px;
height: 90px;
padding-left: 20px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
}
.basicInfoText {
}
.bigText {
font-size: 20px;
}
.urlAndUpdateText {
margin-left: 20px;
}

View File

@@ -0,0 +1,33 @@
import styles from "../../LLMConfig.module.css"
import {LLMCardVO} from "@/app/home/models/component/llm-card/LLMCardVO";
export default function LLMCard({
cardVO
}: {
cardVO: LLMCardVO
}) {
return (
<div className={`${styles.cardContainer}`}>
{/* icon和基本信息 */}
<div className={`${styles.iconBasicInfoContainer}`}>
{/* icon */}
<div className={`${styles.icon}`}>
ICO
</div>
{/* bot基本信息 */}
<div className={`${styles.basicInfoContainer}`}>
<div className={`${styles.basicInfoText} ${styles.bigText}`}>
{cardVO.name}
</div>
<div className={`${styles.basicInfoText}`}>
{cardVO.company}
</div>
</div>
</div>
{/* URL和创建时间 */}
<div className={`${styles.urlAndUpdateText}`}>
URL{cardVO.URL}
</div>
</div>
);
}

View File

@@ -0,0 +1,21 @@
export interface ILLMCardVO {
id: string;
name: string;
company: string;
URL: string;
}
export class LLMCardVO implements ILLMCardVO {
id: string;
name: string;
company: string;
URL: string;
constructor(props: ILLMCardVO) {
this.id = props.id;
this.name = props.name;
this.company = props.company;
this.URL = props.URL;
}
}

View File

@@ -0,0 +1,4 @@
export interface IChooseRequesterEntity {
label: string
value: string
}

View File

@@ -0,0 +1,287 @@
import styles from "@/app/home/models/LLMConfig.module.css";
import { Button, Form, Input, Select, SelectProps, Space, Modal } 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 { httpClient } from "@/app/infra/http/HttpClient";
import { LLMModel } from "@/app/infra/api/api-types";
import { UUID } from "uuidjs";
export default function LLMForm({
editMode,
initLLMId,
onFormSubmit,
onFormCancel,
onLLMDeleted
}: {
editMode: boolean;
initLLMId?: string;
onFormSubmit: (value: ICreateLLMField) => void;
onFormCancel: (value: ICreateLLMField) => void;
onLLMDeleted: () => void;
}) {
const [form] = Form.useForm<ICreateLLMField>();
const extraOptions: SelectProps["options"] = [];
const [initValue] = useState<ICreateLLMField>();
const [showDeleteConfirmModal, setShowDeleteConfirmModal] = useState(false);
const abilityOptions: SelectProps["options"] = [
{
label: "函数调用",
value: "func_call"
},
{
label: "图像识别",
value: "vision"
}
];
const [requesterNameList, setRequesterNameList] = useState<
IChooseRequesterEntity[]
>([]);
useEffect(() => {
initLLMModelFormComponent();
if (editMode && initLLMId) {
getLLMConfig(initLLMId).then((val) => {
form.setFieldsValue(val);
});
} else {
form.resetFields();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function initLLMModelFormComponent() {
const requesterNameList = await httpClient.getProviderRequesters();
setRequesterNameList(
requesterNameList.requesters.map((item) => {
return {
label: item.label.zh_CN,
value: item.name
};
})
);
}
async function getLLMConfig(id: string): Promise<ICreateLLMField> {
const llmModel = await httpClient.getProviderLLMModel(id);
const fakeExtraArgs = [];
const extraArgs = llmModel.model.extra_args as Record<string, string>;
for (const key in extraArgs) {
fakeExtraArgs.push(`${key}:${extraArgs[key]}`);
}
return {
name: llmModel.model.name,
model_provider: llmModel.model.requester,
url: llmModel.model.requester_config?.base_url,
api_key: llmModel.model.api_keys[0],
abilities: llmModel.model.abilities,
extra_args: fakeExtraArgs
};
}
function handleFormSubmit(value: ICreateLLMField) {
if (editMode) {
// 暂不支持更改模型
// onSaveEdit(value)
} else {
onCreateLLM(value);
}
form.resetFields();
}
// 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) {
console.log("create llm", value);
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(() => {
onFormSubmit(value);
});
}
function handleAbilitiesChange() {}
function deleteModel() {
if (initLLMId) {
httpClient.deleteProviderLLMModel(initLLMId).then(() => {
onLLMDeleted();
});
}
}
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);
}}
>
</Button>
</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>
{!editMode && (
<Button type="primary" htmlType="submit">
</Button>
)}
{editMode && (
<Button
color="danger"
variant="solid"
onClick={() => {
setShowDeleteConfirmModal(true);
}}
disabled={false}
>
</Button>
)}
<Button
htmlType="button"
onClick={() => {
onFormCancel(form.getFieldsValue());
}}
disabled={false}
>
</Button>
</Space>
</Form.Item>
</Form>
</div>
);
}

View File

@@ -0,0 +1,116 @@
"use client"
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";
export default function LLMConfigPage() {
const [cardList, setCardList] = useState<LLMCardVO[]>([])
const [modalOpen, setModalOpen] = useState<boolean>(false);
const [isEditForm, setIsEditForm] = useState(false)
const [nowSelectedLLM, setNowSelectedLLM] = useState<LLMCardVO | null>(null)
useEffect(() => {
getLLMModelList()
}, [])
function getLLMModelList() {
httpClient.getProviderLLMModels().then((resp) => {
const llmModelList: LLMCardVO[] = resp.models.map((model: LLMModel) => {
console.log("model", model)
return new LLMCardVO({
id: model.uuid,
name: model.name,
company: model.requester,
URL: model.requester_config?.base_url,
})
})
console.log("get llmModelList", llmModelList)
setCardList(llmModelList)
}).catch((err) => {
// TODO error toast
console.error("get LLM model list error", err)
})
}
function selectLLM(cardVO: LLMCardVO) {
setIsEditForm(true)
setNowSelectedLLM(cardVO)
console.log("set now vo", cardVO)
setModalOpen(true)
}
function handleCreateModelClick() {
setIsEditForm(false)
setNowSelectedLLM(null)
setModalOpen(true);
}
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>
{
cardList.length > 0 &&
<div className={`${styles.modelListContainer}`}
>
{cardList.map(cardVO => {
return <div key={cardVO.id} onClick={() => {selectLLM(cardVO)}}>
<LLMCard cardVO={cardVO}></LLMCard>
</div>
})}
<CreateCardComponent
width={360}
height={200}
plusSize={90}
onClick={handleCreateModelClick}
/>
</div>
}
{
cardList.length === 0 &&
<div className={`${styles.emptyContainer}`}>
<EmptyAndCreateComponent
title={"模型列表空空如也~"}
subTitle={"快去创建一个吧!"}
buttonText={"创建模型 +"}
onButtonClick={() => {
handleCreateModelClick()
}}
/>
</div>
}
</div>
)
}