factory_web/src/views/home/llm_chat.vue

151 lines
3.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="chat-window">
<div class="messages" ref="messageList">
<div v-for="(msg, index) in messages" :key="index" :class="msg.role">
<strong>{{ msg.role === 'user' ? '你' : '助手' }}</strong>
<span>{{ msg.content }}</span>
</div>
</div>
<div class="input-box">
<textarea
v-model="input"
@keydown.enter.prevent="handleSend"
placeholder="请输入..."
/>
<button @click="handleSend" :disabled="loading">发送</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
messages: [],
input: '',
loading: false,
eventSource: null,
conversationId: '3841325303385792512'
};
},
watch: {
conversationId: {
immediate: true,
handler() {
this.messages = []; // 如果你有加载历史消息,可以在此请求
this.closeStream();
}
}
},
methods: {
async handleSend() {
if (!this.input.trim()) return;
this.loading = true;
// 添加用户消息
const userMessage = { role: 'user', content: this.input };
this.messages.push(userMessage);
// 添加助手消息框架
const assistantMessage = { role: 'assistant', content: '' };
this.messages.push(assistantMessage);
const message = encodeURIComponent(this.input);
const url = `/api/ichat/message/completion/`;
const payload = {
conversation: this.conversationId,
message: message
}
this.input = '';
this.scrollToBottom();
try {
const response = await fetch('/api/ichat/message/completion/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
const result = await response.json();
if (response.ok) {
// 更新 assistant 内容
assistantMessage.content = result.answer || '';
// 保存 conversation_id首次发送消息时获取
if (!this.conversationId && result.conversation_id) {
this.conversationId = result.conversation_id;
}
this.scrollToBottom();
} else {
throw new Error(result.detail || '请求失败');
}
} catch (err) {
console.error('发送失败:', err);
assistantMessage.content = '[助手响应失败,请稍后再试]';
} finally {
this.loading = false;
}
},
scrollToBottom() {
this.$nextTick(() => {
const el = this.$refs.messageList;
if (el) el.scrollTop = el.scrollHeight;
});
},
closeStream() {
if (this.eventSource) {
this.eventSource.close();
this.eventSource = null;
}
}
},
beforeUnmount() {
this.closeStream();
}
};
</script>
<style scoped>
.chat-window {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
padding: 10px;
box-sizing: border-box;
}
.messages {
flex: 1;
overflow-y: auto;
padding-right: 10px;
}
.user, .assistant {
margin-bottom: 10px;
white-space: pre-wrap;
}
.input-box {
display: flex;
margin-top: 10px;
}
textarea {
flex: 1;
resize: none;
height: 60px;
padding: 8px;
font-size: 14px;
}
button {
margin-left: 10px;
padding: 0 16px;
}
</style>