tab2.page.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. import { Component } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. import { IonHeader, IonToolbar, IonTitle, IonContent, ModalController, IonButton } from '@ionic/angular/standalone';
  4. import { ExploreContainerComponent } from '../explore-container/explore-container.component';
  5. import { ChatPanelOptions, FmChatModalInput, FmodeChat, FmodeChatMessage, openChatPanelModal } from 'fmode-ng';
  6. // import { ModalAudioMessageComponent } from 'fmode-ng/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component';
  7. import Parse from "parse";
  8. import {
  9. IonCard,
  10. IonCardHeader,
  11. IonCardTitle,
  12. IonCardSubtitle,
  13. IonCardContent,
  14. IonGrid,
  15. IonRow,
  16. IonCol,
  17. IonIcon
  18. } from '@ionic/angular/standalone';
  19. @Component({
  20. selector: 'app-tab2',
  21. templateUrl: 'tab2.page.html',
  22. styleUrls: ['tab2.page.scss'],
  23. standalone: true,
  24. imports: [
  25. IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent,
  26. IonButton,
  27. IonCard,
  28. IonCardHeader,
  29. IonCardTitle,
  30. IonCardSubtitle,
  31. IonCardContent,
  32. IonGrid,
  33. IonRow,
  34. IonCol,
  35. IonIcon,
  36. // ASR语音输入模块
  37. FmChatModalInput,
  38. // ModalAudioMessageComponent
  39. ]
  40. })
  41. export class Tab2Page {
  42. constructor(
  43. private modalCtrl:ModalController,
  44. private router:Router,
  45. ) {
  46. }
  47. title:string = "123"
  48. /** 示例:问诊ChatPanel面板 */
  49. openInquiry(chatId?:string){
  50. localStorage.setItem("company","E4KpGvTEto")
  51. let options:ChatPanelOptions = {
  52. roleId:"2DXJkRsjXK", // 预设,无需更改
  53. chatId:chatId, // 若存在,则恢复会话。若不存在,则开启新会话
  54. onChatInit:(chat:FmodeChat)=>{
  55. console.log("onChatInit");
  56. console.log("Chat类",chat);
  57. console.log("预设角色",chat.role);
  58. // 角色名称
  59. chat.role.set("name","晓晓");
  60. // 角色称号
  61. chat.role.set("title","全科医生");
  62. // 角色描述
  63. chat.role.set("desc","一名亲切和蔼的门诊全科主任医生,晓晓,年龄36岁");
  64. // 角色标签
  65. chat.role.set("tags",["全科","门诊"]);
  66. // 角色头像
  67. chat.role.set("avatar","https://nova-cloud.obs.cn-south-1.myhuaweicloud.com/storage/aigc/imagine/Q4Zif7fTbK-0.png")
  68. // 角色提示词
  69. chat.role.set("prompt",`
  70. # 角色设定
  71. 您是一名亲切和蔼的专业的全科医生,晓晓,年龄36岁,需要完成一次完整的门诊服务。
  72. # 对话环节
  73. 请您严格按照以下环节和用户展开对话,并且注意完成每个环节时,一定要携带[xx完成]的标记。
  74. ## 1. 导诊环节
  75. - **开始话语**:
  76. - “欢迎来到医院,请问您是第一次来吗?我会帮助您找到合适的科室。”
  77. - **进入下个环节条件**:
  78. - “已经大致了解您反映的情况,建议您到XX科室。[导诊完成]
  79. ## 2. 问诊环节
  80. - **对话内容**:
  81. - “请您详细描述一下您的情况,我需要了解您的病史和相关症状。”
  82. - “您是否有过敏史或其他健康问题?”
  83. - “根据您的情况,我认为我们需要进行一些检查,您觉得可以吗?”
  84. - **进入下个环节的条件**:
  85. - “谢谢您的配合,我将为您安排相关检查。[问诊完成]”
  86. ## 3. 检查环节
  87. - **对话内容**:
  88. - “我们已经完成了问诊,现在我会为您安排必要的检查。”
  89. - “请您稍等,检查结果会在不久后出来。”
  90. - “检查结果已经出来了,请您填写下报告的具体数据,让我来为您分析一下。”
  91. - **进入下个环节的条件**:
  92. - “检查结果已经初步分析,接下来需要请主任医生开始诊断。[检查完成]”
  93. ## 4. 诊断与处方环节
  94. - **对话内容**:
  95. - “根据问诊和检查结果,我的诊断是……”
  96. - “接下来,我会为您开具相应的处方,请您仔细阅读治疗方案和注意事项。”
  97. - “您是否有任何问题或者需要进一步的解释?”
  98. - **进入下个环节的条件**:
  99. - “感谢您的配合,您的处方已经开好,请您按照建议进行后续的治疗或复诊安排。[处方完成]”
  100. # 开始话语
  101. 当您准备好了,可以以一个医生的身份,向来访的用户打招呼。`);
  102. // 对话灵感分类
  103. let promptCates = [
  104. {
  105. "img": "https://file-cloud.fmode.cn/UP2cStyjuk/20231211/r1ltv1023812146.png",
  106. "name": "外科"
  107. },
  108. {
  109. "img": "https://file-cloud.fmode.cn/UP2cStyjuk/20231211/fo81fg034154259.png",
  110. "name": "内科"
  111. },
  112. {
  113. "img": "https://file-cloud.fmode.cn/UP2cStyjuk/20231211/fc1nqi034201098.png",
  114. "name": "心理"
  115. }
  116. ]
  117. setTimeout(() => {
  118. chat.role.set("promptCates",promptCates)
  119. }, 500);
  120. // 对话灵感列表
  121. let promptList = [
  122. {
  123. cate:"外科123",img:"https://file-cloud.fmode.cn/UP2cStyjuk/20231211/r1ltv1023812146.png",
  124. messageList:["局部疼痛或肿胀","伤口出血或感染","关节活动受限","体表肿块或结节","外伤后活动障碍","皮肤溃疡不愈合","异物刺入或嵌顿","术后并发症复查","肢体麻木或无力","运动损伤疼痛"]
  125. },
  126. {
  127. cate:"内科",img:"https://file-cloud.fmode.cn/UP2cStyjuk/20231211/fo81fg034154259.png",
  128. messageList:["反复发热或低热","持续咳嗽咳痰","胸闷气短心悸","慢性腹痛腹泻","头晕头痛乏力","体重骤增或骤减","食欲异常或消化不良","尿频尿急尿痛","睡眠障碍易醒","异常出汗或怕冷"]
  129. },
  130. {
  131. cate:"心理",img:"https://file-cloud.fmode.cn/UP2cStyjuk/20231211/fc1nqi034201098.png",
  132. messageList:["持续情绪低落","焦虑紧张不安","失眠或睡眠过多","注意力难以集中","社交恐惧回避","强迫思维或行为","记忆减退疑虑","躯体无器质性疼痛","自杀倾向念头","现实感丧失体验"]
  133. },
  134. ]
  135. let ChatPrompt = Parse.Object.extend("ChatPrompt");
  136. setTimeout(() => {
  137. chat.promptList = promptList.map(item=>{
  138. let prompt = new ChatPrompt();
  139. prompt.set(item);
  140. prompt.img = item.img;
  141. return prompt;
  142. })
  143. }, 500);
  144. // 功能按钮区域预设
  145. chat.leftButtons = [
  146. { // 提示 当角色配置预设提示词时 显示
  147. title:"话题灵感", // 按钮标题
  148. showTitle:true, // 是否显示标题文字
  149. icon:"color-wand-outline", // 标题icon图标
  150. onClick:()=>{ // 按钮点击事件
  151. chat.isPromptModalOpen = true
  152. },
  153. show:()=>{ // 按钮显示条件
  154. return chat?.promptList?.length // 存在话题提示词时显示
  155. }
  156. },
  157. { // 总结 结束并归档本次对话
  158. title:"门诊归档",
  159. showTitle:true,
  160. icon:"archive-outline",
  161. onClick:()=>{
  162. // 门诊归档,记录用户门诊咨询,并进行过程评价
  163. console.log(chat?.chatSession) // 本次会话内容数据
  164. },
  165. show:()=>{
  166. return true // 一直显示
  167. }
  168. }
  169. ]
  170. },
  171. onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
  172. console.log("onMessage",message)
  173. let content:any = message?.content
  174. if(typeof content == "string"){
  175. // 根据阶段标记判断下一步处理过程
  176. if (content.includes('[导诊完成]')) {
  177. // 进入问诊环节
  178. console.log('进入问诊环节');
  179. } else if (content.includes('[问诊完成]')) {
  180. // 进入检查环节
  181. console.log('进入检查环节');
  182. } else if (content.includes('[检查完成]')) {
  183. // 进入诊断与处方环节
  184. console.log('进入诊断与处方环节');
  185. } else if (content.includes('[处方完成]')) {
  186. // 结束会话或其他逻辑
  187. console.log('结束会话');
  188. }
  189. }
  190. },
  191. onChatSaved:(chat:FmodeChat)=>{
  192. // chat?.chatSession?.id 本次会话的 chatId
  193. console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
  194. }
  195. }
  196. openChatPanelModal(this.modalCtrl,options)
  197. }
  198. openConsult(chatId?:string){
  199. localStorage.setItem("company","E4KpGvTEto")
  200. let options:ChatPanelOptions = {
  201. roleId:"2DXJkRsjXK", // 预设,无需更改
  202. // chatId:chatId, // 若存在,则恢复会话。若不存在,则开启新会话
  203. onChatInit:(chat:FmodeChat)=>{
  204. console.log("onChatInit");
  205. console.log("Chat类",chat);
  206. console.log("预设角色",chat.role);
  207. // 角色名称
  208. chat.role.set("name","宋珀尔");
  209. // 角色称号
  210. chat.role.set("title","专业教练");
  211. // 角色描述
  212. chat.role.set("desc","一名亲切和蔼的健身教练,宋珀尔,年龄26岁");
  213. // 角色标签
  214. chat.role.set("tags",['跑步', '动感单车']);
  215. // 角色头像
  216. chat.role.set("avatar","/assets/avatars/jiaolian1.jpg")
  217. // 角色提示词
  218. chat.role.set("prompt",`
  219. # 角色设定
  220. 您是一名亲切和蔼的健身教练,宋珀尔,年龄26岁,需要您解答用户健身方面的专业问题。
  221. `);
  222. // 对话灵感分类
  223. let promptCates = [
  224. {
  225. "img": "/assets/icon/yy.jpg",
  226. "name": "有氧"
  227. },
  228. {
  229. "img": "/assets/icon/jz.jpg",
  230. "name": "减脂"
  231. },
  232. {
  233. "img": "/assets/icon/zj.jpg",
  234. "name": "增肌"
  235. }
  236. ]
  237. setTimeout(() => {
  238. chat.role.set("promptCates",promptCates)
  239. }, 500);
  240. // 对话灵感列表
  241. let promptList = [
  242. {
  243. cate:"有氧",img:"/assets/icon/yy.jpg",
  244. messageList:[
  245. "有氧运动多久才能有效减脂?",
  246. "跑步和游泳哪个减肥效果更好?",
  247. "空腹有氧真的更燃脂吗?",
  248. "有氧运动会不会掉肌肉?",
  249. "心率控制在多少才能高效燃脂?",
  250. "每天做有氧运动会不会过度疲劳?",
  251. "有氧运动前要不要吃东西?",
  252. "椭圆机和跑步机哪个更适合新手?",
  253. "跳绳会不会伤膝盖?",
  254. "有氧运动后怎么补充能量?"
  255. ]
  256. },
  257. {
  258. cate:"减脂",img:"/assets/icon/jz.jpg",
  259. messageList:[
  260. "减脂一定要做有氧吗?",
  261. "为什么体重没变但看起来瘦了?",
  262. "局部减脂(如瘦肚子)真的存在吗?",
  263. "减脂期每天应该吃多少热量?",
  264. "低碳饮食和低脂饮食哪个更适合减脂?",
  265. "为什么运动后体重反而增加了?",
  266. "减脂期可以吃零食吗?",
  267. "平台期怎么突破?",
  268. "晚上吃东西会不会更容易长胖?",
  269. "减脂期要不要计算蛋白质摄入?"
  270. ]
  271. },
  272. {
  273. cate:"增肌",img:"/assets/icon/zj.jpg",
  274. messageList: [
  275. "增肌一定要喝蛋白粉吗?",
  276. "为什么练了很久肌肉不长?",
  277. "增肌期可以同时减脂吗?",
  278. "训练后多久补充蛋白质最有效?",
  279. "增肌需要每天练同一个部位吗?",
  280. "徒手训练(如俯卧撑)能有效增肌吗?",
  281. "增肌期体重不增长是怎么回事?",
  282. "肌肉酸痛还能继续练吗?",
  283. "增肌训练每组做多少次最合适?",
  284. "睡眠对增肌的影响有多大?"
  285. ]
  286. },
  287. ]
  288. let ChatPrompt = Parse.Object.extend("ChatPrompt");
  289. setTimeout(() => {
  290. chat.promptList = promptList.map(item=>{
  291. let prompt = new ChatPrompt();
  292. prompt.set(item);
  293. prompt.img = item.img;
  294. return prompt;
  295. })
  296. }, 500);
  297. // 功能按钮区域预设
  298. chat.leftButtons = [
  299. { // 提示 当角色配置预设提示词时 显示
  300. title:"话题灵感", // 按钮标题
  301. showTitle:true, // 是否显示标题文字
  302. icon:"color-wand-outline", // 标题icon图标
  303. onClick:()=>{ // 按钮点击事件
  304. chat.isPromptModalOpen = true
  305. },
  306. show:()=>{ // 按钮显示条件
  307. return chat?.promptList?.length // 存在话题提示词时显示
  308. }
  309. },
  310. ]
  311. },
  312. onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
  313. console.log("onMessage",message)
  314. let content:any = message?.content
  315. if(typeof content == "string"){
  316. // 根据阶段标记判断下一步处理过程
  317. if (content.includes('[导诊完成]')) {
  318. // 进入问诊环节
  319. console.log('进入问诊环节');
  320. } else if (content.includes('[问诊完成]')) {
  321. // 进入检查环节
  322. console.log('进入检查环节');
  323. } else if (content.includes('[检查完成]')) {
  324. // 进入诊断与处方环节
  325. console.log('进入诊断与处方环节');
  326. } else if (content.includes('[处方完成]')) {
  327. // 结束会话或其他逻辑
  328. console.log('结束会话');
  329. }
  330. }
  331. },
  332. onChatSaved:(chat:FmodeChat)=>{
  333. // chat?.chatSession?.id 本次会话的 chatId
  334. console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
  335. }
  336. }
  337. openChatPanelModal(this.modalCtrl,options)
  338. }
  339. /**
  340. * 开始聊天
  341. */
  342. openChat(){
  343. let options:ChatPanelOptions = {
  344. roleId:"2DXJkRsjXK",
  345. onChatSaved:(chat:FmodeChat)=>{
  346. // chat?.chatSession?.id 本次会话的 chatId
  347. console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
  348. },
  349. }
  350. openChatPanelModal(this.modalCtrl,options)
  351. }
  352. /**
  353. * 恢复聊天
  354. * @chatId 从onChatSaved生命周期中,获取chat?.chatSession?.id
  355. */
  356. restoreChat(chatId:string){
  357. let options:ChatPanelOptions = {
  358. roleId:"2DXJkRsjXK",
  359. chatId:chatId
  360. }
  361. openChatPanelModal(this.modalCtrl,options)
  362. }
  363. goChat(){
  364. this.router.navigateByUrl("/chat/session/role/2DXJkRsjXK")
  365. }
  366. // audioModalHeightPoint:number = 0.35;
  367. // async startTalk(){
  368. // // 根据手机兼容性,适配组件弹出高度
  369. // let height = document.body.clientHeight || 960;
  370. // this.audioModalHeightPoint = Number((165/height).toFixed(2));
  371. // // 弹出组件
  372. // let modal:any
  373. // let chat:any
  374. // modal = await this.modalCtrl.create({
  375. // component:ModalAudioMessageComponent,
  376. // componentProps:{
  377. // chat:chat,
  378. // modal:modal,
  379. // onBreakPointSet:()=>{
  380. // modal?.setCurrentBreakpoint(this.audioModalHeightPoint)
  381. // }
  382. // }
  383. // })
  384. // modal.present();
  385. // }
  386. }