index.js 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. "use strict";
  2. const common_vendor = require("../../common/vendor.js");
  3. const pages_api_ai = require("../api/ai.js");
  4. const pages_api_config = require("../api/config.js");
  5. const common_assets = require("../../common/assets.js");
  6. const _sfc_main = {
  7. data() {
  8. return {
  9. inputMessage: "",
  10. messages: [],
  11. isLoading: false,
  12. scrollTop: 0,
  13. maxLength: 300,
  14. userId: "user_123",
  15. // 模拟用户ID
  16. sessionId: "",
  17. eventSource: null,
  18. // SSE连接对象
  19. pollingInterval: null,
  20. // 轮询定时器
  21. isConnected: false,
  22. // SSE连接状态
  23. isDevelopment: true,
  24. // 控制测试按钮显示
  25. // 快捷问题
  26. quickQuestions: {
  27. "重庆深度5日游": {
  28. destination: "重庆",
  29. days: 5,
  30. budget: 3e3,
  31. preferences: ["景点", "美食", "文化"],
  32. transportation: "公共交通"
  33. },
  34. "推荐几个热门旅游城市": {
  35. requestType: "recommendation",
  36. preferences: ["热门", "旅游城市"]
  37. },
  38. "旅游注意事项有哪些": {
  39. requestType: "travelTips",
  40. preferences: ["安全", "注意事项"]
  41. }
  42. }
  43. };
  44. },
  45. computed: {
  46. // 用于显示除欢迎消息外的其他消息
  47. displayMessages() {
  48. if (this.messages.length === 0 || this.messages.length === 1 && this.messages[0].type === "ai") {
  49. return [];
  50. }
  51. if (this.messages.length > 1 && this.messages[0].type === "ai") {
  52. return this.messages.slice(1);
  53. }
  54. return this.messages;
  55. }
  56. },
  57. onLoad(options) {
  58. if (typeof __wxConfig !== "undefined") {
  59. this.isDevelopment = __wxConfig.envVersion === "develop" || __wxConfig.envVersion === "trial";
  60. }
  61. try {
  62. const savedMessages = common_vendor.index.getStorageSync("chat_messages");
  63. if (savedMessages) {
  64. this.messages = JSON.parse(savedMessages);
  65. } else {
  66. this.addMessage("您好,欢迎遇见Gooh旅记旅行规划师!我将为您设计专属行程,解答旅途中的各类问题,让旅行无忧。有任何想法,请随时告诉我~", "ai");
  67. }
  68. } catch (e) {
  69. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:296", "加载消息历史失败:", e);
  70. this.addMessage("您好,欢迎遇见Gooh旅记旅行规划师!我将为您设计专属行程,解答旅途中的各类问题,让旅行无忧。有任何想法,请随时告诉我~", "ai");
  71. }
  72. this.startSession();
  73. },
  74. onUnload() {
  75. try {
  76. common_vendor.index.setStorageSync("chat_messages", JSON.stringify(this.messages));
  77. } catch (e) {
  78. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:309", "保存消息历史失败:", e);
  79. }
  80. if (this.eventSource) {
  81. this.eventSource.close();
  82. }
  83. this.stopPolling();
  84. },
  85. methods: {
  86. // 返回旅游规划页面
  87. goBack() {
  88. common_vendor.index.switchTab({
  89. url: "/pages/planning/index"
  90. });
  91. },
  92. // 创建新对话
  93. async createNewChat() {
  94. if (this.eventSource) {
  95. try {
  96. this.eventSource.close();
  97. this.eventSource = null;
  98. } catch (e) {
  99. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:337", "关闭SSE连接失败:", e);
  100. }
  101. }
  102. if (this.pollingInterval) {
  103. clearInterval(this.pollingInterval);
  104. this.pollingInterval = null;
  105. }
  106. this.messages = [];
  107. this.inputMessage = "";
  108. this.sessionId = "";
  109. await this.startSession();
  110. common_vendor.index.showToast({
  111. title: "已创建新对话",
  112. icon: "none"
  113. });
  114. },
  115. // 开始新会话
  116. async startSession() {
  117. try {
  118. const response = await pages_api_ai.startAISession();
  119. if (response && response.code === 200 && response.sessionId) {
  120. this.sessionId = response.sessionId;
  121. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:368", "会话创建成功,sessionId:", this.sessionId);
  122. if (response.msg && this.messages.length === 0) {
  123. this.addMessage(response.msg, "ai");
  124. }
  125. if (this.sessionId) {
  126. await this.setupWebSocket();
  127. } else {
  128. throw new Error("未获取到有效的sessionId");
  129. }
  130. } else {
  131. throw new Error((response == null ? void 0 : response.msg) || "创建会话失败");
  132. }
  133. } catch (error) {
  134. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:386", "创建会话失败:", error);
  135. common_vendor.index.showToast({
  136. title: error.message || "连接失败,请重试",
  137. icon: "none"
  138. });
  139. }
  140. },
  141. // 设置SSE连接
  142. async setupWebSocket() {
  143. if (!this.sessionId) {
  144. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:397", "无法建立SSE连接:sessionId不存在");
  145. return;
  146. }
  147. const url = pages_api_ai.getSSEUrl(this.sessionId);
  148. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:403", "尝试连接SSE:", url);
  149. if (this.eventSource) {
  150. try {
  151. this.eventSource.close();
  152. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:409", "已关闭旧的SSE连接");
  153. } catch (e) {
  154. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:411", "关闭旧SSE连接失败:", e);
  155. }
  156. this.eventSource = null;
  157. }
  158. return new Promise((resolve, reject) => {
  159. try {
  160. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:418", "开始创建SSE连接...");
  161. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:465", "在小程序环境下使用替代方法连接SSE");
  162. this.isConnected = true;
  163. this.setupPolling();
  164. resolve();
  165. setTimeout(() => {
  166. if (!this.isConnected) {
  167. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:476", "SSE连接超时");
  168. reject(new Error("SSE连接超时"));
  169. }
  170. }, 1e4);
  171. } catch (error) {
  172. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:488", "创建SSE连接时发生错误:", error);
  173. reject(error);
  174. }
  175. });
  176. },
  177. // 处理WebSocket消息
  178. handleSocketMessage(res) {
  179. try {
  180. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:497", "开始处理WebSocket消息:", res.data);
  181. let data;
  182. try {
  183. data = JSON.parse(res.data);
  184. } catch (parseError) {
  185. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:505", "WebSocket数据不是JSON格式,尝试作为纯文本处理");
  186. data = {
  187. type: "message",
  188. content: res.data
  189. };
  190. }
  191. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:512", "处理后的WebSocket消息数据:", data);
  192. if (!data.type && data.content) {
  193. data.type = "message";
  194. }
  195. switch (data.type) {
  196. case "start":
  197. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:521", "收到start类型消息");
  198. if (this.messages.length > 0 && this.messages[this.messages.length - 1].type === "user") {
  199. this.addMessage("AI正在思考...", "ai", true);
  200. }
  201. this.setupPolling();
  202. break;
  203. case "message":
  204. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:532", "收到message类型消息:", data.content);
  205. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  206. this.messages.pop();
  207. }
  208. if (data.content) {
  209. const isPlanContent = this.checkIfTravelPlanContent(data.content);
  210. if (isPlanContent) {
  211. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:540", "检测到旅游行程信息,解析为卡片显示");
  212. const planData = this.parseTravelPlanContent(data.content);
  213. this.addTravelPlanMessage(planData);
  214. } else {
  215. let formattedContent = this.formatAIResponse(data.content);
  216. this.addMessage(formattedContent, "ai");
  217. }
  218. }
  219. break;
  220. case "done":
  221. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:550", "收到done类型消息");
  222. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  223. this.messages.pop();
  224. }
  225. this.isLoading = false;
  226. this.stopPolling();
  227. break;
  228. case "error":
  229. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:561", "收到error类型消息:", data.content);
  230. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  231. this.messages.pop();
  232. }
  233. this.addMessage(`错误: ${data.content}`, "ai");
  234. this.isLoading = false;
  235. common_vendor.index.showToast({
  236. title: "发生错误,请重试",
  237. icon: "none"
  238. });
  239. this.stopPolling();
  240. break;
  241. default:
  242. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:577", "收到未知类型消息:", data);
  243. if (data.content || typeof data === "string" && data) {
  244. const content = data.content || data;
  245. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  246. this.messages.pop();
  247. }
  248. let formattedContent = this.formatAIResponse(content);
  249. this.addMessage(formattedContent, "ai");
  250. }
  251. break;
  252. }
  253. } catch (error) {
  254. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:590", "处理WebSocket消息失败:", error);
  255. this.isLoading = false;
  256. try {
  257. let content = res.data;
  258. if (typeof content === "string" && content.length > 0) {
  259. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:598", "尝试直接显示原始消息内容");
  260. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  261. this.messages.pop();
  262. }
  263. let formattedContent = this.formatAIResponse(content);
  264. this.addMessage(formattedContent, "ai");
  265. return;
  266. }
  267. } catch (e) {
  268. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:607", "尝试直接显示消息内容也失败:", e);
  269. }
  270. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  271. this.messages.pop();
  272. }
  273. this.addMessage("消息处理出错,请重试", "ai");
  274. }
  275. },
  276. // 设置轮询 - 仅当需要时才开始轮询,有结果就停止
  277. setupPolling() {
  278. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:619", "设置轮询检查");
  279. this.stopPolling();
  280. this.pollingCount = 0;
  281. const maxPollingCount = 20;
  282. this.pollingInterval = setInterval(async () => {
  283. try {
  284. this.pollingCount++;
  285. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:631", `第${this.pollingCount}次轮询检查`);
  286. if (!this.isLoading || this.pollingCount > maxPollingCount) {
  287. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:635", "条件不满足,停止轮询:", {
  288. isLoading: this.isLoading,
  289. pollingCount: this.pollingCount
  290. });
  291. this.stopPolling();
  292. return;
  293. }
  294. const response = await pages_api_ai.getLastAIReply(this.sessionId);
  295. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:645", "轮询结果:", response);
  296. if (response && response.code === 200 && response.reply) {
  297. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:649", "轮询发现新消息");
  298. this.handleSocketMessage({
  299. data: JSON.stringify({
  300. type: "message",
  301. content: response.reply
  302. })
  303. });
  304. setTimeout(() => {
  305. this.handleSocketMessage({
  306. data: JSON.stringify({
  307. type: "done"
  308. })
  309. });
  310. }, 500);
  311. this.stopPolling();
  312. }
  313. } catch (err) {
  314. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:670", "轮询出错:", err);
  315. this.pollingErrorCount = (this.pollingErrorCount || 0) + 1;
  316. if (this.pollingErrorCount > 3) {
  317. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:675", "轮询错误太多,停止轮询");
  318. this.stopPolling();
  319. }
  320. }
  321. }, 3e3);
  322. },
  323. // 停止轮询
  324. stopPolling() {
  325. if (this.pollingInterval) {
  326. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:685", "停止轮询");
  327. clearInterval(this.pollingInterval);
  328. this.pollingInterval = null;
  329. this.pollingCount = 0;
  330. this.pollingErrorCount = 0;
  331. }
  332. },
  333. // 发送消息
  334. async sendMessage() {
  335. if (!this.inputMessage.trim() || this.isLoading)
  336. return;
  337. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:697", "准备发送消息:", this.inputMessage);
  338. if (!this.sessionId) {
  339. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:701", "sessionId不存在,先创建新会话");
  340. try {
  341. const response = await pages_api_ai.startAISession();
  342. if (response && response.code === 200 && response.sessionId) {
  343. this.sessionId = response.sessionId;
  344. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:706", "新会话创建成功,sessionId:", this.sessionId);
  345. } else {
  346. throw new Error("创建会话失败");
  347. }
  348. } catch (error) {
  349. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:711", "创建会话失败:", error);
  350. common_vendor.index.showToast({
  351. title: "创建会话失败,请重试",
  352. icon: "none"
  353. });
  354. return;
  355. }
  356. }
  357. if (this.inputMessage.length > this.maxLength) {
  358. common_vendor.index.showToast({
  359. title: `消息不能超过${this.maxLength}字`,
  360. icon: "none"
  361. });
  362. return;
  363. }
  364. const messageToSend = this.inputMessage.trim();
  365. this.inputMessage = "";
  366. this.addMessage(messageToSend, "user");
  367. this.isLoading = true;
  368. try {
  369. if (!this.isConnected) {
  370. common_vendor.index.__f__("warn", "at pages/ai-assistant/index.vue:741", "SSE未连接,尝试重新连接");
  371. await this.setupWebSocket();
  372. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:743", "SSE重连状态:", this.isConnected ? "已连接" : "未连接");
  373. }
  374. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:747", "发送消息到服务器:", {
  375. sessionId: this.sessionId,
  376. message: messageToSend
  377. });
  378. const response = await pages_api_ai.chatWithAI(this.sessionId, messageToSend);
  379. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:754", "服务器响应:", response);
  380. if (response.code === 200) {
  381. if (response.msg) {
  382. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:759", "服务器返回的消息:", response.msg);
  383. let formattedContent = this.formatAIResponse(response.msg);
  384. this.addMessage(formattedContent, "ai");
  385. } else {
  386. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:764", "服务器未返回消息,等待WebSocket响应");
  387. }
  388. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:769", "小程序环境中启动轮询检查");
  389. this.setupPolling();
  390. } else if (response.code === 404) {
  391. common_vendor.index.__f__("warn", "at pages/ai-assistant/index.vue:773", "会话不存在,尝试重新开始会话");
  392. const newSessionResponse = await pages_api_ai.startAISession();
  393. if (newSessionResponse && newSessionResponse.code === 200 && newSessionResponse.sessionId) {
  394. this.sessionId = newSessionResponse.sessionId;
  395. const retryResponse = await pages_api_ai.chatWithAI(this.sessionId, messageToSend);
  396. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:779", "重试响应:", retryResponse);
  397. if (retryResponse.code === 200) {
  398. if (retryResponse.msg) {
  399. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:784", "重试后服务器返回的消息:", retryResponse.msg);
  400. let formattedContent = this.formatAIResponse(retryResponse.msg);
  401. this.addMessage(formattedContent, "ai");
  402. }
  403. } else {
  404. throw new Error(retryResponse.msg || "重试发送失败");
  405. }
  406. } else {
  407. throw new Error("重新创建会话失败");
  408. }
  409. } else {
  410. throw new Error(response.msg || "发送失败");
  411. }
  412. } catch (error) {
  413. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:798", "发送消息失败:", error);
  414. common_vendor.index.showToast({
  415. title: error.message || "发送失败,请重试",
  416. icon: "none"
  417. });
  418. this.addMessage("抱歉,发送消息失败,请重试。", "ai");
  419. } finally {
  420. this.isLoading = false;
  421. }
  422. },
  423. // 处理快捷问题
  424. async handleQuickQuestion(question) {
  425. if (this.isLoading)
  426. return;
  427. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:813", "处理快捷问题:", question);
  428. this.isLoading = true;
  429. try {
  430. if (!this.sessionId) {
  431. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:819", "sessionId不存在,先创建新会话");
  432. try {
  433. const response2 = await pages_api_ai.startAISession();
  434. if (response2 && response2.code === 200 && response2.sessionId) {
  435. this.sessionId = response2.sessionId;
  436. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:824", "新会话创建成功,sessionId:", this.sessionId);
  437. } else {
  438. throw new Error("创建会话失败");
  439. }
  440. } catch (error) {
  441. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:829", "创建会话失败:", error);
  442. common_vendor.index.showToast({
  443. title: "创建会话失败,请重试",
  444. icon: "none"
  445. });
  446. this.isLoading = false;
  447. return;
  448. }
  449. }
  450. this.addMessage(question, "user");
  451. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:843", "发送快捷问题到服务器:", {
  452. sessionId: this.sessionId,
  453. message: question
  454. });
  455. const response = await pages_api_ai.chatWithAI(this.sessionId, question);
  456. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:849", "快捷问题服务器响应:", response);
  457. if (response.code === 200) {
  458. if (response.msg) {
  459. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:854", "服务器返回的消息:", response.msg);
  460. let formattedContent = this.formatAIResponse(response.msg);
  461. this.addMessage(formattedContent, "ai");
  462. } else {
  463. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:859", "服务器未返回消息,等待WebSocket响应");
  464. }
  465. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:864", "小程序环境中启动轮询检查");
  466. this.setupPolling();
  467. } else if (response.code === 404) {
  468. common_vendor.index.__f__("warn", "at pages/ai-assistant/index.vue:868", "会话不存在,尝试重新开始会话");
  469. this.addMessage("会话已过期,正在重新创建会话...", "system");
  470. const newSessionResponse = await pages_api_ai.startAISession();
  471. if (newSessionResponse && newSessionResponse.code === 200 && newSessionResponse.sessionId) {
  472. this.sessionId = newSessionResponse.sessionId;
  473. this.handleQuickQuestion(question);
  474. } else {
  475. throw new Error("重新创建会话失败");
  476. }
  477. } else {
  478. throw new Error(response.msg || "发送失败");
  479. }
  480. } catch (error) {
  481. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:883", "处理快捷问题失败:", error);
  482. common_vendor.index.showToast({
  483. title: error.message || "发送失败,请重试",
  484. icon: "none"
  485. });
  486. this.addMessage("抱歉,处理问题失败,请重试。", "ai");
  487. } finally {
  488. this.isLoading = false;
  489. }
  490. },
  491. // 添加消息
  492. addMessage(content, type, isThinking = false) {
  493. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:896", "添加新消息:", { content, type, isThinking });
  494. if (type === "user") {
  495. content = content.replace(/</g, "&lt;").replace(/>/g, "&gt;");
  496. }
  497. const message = {
  498. type,
  499. content,
  500. isThinking,
  501. timestamp: Date.now()
  502. };
  503. if (!isThinking && this.messages.length > 0) {
  504. const lastMessage = this.messages[this.messages.length - 1];
  505. if (lastMessage.isThinking && lastMessage.type === type) {
  506. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:914", "替换思考状态消息");
  507. this.messages.splice(-1, 1);
  508. }
  509. }
  510. this.messages.push(message);
  511. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:920", "当前消息列表:", this.messages);
  512. try {
  513. common_vendor.index.setStorageSync("chat_messages", JSON.stringify(this.messages));
  514. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:925", "消息已保存到本地存储");
  515. } catch (e) {
  516. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:927", "保存消息到本地存储失败:", e);
  517. }
  518. this.$nextTick(() => {
  519. this.scrollToBottom();
  520. });
  521. },
  522. // 滚动到底部
  523. scrollToBottom() {
  524. const query = common_vendor.index.createSelectorQuery().in(this);
  525. query.select(".message-list").boundingClientRect((data) => {
  526. if (data) {
  527. this.scrollTop = data.height;
  528. }
  529. }).exec();
  530. },
  531. // 格式化时间
  532. formatTime(timestamp) {
  533. if (!timestamp)
  534. return "";
  535. const date = new Date(timestamp);
  536. const hours = date.getHours().toString().padStart(2, "0");
  537. const minutes = date.getMinutes().toString().padStart(2, "0");
  538. return `${hours}:${minutes}`;
  539. },
  540. // 加载更多消息
  541. loadMoreMessages() {
  542. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:958", "加载更多消息");
  543. },
  544. // 格式化AI响应的方法增加日志
  545. formatAIResponse(content) {
  546. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:963", "开始格式化AI响应:", content);
  547. content = content.replace(/\d+e\d+;margin:[\s\d]+px[\s\d]+px[\s\d]+;"/g, '"');
  548. content = content.replace(/\n/g, "<br/>");
  549. content = content.replace(/最佳旅行时间[::]/g, '<div class="enhanced-title"><span class="title-icon">🕒</span><span class="title-text">最佳旅行时间:</span></div>');
  550. content = content.replace(/景点推荐[::]/g, '<div class="enhanced-title"><span class="title-icon">🏞️</span><span class="title-text">景点推荐:</span></div>');
  551. content = content.replace(/美食推荐[::]/g, '<div class="enhanced-title"><span class="title-icon">🍜</span><span class="title-text">美食推荐:</span></div>');
  552. content = content.replace(/住宿推荐[::]/g, '<div class="enhanced-title"><span class="title-icon">🏨</span><span class="title-text">住宿推荐:</span></div>');
  553. content = content.replace(/交通指南[::]/g, '<div class="enhanced-title"><span class="title-icon">🚗</span><span class="title-text">交通指南:</span></div>');
  554. content = content.replace(/旅游贴士[::]/g, '<div class="enhanced-title"><span class="title-icon">💡</span><span class="title-text">旅游贴士:</span></div>');
  555. content = content.replace(/费用预算[::]/g, '<div class="enhanced-title"><span class="title-icon">💰</span><span class="title-text">费用预算:</span></div>');
  556. content = content.replace(/行程安排[::]/g, '<div class="enhanced-title"><span class="title-icon">📅</span><span class="title-text">行程安排:</span></div>');
  557. content = content.replace(/###\s*(.*?)(\*\*)?(\*\*)?(\<br\/\>|\s|$)/g, '<h3 class="md-heading">$1</h3>');
  558. content = content.replace(/##\s*(.*?)(\<br\/\>|\s|$)/g, '<h2 class="md-heading">$2</h2>');
  559. content = content.replace(/#\s*(.*?)(\<br\/\>|\s|$)/g, '<h1 class="md-heading">$1</h1>');
  560. content = content.replace(/---(\<br\/\>|\s|$)/g, '<hr style="border: 0; height: 1px; background: #eee; margin: 20px 0;">');
  561. content = content.replace(/- ([^<]+)(?:<br\/>|$)/g, '<div class="enhanced-list-item"><span class="item-bullet"></span>$1</div>');
  562. content = content.replace(/([^<::]+)[::](?=\s*亚洲|世界|有"|\w)/g, '<span class="spot-name">$1:</span>');
  563. content = content.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>");
  564. content = content.replace(/【(.*?)】/g, '<span class="bracket-title">【$1】</span>');
  565. content = content.replace(/\*(.*?)\*/g, "<i>$1</i>");
  566. if (content.includes("行程") || content.includes("旅游") || content.includes("景点") || content.includes("住宿") || content.includes("Day") || content.includes("预算")) {
  567. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1007", "检测到旅游相关内容,进行格式化");
  568. content = content.replace(/¥(\d+)/g, '<span class="price-highlight">¥$1</span>');
  569. content = content.replace(/(\d+)元/g, '<span class="price-highlight">$1元</span>');
  570. content = content.replace(/¥(\d+)/g, '<span class="price-highlight">¥$1</span>');
  571. content = content.replace(/¥(\d+[-~]\d+)/g, '<span class="price-highlight">¥$1</span>');
  572. content = content.replace(/(Day\d+)[::]/g, '<span class="day-highlight">$1:</span>');
  573. content = content.replace(/(第\d+天)[::]/g, '<span class="day-highlight">$1:</span>');
  574. content = content.replace(/(上午|下午|晚上|早上|中午|傍晚)[::]/g, '<span class="time-highlight">$1:</span>');
  575. content = content.replace(/(著名|必去|推荐|特色|知名)/g, '<span class="keyword-highlight">$1</span>');
  576. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1023", "格式化后的内容:", content);
  577. }
  578. return content;
  579. },
  580. async testConnection() {
  581. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1030", "开始测试连接");
  582. try {
  583. common_vendor.index.showLoading({
  584. title: "测试连接中..."
  585. });
  586. if (!this.isConnected) {
  587. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1039", "WebSocket未连接,尝试重新连接");
  588. await this.startSession();
  589. }
  590. const testMessage = "测试消息:你好";
  591. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1045", "发送测试消息:", testMessage);
  592. this.addMessage("开始连接测试...", "system");
  593. await this.testWebSocketConnection();
  594. try {
  595. const response = await pages_api_ai.chatWithAI(this.sessionId, testMessage);
  596. if (response.code === 200) {
  597. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1057", "测试消息发送成功");
  598. } else {
  599. throw new Error(response.msg || "测试消息发送失败");
  600. }
  601. } catch (error) {
  602. throw new Error("测试消息发送失败: " + error.message);
  603. }
  604. common_vendor.index.hideLoading();
  605. common_vendor.index.showToast({
  606. title: "连接测试成功",
  607. icon: "success"
  608. });
  609. } catch (error) {
  610. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1075", "测试连接失败:", error);
  611. common_vendor.index.hideLoading();
  612. common_vendor.index.showToast({
  613. title: "测试失败",
  614. icon: "error"
  615. });
  616. }
  617. },
  618. // WebSocket连接测试
  619. async testWebSocketConnection() {
  620. return new Promise((resolve, reject) => {
  621. try {
  622. if (!this.isConnected) {
  623. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1092", "WebSocket未连接,无法发送测试消息");
  624. reject(new Error("WebSocket未连接"));
  625. return;
  626. }
  627. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1097", "尝试通过WebSocket发送测试消息");
  628. common_vendor.index.sendSocketMessage({
  629. data: JSON.stringify({ type: "test", message: "WebSocket测试消息" }),
  630. success: () => {
  631. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1103", "WebSocket测试消息发送成功");
  632. this.addMessage("WebSocket测试消息已发送,等待回应...", "system");
  633. setTimeout(() => {
  634. resolve();
  635. }, 1e3);
  636. },
  637. fail: (error) => {
  638. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1111", "WebSocket测试消息发送失败:", error);
  639. this.addMessage("WebSocket测试消息发送失败", "system");
  640. reject(error);
  641. }
  642. });
  643. } catch (error) {
  644. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1117", "WebSocket测试过程出错:", error);
  645. reject(error);
  646. }
  647. });
  648. },
  649. // 轮询获取AI回复
  650. async pollForAIReply(sessionId, maxAttempts = 3, interval = 5e3) {
  651. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1125", `开始轮询获取AI回复,最多${maxAttempts}次,间隔${interval}ms`);
  652. this.addMessage("正在获取AI回复...", "system");
  653. const lastMessage = this.messages[this.messages.length - 1];
  654. if (lastMessage && lastMessage.type === "ai" && !lastMessage.isThinking) {
  655. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1133", "已通过WebSocket收到回复,停止轮询");
  656. return;
  657. }
  658. let attempt = 0;
  659. const poll = async () => {
  660. if (attempt >= maxAttempts) {
  661. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1141", `已达到最大轮询次数(${maxAttempts}),停止轮询`);
  662. this.addMessage("获取AI回复超时,尝试从服务器直接获取回复...", "system");
  663. try {
  664. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1148", "尝试通过直接聊天请求获取回复");
  665. const response = await pages_api_ai.chatWithAI(sessionId, "获取上一条回复");
  666. if (response && response.data && response.data.reply) {
  667. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1152", "成功通过chatWithAI获取回复:", response.data.reply);
  668. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  669. this.messages.pop();
  670. }
  671. const isPlanContent = this.checkIfTravelPlanContent(response.data.reply);
  672. if (isPlanContent) {
  673. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1160", "轮询检测到旅游行程信息,解析为卡片显示");
  674. const planData = this.parseTravelPlanContent(response.data.reply);
  675. this.addTravelPlanMessage(planData);
  676. } else {
  677. let formattedContent = this.formatAIResponse(response.data.reply);
  678. this.addMessage(formattedContent, "ai");
  679. }
  680. this.isLoading = false;
  681. return;
  682. }
  683. } catch (error) {
  684. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1173", "通过直接聊天请求获取回复失败:", error);
  685. }
  686. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  687. this.messages.pop();
  688. this.addMessage("获取回复失败,请重新发送消息", "ai");
  689. }
  690. this.isLoading = false;
  691. return;
  692. }
  693. attempt++;
  694. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1186", `第${attempt}次轮询获取AI回复`);
  695. try {
  696. const response = await pages_api_ai.getLastAIReply(sessionId);
  697. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1190", `第${attempt}次轮询响应:`, response);
  698. if (response && response.code === 200 && response.reply) {
  699. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1193", "轮询成功获取到AI回复:", response.reply);
  700. const lastMessage2 = this.messages[this.messages.length - 1];
  701. if (lastMessage2 && lastMessage2.type === "ai" && !lastMessage2.isThinking && lastMessage2.content === response.reply) {
  702. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1199", "已有此消息,不重复显示");
  703. return;
  704. }
  705. const isPlanContent = this.checkIfTravelPlanContent(response.reply);
  706. if (isPlanContent) {
  707. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1206", "轮询检测到旅游行程信息,解析为卡片显示");
  708. const planData = this.parseTravelPlanContent(response.reply);
  709. this.addTravelPlanMessage(planData);
  710. } else {
  711. let formattedContent = this.formatAIResponse(response.reply);
  712. this.addMessage(formattedContent, "ai");
  713. }
  714. this.isLoading = false;
  715. return;
  716. }
  717. setTimeout(poll, interval);
  718. } catch (error) {
  719. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1222", `第${attempt}次轮询出错:`, error);
  720. setTimeout(poll, interval);
  721. }
  722. };
  723. poll();
  724. },
  725. async fetchServerResponse() {
  726. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1233", "开始获取服务器响应");
  727. try {
  728. common_vendor.index.showLoading({
  729. title: "获取服务器响应中..."
  730. });
  731. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1241", "发送HTTP请求到服务器:", {
  732. sessionId: this.sessionId,
  733. message: "获取服务器响应",
  734. baseUrl: pages_api_config.baseUrl,
  735. url: `${pages_api_config.baseUrl}/api/ai/travel/fetchServerResponse`
  736. });
  737. const response = await pages_api_ai.fetchServerResponse(this.sessionId);
  738. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1249", "服务器响应:", response);
  739. if (response.code === 200) {
  740. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1252", "服务器响应获取成功");
  741. if (this.messages.length > 0 && this.messages[this.messages.length - 1].isThinking) {
  742. this.messages.pop();
  743. }
  744. let formattedContent = this.formatAIResponse(response.data.reply);
  745. this.addMessage(formattedContent, "ai");
  746. } else {
  747. throw new Error(response.msg || "获取服务器响应失败");
  748. }
  749. } catch (error) {
  750. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1263", "获取服务器响应失败:", error);
  751. common_vendor.index.showToast({
  752. title: error.message || "获取服务器响应失败,请重试",
  753. icon: "none"
  754. });
  755. this.addMessage("抱歉,获取服务器响应失败,请重试。", "ai");
  756. } finally {
  757. this.isLoading = false;
  758. common_vendor.index.hideLoading();
  759. }
  760. },
  761. // 检查是否有未接收的消息
  762. async checkForMissedMessages() {
  763. if (!this.sessionId)
  764. return;
  765. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1280", "检查是否有未接收的消息");
  766. try {
  767. if (this.socketTask && this.isConnected) {
  768. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1285", "WebSocket已连接,发送请求获取最新消息");
  769. this.socketTask.send({
  770. data: JSON.stringify({
  771. type: "get_last_message",
  772. sessionId: this.sessionId
  773. }),
  774. success() {
  775. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1292", "请求最新消息发送成功");
  776. },
  777. fail(error) {
  778. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1295", "请求最新消息发送失败:", error);
  779. }
  780. });
  781. }
  782. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1301", "尝试通过HTTP接口获取最新回复");
  783. const response = await pages_api_ai.getLastAIReply(this.sessionId);
  784. if (response && response.code === 200 && response.reply) {
  785. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1305", "成功获取到最新回复:", response.reply);
  786. const lastMessage = this.messages[this.messages.length - 1];
  787. if (lastMessage && lastMessage.type === "ai" && !lastMessage.isThinking && lastMessage.content === response.reply) {
  788. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1311", "已有此消息,不重复显示");
  789. return;
  790. }
  791. const isPlanContent = this.checkIfTravelPlanContent(response.reply);
  792. if (isPlanContent) {
  793. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1318", "检测到旅游行程信息,解析为卡片显示");
  794. const planData = this.parseTravelPlanContent(response.reply);
  795. this.addTravelPlanMessage(planData);
  796. } else {
  797. let formattedContent = this.formatAIResponse(response.reply);
  798. this.addMessage(formattedContent, "ai");
  799. }
  800. }
  801. } catch (error) {
  802. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1328", "检查未接收消息失败:", error);
  803. }
  804. },
  805. // 检查是否是旅游行程信息
  806. checkIfTravelPlanContent(content) {
  807. const keywords = [
  808. "行程安排",
  809. "旅游计划",
  810. "旅行计划",
  811. "计划名称",
  812. "计划简介",
  813. "行程特色",
  814. "行程总花费",
  815. "行程总费用",
  816. "旅游地点",
  817. "¥",
  818. "¥",
  819. "预算",
  820. "第一天",
  821. "第二天",
  822. "第三天",
  823. "Day1",
  824. "Day2",
  825. "第.*天"
  826. ];
  827. const contentHasKeywords = keywords.some((keyword) => {
  828. const regex = new RegExp(keyword, "i");
  829. return regex.test(content);
  830. });
  831. const hasColonFormat = (content.match(/[::]/g) || []).length >= 3;
  832. const hasDayPattern = /第\s*\d+\s*天|Day\s*\d+/i.test(content);
  833. return contentHasKeywords && (hasColonFormat || hasDayPattern);
  834. },
  835. // 解析旅游行程信息
  836. parseTravelPlanContent(content) {
  837. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1358", "开始解析旅游行程内容");
  838. const planData = {
  839. name: "",
  840. description: "",
  841. features: "",
  842. price: "",
  843. currentDay: "1",
  844. city: "",
  845. attractions: "",
  846. food: "",
  847. arrangement: "",
  848. note: "",
  849. days: "5天4晚",
  850. spots: "12个地点"
  851. };
  852. const nameMatch = content.match(/计划名称[::]\s*([^\n]+)/);
  853. if (nameMatch)
  854. planData.name = nameMatch[1].trim();
  855. if (!planData.name) {
  856. const altNameMatch = content.match(/(.*)[日游|旅行|旅游计划]/);
  857. if (altNameMatch)
  858. planData.name = altNameMatch[1].trim();
  859. }
  860. if (!planData.name)
  861. planData.name = "旅游计划";
  862. const descMatch = content.match(/计划简介[::]\s*([^\n]+)/);
  863. if (descMatch)
  864. planData.description = descMatch[1].trim();
  865. else {
  866. const altDescMatch = content.match(/简介[::]\s*([^\n]+)/);
  867. if (altDescMatch)
  868. planData.description = altDescMatch[1].trim();
  869. }
  870. const featuresMatch = content.match(/行程特色[::]\s*([^\n]+)/);
  871. if (featuresMatch)
  872. planData.features = featuresMatch[1].trim();
  873. const priceMatch = content.match(/行程总花费[::]\s*([^\n]+)|预算[::]\s*([^\n]+)|总花费[::]\s*([^\n]+)|花费[::]\s*([^\n]+)/);
  874. if (priceMatch) {
  875. planData.price = (priceMatch[1] || priceMatch[2] || priceMatch[3] || priceMatch[4]).trim();
  876. planData.price = planData.price.replace(/[¥¥]/g, "");
  877. }
  878. const dayMatch = content.match(/第\s*(\d+)\s*天|Day\s*(\d+)/i);
  879. if (dayMatch) {
  880. planData.currentDay = dayMatch[1] || dayMatch[2];
  881. }
  882. const cityMatch = content.match(/城市[::]\s*([^\n]+)|地点[::]\s*([^\n]+)|国家[::]\s*([^\n]+)/);
  883. if (cityMatch)
  884. planData.city = (cityMatch[1] || cityMatch[2] || cityMatch[3]).trim();
  885. const attractionsMatch = content.match(/地点[::]\s*([^\n]+)|景点[::]\s*([^\n]+)|旅游地点[::]\s*([^\n]+)/);
  886. if (attractionsMatch)
  887. planData.attractions = (attractionsMatch[1] || attractionsMatch[2] || attractionsMatch[3]).trim();
  888. const foodMatch = content.match(/周边美食[::]\s*([^\n]+)|美食[::]\s*([^\n]+)|特色美食[::]\s*([^\n]+)/);
  889. if (foodMatch)
  890. planData.food = (foodMatch[1] || foodMatch[2] || foodMatch[3]).trim();
  891. const arrangementMatch = content.match(/安排说明[::]\s*([^\n]+)|安排[::]\s*([^\n]+)|行程安排[::]\s*([^\n]+)/);
  892. if (arrangementMatch)
  893. planData.arrangement = (arrangementMatch[1] || arrangementMatch[2] || arrangementMatch[3]).trim();
  894. const noteMatch = content.match(/备注[::]\s*([^\n]+)/);
  895. if (noteMatch)
  896. planData.note = noteMatch[1].trim();
  897. const totalDaysMatch = content.match(/(\d+)\s*天\s*(\d+)\s*晚|(\d+)\s*日\s*(\d+)\s*晚/);
  898. if (totalDaysMatch) {
  899. const days = totalDaysMatch[1] || totalDaysMatch[3];
  900. const nights = totalDaysMatch[2] || totalDaysMatch[4];
  901. planData.days = `${days}天${nights}晚`;
  902. }
  903. const spotsMatch = content.match(/(\d+)\s*个景点|(\d+)\s*个地点/);
  904. if (spotsMatch) {
  905. const count = spotsMatch[1] || spotsMatch[2];
  906. planData.spots = `${count}个地点`;
  907. }
  908. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1451", "解析后的旅游行程数据:", planData);
  909. return planData;
  910. },
  911. // 添加旅游行程消息
  912. addTravelPlanMessage(planData) {
  913. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1457", "添加旅游行程卡片消息:", planData);
  914. const message = {
  915. type: "ai-plan",
  916. planData,
  917. isThinking: false,
  918. timestamp: Date.now()
  919. };
  920. this.messages.push(message);
  921. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1467", "当前消息列表:", this.messages);
  922. try {
  923. common_vendor.index.setStorageSync("chat_messages", JSON.stringify(this.messages));
  924. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1472", "消息已保存到本地存储");
  925. } catch (e) {
  926. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1474", "保存消息到本地存储失败:", e);
  927. }
  928. this.$nextTick(() => {
  929. this.scrollToBottom();
  930. });
  931. },
  932. async testConsoleLog() {
  933. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1483", "开始测试控制台输出");
  934. try {
  935. common_vendor.index.showLoading({
  936. title: "测试控制台输出中..."
  937. });
  938. if (!this.sessionId) {
  939. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1492", "sessionId不存在,先创建新会话");
  940. const response2 = await pages_api_ai.startAISession();
  941. if (response2 && response2.code === 200 && response2.sessionId) {
  942. this.sessionId = response2.sessionId;
  943. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1496", "新会话创建成功,sessionId:", this.sessionId);
  944. } else {
  945. throw new Error("创建会话失败");
  946. }
  947. }
  948. const testMessage = "[CONSOLE_TEST] 这是一条测试控制台输出的消息 " + (/* @__PURE__ */ new Date()).toLocaleString();
  949. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1504", "发送测试消息:", testMessage);
  950. this.addMessage("开始测试控制台输出...", "system");
  951. const response = await pages_api_ai.chatWithAI(this.sessionId, testMessage);
  952. common_vendor.index.__f__("log", "at pages/ai-assistant/index.vue:1511", "测试消息发送结果:", response);
  953. if (response.code === 200) {
  954. this.addMessage("测试消息已发送到后端,请检查后端控制台输出", "system");
  955. } else {
  956. throw new Error(response.msg || "发送测试消息失败");
  957. }
  958. common_vendor.index.hideLoading();
  959. common_vendor.index.showToast({
  960. title: "消息已发送",
  961. icon: "success"
  962. });
  963. } catch (error) {
  964. common_vendor.index.__f__("error", "at pages/ai-assistant/index.vue:1530", "控制台输出测试失败:", error);
  965. common_vendor.index.hideLoading();
  966. common_vendor.index.showToast({
  967. title: "控制台输出测试失败",
  968. icon: "error"
  969. });
  970. this.addMessage(`控制台输出测试失败: ${error.message}`, "system");
  971. }
  972. }
  973. }
  974. };
  975. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  976. return common_vendor.e({
  977. a: common_vendor.o((...args) => $options.goBack && $options.goBack(...args)),
  978. b: common_vendor.o((...args) => $options.createNewChat && $options.createNewChat(...args)),
  979. c: $data.messages.length > 0 && $data.messages[0].type === "ai"
  980. }, $data.messages.length > 0 && $data.messages[0].type === "ai" ? {
  981. d: common_assets._imports_0$3,
  982. e: $data.messages[0].content,
  983. f: common_vendor.f($data.quickQuestions, (question, key, i0) => {
  984. return {
  985. a: common_vendor.t(key),
  986. b: key,
  987. c: common_vendor.o(($event) => $options.handleQuickQuestion(key), key)
  988. };
  989. })
  990. } : {}, {
  991. g: common_vendor.f($options.displayMessages, (msg, index, i0) => {
  992. return common_vendor.e({
  993. a: common_vendor.t($options.formatTime(msg.timestamp)),
  994. b: common_vendor.t(msg.type === "user" ? "我" : "AI助手"),
  995. c: msg.type === "user" ? "/static/images/user-avatar.png" : "/static/images/ai-avatar.png",
  996. d: !msg.isThinking && msg.type !== "ai-plan"
  997. }, !msg.isThinking && msg.type !== "ai-plan" ? {
  998. e: msg.content
  999. } : msg.type === "ai-plan" ? common_vendor.e({
  1000. g: common_vendor.t(msg.planData.name),
  1001. h: common_vendor.t(msg.planData.description),
  1002. i: common_vendor.t(msg.planData.features),
  1003. j: common_vendor.t(msg.planData.price),
  1004. k: msg.planData.price.includes("-")
  1005. }, msg.planData.price.includes("-") ? {} : {}, {
  1006. l: common_vendor.t(msg.planData.currentDay),
  1007. m: common_vendor.t(msg.planData.city),
  1008. n: msg.planData.attractions
  1009. }, msg.planData.attractions ? {
  1010. o: common_vendor.t(msg.planData.attractions)
  1011. } : {}, {
  1012. p: msg.planData.food
  1013. }, msg.planData.food ? {
  1014. q: common_vendor.t(msg.planData.food)
  1015. } : {}, {
  1016. r: common_vendor.t(msg.planData.arrangement),
  1017. s: common_vendor.t(msg.planData.days),
  1018. t: common_vendor.t(msg.planData.price),
  1019. v: common_vendor.t(msg.planData.spots),
  1020. w: msg.planData.note
  1021. }, msg.planData.note ? {
  1022. x: common_vendor.t(msg.planData.note)
  1023. } : {}) : {}, {
  1024. f: msg.type === "ai-plan",
  1025. y: index,
  1026. z: common_vendor.n(msg.type)
  1027. });
  1028. }),
  1029. h: $data.scrollTop,
  1030. i: common_vendor.o((...args) => $options.loadMoreMessages && $options.loadMoreMessages(...args)),
  1031. j: $data.isLoading,
  1032. k: $data.maxLength,
  1033. l: common_vendor.o((...args) => $options.sendMessage && $options.sendMessage(...args)),
  1034. m: $data.inputMessage,
  1035. n: common_vendor.o(($event) => $data.inputMessage = $event.detail.value),
  1036. o: common_vendor.t($data.isLoading ? "发送中..." : "发送"),
  1037. p: $data.isLoading || !$data.inputMessage.trim(),
  1038. q: $data.isLoading ? 1 : "",
  1039. r: common_vendor.o((...args) => $options.sendMessage && $options.sendMessage(...args))
  1040. });
  1041. }
  1042. const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
  1043. wx.createPage(MiniProgramPage);
  1044. //# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/ai-assistant/index.js.map