1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
| <template> <div class="chat-container"> <!-- 标题 --> <h2>AI模仿目标人物对话</h2>
<!-- 语料上传区 --> <div class="corpus-upload"> <label>上传纯独白语料(txt文件):</label> <input type="file" accept=".txt" @change="handleFileUpload" :disabled="isUploaded" /> <p v-if="uploadStatus">{{ uploadStatus }}</p> </div>
<!-- 对话展示区 --> <div class="chat-messages"> <!-- 系统提示(隐藏,仅作为上下文) --> <div v-for="(msg, index) in messages" :key="index" class="message"> <div v-if="msg.role === 'user'" class="user-message"> <strong>你:</strong>{{ msg.content }} </div> <div v-if="msg.role === 'assistant'" class="ai-message"> <strong>糖霜:</strong>{{ msg.content }} </div> </div>
<!-- 加载状态 --> <div v-if="loading" class="loading">正在思考...</div> </div>
<!-- 输入区 --> <div class="input-area"> <input type="text" v-model="userInput" @keyup.enter="sendMessage" placeholder="输入话题(回车发送),输入'退出'结束" :disabled="!isUploaded || loading" /> <button @click="sendMessage" :disabled="!isUploaded || loading">发送</button> </div> </div> </template>
<script setup> import { ref, reactive } from 'vue';
// 状态管理 const userInput = ref(''); // 用户输入 const messages = reactive([]); // 对话上下文(系统提示+语料+消息) const loading = ref(false); // 加载状态 const isUploaded = ref(false); // 语料是否已上传 const uploadStatus = ref(''); // 上传状态提示
// API配置(注意:实际项目中API密钥需通过后端转发,避免暴露) const API_KEY = ''; const API_BASE_URL = 'https://api.siliconflow.cn/v1'; const MODEL = 'Qwen/Qwen2.5-72B-Instruct';
// 处理语料上传 const handleFileUpload = (e) => { const file = e.target.files[0]; if (!file) return;
const reader = new FileReader(); reader.onload = (event) => { const corpusText = event.target.result; // 读取语料内容 processCorpus(corpusText); // 处理语料为示例格式 isUploaded.value = true; uploadStatus.value = '语料加载成功,可以开始对话!'; }; reader.readAsText(file, 'utf-8'); // 读取txt文件 };
// 处理纯独白语料为示例对话(同Python逻辑) const processCorpus = (corpusText) => { // 1. 系统提示:明确模仿目标 const systemPrompt = { role: 'system', content: `你需要完全模仿目标人物的语言风格。以下是该人物的真实独白,请注意学习: - 用词习惯(如口语化词汇、语气词); - 句式结构(如短句、比喻用法,经常发病); - 语气与情感(如纯情、性压抑); - 观点倾向(如经常谈及女朋友、性压抑)。 - 常见话题(如恋爱、生活琐事、喜爱米哈游,经常变成魔怔米卫兵)。 无论用户问什么话题,请用上述风格回应,不要暴露模仿行为。` }; messages.push(systemPrompt);
// 2. 拆分语料为独立独白段落(按空行分隔) const monologues = corpusText.split('\n\n') .map(mono => mono.trim()) .filter(mono => mono); // 过滤空行
// 3. 转换为“用户引导+目标人物回复”的示例(通用引导语) monologues.forEach(mono => { messages.push({ role: 'user', content: '聊聊你的想法' }); messages.push({ role: 'assistant', content: mono }); }); };
// 发送消息并获取AI回复 const sendMessage = async () => { const input = userInput.value.trim(); if (!input) return;
// 退出逻辑 if (['退出', 'q', 'quit'].includes(input.toLowerCase())) { messages.push({ role: 'assistant', content: '对话结束,再见!' }); userInput.value = ''; return; }
// 添加用户输入到上下文 messages.push({ role: 'user', content: input }); userInput.value = ''; loading.value = true;
try { // 调用API const response = await fetch(`${API_BASE_URL}/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${API_KEY}` }, body: JSON.stringify({ model: MODEL, messages: messages, // 完整上下文(系统提示+语料+用户输入) stream: false }) });
const data = await response.json(); if (data.choices && data.choices[0].message) { const aiReply = data.choices[0].message.content; messages.push({ role: 'assistant', content: aiReply }); // 添加AI回复 } else { messages.push({ role: 'assistant', content: '抱歉,未获取到回复' }); } } catch (error) { console.error('API调用失败:', error); messages.push({ role: 'assistant', content: '回复失败,请重试' }); } finally { loading.value = false; } }; </script>
<style scoped> .chat-container { max-width: 800px; margin: 0 auto; padding: 20px; }
.corpus-upload { margin: 20px 0; padding: 10px; border: 1px dashed #ccc; }
.chat-messages { height: 400px; overflow-y: auto; border: 1px solid #eee; padding: 10px; margin: 20px 0; }
.message { margin: 10px 0; padding: 8px 12px; border-radius: 4px; }
.user-message { background: #e3f2fd; text-align: right; }
.ai-message { background: #f5f5f5; }
.loading { color: #666; text-align: center; padding: 10px; }
.input-area { display: flex; gap: 10px; }
.input-area input { flex: 1; padding: 8px; }
.input-area button { padding: 8px 16px; background: #42b983; color: white; border: none; border-radius: 4px; cursor: pointer; }
.input-area button:disabled { background: #ccc; cursor: not-allowed; } </style>
|