page-crm-decision.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. import {
  2. Component,
  3. OnInit,
  4. ViewChild,
  5. ElementRef,
  6. AfterViewChecked
  7. } from '@angular/core';
  8. import { FormsModule } from '@angular/forms';
  9. import { CommonModule } from '@angular/common';
  10. import { TestCompletion, TestMessage,extractJSON} from '../../../../lib/cloud/comletion';
  11. type SceneType = 'first-contact' | 'deep-talk';
  12. type MessageRole = 'customer' | 'assistant';
  13. interface StrategyAnalysis {
  14. aggressive: {
  15. title: string;
  16. highlight: string;
  17. applicable: string;
  18. advantage: string;
  19. successRate: string;
  20. };
  21. neutral: {
  22. title: string;
  23. highlight: string;
  24. applicable: string;
  25. advantage: string;
  26. successRate: string;
  27. };
  28. conservative: {
  29. title: string;
  30. highlight: string;
  31. applicable: string;
  32. advantage: string;
  33. successRate: string;
  34. };
  35. }
  36. interface Message {
  37. role: MessageRole;
  38. content: string;
  39. time: string;
  40. }
  41. interface Tag {
  42. text: string;
  43. icon: string;
  44. background: string;
  45. color: string;
  46. }
  47. interface Strategy {
  48. type: string;
  49. title: string;
  50. icon: string;
  51. iconBg: string;
  52. iconColor: string;
  53. description: string;
  54. highlight: string;
  55. applicable: string;
  56. advantage: string;
  57. successRate: string;
  58. rating: string;
  59. isDefault: boolean; // 新增:标记是否为默认策略
  60. }
  61. interface ChatRecord {
  62. id: string;
  63. scene: SceneType;
  64. messages: Message[];
  65. tags: Tag[];
  66. strategies: Strategy[];
  67. timestamp: number;
  68. }
  69. @Component({
  70. selector: 'app-page-crm-decision',
  71. standalone: true,
  72. imports: [CommonModule, FormsModule],
  73. templateUrl: './page-crm-decision.html',
  74. styleUrls: ['./page-crm-decision.scss']
  75. })
  76. export class PageCrmDecision implements OnInit, AfterViewChecked {
  77. @ViewChild('chatContainer') chatContainer!: ElementRef;
  78. @ViewChild('fileInput') fileInput!: ElementRef;
  79. private aiAssistant!: TestCompletion;
  80. private scenePrompts = {
  81. 'first-contact': `你是一名专业的酒店销售顾问,正在与一位潜在客户进行首次接触。
  82. 客户可能对酒店服务、房型、价格等方面有疑问。你的任务是:
  83. 1. 建立良好的沟通氛围
  84. 2. 了解客户基本需求
  85. 3. 介绍酒店核心优势
  86. 4. 避免过于强硬的推销语气
  87. 5. 为后续沟通留下空间`,
  88. 'deep-talk': `你是一名经验丰富的酒店销售顾问,正在与一位对酒店有一定兴趣的客户进行深度交流。
  89. 客户可能已经了解了基本信息,正在比较选择或寻求更详细的信息。你的任务是:
  90. 1. 深入挖掘客户具体需求和关注点
  91. 2. 提供针对性的解决方案和建议
  92. 3. 有效处理客户提出的异议和问题
  93. 4. 展示酒店差异化竞争优势
  94. 5. 推动客户向决策阶段发展`
  95. };
  96. openHistory() {
  97. this.showHistoryModal = true;
  98. }
  99. selectedScene: SceneType = 'first-contact';
  100. sceneTitle = '首次接触';
  101. messages: Message[] = [];
  102. tags: Tag[] = [
  103. { text: 'VIP客户', icon: 'fas fa-user', background: 'rgba(100, 160, 255, 0.15)', color: '#64a0ff' },
  104. { text: '旺季时段', icon: 'fas fa-calendar', background: 'rgba(255, 212, 59, 0.15)', color: '#ffd43b' },
  105. { text: '价格敏感', icon: 'fas fa-percent', background: 'rgba(156, 54, 181, 0.15)', color: '#9c36b5' }
  106. ];
  107. currentRole: MessageRole = 'customer';
  108. newMessage = '';
  109. strategies: Strategy[] = [
  110. {
  111. type: 'aggressive',
  112. title: '主动型策略',
  113. icon: 'fas fa-bolt',
  114. iconBg: 'var(--blue-light)',
  115. iconColor: 'var(--blue)',
  116. description: '直接强调酒店独特价值,制造紧迫感:',
  117. highlight: '',
  118. applicable: '客户表现出明确兴趣,决策周期短',
  119. advantage: '快速成交,提升单笔订单价值',
  120. successRate: '68%',
  121. rating: '⭐⭐⭐⭐',
  122. isDefault: true
  123. },
  124. {
  125. type: 'neutral',
  126. title: '平衡型策略',
  127. icon: 'fas fa-balance-scale',
  128. iconBg: 'rgba(255, 212, 59, 0.15)',
  129. iconColor: 'var(--yellow)',
  130. description: '提供阶梯式优惠,引导客户选择:',
  131. highlight: '',
  132. applicable: '客户在多个选项间犹豫',
  133. advantage: '平衡双方利益,建立长期关系',
  134. successRate: '82%',
  135. rating: '⭐⭐⭐⭐⭐',
  136. isDefault: true
  137. },
  138. {
  139. type: 'conservative',
  140. title: '保守型策略',
  141. icon: 'fas fa-shield-alt',
  142. iconBg: 'rgba(156, 54, 181, 0.15)',
  143. iconColor: 'var(--purple)',
  144. description: '提供灵活方案,降低决策风险:',
  145. highlight: '',
  146. applicable: '客户犹豫不决,决策周期长',
  147. advantage: '降低客户风险感知,提高转化率',
  148. successRate: '75%',
  149. rating: '⭐⭐⭐⭐',
  150. isDefault: true
  151. }
  152. ];
  153. activeCardIndex = 0;
  154. isProcessing = false;
  155. showHistoryModal = false;
  156. chatRecords: ChatRecord[] = [];
  157. private strategiesContent: Record<SceneType, { aggressive: string; neutral: string; conservative: string }> = {
  158. "first-contact": {
  159. aggressive: "主动介绍酒店特色和限时优惠,强调独特卖点",
  160. neutral: "提供套餐选择,引导客户了解不同房型",
  161. conservative: "邀请客户参观虚拟酒店,提供详细资料"
  162. },
  163. "deep-talk": {
  164. aggressive: "深度挖掘客户需求,提供定制化解决方案",
  165. neutral: "建立信任关系,分享成功案例和客户评价",
  166. conservative: "提供专业建议,解答客户深层疑问"
  167. }
  168. };
  169. ngOnInit() {
  170. this.loadRecords();
  171. this.selectScene('first-contact');
  172. }
  173. ngAfterViewChecked() {
  174. this.scrollToBottom();
  175. }
  176. scrollToBottom(): void {
  177. try {
  178. if (this.chatContainer) {
  179. this.chatContainer.nativeElement.scrollTop = this.chatContainer.nativeElement.scrollHeight;
  180. }
  181. } catch (err) {
  182. console.error(err);
  183. }
  184. }
  185. onTextareaKeydown(event: KeyboardEvent): void {
  186. if (event.key === 'Enter' && !event.shiftKey) {
  187. event.preventDefault();
  188. this.sendMessage();
  189. }
  190. }
  191. // 只在初始化时设置默认策略
  192. initializeDefaultStrategies(): void {
  193. const sceneStrategies = this.strategiesContent[this.selectedScene];
  194. this.strategies[0] = {
  195. ...this.strategies[0],
  196. highlight: sceneStrategies.aggressive,
  197. isDefault: true
  198. };
  199. this.strategies[1] = {
  200. ...this.strategies[1],
  201. highlight: sceneStrategies.neutral,
  202. isDefault: true
  203. };
  204. this.strategies[2] = {
  205. ...this.strategies[2],
  206. highlight: sceneStrategies.conservative,
  207. isDefault: true
  208. };
  209. }
  210. selectScene(scene: SceneType): void {
  211. this.selectedScene = scene;
  212. this.sceneTitle = scene === 'first-contact' ? '首次接触' : '深度交流';
  213. // 初始化AI助手
  214. this.messages = [];
  215. const systemPrompt = this.scenePrompts[scene];
  216. this.aiAssistant = new TestCompletion([
  217. { role: "system", content: systemPrompt },
  218. { role: "assistant", content: scene === 'first-contact' ?
  219. "您好!我是九州宴会的销售顾问,很高兴认识您。请问您今天想了解哪方面的信息呢?" :
  220. "感谢您继续深入交流。基于我们之前的沟通,我整理了几个可能适合您的方案,您想先了解哪个方面?"
  221. }
  222. ]);
  223. // 添加初始问候语
  224. this.addMessage('assistant', scene === 'first-contact' ?
  225. "您好!我是九州宴会的销售顾问,很高兴认识您。请问您今天想了解哪方面的信息呢?" :
  226. "感谢您继续深入交流。基于我们之前的沟通,我整理了几个可能适合您的方案,您想先了解哪个方面?"
  227. );
  228. // 重置并初始化策略
  229. this.resetStrategies();
  230. this.initializeDefaultStrategies();
  231. }
  232. // 重置策略内容(切换场景时调用)
  233. private resetStrategies() {
  234. this.strategies = [
  235. {
  236. ...this.strategies[0],
  237. highlight: "",
  238. applicable: "客户表现出明确兴趣,决策周期短",
  239. advantage: "快速成交,提升单笔订单价值",
  240. successRate: "68%",
  241. isDefault: true
  242. },
  243. {
  244. ...this.strategies[1],
  245. highlight: "",
  246. applicable: "客户在多个选项间犹豫",
  247. advantage: "平衡双方利益,建立长期关系",
  248. successRate: "82%",
  249. isDefault: true
  250. },
  251. {
  252. ...this.strategies[2],
  253. highlight: "",
  254. applicable: "客户犹豫不决,决策周期长",
  255. advantage: "降低客户风险感知,提高转化率",
  256. successRate: "75%",
  257. isDefault: true
  258. }
  259. ];
  260. }
  261. setRole(role: MessageRole): void {
  262. this.currentRole = role;
  263. }
  264. addTag(): void {
  265. const newTag: Tag = {
  266. text: '新标签',
  267. icon: 'fas fa-tag',
  268. background: 'rgba(100, 160, 255, 0.15)',
  269. color: '#64a0ff'
  270. };
  271. this.tags.push(newTag);
  272. }
  273. removeTag(event: Event, tag: Tag): void {
  274. event.stopPropagation();
  275. this.tags = this.tags.filter(t => t !== tag);
  276. }
  277. async sendMessage() {
  278. if (!this.newMessage.trim() || !this.selectedScene) return;
  279. this.isProcessing = true;
  280. // 添加用户消息
  281. const now = new Date();
  282. this.addMessage(this.currentRole, this.newMessage.trim());
  283. this.newMessage = '';
  284. // 如果是客户消息,更新策略分析
  285. if (this.currentRole === 'customer') {
  286. try {
  287. // 显示加载状态
  288. this.strategies.forEach(strategy => {
  289. strategy.highlight = "分析中...";
  290. strategy.applicable = "生成最佳策略...";
  291. strategy.successRate = "--";
  292. strategy.isDefault = false;
  293. });
  294. // 更新策略分析(基于最新客户消息)
  295. await this.updateStrategiesBasedOnMessage(this.messages[this.messages.length-1].content);
  296. } catch (error) {
  297. console.error('更新策略失败:', error);
  298. // 失败时使用关键词匹配生成动态内容
  299. const fallbackStrategies = this.generateDynamicStrategies(this.messages[this.messages.length-1].content);
  300. this.updateStrategiesWithFallback(fallbackStrategies);
  301. } finally {
  302. this.isProcessing = false;
  303. }
  304. } else {
  305. this.isProcessing = false;
  306. }
  307. }
  308. private addMessage(role: MessageRole, content: string): void {
  309. const now = new Date();
  310. this.messages.push({
  311. role,
  312. content,
  313. time: `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')}`
  314. });
  315. this.scrollToBottom();
  316. }
  317. // 根据客户消息动态更新策略卡片内容
  318. private async updateStrategiesBasedOnMessage(customerMessage: string) {
  319. try {
  320. // 调用AI分析客户消息,生成策略建议
  321. const analysis = await this.analyzeCustomerMessage(customerMessage);
  322. // 更新策略卡片内容
  323. this.strategies[0] = {
  324. ...this.strategies[0],
  325. highlight: analysis.aggressive.highlight,
  326. applicable: analysis.aggressive.applicable,
  327. advantage: analysis.aggressive.advantage,
  328. successRate: analysis.aggressive.successRate,
  329. isDefault: false
  330. };
  331. this.strategies[1] = {
  332. ...this.strategies[1],
  333. highlight: analysis.neutral.highlight,
  334. applicable: analysis.neutral.applicable,
  335. advantage: analysis.neutral.advantage,
  336. successRate: analysis.neutral.successRate,
  337. isDefault: false
  338. };
  339. this.strategies[2] = {
  340. ...this.strategies[2],
  341. highlight: analysis.conservative.highlight,
  342. applicable: analysis.conservative.applicable,
  343. advantage: analysis.conservative.advantage,
  344. successRate: analysis.conservative.successRate,
  345. isDefault: false
  346. };
  347. // 根据消息内容选择最合适的策略
  348. this.selectBestStrategy(customerMessage);
  349. } catch (error) {
  350. console.error('更新策略失败:', error);
  351. throw error; // 让调用者处理错误
  352. }
  353. }
  354. // 使用备用策略更新(AI调用失败时)
  355. private updateStrategiesWithFallback(strategies: ReturnType<typeof this.generateDynamicStrategies>) {
  356. this.strategies[0] = {
  357. ...this.strategies[0],
  358. highlight: strategies.aggressive.highlight,
  359. applicable: "客户表现出明确兴趣,决策周期短",
  360. successRate: "68%",
  361. isDefault: false
  362. };
  363. this.strategies[1] = {
  364. ...this.strategies[1],
  365. highlight: strategies.neutral.highlight,
  366. applicable: "客户在多个选项间犹豫",
  367. successRate: "82%",
  368. isDefault: false
  369. };
  370. this.strategies[2] = {
  371. ...this.strategies[2],
  372. highlight: strategies.conservative.highlight,
  373. applicable: "客户犹豫不决,决策周期长",
  374. successRate: "75%",
  375. isDefault: false
  376. };
  377. // 仍然选择最佳策略
  378. this.selectBestStrategy(this.messages[this.messages.length-1].content);
  379. }
  380. // 生成动态策略内容(关键词匹配)
  381. private generateDynamicStrategies(customerMessage: string) {
  382. // 关键词匹配,确保内容随客户消息变化
  383. let focus = "酒店服务";
  384. if (customerMessage.toLowerCase().includes("价格")) focus = "价格优势";
  385. if (customerMessage.toLowerCase().includes("位置")) focus = "地理位置";
  386. if (customerMessage.toLowerCase().includes("设施")) focus = "设施特色";
  387. if (customerMessage.toLowerCase().includes("日期")) focus = "日期灵活性";
  388. if (customerMessage.toLowerCase().includes("容量")) focus = "场地容量";
  389. return {
  390. aggressive: {
  391. highlight: `立即强调${focus},提供专属限时优惠`,
  392. applicable: "客户表现出明确兴趣",
  393. advantage: "快速促成交易",
  394. successRate: "68%"
  395. },
  396. neutral: {
  397. highlight: `提供${focus}的3种选择方案,满足不同需求`,
  398. applicable: "客户需要比较选择",
  399. advantage: "提高选择满意度",
  400. successRate: "82%"
  401. },
  402. conservative: {
  403. highlight: `详细说明${focus}的优势,提供案例参考`,
  404. applicable: "客户需要更多决策信息",
  405. advantage: "降低决策阻力",
  406. successRate: "75%"
  407. }
  408. };
  409. }
  410. activateCard(index: number): void {
  411. this.activeCardIndex = index;
  412. }
  413. getCardTransform(index: number): string {
  414. if (index === this.activeCardIndex) {
  415. return 'translateY(0) scale(1)';
  416. } else if (Math.abs(index - this.activeCardIndex) === 1) {
  417. return `translateY(${20 * Math.abs(index - this.activeCardIndex)}px) scale(${1 - 0.05 * Math.abs(index - this.activeCardIndex)})`;
  418. } else {
  419. return `translateY(${40 * Math.abs(index - this.activeCardIndex)}px) scale(${1 - 0.1 * Math.abs(index - this.activeCardIndex)})`;
  420. }
  421. }
  422. getCardZIndex(index: number): string {
  423. if (index === this.activeCardIndex) {
  424. return '30';
  425. } else if (Math.abs(index - this.activeCardIndex) === 1) {
  426. return '20';
  427. } else {
  428. return '10';
  429. }
  430. }
  431. // 文件上传处理
  432. onFileSelected(event: Event) {
  433. const input = event.target as HTMLInputElement;
  434. if (!input.files || input.files.length === 0) return;
  435. const file = input.files[0];
  436. if (file.type !== 'application/json' && !file.name.endsWith('.json')) {
  437. alert('请上传JSON格式的文件');
  438. return;
  439. }
  440. const reader = new FileReader();
  441. reader.onload = (e: ProgressEvent<FileReader>) => {
  442. try {
  443. const content = e.target?.result as string;
  444. const data = JSON.parse(content);
  445. if (Array.isArray(data) && data.every(item => item.role && item.content && item.time)) {
  446. this.messages = data as Message[];
  447. this.updateStrategiesBasedOnMessages();
  448. this.fileInput.nativeElement.value = ''; // 清空文件选择
  449. } else {
  450. alert('文件格式不正确,请上传有效的聊天记录JSON文件');
  451. }
  452. } catch (error) {
  453. console.error('文件解析错误:', error);
  454. alert('解析文件时出错');
  455. }
  456. };
  457. reader.readAsText(file);
  458. }
  459. // 根据完整对话更新策略
  460. private updateStrategiesBasedOnMessages() {
  461. // 从对话中提取最后一条客户消息
  462. const lastCustomerMessage = this.messages
  463. .filter(msg => msg.role === 'customer')
  464. .pop();
  465. if (lastCustomerMessage) {
  466. this.updateStrategiesBasedOnMessage(lastCustomerMessage.content);
  467. }
  468. }
  469. // 保存记录
  470. saveRecord() {
  471. if (!this.messages.length) {
  472. alert('没有可保存的对话记录');
  473. return;
  474. }
  475. const record: ChatRecord = {
  476. id: Date.now().toString(),
  477. scene: this.selectedScene,
  478. messages: [...this.messages],
  479. tags: [...this.tags],
  480. strategies: [...this.strategies],
  481. timestamp: Date.now()
  482. };
  483. this.chatRecords.unshift(record); // 添加到开头
  484. this.saveRecords();
  485. alert('记录已保存');
  486. }
  487. // 加载记录
  488. loadRecords() {
  489. const records = localStorage.getItem('chatRecords');
  490. if (records) {
  491. this.chatRecords = JSON.parse(records);
  492. }
  493. }
  494. // 保存记录到本地存储
  495. saveRecords() {
  496. localStorage.setItem('chatRecords', JSON.stringify(this.chatRecords));
  497. }
  498. // 查看历史
  499. viewHistory() {
  500. this.showHistoryModal = true;
  501. }
  502. // 选择历史记录
  503. selectRecord(record: ChatRecord) {
  504. this.selectedScene = record.scene;
  505. this.sceneTitle = record.scene === 'first-contact' ? '首次接触' : '深度交流';
  506. this.messages = [...record.messages];
  507. this.tags = [...record.tags];
  508. this.strategies = [...record.strategies];
  509. // 初始化AI助手
  510. const systemPrompt = this.scenePrompts[record.scene];
  511. this.aiAssistant = new TestCompletion([
  512. { role: "system", content: systemPrompt },
  513. ...record.messages.map(msg => ({
  514. role: msg.role === 'customer' ? 'user' : msg.role,
  515. content: msg.content
  516. }))
  517. ]);
  518. this.showHistoryModal = false;
  519. }
  520. // 删除历史记录
  521. deleteRecord(record: ChatRecord) {
  522. if (confirm('确定要删除这条记录吗?')) {
  523. this.chatRecords = this.chatRecords.filter(r => r.id !== record.id);
  524. this.saveRecords();
  525. }
  526. }
  527. // 格式化日期
  528. formatDate(timestamp: number) {
  529. const date = new Date(timestamp);
  530. return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')} ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
  531. }
  532. // 导出对话记录为JSON文件
  533. exportChat() {
  534. if (!this.messages.length) {
  535. alert('没有可导出的对话记录');
  536. return;
  537. }
  538. const jsonContent = JSON.stringify(this.messages, null, 2);
  539. const blob = new Blob([jsonContent], { type: 'application/json' });
  540. const url = URL.createObjectURL(blob);
  541. const a = document.createElement('a');
  542. a.href = url;
  543. a.download = `chat-record-${new Date().toISOString().slice(0,10)}.json`;
  544. document.body.appendChild(a);
  545. a.click();
  546. document.body.removeChild(a);
  547. URL.revokeObjectURL(url);
  548. }
  549. // 生成AI回复
  550. async generateAIResponse() {
  551. if (!this.messages.length || this.messages[this.messages.length - 1].role === 'assistant') {
  552. alert('请先发送客户消息');
  553. return;
  554. }
  555. this.isProcessing = true;
  556. try {
  557. const aiReply = await this.aiAssistant.sendMessage(
  558. [...this.messages.map(msg => ({
  559. role: msg.role === 'customer' ? 'user' : msg.role,
  560. content: msg.content
  561. }))],
  562. (partialContent) => {
  563. const lastMsg = this.messages[this.messages.length - 1];
  564. if (lastMsg.role === 'assistant') {
  565. lastMsg.content = partialContent;
  566. } else {
  567. this.addMessage('assistant', partialContent);
  568. }
  569. }
  570. );
  571. if (typeof aiReply === 'string') {
  572. this.addMessage('assistant', aiReply);
  573. // 基于最新客户消息更新策略
  574. const lastCustomerMsg = this.messages
  575. .filter(msg => msg.role === 'customer')
  576. .pop();
  577. if (lastCustomerMsg) {
  578. this.updateStrategiesBasedOnMessage(lastCustomerMsg.content);
  579. }
  580. }
  581. } catch (error) {
  582. console.error('AI交互错误:', error);
  583. this.addMessage('assistant', '抱歉,处理您的请求时出现了问题。');
  584. } finally {
  585. this.isProcessing = false;
  586. }
  587. }
  588. // 调用AI分析客户消息并生成策略建议
  589. private async analyzeCustomerMessage(customerMessage: string): Promise<StrategyAnalysis> {
  590. // 构建提示词,引导AI生成三种策略
  591. const prompt = `
  592. 客户消息: "${customerMessage}"
  593. 请针对此客户消息,为酒店销售顾问生成三种应对策略:
  594. 1. 主动型策略: 直接、果断的销售方法
  595. 2. 平衡型策略: 中等强度的销售方法
  596. 3. 保守型策略: 温和、信息丰富的销售方法
  597. 请以JSON格式返回,包含以下字段:
  598. {
  599. "aggressive": {
  600. "title": "主动型策略标题",
  601. "highlight": "核心建议",
  602. "applicable": "适用场景",
  603. "advantage": "主要优势",
  604. "successRate": "成功率百分比"
  605. },
  606. "neutral": {
  607. "title": "平衡型策略标题",
  608. "highlight": "核心建议",
  609. "applicable": "适用场景",
  610. "advantage": "主要优势",
  611. "successRate": "成功率百分比"
  612. },
  613. "conservative": {
  614. "title": "保守型策略标题",
  615. "highlight": "核心建议",
  616. "applicable": "适用场景",
  617. "advantage": "主要优势",
  618. "successRate": "成功率百分比"
  619. }
  620. }
  621. `;
  622. // 使用TestCompletion调用AI
  623. const strategyAnalyzer = new TestCompletion([
  624. { role: "system", content: "你是一位专业的酒店销售策略顾问,擅长根据客户消息生成针对性的销售策略。" },
  625. { role: "user", content: prompt }
  626. ]);
  627. // 获取AI响应
  628. const response = await strategyAnalyzer.sendMessage([
  629. { role: "user", content: prompt }
  630. ],(content)=>{
  631. this.aicontent = content
  632. });
  633. // 解析JSON响应
  634. try {
  635. let json = extractJSON(response)
  636. return json;
  637. } catch (parseError) {
  638. console.error('解析策略分析失败:', parseError);
  639. // 返回默认策略
  640. return this.getDefaultStrategies();
  641. }
  642. }
  643. aicontent:string = ""
  644. // 根据客户消息选择最合适的策略
  645. private selectBestStrategy(customerMessage: string) {
  646. const lowerCaseMsg = customerMessage.toLowerCase();
  647. if (lowerCaseMsg.includes('价格') || lowerCaseMsg.includes('优惠')) {
  648. this.activeCardIndex = 1; // 平衡型策略通常最适合价格讨论
  649. } else if (lowerCaseMsg.includes('兴趣') || lowerCaseMsg.includes('考虑')) {
  650. this.activeCardIndex = 0; // 主动型策略适合有兴趣的客户
  651. } else if (lowerCaseMsg.includes('犹豫') || lowerCaseMsg.includes('比较')) {
  652. this.activeCardIndex = 2; // 保守型策略适合犹豫的客户
  653. } else {
  654. // 默认选择平衡型策略
  655. this.activeCardIndex = 1;
  656. }
  657. }
  658. // 返回默认策略(当AI分析失败时使用)
  659. private getDefaultStrategies(): StrategyAnalysis {
  660. return {
  661. aggressive: {
  662. title: "主动型策略",
  663. highlight: "直接介绍酒店特色和限时优惠",
  664. applicable: "客户表现出明确兴趣,决策周期短",
  665. advantage: "快速成交,提升单笔订单价值",
  666. successRate: "68%"
  667. },
  668. neutral: {
  669. title: "平衡型策略",
  670. highlight: "提供套餐选择,引导客户了解不同房型",
  671. applicable: "客户在多个选项间犹豫",
  672. advantage: "平衡双方利益,建立长期关系",
  673. successRate: "82%"
  674. },
  675. conservative: {
  676. title: "保守型策略",
  677. highlight: "邀请客户参观虚拟酒店,提供详细资料",
  678. applicable: "客户犹豫不决,决策周期长",
  679. advantage: "降低客户风险感知,提高转化率",
  680. successRate: "75%"
  681. }
  682. };
  683. }
  684. }