feat: change pipeline form

This commit is contained in:
HYana
2025-04-28 02:49:11 +08:00
committed by Junyan Qin
parent 1765fd5ff2
commit 5562148327
6 changed files with 393 additions and 131 deletions

View File

@@ -134,6 +134,7 @@ export default function BotForm({
httpClient.updateBot(initBotId, updateBot).then(res => { httpClient.updateBot(initBotId, updateBot).then(res => {
// TODO success toast // TODO success toast
console.log("update bot success", res) console.log("update bot success", res)
onFormSubmit(form.getFieldsValue())
}).catch(err => { }).catch(err => {
// TODO error toast // TODO error toast
console.log("update bot error", err) console.log("update bot error", err)
@@ -150,13 +151,13 @@ export default function BotForm({
httpClient.createBot(newBot).then(res => { httpClient.createBot(newBot).then(res => {
// TODO success toast // TODO success toast
console.log(res) console.log(res)
onFormSubmit(form.getFieldsValue())
}).catch(err => { }).catch(err => {
// TODO error toast // TODO error toast
console.log(err) console.log(err)
}) })
} }
setShowDynamicForm(false) setShowDynamicForm(false)
onFormSubmit(form.getFieldsValue())
form.resetFields() form.resetFields()
dynamicForm.resetFields() dynamicForm.resetFields()
} }

View File

@@ -0,0 +1,33 @@
import styles from "./pipelineCard.module.css";
import {PipelineCardVO} from "@/app/home/pipelines/components/pipeline-card/PipelineCardVO";
export default function PipelineCardComponent({
cardVO
}: {
cardVO: PipelineCardVO
}) {
return (
<div className={`${styles.cardContainer}`}>
{/* icon和基本信息 */}
<div className={`${styles.iconBasicInfoContainer}`}>
{/* icon */}
<div className={`${styles.icon}`}>
ICO
</div>
{/* 基本信息 */}
<div className={`${styles.basicInfoContainer}`}>
<div className={`${styles.basicInfoText} ${styles.bigText}`}>
{cardVO.name}
</div>
<div className={`${styles.basicInfoText}`}>
{cardVO.description}
</div>
</div>
</div>
{/* URL和创建时间 */}
<div className={`${styles.urlAndUpdateText}`}>
{cardVO.version}
</div>
</div>
);
}

View File

@@ -0,0 +1,23 @@
export interface IPipelineCardVO {
id: string;
name: string;
description: string;
createTime: string;
version: string;
}
export class PipelineCardVO implements IPipelineCardVO {
createTime: string;
description: string;
id: string;
name: string;
version: string;
constructor(props: IPipelineCardVO) {
this.id = props.id;
this.name = props.name;
this.description = props.description;
this.createTime = props.createTime;
this.version = props.version;
}
}

View File

@@ -0,0 +1,59 @@
.iconBasicInfoContainer {
width: 300px;
height: 100px;
margin-left: 20px;
display: flex;
flex-direction: row;
}
.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;
}
.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;
}
.createCardContainer {
font-size: 90px;
background: #6062E7;
color: white;
}

View File

@@ -1,7 +1,11 @@
import {Form, Button, Switch, Select, Input, InputNumber} from "antd"; import {Form, Button, Switch, Select, Input, InputNumber, SelectProps} from "antd";
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'; import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import {useState} from "react"; import {useEffect, useState} from "react";
import styles from "./pipelineFormStyle.module.css" import styles from "./pipelineFormStyle.module.css"
import {httpClient} from "@/app/infra/http/HttpClient";
import {LLMModel, Pipeline} from "@/app/infra/api/api-types";
import {LLMCardVO} from "@/app/home/models/component/llm-card/LLMCardVO";
import {UUID} from "uuidjs";
export default function PipelineFormComponent({ export default function PipelineFormComponent({
onFinish, onFinish,
@@ -11,13 +15,38 @@ export default function PipelineFormComponent({
onCancel: () => void; onCancel: () => void;
}) { }) {
const [nowFormIndex, setNowFormIndex] = useState<number>(0) const [nowFormIndex, setNowFormIndex] = useState<number>(0)
const [nowAIRunner, setNowAIRunner] = useState("")
const [llmModelList, setLlmModelList] = useState<SelectProps['options']>([])
// 这里不好可以改成enum等 // 这里不好可以改成enum等
const formLabelList: FormLabel[] = [ const formLabelList: FormLabel[] = [
{label: "基础", name: "basic"},
{label: "AI能力", name: "ai"}, {label: "AI能力", name: "ai"},
{label: "触发条件", name: "trigger"}, {label: "触发条件", name: "trigger"},
{label: "安全能力", name: "safety"}, {label: "安全能力", name: "safety"},
{label: "输出处理", name: "output"}, {label: "输出处理", name: "output"},
] ]
const [basicForm] = Form.useForm()
const [aiForm] = Form.useForm()
const [triggerForm] = Form.useForm()
const [safetyForm] = Form.useForm()
const [outputForm] = Form.useForm()
useEffect(() => {
getLLMModelList()
}, [])
function getLLMModelList() {
httpClient.getProviderLLMModels().then((resp) => {
setLlmModelList(resp.models.map((model: LLMModel) => {
return {
value: model.uuid,
label: model.name,
}
}))
}).catch((err) => {
console.error("get LLM model list error", err)
})
}
function getNowFormLabel() { function getNowFormLabel() {
return formLabelList[nowFormIndex] return formLabelList[nowFormIndex]
@@ -52,6 +81,50 @@ export default function PipelineFormComponent({
} }
} }
function handleCommit() {
Promise.all([
basicForm.validateFields(),
aiForm.validateFields(),
triggerForm.validateFields(),
safetyForm.validateFields(),
outputForm.validateFields(),
]).then(() => {
const pipeline = assembleForm()
httpClient.createPipeline(pipeline).then(r =>
onFinish()
)
}).catch(e => {
console.error(e)
})
}
// TODO 类型混乱,需要优化
function assembleForm(): Pipeline {
console.log("basicForm:", basicForm.getFieldsValue())
console.log("aiForm:", aiForm.getFieldsValue())
console.log("triggerForm:", triggerForm.getFieldsValue())
console.log("safetyForm:", safetyForm.getFieldsValue())
console.log("outputForm:", outputForm.getFieldsValue())
const config: object = {
ai: aiForm.getFieldsValue(),
trigger: triggerForm.getFieldsValue(),
safety: safetyForm.getFieldsValue(),
output: outputForm.getFieldsValue(),
}
return {
config,
created_at: "",
description: basicForm.getFieldsValue().description,
for_version: "",
name: basicForm.getFieldsValue().name,
stages: [],
updated_at: "",
uuid: UUID.generate(),
}
}
return ( return (
<div <div
style={{ maxHeight: '70vh', overflowY: 'auto' }} style={{ maxHeight: '70vh', overflowY: 'auto' }}
@@ -59,10 +132,35 @@ export default function PipelineFormComponent({
<h1> <h1>
{getNowFormLabel().label} {getNowFormLabel().label}
</h1> </h1>
<Form
layout={"vertical"}
style={{ display: getNowFormLabel().name === "basic" ? 'block' : 'none' }}
form={basicForm}>
<Form.Item
label="流水线名称"
name={"name"}
rules={[{
required: true,
}]}
>
<Input/>
</Form.Item>
<Form.Item
label="流水线描述"
name={"description"}
rules={[{
required: true,
}]}
>
<Input/>
</Form.Item>
</Form>
{/* AI能力表单 ai */} {/* AI能力表单 ai */}
<Form <Form
layout={"vertical"} layout={"vertical"}
style={{ display: getNowFormLabel().name === "ai" ? 'block' : 'none' }} style={{ display: getNowFormLabel().name === "ai" ? 'block' : 'none' }}
form={aiForm}
> >
{/* Runner 配置区块 */} {/* Runner 配置区块 */}
<div className={`${styles.formItemSubtitle}`}></div> <div className={`${styles.formItemSubtitle}`}></div>
@@ -77,20 +175,24 @@ export default function PipelineFormComponent({
{ label: "Dify 服务 API", value: "dify-service-api" }, { label: "Dify 服务 API", value: "dify-service-api" },
{ label: "阿里云百炼平台 API", value: "dashscope-app-api" } { label: "阿里云百炼平台 API", value: "dashscope-app-api" }
]} ]}
onChange={value => setNowAIRunner(value)}
/> />
</Form.Item> </Form.Item>
{/* 内置 Agent 配置区块 */} {/* 内置 Agent 配置区块 */}
{
nowAIRunner === "local-agent" &&
<>
<div className={`${styles.formItemSubtitle}`}>Agent</div> <div className={`${styles.formItemSubtitle}`}>Agent</div>
{/* TODO 这里要拉模型 */} {/* TODO 这里要拉模型 */}
<Form.Item <Form.Item
label="模型" label="模型"
name={["local-agent", "model"]} name={["local-agent", "model"]}
rules={[{ required: true }]} rules={[{required: true}]}
tooltip="从模型库中选择" tooltip="从模型库中选择"
> >
<Select <Select
options={[]} options={llmModelList}
placeholder="请选择语言模型" placeholder="请选择语言模型"
showSearch showSearch
/> />
@@ -110,7 +212,7 @@ export default function PipelineFormComponent({
<Form.Item <Form.Item
label="提示词" label="提示词"
name={["local-agent", "prompt"]} name={["local-agent", "prompt"]}
rules={[{ required: true }]} rules={[{required: true}]}
tooltip="按JSON格式输入" tooltip="按JSON格式输入"
> >
<Input.TextArea <Input.TextArea
@@ -119,14 +221,19 @@ export default function PipelineFormComponent({
/> />
</Form.Item> </Form.Item>
</>
}
{/* Dify 服务 API 区块 */} {/* Dify 服务 API 区块 */}
{
nowAIRunner === "dify-service-api" &&
<>
<div className={`${styles.formItemSubtitle}`}>Dify服务API</div> <div className={`${styles.formItemSubtitle}`}>Dify服务API</div>
<Form.Item <Form.Item
label="基础 URL" label="基础 URL"
name={["dify-service-api", "base-url"]} name={["dify-service-api", "base-url"]}
rules={[ rules={[
{ required: true }, {required: true},
{ type: 'url', message: '请输入有效的URL地址' } {type: 'url', message: '请输入有效的URL地址'}
]} ]}
> >
<Input/> <Input/>
@@ -135,105 +242,112 @@ export default function PipelineFormComponent({
label="应用类型" label="应用类型"
name={["dify-service-api", "app-type"]} name={["dify-service-api", "app-type"]}
initialValue={"chat"} initialValue={"chat"}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Select <Select
options={[ options={[
{ label: "聊天包括Chatflow", value: "chat" }, {label: "聊天包括Chatflow", value: "chat"},
{ label: "Agent", value: "agent" }, {label: "Agent", value: "agent"},
{ label: "工作流", value: "workflow" } {label: "工作流", value: "workflow"}
]} ]}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="API 密钥" label="API 密钥"
name={["dify-service-api", "api-key"]} name={["dify-service-api", "api-key"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Input.Password visibilityToggle={false} /> <Input.Password visibilityToggle={false}/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="思维链转换" label="思维链转换"
name={["dify-service-api", "thinking-convert"]} name={["dify-service-api", "thinking-convert"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Select <Select
options={[ options={[
{ label: "转换成 \<think\>...\<\/think\>", value: "plain" }, {label: "转换成 \<think\>...\<\/think\>", value: "plain"},
{ label: "原始", value: "original" }, {label: "原始", value: "original"},
{ label: "移除", value: "remove" } {label: "移除", value: "remove"}
]} ]}
/> />
</Form.Item> </Form.Item>
</>
}
{/* 阿里云百炼区块 */} {/* 阿里云百炼区块 */}
{
nowAIRunner === "dashscope-app-api" &&
<>
<div className={`${styles.formItemSubtitle}`}> API</div> <div className={`${styles.formItemSubtitle}`}> API</div>
<Form.Item <Form.Item
label="应用类型" label="应用类型"
name={["dashscope-app-api", "app-type"]} name={["dashscope-app-api", "app-type"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Select <Select
options={[ options={[
{ label: "Agent", value: "agent" }, {label: "Agent", value: "agent"},
{ label: "工作流", value: "workflow" } {label: "工作流", value: "workflow"}
]} ]}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="API 密钥" label="API 密钥"
name={["dashscope-app-api", "api-key"]} name={["dashscope-app-api", "api-key"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Input.Password visibilityToggle={false} /> <Input.Password visibilityToggle={false}/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="应用 ID" label="应用 ID"
name={["dashscope-app-api", "app-id"]} name={["dashscope-app-api", "app-id"]}
rules={[ rules={[
{ required: true }, {required: true},
]} ]}
> >
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="引用文本" label="引用文本"
name={["dashscope-app-api", "references_quote"]} name={["dashscope-app-api", "references_quote"]}
initialValue={"参考资料来自:"} initialValue={"参考资料来自:"}
> >
<Input.TextArea rows={2} /> <Input.TextArea rows={2}/>
</Form.Item> </Form.Item>
</>
}
</Form> </Form>
{/* 触发条件表单 trigger */} {/* 触发条件表单 trigger */}
<Form <Form
layout={"vertical"} layout={"vertical"}
style={{ display: getNowFormLabel().name === "trigger" ? 'block' : 'none' }} style={{display: getNowFormLabel().name === "trigger" ? 'block' : 'none'}}
form={triggerForm}
> >
{/* 群响应规则块 */} {/* 群响应规则块 */}
<div className={`${styles.formItemSubtitle}`}> </div> <div className={`${styles.formItemSubtitle}`}> </div>
<Form.Item <Form.Item
label={"是否在消息@机器人时触发"} label={"是否在消息@机器人时触发"}
name={["group-respond-rules", "at"]} name={["group-respond-rules", "at"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Switch /> <Switch/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={"消息前缀"} label={"消息前缀"}
name={["group-respond-rules", "prefix"]} name={["group-respond-rules", "prefix"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Select <Select
options={[ options={[
{ value: "\"type\": \"string\"", label: "\"type\": \"string\"" }, {value: "\"type\": \"string\"", label: "\"type\": \"string\""},
]} ]}
/> />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={"正则表达式"} label={"正则表达式"}
name={["group-respond-rules", "regexp"]} name={["group-respond-rules", "regexp"]}
rules={[{ required: true }]} rules={[{required: true}]}
> >
<Select <Select
mode="tags" mode="tags"
@@ -319,6 +433,7 @@ export default function PipelineFormComponent({
<Form <Form
layout={"vertical"} layout={"vertical"}
style={{ display: getNowFormLabel().name === "safety" ? 'block' : 'none' }} style={{ display: getNowFormLabel().name === "safety" ? 'block' : 'none' }}
form={safetyForm}
> >
{/* 内容过滤块 content-filter */} {/* 内容过滤块 content-filter */}
<div className={`${styles.formItemSubtitle}`}> </div> <div className={`${styles.formItemSubtitle}`}> </div>
@@ -382,6 +497,7 @@ export default function PipelineFormComponent({
<Form <Form
layout={"vertical"} layout={"vertical"}
style={{ display: getNowFormLabel().name === "output" ? 'block' : 'none' }} style={{ display: getNowFormLabel().name === "output" ? 'block' : 'none' }}
form={outputForm}
> >
{/* 长文本处理区块 */} {/* 长文本处理区块 */}
<div className={`${styles.formItemSubtitle}`}> </div> <div className={`${styles.formItemSubtitle}`}> </div>
@@ -486,7 +602,7 @@ export default function PipelineFormComponent({
<Button <Button
type="primary" type="primary"
onClick={addFormLabelIndex} onClick={handleCommit}
> >
</Button> </Button>
@@ -510,3 +626,8 @@ interface FormLabel {
label: string, label: string,
name: string, name: string,
} }
interface LLMSelectList {
label: string,
name: string,
}

View File

@@ -3,13 +3,33 @@ import {Modal} from "antd";
import {useState} from "react"; import {useState} from "react";
import CreateCardComponent from "@/app/infra/basic-component/create-card-component/CreateCardComponent"; import CreateCardComponent from "@/app/infra/basic-component/create-card-component/CreateCardComponent";
import PipelineFormComponent from "./components/pipeline-form/PipelineFormComponent"; import PipelineFormComponent from "./components/pipeline-form/PipelineFormComponent";
import {httpClient} from "@/app/infra/http/HttpClient";
import {PipelineCardVO} from "@/app/home/pipelines/components/pipeline-card/PipelineCardVO";
export default function PluginConfigPage() { export default function PluginConfigPage() {
const [modalOpen, setModalOpen] = useState<boolean>(false); const [modalOpen, setModalOpen] = useState<boolean>(false);
const [isEditForm, setIsEditForm] = useState(false) const [isEditForm, setIsEditForm] = useState(false)
const [pipelineList, setPipelineList] = useState([])
function getPipelines() {
httpClient.getPipelines().then(value => {
value.pipelines.map(pipeline => {
return new PipelineCardVO({
createTime: pipeline.created_at,
description: pipeline.description,
id: pipeline.uuid,
name: pipeline.name,
version: pipeline.for_version
})
})
}).catch(error => {
// TODO toast
console.log(error)
})
}
return ( return (
<div className={``}> <div className={``}>
<Modal <Modal
@@ -21,7 +41,12 @@ export default function PluginConfigPage() {
width={700} width={700}
footer={null} footer={null}
> >
<PipelineFormComponent onFinish={() => {}} onCancel={() => {}}/> <PipelineFormComponent
onFinish={() => {
getPipelines()
setModalOpen(false)
}}
onCancel={() => {}}/>
</Modal> </Modal>
<CreateCardComponent width={360} height={200} plusSize={90} onClick={() => {setModalOpen(true)}}/> <CreateCardComponent width={360} height={200} plusSize={90} onClick={() => {setModalOpen(true)}}/>