feat: Consciousness recognition node

v3.2
wangdan-fit2cloud 2025-09-18 14:55:03 +08:00
parent 16ade76446
commit 7af880f1db
9 changed files with 42 additions and 40 deletions

View File

@ -173,7 +173,7 @@
v-if=" v-if="
data.type == WorkflowType.AiChat || data.type == WorkflowType.AiChat ||
data.type == WorkflowType.Question || data.type == WorkflowType.Question ||
data.type == WorkflowType.Application data.type == WorkflowType.Application || data.type == WorkflowType.IntentNode
" "
> >
<div class="card-never border-r-6" v-if="data.type !== WorkflowType.Application"> <div class="card-never border-r-6" v-if="data.type !== WorkflowType.Application">

View File

@ -329,6 +329,7 @@ export default {
}, },
intentNode: { intentNode: {
label: 'IntentNode', label: 'IntentNode',
text: 'Match user questions with user-defined intent classifications',
other: 'other', other: 'other',
placeholder: 'Please choose a classification option', placeholder: 'Please choose a classification option',
classify: { classify: {

View File

@ -141,6 +141,7 @@ export default {
continue: 'Continue Generating', continue: 'Continue Generating',
replace: 'Replace', replace: 'Replace',
exit: 'Are you sure you want to exit and discard the AI-generated content?', exit: 'Are you sure you want to exit and discard the AI-generated content?',
loading: 'Generating...',
}, },
dialog: { dialog: {
addKnowledge: 'Add Related Knowledge', addKnowledge: 'Add Related Knowledge',

View File

@ -329,6 +329,7 @@ export default {
}, },
intentNode: { intentNode: {
label: '意图识别', label: '意图识别',
text: '将用户问题与用户预设的意图分类进行匹配',
other: '其他', other: '其他',
placeholder: '请选择分类项', placeholder: '请选择分类项',
classify: { classify: {

View File

@ -133,6 +133,7 @@ export default {
continue: '继续生成', continue: '继续生成',
replace: '替换', replace: '替换',
exit: '确认退出并舍弃 AI 生成的内容吗?', exit: '确认退出并舍弃 AI 生成的内容吗?',
loading: '生成中...',
}, },
dialog: { dialog: {
addKnowledge: '添加关联知识库', addKnowledge: '添加关联知识库',

View File

@ -322,6 +322,7 @@ export default {
}, },
intentNode: { intentNode: {
label: '意圖識別', label: '意圖識別',
text: '將用戶問題與用戶預設的意圖分類進行匹配',
other: '其他', other: '其他',
placeholder: '請選擇分類項', placeholder: '請選擇分類項',
classify: { classify: {

View File

@ -132,6 +132,7 @@ export default {
continue: '繼續生成', continue: '繼續生成',
replace: '替換', replace: '替換',
exit: '確認退出並捨棄 AI 生成的內容嗎?', exit: '確認退出並捨棄 AI 生成的內容嗎?',
loading: '生成中...',
}, },
dialog: { dialog: {
addKnowledge: '新增關聯知識庫', addKnowledge: '新增關聯知識庫',

View File

@ -24,7 +24,7 @@
</div> </div>
<p v-else-if="loading" shadow="always" style="margin: 0.5rem 0"> <p v-else-if="loading" shadow="always" style="margin: 0.5rem 0">
<el-icon class="is-loading color-primary mr-4"><Loading /></el-icon> <el-icon class="is-loading color-primary mr-4"><Loading /></el-icon>
{{ $t('chat.tip.answerLoading') }} {{ $t('views.application.generateDialog.loading') }}
<span class="dotting"></span> <span class="dotting"></span>
</p> </p>
<p v-else class="flex align-center"> <p v-else class="flex align-center">
@ -33,11 +33,18 @@
</p> </p>
</el-scrollbar> </el-scrollbar>
<div v-if="answer && !loading && !isStreaming && !showContinueButton"> <div v-if="answer && !loading && !isStreaming && !showContinueButton">
<el-button type="primary" @click="() => emit('replace', answer)"> {{ $t('views.application.generateDialog.replace') }} </el-button> <el-button type="primary" @click="() => emit('replace', answer)">
{{ $t('views.application.generateDialog.replace') }}
</el-button>
<el-button @click="reAnswerClick" :disabled="!answer || loading" :loading="loading"> <el-button @click="reAnswerClick" :disabled="!answer || loading" :loading="loading">
{{ $t('views.application.generateDialog.remake') }} {{ $t('views.application.generateDialog.remake') }}
</el-button> </el-button>
</div> </div>
<div class="mt-8" v-else>
<el-button type="primary" v-if="showContinueButton" @click="continueStreaming" link>
{{ $t('views.application.generateDialog.continue') }}
</el-button>
</div>
</div> </div>
<!-- 文本输入框 --> <!-- 文本输入框 -->
@ -49,12 +56,7 @@
{{ $t('views.application.generateDialog.stop') }} {{ $t('views.application.generateDialog.stop') }}
</el-button> </el-button>
</div> </div>
<div v-if="showContinueButton" class="text-center mb-8">
<el-button class="border-primary video-stop-button" @click="continueStreaming">
<app-icon iconName="app-video-stop" class="mr-8"></app-icon>
{{ $t('views.application.generateDialog.continue') }}
</el-button>
</div>
<div class="operate-textarea"> <div class="operate-textarea">
<el-input <el-input
ref="quickInputRef" ref="quickInputRef"
@ -75,7 +77,11 @@
:disabled="!inputValue.trim() || loading || isStreaming" :disabled="!inputValue.trim() || loading || isStreaming"
@click="handleSubmit" @click="handleSubmit"
> >
<img v-show="!inputValue.trim() || loading || isStreaming" src="@/assets/icon_send.svg" alt="" /> <img
v-show="!inputValue.trim() || loading || isStreaming"
src="@/assets/icon_send.svg"
alt=""
/>
<SendIcon v-show="inputValue.trim() && !loading && !isStreaming" /> <SendIcon v-show="inputValue.trim() && !loading && !isStreaming" />
</el-button> </el-button>
</div> </div>
@ -88,7 +94,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onUnmounted,reactive, ref, nextTick, watch } from 'vue' import { computed, onUnmounted, reactive, ref, nextTick, watch } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { MsgConfirm } from '@/utils/message' import { MsgConfirm } from '@/utils/message'
import { t } from '@/locales' import { t } from '@/locales'
@ -161,7 +167,6 @@ const currentDisplayIndex = ref<number>(0) // 当前显示到的字符位置
let streamTimer: number | null = null // let streamTimer: number | null = null //
const isOutputComplete = ref<boolean>(false) const isOutputComplete = ref<boolean>(false)
// //
const startStreamingOutput = () => { const startStreamingOutput = () => {
if (streamTimer) { if (streamTimer) {
@ -182,9 +187,9 @@ const startStreamingOutput = () => {
if (currentAnswer && currentAnswer.role === 'ai') { if (currentAnswer && currentAnswer.role === 'ai') {
currentAnswer.content = fullContent.value.substring(0, currentDisplayIndex.value) currentAnswer.content = fullContent.value.substring(0, currentDisplayIndex.value)
} }
} else if (loading.value === false && currentDisplayIndex.value >= fullContent.value.length) { } else if (loading.value === false && currentDisplayIndex.value >= fullContent.value.length) {
stopStreaming() stopStreaming()
} }
}, 50) // 50ms }, 50) // 50ms
} }
@ -195,7 +200,7 @@ const stopStreaming = () => {
streamTimer = null streamTimer = null
} }
isStreaming.value = false isStreaming.value = false
isPaused.value = false isPaused.value = false
loading.value = false loading.value = false
isOutputComplete.value = true isOutputComplete.value = true
} }
@ -204,7 +209,6 @@ const showStopButton = computed(() => {
return isStreaming.value return isStreaming.value
}) })
// //
const pauseStreaming = () => { const pauseStreaming = () => {
isPaused.value = true isPaused.value = true
@ -218,7 +222,6 @@ const continueStreaming = () => {
} }
} }
/** /**
* 获取一个递归函数,处理流式数据 * 获取一个递归函数,处理流式数据
* @param chat 每一条对话记录 * @param chat 每一条对话记录
@ -227,8 +230,8 @@ const continueStreaming = () => {
*/ */
const getWrite = (reader: any) => { const getWrite = (reader: any) => {
let tempResult = '' let tempResult = ''
const middleAnswer = reactive({ content: '', role: 'ai' }) const middleAnswer = reactive({ content: '', role: 'ai' })
chatMessages.value.push(middleAnswer ) chatMessages.value.push(middleAnswer)
// //
fullContent.value = '' fullContent.value = ''
@ -245,7 +248,7 @@ const getWrite = (reader: any) => {
const write_stream = ({ done, value }: { done: boolean; value: any }) => { const write_stream = ({ done, value }: { done: boolean; value: any }) => {
try { try {
if (done) { if (done) {
// //
loading.value = false loading.value = false
return return
} }
@ -302,10 +305,11 @@ const answer = computed(() => {
// //
const showContinueButton = computed(() => { const showContinueButton = computed(() => {
return !isStreaming.value && isPaused.value && currentDisplayIndex.value < fullContent.value.length return (
!isStreaming.value && isPaused.value && currentDisplayIndex.value < fullContent.value.length
)
}) })
function generatePrompt(inputValue: any) { function generatePrompt(inputValue: any) {
loading.value = true loading.value = true
const workspaceId = user.getWorkspaceId() || 'default' const workspaceId = user.getWorkspaceId() || 'default'
@ -360,12 +364,10 @@ const handleSubmit = (event?: any) => {
if (!originalUserInput.value) { if (!originalUserInput.value) {
originalUserInput.value = inputValue.value originalUserInput.value = inputValue.value
} }
if (inputValue.value) { if (inputValue.value) {
generatePrompt(inputValue.value) generatePrompt(inputValue.value)
inputValue.value = '' inputValue.value = ''
} }
} else { } else {
// ctrl/shift/cmd/opt +enter // ctrl/shift/cmd/opt +enter
insertNewlineAtCursor(event) insertNewlineAtCursor(event)
@ -415,17 +417,12 @@ const handleScroll = () => {
} }
const handleDialogClose = (done: () => void) => { const handleDialogClose = (done: () => void) => {
// //
MsgConfirm( MsgConfirm(t('common.tip'), t('views.application.generateDialog.exit'), {
t('common.tip'), confirmButtonText: t('common.confirm'),
t('views.application.generateDialog.exit'), cancelButtonText: t('common.cancel'),
{ distinguishCancelAndClose: true,
confirmButtonText: t('common.confirm'), })
cancelButtonText: t('common.cancel'),
distinguishCancelAndClose: true,
}
)
.then(() => { .then(() => {
// //
stopStreaming() stopStreaming()
@ -437,8 +434,7 @@ const handleDialogClose = (done: () => void) => {
}) })
.catch(() => { .catch(() => {
// //
} })
)
} }
// //

View File

@ -362,7 +362,7 @@ export const toolNode = {
export const intentNode = { export const intentNode = {
type: WorkflowType.IntentNode, type: WorkflowType.IntentNode,
text: t('views.applicationWorkflow.nodes.intentNode.label'), text: t('views.applicationWorkflow.nodes.intentNode.text'),
label: t('views.applicationWorkflow.nodes.intentNode.label'), label: t('views.applicationWorkflow.nodes.intentNode.label'),
height: 260, height: 260,
properties: { properties: {