Browse Source

智能体:问答审查智能体集成

lwx_v27
han2015 2 weeks ago
parent
commit
152183624a
  1. 2
      .env.development
  2. 2
      .env.production
  3. 292
      src/components/DesignForm/public/form/aiassist.vue

2
.env.development

@ -12,3 +12,5 @@ VITE_APP_SJZT_URL = 'http://172.20.5.86/prod-api'
VITE_OFFICE_HOST='http://myvuetest.net/kkapi' VITE_OFFICE_HOST='http://myvuetest.net/kkapi'
VITE_ONLYOFFICE_HOST = 'http://myvuetest.net/onlyoffice' VITE_ONLYOFFICE_HOST = 'http://myvuetest.net/onlyoffice'
VITE_DEFAULT_AI_AGENT = '5bd9b0e9-d3f4-4089-670a-880009e925a8' VITE_DEFAULT_AI_AGENT = '5bd9b0e9-d3f4-4089-670a-880009e925a8'
#流程制度
VITE_REGUL_AI_AGENT = 'e3be1378-3915-4e5c-b526-9f5447df39ea'

2
.env.production

@ -8,3 +8,5 @@ VITE_APP_SJZT_URL = 'http://120.224.6.6:29911/prod-api'
VITE_OFFICE_HOST='https://gyhlw.hxgk.group/kkapi' VITE_OFFICE_HOST='https://gyhlw.hxgk.group/kkapi'
VITE_ONLYOFFICE_HOST = 'https://gyhlw.hxgk.group/onlyoffice' VITE_ONLYOFFICE_HOST = 'https://gyhlw.hxgk.group/onlyoffice'
VITE_DEFAULT_AI_AGENT = '74938263-ffe5-43c5-90af-25e62d34a51f' VITE_DEFAULT_AI_AGENT = '74938263-ffe5-43c5-90af-25e62d34a51f'
#流程制度
VITE_REGUL_AI_AGENT = 'e3be1378-3915-4e5c-b526-9f5447df39ea'

292
src/components/DesignForm/public/form/aiassist.vue

@ -7,17 +7,24 @@
import { doAiChat,aiChatData} from "@/api/doc/space" import { doAiChat,aiChatData} from "@/api/doc/space"
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";
import { VueMarkdown } from '@crazydos/vue-markdown'
import rehypeRaw from 'rehype-raw'
// //
const userStore = useUserStore(); const userStore = useUserStore();
const userid="p0"+userStore.userInfoCont.userId; const userid="p0"+userStore.userInfoCont.userId;
const regulaKey=import.meta.env.VITE_REGUL_AI_AGENT;
const baseURL=import.meta.env.VITE_APP_BASE_API const baseURL=import.meta.env.VITE_APP_BASE_API
const regulaURL =`${baseURL}/aibot/agents/${regulaKey}/chat`
const conversation=ref("") //uuid const conversation=ref("") //uuid
const controller = ref<AbortController | null>(null) const controller = ref<AbortController | null>(null)
const interact_msg=ref<{ask:boolean,think:string,content:string}[]>([]) const interact_msg=ref<{ask:boolean,think:string,content:string}[]>([{ask:false,think:"是",content:`你好!我是你的AI助手,
你可以直接向我提问或者编辑表单我会自动为你提供相关信息`}])
//
const inputText = ref('');
const respMsg=ref("") //markdown
// //
interface message{ interface message{
@ -37,29 +44,34 @@ interface chatRecord{
defineExpose({onSendParamToAI}) defineExpose({onSendParamToAI})
async function onSendParamToAI(arr:Array<{ uuids: string[]; params: { [key: string]: any } }>){ async function onSendParamToAI(arr:Array<{ uuids: string[]; params: { [key: string]: any } }>){
interact_msg.value=[] //interact_msg.value=[]
for (let ele of arr){ for (let ele of arr){
//interact_msg.value.unshift({ask:true,think:"", content:"AI"}) //interact_msg.value.unshift({ask:true,think:"", content:"AI"})
for (let uid of ele.uuids){ for (let uid of ele.uuids){
await doRequest(userid,uid,ele.params) let para={
inputs: {
"checkType":"travel",
"checkInfo":JSON.stringify(ele.params)
},
response_mode:"streaming",
user:userid,//base64
}
//
interact_msg.value.push({ask:true,think:"", content:JSON.stringify(para)})
await doRequest(`${baseURL}/aibot/assisted/${uid}/workflow`,para)
} }
} }
} }
async function doRequest(_user:string,uuid:string,param:any){ async function doRequest(furl:string,param:any){
let mRespMsg="" let mRespMsg=""
const params={
"checkType":"travel",
"checkInfo":JSON.stringify(param)
}
controller.value = new AbortController(); controller.value = new AbortController();
try{ try{
const res= await doAiChat(`${baseURL}/aibot/assisted/${uuid}/workflow`,{ const res= await doAiChat(
inputs: params, furl,
response_mode:"streaming", param,
user:_user,//base64 controller.value.signal
},controller.value.signal
) )
if (!res.ok) { if (!res.ok) {
@ -86,6 +98,9 @@ async function doRequest(_user:string,uuid:string,param:any){
if(json.event==="text_chunk"){ if(json.event==="text_chunk"){
//conversation.value=json.conversation_id //conversation.value=json.conversation_id
mRespMsg+=json.data.text mRespMsg+=json.data.text
}else if(json.event==="message"){
respMsg.value+=json.answer
mRespMsg+=json.answer
} }
} }
} }
@ -95,19 +110,18 @@ async function doRequest(_user:string,uuid:string,param:any){
console.log('用户手动中断') console.log('用户手动中断')
} }
} }
respMsg.value=""
interact_msg.value.unshift({ask:true,think:"", content:JSON.stringify(param)})
const arr=mRespMsg.split("</think>") const arr=mRespMsg.split("</think>")
if(arr.length===1){ if(arr.length===1){
interact_msg.value.unshift({ask:false,think:"",content:arr[0]}) interact_msg.value.push({ask:false,think:"",content:arr[0]})
}else{ }else{
// //
let st = arr[1].trim().match(/({.*})/s) let st = arr[1].trim().match(/({.*})/s)
if (st){ if (st){
let res= JSON.parse(st[1]) let res= JSON.parse(st[1])
interact_msg.value.unshift({ask:false,think:res.success,content:res.reason}) interact_msg.value.push({ask:false,think:res.success,content:res.reason})
}else{ }else{
interact_msg.value.unshift({ask:false,think:arr[0],content:arr[1]}) interact_msg.value.push({ask:false,think:arr[0],content:arr[1]})
} }
} }
} }
@ -118,50 +132,242 @@ function resetContext(){
//props.closefunc() //props.closefunc()
} }
//
const sendMessage = () => {
const content = inputText.value.trim();
if (!content) return;
//
interact_msg.value.push({ ask: true,think:"", content });
const params={
inputs: {"onlineSearch":"否",
"useDataset":"是",
"queryUrl":""},
query:content,
response_mode:"streaming",
conversation_id:conversation.value,
user:userid
}
doRequest(regulaURL,params)
//
inputText.value = '';
};
// //
// onMounted(() => { // onMounted(() => {
// }); // });
</script> </script>
<template> <template>
<div :style="{backgroundColor:'#f3f3f3'}"> <div class="chat-container">
<div class="reply_area" > <!-- 头部 -->
<template v-for="msg of interact_msg"> <div class="chat-header">
<div v-if="msg.ask" class="t_ask" >{{ msg.content }}</div> <span class="header-icon">🤖</span>
<div v-else class="t_resp" :class="{merr:msg.think==false}"> AI 助手
</div>
<!-- 消息区域 -->
<div class="reply-area">
<template v-for="(msg, index) in interact_msg" :key="index">
<!-- 用户消息 -->
<div v-if="msg.ask" class="message message-ask">
{{ msg.content }} {{ msg.content }}
<!-- <VueMarkdown :markdown="msg.content"></VueMarkdown> --> </div>
<!-- AI 回复 -->
<div v-else class="message message-resp" :class="{ 'message-error': msg.think == false }">
<VueMarkdown :markdown="msg.content" :rehype-plugins="[rehypeRaw]" ></VueMarkdown>
</div> </div>
</template> </template>
<div v-show="respMsg" class="message message-resp">
<VueMarkdown :markdown="respMsg" :rehype-plugins="[rehypeRaw]" class="t_resp"></VueMarkdown>
</div>
</div>
<!-- 底部输入区域 -->
<div class="input-area">
<input
v-model="inputText"
placeholder="输入您的问题..."
class="input-box"
type="text"
/>
<button
@click="sendMessage"
:disabled="!inputText.trim()"
class="send-button"
>
<span>发送</span>
</button>
</div> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.reply_area{ .chat-container {
width: 260px; width: 360px;
background: white; background: #ffffff;
border-radius: 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12);
display: flex;
flex-direction: column;
overflow: hidden;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
/* 头部样式 */
.chat-header {
background: linear-gradient(180deg, #469edf, #bbdefb);
color: white;
padding: 8px 20px;
font-size: 18px;
font-weight: 600;
text-align: center;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.header-icon {
margin-right: 8px;
font-size: 20px;
}
/* 消息区域 */
.reply-area {
flex: 1;
padding: 20px;
overflow-y: auto; overflow-y: auto;
background: #f8f9ff;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-wrap:anywhere; gap: 12px;
}
/* 消息气泡 */
.message {
max-width: 85%;
padding: 12px 16px;
border-radius: 18px;
line-height: 1.5;
font-size: 14px;
word-wrap: break-word;
animation: fadeIn 0.3s ease-out;
}
/* 用户消息 - 右对齐 */
.message-ask {
align-self: flex-end;
background: linear-gradient(135deg, #4b6cb7 0%, #3a56a0 100%);
color: white;
border-bottom-right-radius: 6px;
box-shadow: 0 4px 12px rgba(75, 108, 183, 0.25);
}
/* AI 回复 - 左对齐 */
.message-resp {
align-self: flex-start;
background: #e8f5e9;
color: #2e7d32;
border-bottom-left-radius: 6px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
}
/* 错误状态 */
.message-error {
background: #ffebee;
color: #c62828;
}
/* 底部输入区域 */
.input-area {
display: flex;
padding: 16px;
background: white;
border-top: 1px solid #e8eaf6;
gap: 10px;
}
/* 输入框 */
.input-box {
flex: 1;
padding: 12px 18px;
border: 1px solid #e0e0e0;
border-radius: 24px;
outline: none;
font-size: 14px;
transition: all 0.3s ease;
background: #f5f7ff;
}
.input-box:focus {
border-color: #4b6cb7;
background: white;
box-shadow: 0 0 0 3px rgba(75, 108, 183, 0.15);
} }
.t_ask{ /* 发送按钮 */
margin: 5px; .send-button {
align-self: end; padding: 12px 22px;
background-color: rgb(188 211 241); background: linear-gradient(135deg, #4b6cb7 0%, #3a56a0 100%);
border-radius:10px; color: white;
border: none;
border-radius: 24px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 64px;
} }
.t_resp{
margin: 5px; .send-button:hover:not(:disabled) {
font-size:14px; transform: translateY(-2px);
align-self: start; box-shadow: 0 6px 16px rgba(75, 108, 183, 0.35);
color: black; filter: brightness(1.05);
background-color: rgb(222, 243, 222);
} }
.merr{
background-color: rgb(253 176 211); .send-button:active:not(:disabled) {
transform: translateY(0);
}
.send-button:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
/* 动画效果 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 滚动条美化 */
.reply-area::-webkit-scrollbar {
width: 6px;
}
.reply-area::-webkit-scrollbar-track {
background: #f1f4ff;
}
.reply-area::-webkit-scrollbar-thumb {
background: #4b6cb7;
border-radius: 3px;
}
.reply-area::-webkit-scrollbar-thumb:hover {
background: #3a56a0;
} }
</style> </style>

Loading…
Cancel
Save