page-create-agent.component.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. import { Component, OnInit } from '@angular/core';
  2. import { Router } from '@angular/router';
  3. import { CloudObject, CloudQuery, CloudUser } from 'src/lib/ncloud';
  4. import { LoadingController,IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonIcon, ModalController, IonTextarea, IonInput, IonCard, IonCardHeader, IonCardTitle, IonThumbnail, IonCardContent, IonCardSubtitle, IonItem, IonList, IonLabel, IonAvatar, IonSelect, IonSelectOption, AlertController, IonButtons, IonProgressBar, IonText, IonRefresherContent, IonRefresher, ToastController, IonToast, IonFooter, IonBackButton } from '@ionic/angular/standalone';
  5. import { CommonModule } from '@angular/common';
  6. import { AvatarModule, ChatPanelOptions, DalleOptions, FmodeChat, FmodeChatCompletion, FmodeChatMessage, ImagineWork, openChatPanelModal } from 'fmode-ng';
  7. import { FormsModule } from '@angular/forms';
  8. import { IonicModule } from '@ionic/angular';
  9. @Component({
  10. selector: 'app-page-create-agent',
  11. templateUrl: './page-create-agent.component.html',
  12. styleUrls: ['./page-create-agent.component.scss'],
  13. standalone: true,
  14. imports: [
  15. IonFooter,
  16. IonBackButton,
  17. IonHeader,
  18. IonToolbar,
  19. IonTitle,
  20. IonContent,
  21. IonButton,
  22. IonTextarea,
  23. IonInput,
  24. IonIcon,
  25. IonCard,
  26. IonCardHeader,
  27. IonCardTitle,
  28. IonCardSubtitle,
  29. IonCardContent,
  30. IonThumbnail,
  31. IonItem,
  32. IonList,
  33. CommonModule,
  34. IonLabel,
  35. IonAvatar,
  36. IonSelect,
  37. IonSelectOption,
  38. IonButtons,
  39. IonProgressBar,
  40. IonText,
  41. IonCardHeader,
  42. IonCardSubtitle,
  43. IonRefresher,
  44. IonRefresherContent,
  45. IonToast,FormsModule
  46. ],
  47. })
  48. export class PageCreateAgentComponent implements OnInit {
  49. public buffer = 0.05;
  50. public progress = 0;
  51. // async presentToast(position: 'top' | 'middle' | 'bottom') {
  52. // const toast = await this.toastController.create({
  53. // message: '正在创建智能体,请耐心等待!',
  54. // duration: 1500,
  55. // position: position,
  56. // });
  57. // await toast.present();
  58. // }
  59. handleRefresh(event:any) {
  60. setTimeout(() => {
  61. // Any calls to load data go here
  62. this.loadAgentData()
  63. event.target.complete();
  64. }, 2000);
  65. }
  66. currentUser: CloudUser;
  67. constructor(
  68. private toastController: ToastController,
  69. private modalCtrl:ModalController,
  70. private router:Router,
  71. private alertController: AlertController,
  72. private loadingController: LoadingController,
  73. ) {
  74. this.currentUser = new CloudUser();
  75. // 示例任务,自己生成图片后请存储新的ID
  76. this.imagineWork = new ImagineWork("");
  77. this.imagineWork.fetchTask().then(work=>{
  78. if(work){
  79. this.imagineWork.id = work.id
  80. }
  81. this.images = this.imagineWork?.images || '../../assets/image/头像示例.png';
  82. })
  83. this.loadAgentData()
  84. }
  85. images:Array<string> = []
  86. ngOnInit() {
  87. }
  88. name: string = ''
  89. nameInput(e:any) {
  90. this.name = e.detail.value;
  91. console.log(this.name);
  92. }
  93. age: number = 18;
  94. ageInput(e:any) {
  95. this.age = e.detail.value;
  96. console.log(this.age);
  97. }
  98. gender: string = "男";
  99. genderChange(e:any) {
  100. console.log('ionChange fired with value: ' + e.detail.value);
  101. this.gender = e.detail.value;
  102. }
  103. genderCancel(){
  104. }
  105. genderDismiss(){
  106. }
  107. // 描述
  108. desc: string = ''
  109. descInput(e:any) {
  110. this.desc = e.detail.value;
  111. console.log(this.desc);
  112. }
  113. imagineWork:ImagineWork
  114. PictureDescResult:string = `` // 画面描述结果
  115. loading: HTMLIonLoadingElement | null = null;
  116. // 创建医生
  117. async createAgent() {
  118. let alert1 = await this.alertController.create({
  119. header: '温馨提示',
  120. subHeader: 'Tips',
  121. message: '把信息填写完整哦~',
  122. buttons: ['好的'],
  123. });
  124. let alert2 = await this.alertController.create({
  125. header: '温馨提示',
  126. subHeader: 'Tips',
  127. message: '智能体已经创建成功!',
  128. buttons: ['好的'],
  129. });
  130. let alert4 = await this.alertController.create({
  131. header: '温馨提示',
  132. subHeader: 'Tips',
  133. message: '智能体创建失败,请重新创建!',
  134. buttons: ['好的'],
  135. });
  136. if (this.name == '' || this.age == 0 || this.gender == '' || this.desc == '') {
  137. await alert1.present();
  138. return;
  139. }
  140. this.loading = await this.loadingController.create({
  141. message: '智能体生成中...',
  142. });
  143. await this.loading.present();
  144. localStorage.setItem("company","E4KpGvTEto")
  145. let consult = new CloudObject("DoctorAgent")
  146. let now = new Date();
  147. let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
  148. // 对象权限的精确指定
  149. let ACL:any = {
  150. "*":{read:true,write:true}
  151. }
  152. if(this.currentUser?.id){
  153. ACL[this.currentUser?.id] = {read:true,write:true}
  154. }
  155. this.imagineWork = new ImagineWork();
  156. // 文本生成
  157. let PromptTemplate = `您是一名专业的美术画家,擅长画各类型头像图,请您根据下面提供的需求内容,将其描述的画面、场景、人物、物品等用最简短的语言表达,直接写出画面,
  158. 需求如下:
  159. ${this.name},${this.age}岁,${this.gender},描述:${this.desc}
  160. `
  161. let completion = new FmodeChatCompletion([
  162. {role:"system",content:""},
  163. {role:"user",content:PromptTemplate}
  164. ])
  165. let avatar = ""
  166. if (!this.name || !this.desc){
  167. this.progress = 0; // 进度条重置
  168. await alert4.present();
  169. }
  170. completion.sendCompletion().subscribe((message:any)=>{
  171. // 打印消息体
  172. console.log(message.content)
  173. // 赋值消息内容给组件内属性
  174. this.PictureDescResult = message.content
  175. if(this.progress<0.97){
  176. if(this.progress<0.5){
  177. this.progress+=0.002
  178. }
  179. if(this.progress>=0.8){
  180. this.progress+=0.001
  181. }
  182. }
  183. if(message?.complete){ // 判断message为完成状态,则设置isComplete为完成
  184. // 图片生成
  185. let PicturePrompt = `${this.PictureDescResult}\n风格:画面不带任何文字。人物为主体,人物要在图片的正中央。其中人物必须帅气,符合现代中国人审美。`
  186. let options:DalleOptions = {prompt:PicturePrompt}
  187. this.imagineWork?.draw(options).subscribe(async work=>{
  188. if(this.progress<0.5){
  189. this.progress+=0.01
  190. }
  191. if(this.progress>=0.8){
  192. this.progress+=0.001
  193. }
  194. if(work?.get("images")?.length){
  195. if (this.loading) {
  196. await this.loading.dismiss();
  197. this.loading = null; // 清空 loading 实例
  198. }
  199. avatar = work?.get("images")[0];
  200. consult.set({
  201. avatar:`${avatar}`,
  202. name:`${this.name}`,
  203. age:`${this.age}`,
  204. gender:`${this.gender}`,
  205. desc:`${this.desc}`,
  206. user:this.currentUser.toPointer(),
  207. ACL:ACL,
  208. })
  209. this.progress=0
  210. consult.save();
  211. // this.progress = 1;
  212. console.log("consult",consult);
  213. alert2.present();
  214. this.loadAgentData();
  215. this.name = ''
  216. this.desc = ''
  217. }
  218. })
  219. }
  220. })
  221. }
  222. agentList: Array<CloudObject> = [];
  223. async loadAgentData() {
  224. let user = new CloudUser();
  225. let query = new CloudQuery("DoctorAgent")
  226. query.equalTo("user",user?.id)
  227. let agentlist = await query.find()
  228. // 将查询到的数据反向排序
  229. this.agentList = agentlist.reverse()
  230. console.log(this.agentList);
  231. }
  232. openInquiry(doctor:CloudObject){
  233. // 验证用户登录
  234. let currentUser = new CloudUser();
  235. let userPrompt = ``
  236. if(currentUser?.get("realname")){
  237. userPrompt += `当前来访的患者,姓名:${currentUser?.get("realname")}`
  238. }
  239. if(currentUser?.get("gender")){
  240. userPrompt += `,性别:${currentUser?.get("gender")}`
  241. }
  242. if(currentUser?.get("age")){
  243. userPrompt += `,年龄:${currentUser?.get("age")}`
  244. }
  245. localStorage.setItem("company","E4KpGvTEto")
  246. let consult = new CloudObject("Consultation")
  247. let now = new Date();
  248. let dateStr = `${now.getFullYear()}-${now.getMonth()+1}-${now.getDate()}`
  249. // 对象权限的精确指定
  250. let ACL:any = {
  251. "*":{read:true,write:true}
  252. }
  253. if(currentUser?.id){
  254. ACL[currentUser?.id] = {read:true,write:true}
  255. }
  256. consult.set({
  257. title:`门诊记录${dateStr}-${doctor?.get("name")}`,
  258. doctor:doctor.toPointer(),
  259. user:currentUser.toPointer(),
  260. ACL:ACL
  261. })
  262. let options:ChatPanelOptions = {
  263. roleId:"2DXJkRsjXK",
  264. onChatInit:(chat:FmodeChat)=>{
  265. console.log("onChatInit");
  266. console.log("预设角色",chat.role);
  267. chat.role.set("name",doctor?.get("name"));
  268. chat.role.set("desc",doctor?.get("desc"));
  269. chat.role.set("avatar",doctor?.get("avatar") || "../../assets/image/doctor7.png")
  270. chat.role.set("prompt",`
  271. # 角色设定
  272. 您是${doctor?.get("name")},${doctor?.get("desc")},年龄${doctor?.get("age")}岁,需要完成一次完整的门诊服务。
  273. # 对话环节
  274. 0.直接和用户打招呼(如:你好,XXX,我是···)
  275. - 注意:如果用户问的问题和你的${doctor?.get("desc")}的不符,请直接引导用户去其他的地方
  276. 1.预设的问询方式(根据不同症状来问询具体的情况)
  277. - 打招呼,以用户自述为主
  278. - 当信息充足时候,确认用户症状对应的科室,并进入下一个环节
  279. 2.拓展的问询细节
  280. 例如:用户反映呼吸不畅,拓展出:是否咳嗽;是否感觉痛或者痒等其他需要的问题。
  281. - 当问询细节补充完成后进入下一个环节
  282. 3.初步的诊断结果,并且同时列出检查检验项目
  283. 初步诊断:确定需要有哪些进一步检查
  284. 检查检验:获取医学客观数据
  285. - 等待用户提交客观数据,进入下一阶段
  286. 4.给出诊断方案并给出处方
  287. - 完成处方时,请在消息结尾附带: [处方完成]
  288. # 开始话语
  289. 当您准备好了,可以以一个医生的身份,向来访的用户打招呼。
  290. ${userPrompt}
  291. `);
  292. },
  293. onMessage:(chat:FmodeChat,message:FmodeChatMessage)=>{
  294. console.log("onMessage",message)
  295. let content:any = message?.content
  296. if(typeof content == "string"){
  297. if(content?.indexOf("[处方完成]")>-1){
  298. console.log("门诊已完成")
  299. let list = chat?.messageList
  300. console.log("门诊已完成")
  301. consult.set({
  302. allContent:list,
  303. content:content // 处方内容
  304. })
  305. consult.save();
  306. }
  307. }
  308. },
  309. onChatSaved:(chat:FmodeChat)=>{
  310. // chat?.chatSession?.id 本次会话的 chatId
  311. console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
  312. }
  313. }
  314. openChatPanelModal(this.modalCtrl,options)
  315. }
  316. async deleteAgent(agent:CloudObject){
  317. const alert = await this.alertController.create({
  318. header: '确认删除',
  319. message: `确定要删除 ${agent.get('name')} 吗?`,
  320. buttons: [
  321. {
  322. text: '取消',
  323. role: 'cancel',
  324. },
  325. {
  326. text: '确认',
  327. handler: () => {
  328. this.agentList = this.agentList.filter(a => a.id !== agent.id);
  329. this.presentToast('智能体已删除。');
  330. },
  331. },
  332. ],
  333. });
  334. await alert.present();
  335. console.log("删除了",agent);
  336. agent.destroy();
  337. this.loadAgentData();
  338. }
  339. async presentToast(message: string) {
  340. const toast = await this.toastController.create({
  341. message,
  342. duration: 2000,
  343. position: 'bottom',
  344. });
  345. toast.present();
  346. }
  347. }