| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- <template>
- <a-modal
- v-model:visible="visible"
- title="智能体配置"
- @before-open="handleOpened"
- @cancel="handleCancel"
- :ok-loading="loading"
- @before-ok="handleBeforeOk"
- :footer="true"
- title-align="start"
- width="600px"
- >
- <a-row class="">
- <a-col :span="24">
- <a-tabs type="capsule" size="large" :active-key="activeKey" @change="handleTabChange">
- <a-tab-pane key="1" title="助理设置">
- <a-divider style="margin-bottom: 20px; margin-top: 0" />
- <div style="width: 100%" :style="{ height: height }">
- <a-form
- ref="formRef"
- :rules="rules"
- :model="form"
- @submit="handleSubmit"
- :style="{ width: '90%', margin: '0 auto' }"
- >
- <a-form-item field="name" label="智能体名称">
- <a-input v-model="form.name" placeholder="请输入名称" />
- </a-form-item>
- <a-form-item label="智能体图标">
- <a-space direction="vertical" :style="{ width: '100%' }">
- <Upload
- v-if="avatarShow"
- :action="uploadAction"
- :limit="1"
- :url="form.icon ? httpUrl + form.icon : ''"
- @update:fileList="updateFileList"
- @success="handleSuccess"
- ></Upload>
- </a-space>
- </a-form-item>
- <a-form-item label="空回复">
- <a-input v-model="form.prompt_config.empty_response" placeholder="" />
- </a-form-item>
- <a-form-item label="设置开场白">
- <a-textarea v-model="form.prompt_config.prologue" placeholder="" style="height: 100px" />
- </a-form-item>
- <a-form-item label="显示引文">
- <a-space direction="vertical">
- <a-switch v-model="form.prompt_config.quote" size="small" />
- </a-space>
- </a-form-item>
- <a-form-item label="Self-RAG">
- <a-space direction="vertical">
- <a-switch v-model="form.prompt_config.self_rag" size="small" />
- </a-space>
- </a-form-item>
- <a-form-item field="kb_ids" label="知识库">
- <a-select v-model="form.kb_ids" placeholder="请选择 ..." multiple>
- <a-option v-for="item in tabs" :key="item.id" :value="item.id">
- {{ item.name }}
- </a-option>
- </a-select>
- </a-form-item>
- </a-form>
- </div>
- </a-tab-pane>
- <a-tab-pane key="2" title="提示引擎">
- <a-divider style="margin-bottom: 20px; margin-top: 0" />
- <a-scrollbar style="width: 100%; overflow: auto" :style="{ height: height }">
- <a-form
- ref="formRef1"
- :rules="rules"
- :model="form"
- @submit="handleSubmit"
- :style="{ width: '90%', margin: '0 auto' }"
- >
- <a-form-item field="prompt_config.system" label="系统">
- <a-textarea v-model="form.prompt_config.system" placeholder="" style="height: 180px" />
- </a-form-item>
- <a-divider style="margin: 0; margin-bottom: 10px" />
- <a-form-item label="相似度阈值">
- <a-slider v-model="form.similarity_threshold" :step="0.01" :min="0" :max="1" />
- </a-form-item>
- <a-form-item label="关键字相似度权重">
- <a-slider v-model="form.vector_similarity_weight" :step="0.01" :min="0" :max="1" />
- </a-form-item>
- <a-form-item label="Top N">
- <a-slider v-model="form.top_n" :min="0" :max="30" />
- </a-form-item>
- <a-form-item label="Rerank模型">
- <a-space direction="vertical" size="large">
- <a-select :size="'large'" v-model="form.rerank_id" placeholder="请选择 ..." allow-clear>
- <a-optgroup :label="index" v-for="(item, index) in rankModelList" :key="index">
- <a-option v-for="obj in item" :key="obj.fid" :disabled="!obj.available" :value="obj.llm_name">
- {{ obj.llm_name }}
- </a-option>
- </a-optgroup>
- </a-select>
- </a-space>
- </a-form-item>
- <a-form-item v-if="form.rerank_id" label="Top-K">
- <a-slider v-model="form.top_k" :min="1" :max="2048" />
- </a-form-item>
- <a-form-item label="变量">
- <div style="width: 100%; text-align: right">
- <a-button type="outline" @click="addVariable" style="" size="mini" shape="round"> 新建 </a-button>
- </div>
- </a-form-item>
- <a-form-item label="">
- <a-table :columns="columns" :data="form.prompt_config.parameters" style="width: 100%">
- <template #name="{ record, rowIndex }">
- <a-input v-model="record.name" placeholder="" />
- <!-- <a-input v-model="form.prompt_config.parameters[rowIndex].key" />-->
- </template>
- <template #optional="{ record }">
- <a-switch v-model="record.optional" size="small" />
- </template>
- <template #action="{ record }">
- <a-button type="text" @click="deleteParameters(record)" style="margin-left: 0" size="small">
- <template #icon>
- <icon-delete />
- </template>
- </a-button>
- </template>
- </a-table>
- </a-form-item>
- </a-form>
- </a-scrollbar>
- </a-tab-pane>
- <a-tab-pane key="3" title="模型设置">
- <a-divider style="margin-bottom: 20px; margin-top: 0" />
- <div style="width: 100%" :style="{ height: height }">
- <a-form
- ref="formRef2"
- :rules="rules"
- :model="form"
- @submit="handleSubmit"
- :style="{ width: '90%', margin: '0 auto' }"
- >
- <a-form-item field="llm_id" label="模型">
- <a-space direction="vertical" size="large">
- <a-select
- :size="'large'"
- field="llm_id"
- v-model="form.llm_id"
- style="width: 400px"
- placeholder="请选择"
- >
- <template v-for="(item, index) in modelList" :key="index">
- <a-optgroup :label="index" v-if="item.length > 0">
- <a-option v-for="obj in item" :key="obj.fid" :value="obj.llm_name">
- {{ obj.llm_name }}
- </a-option>
- </a-optgroup>
- </template>
- </a-select>
- </a-space>
- </a-form-item>
- <a-divider style="margin-bottom: 20px; margin-top: 0" />
- <a-form-item label="自由">
- <a-select default-value="2" :style="{ width: '400px' }" placeholder="">
- <a-option value="1">即兴创作</a-option>
- <a-option value="2">精确</a-option>
- <a-option value="3">平衡</a-option>
- </a-select>
- </a-form-item>
- <a-form-item label="温度">
- <a-switch size="small" v-model="temperature" />
- <a-space direction="vertical" size="large">
- <a-slider
- :disabled="!temperature"
- v-model="form.llm_setting.temperature"
- :step="0.01"
- :min="0"
- :max="1"
- :style="{
- width: '350px',
- marginLeft: '20px',
- display: 'flex'
- }"
- show-input
- />
- </a-space>
- </a-form-item>
- <a-form-item label="top P">
- <a-switch size="small" v-model="top_p" />
- <a-space direction="vertical" size="large">
- <a-slider
- :disabled="!top_p"
- v-model="form.llm_setting.top_p"
- :step="0.01"
- :min="0"
- :max="1"
- :style="{
- width: '350px',
- marginLeft: '20px',
- display: 'flex'
- }"
- show-input
- />
- </a-space>
- </a-form-item>
- <a-form-item label="出席处罚">
- <a-switch size="small" v-model="presence_penalty" />
- <a-space direction="vertical" size="large">
- <a-slider
- :disabled="!presence_penalty"
- v-model="form.llm_setting.presence_penalty"
- :step="0.01"
- :min="0"
- :max="1"
- :style="{
- width: '350px',
- marginLeft: '20px',
- display: 'flex'
- }"
- show-input
- />
- </a-space>
- </a-form-item>
- <a-form-item label="频率处罚">
- <a-switch size="small" v-model="frequency_penalty" />
- <a-space direction="vertical" size="large">
- <a-slider
- :disabled="!frequency_penalty"
- v-model="form.llm_setting.frequency_penalty"
- :step="0.01"
- :min="0"
- :max="1"
- :style="{
- width: '350px',
- marginLeft: '20px',
- display: 'flex'
- }"
- show-input
- />
- </a-space>
- </a-form-item>
- <a-form-item label="最大token数">
- <a-switch size="small" v-model="max_tokens" />
- <a-space direction="vertical" size="large">
- <a-slider
- :disabled="!max_tokens"
- v-model="form.llm_setting.max_tokens"
- :min="0"
- :max="2048"
- :style="{
- width: '350px',
- marginLeft: '20px',
- display: 'flex'
- }"
- show-input
- />
- </a-space>
- </a-form-item>
- </a-form>
- </div>
- </a-tab-pane>
- </a-tabs>
- </a-col>
- </a-row>
- </a-modal>
- </template>
- <script setup>
- import { onMounted, onBeforeMount, reactive, ref, nextTick, onUnmounted, onBeforeUnmount, computed } from 'vue';
- import { queryKbList, queryModelList, createRgFlow } from '../../../apis/rgflow-dify';
- import { createDialog } from '../../../apis/intelligent';
- import { getKnowledgeList } from '../../../apis/knowledge';
- import { dialogType } from '../../../views/manage/common';
- import useLoading from './loading';
- import Upload from './Upload.vue';
- import { Message } from '@arco-design/web-vue';
- // import { dialogSet } from '@/api/Agent';
- const props = defineProps(['show_rg_config', 'typeAngint', 'formData']);
- const emit = defineEmits(['queryList', 'update:show_rg_config', 'updateIntelligentList']);
- const { loading, setLoading } = useLoading(true);
- const visible = computed(() => props.show_rg_config);
- const modelList = ref({});
- const rankModelList = ref({});
- let tabs = ref([]);
- const file = ref();
- const formRef = ref();
- const formRef1 = ref();
- const formRef2 = ref();
- const activeKey = ref('1');
- const form = reactive({
- name: '',
- icon: '',
- language: 'English',
- prompt_config: {
- empty_response: '',
- prologue: '你好! 我是你的助理,有什么可以帮到你的吗?',
- quote: true,
- self_rag: false,
- system:
- '你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。' +
- '回答需要考虑聊天历史。\n 以下是知识库:\n {knowledge}\n 以上是知识库。',
- parameters: [
- {
- index: 0,
- name: 'knowledge',
- key: 'knowledge',
- optional: false
- }
- ]
- },
- kb_ids: [],
- llm_id: undefined,
- llm_setting: {
- temperature: 0.1,
- top_p: 0.3,
- presence_penalty: 0.4,
- frequency_penalty: 0.7,
- max_tokens: 512
- },
- similarity_threshold: 0.2,
- vector_similarity_weight: 0.30000000000000004,
- top_n: 8,
- rerank_id: '',
- top_k: 1024
- });
- let temperature = ref(true);
- let top_p = ref(true);
- let presence_penalty = ref(true);
- let frequency_penalty = ref(true);
- let max_tokens = ref(true);
- const httpUrl = localStorage.getItem('httpUrl');
- let avatarShow = ref(true);
- const height = ref('calc(500px)');
- const columns = [
- {
- title: '关键字',
- dataIndex: 'name',
- slotName: 'name'
- },
- {
- title: '可选',
- dataIndex: 'optional',
- slotName: 'optional'
- },
- {
- title: '操作',
- dataIndex: 'action',
- slotName: 'action'
- }
- ];
- const formatter = (value) => {
- return `${(value / 100).toFixed(2)}`;
- };
- const uploadAction = '/api/v1/llm/upload'; // 替换为你的上传API
- const fileList = ref([]);
- const imageUrls = ref([]);
- const updateFileList = (newFileList) => {
- fileList.value = newFileList;
- console.log(newFileList, 88);
- };
- const handleSuccess = (urls) => {
- imageUrls.value = urls; // 拿到上传的图片地址
- form.icon = urls[0];
- };
- const rules = {
- name: [
- {
- required: true,
- message: '名称不允许为空'
- }
- ],
- 'prompt_config.system': [
- {
- required: true,
- message: '系统不允许为空'
- }
- ],
- llm_id: [
- {
- required: true,
- message: '模型不能为空'
- }
- ],
- kb_ids: [
- {
- required: true,
- message: '知识库不能为空'
- }
- ]
- };
- const handleSubmit = ({ values, errors }) => {
- console.log('values:', values, '\nerrors:', errors);
- if (!errors) {
- }
- };
- const handleCancel = () => {
- formRef.value.resetFields();
- formRef1.value.resetFields();
- formRef2.value.resetFields();
- form.name = '';
- emit('update:show_rg_config', false);
- emit('queryList');
- };
- const handleOpened = (el) => {
- // Object.assign(form,{
- // name: '',// 用户名
- // nameJoin: '',// 昵称
- // post: '',// 岗位
- // txt: '',// 备注
- // });
- activeKey.value = '1';
- formRef.value.resetFields();
- formRef1.value.resetFields();
- formRef2.value.resetFields();
- nextTick(() => {
- if (props.typeAngint == 'add') {
- form.name = '';
- form.icon = '';
- form.prompt_config.system =
- '你是一个智能助手,请总结知识库的内容来回答问题,请列举知识库中的数据详细回答。当所有知识库内容都与问题无关时,你的回答必须包括“知识库中未找到您要的答案!”这句话。' +
- '回答需要考虑聊天历史。\n 以下是知识库:\n {knowledge}\n 以上是知识库。';
- }
- // console.log(form, '新建智能体弹窗');
- avatarShow.value = false;
- setTimeout(() => {
- avatarShow.value = true;
- }, 100);
- });
- };
- const createOwnDialog = async (data, title) => {
- console.log(data, 'data');
- const res = await createDialog(data);
- if (res.code == 200) {
- Message.success(title);
- handleCancel();
- emit('updateIntelligentList');
- }
- };
- const handleBeforeOk = async (done) => {
- formRef.value.validate().then((res) => {
- // console.log('res:', res)
- });
- formRef1.value.validate().then((res) => {
- // console.log('res:', res)
- });
- formRef2.value.validate().then((res) => {
- // console.log('res:', res)
- });
- // TODO: 先写死知识库和模型
- // form.kb_ids = ['5e96cc5aad3111ef93990242ac130006'];
- form.llm_id = 'qwen-2.5-72b-instruct___OpenAI-API@OpenAI-API-Compatible';
- if (form.name && form.kb_ids.length > 0 && form.prompt_config.system && form.llm_id) {
- let title = '创建成功';
- let formNew = { ...form };
- if (formNew.rerank_id) {
- delete formNew.top_k;
- }
- if (formNew.rerank_id) {
- delete formNew.top_k;
- }
- formNew.prompt_config.parameters = form.prompt_config.parameters.map((item) => {
- return {
- ...item,
- key: item.name
- };
- });
- if (props.typeAngint == 'edit') {
- formNew.dialog_id = form.id;
- delete formNew.id;
- delete formNew.off;
- title = '修改成功';
- }
- if (!max_tokens.value) {
- //formNew.llm_setting.max_tokens = '';
- delete formNew.llm_setting.max_tokens;
- }
- setLoading(true);
- try {
- const res = await createRgFlow(formNew);
- if (res.data.id && res.data.id.length) {
- const dialogData = {
- id: res.data.id,
- name: form.name,
- description: '',
- icon: form.icon,
- dialogType: dialogType.RAGFLOW_TYPE,
- mode: 'ragflow'
- };
- // TODO: 调用自己系统的新增
- if (props.typeAngint == 'add') {
- createOwnDialog(dialogData, title);
- } else {
- emit('updateIntelligentList');
- handleCancel();
- Message.success(title);
- }
- } else {
- Message.error(data.msg);
- }
- done(true);
- setLoading(false);
- } catch (err) {
- // you can report use errorHandler or other
- setLoading(false);
- }
- } else {
- Message.warning('请填写必填项');
- done(false);
- }
- };
- const editClick = (data) => {
- visible.value = true;
- nextTick(() => {
- if (props.formData.llm_setting.max_tokens == '') {
- max_tokens.value = false;
- delete props.formData.llm_setting.max_tokens;
- } else {
- max_tokens.value = true;
- }
- Object.assign(form, props.formData);
- console.log(form, '表单数据');
- });
- };
- const addVariable = () => {
- form.prompt_config.parameters.push({
- index: form.prompt_config.parameters.length,
- key: '',
- name: '',
- optional: true
- });
- nextTick(() => {
- formRef.value.validate();
- });
- };
- const deleteParameters = (record) => {
- // console.log(record, 'record');
- // console.log(form.prompt_config.parameters);
- form.prompt_config.parameters = form.prompt_config.parameters.filter((item) => item.index !== record.index);
- };
- function handleTabChange(key) {
- // 处理标签改变事件
- activeKey.value = key;
- }
- const queryModel = async () => {
- try {
- const data = await queryModelList();
- const arrObj = {};
- for (const key in data.data) {
- if (Object.hasOwnProperty.call(data.data, key)) {
- const element = data.data[key];
- arrObj[key] = element.filter((item) => item.available === true && item.model_type === 'chat');
- }
- }
- modelList.value = arrObj;
- rankModelList.value = {
- BAAI: [data.data.BAAI[1]],
- Jina: data.data.Jina,
- youdao: data.data.Youdao
- };
- } catch (err) {
- // you can report use errorHandler or other
- } finally {
- }
- };
- const knowledgeData = async () => {
- setLoading(true);
- try {
- const params = {
- current: 1,
- pageSize: 1000,
- keyword: '',
- location: '1'
- };
- const res = await getKnowledgeList(params.current, params.pageSize, params.keyword, params.location);
- if (res.code == 200) {
- nextTick(() => {
- tabs.value = res.data.rows;
- });
- }
- } catch (err) {
- // you can report use errorHandler or other
- } finally {
- setLoading(false);
- }
- };
- onBeforeMount(() => {
- queryModel();
- knowledgeData();
- });
- onMounted(() => {});
- onBeforeUnmount(() => {});
- defineExpose({
- editClick
- });
- </script>
- <style scoped>
- :deep .arco-tabs-nav-tab-list {
- width: 100%;
- .arco-tabs-tab {
- width: 33%;
- .arco-tabs-tab-title {
- width: 100%;
- display: inline-block;
- text-align: center;
- }
- }
- }
- :deep .arco-input-wrapper {
- background-color: var(--color-neutral-2);
- }
- </style>
|