fmode-ng 0.0.48 → 0.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/aigc/chat/chat-list/chat-list.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-message-card/duration-str.pipe.mjs +10 -0
- package/esm2022/lib/aigc/chat/chat-message-card/index.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/chat-panel/chat-panel.component.mjs +1 -1
- package/esm2022/lib/aigc/chat/comp-role-prompt/comp-role-prompt.component.mjs +1 -1
- package/esm2022/lib/aigc/comp-markdown-preview/markdown-parse.mjs +1 -1
- package/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs +1 -1
- package/esm2022/lib/platform/cross.service.mjs +1 -1
- package/esm2022/lib/user/account/account.service.mjs +1 -1
- package/esm2022/lib/user/comp-user-avatar/comp-user-avatar.component.mjs +1 -1
- package/esm2022/lib/user/modal-user-login/modal-user-login.component.mjs +1 -1
- package/fesm2022/fmode-ng.mjs +1 -1
- package/fesm2022/fmode-ng.mjs.map +1 -1
- package/lib/aigc/chat/chat-message-card/comp-message-card.component.d.ts +3 -1
- package/lib/aigc/chat/chat-message-card/duration-str.pipe.d.ts +7 -0
- package/lib/aigc/chat/chat-message-card/index.d.ts +1 -0
- package/lib/aigc/chat/chat-modal-input/modal-input.component.d.ts +7 -2
- package/lib/aigc/chat/chat-panel/chat-panel.component.d.ts +7 -2
- package/lib/aigc/service-fmai/service-chat/chat-class.d.ts +14 -0
- package/lib/platform/cross.service.d.ts +3 -4
- package/lib/user/modal-user-login/modal-user-login.component.d.ts +3 -0
- package/package.json +2 -2
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-list/chat-list.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{CommonModule}from"@angular/common";import{Component,Input}from"@angular/core";import{AlertController,IonAvatar,IonButton,IonIcon,IonItem,IonLabel,IonList,IonNote,IonText,NavController}from"@ionic/angular/standalone";import{ChatService}from"../../service-fmai/service-chat/chat.service";import*as i0 from"@angular/core";import*as i1 from"../../service-fmai/service-chat/chat.service";import*as i2 from"@ionic/angular/standalone";import*as i3 from"@angular/common";export class ChatListComponent{constructor(t,e,n){this.chatServ=t,this.alertCtrl=e,this.navCtrl=n,this.chatList=[],this.onItemClick=t=>{this.goSession(t)},this.avatar="https://ionicframework.com/docs/img/demos/avatar.svg",this.isPreventGo=!1,this.chatServ.getChatSession().then((()=>{}))}async goSession(t){if(!this.isPreventGo)if(t?.rid||t?.sid)this.chatServ.restoreChatPanel(t);else{(await this.alertCtrl.create({header:"注意",subHeader:"请您选择右侧角色",message:"开始对话",buttons:[{role:"ok",text:"知道了",handler:()=>{}}]})).present(),this.navCtrl.navigateRoot("/chat/pro/mask")}}async presentEditTitle(t,e,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const i=await this.alertCtrl.create({header:"修改会话标题",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:n=>{e.title=n.title,t?.set("title",n.title),t?.save()}}],inputs:[{placeholder:"会话标题",name:"title",value:e?.title||""}]});await i.present()}async presentDeleteTItle(t,e,n){this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const i=await this.alertCtrl.create({header:"确认删除?",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:()=>{e.isHidden=!0,t?.set("isDeleted",!0),t?.save()}}]});await i.present()}truncateString(t){return t&&t.length>10?t.slice(0,10)+"...":t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,deps:[{token:i1.ChatService},{token:i2.AlertController},{token:i2.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatListComponent,isStandalone:!0,selector:"app-chat-list",inputs:{onItemClick:"onItemClick"},providers:[],ngImport:i0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i3.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i3.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i3.DatePipe,name:"date"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:IonAvatar,selector:"ion-avatar"},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonText,selector:"ion-text",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,decorators:[{type:Component,args:[{selector:"app-chat-list",imports:[CommonModule,IonIcon,IonList,IonLabel,IonNote,IonButton,IonAvatar,IonItem,IonText],providers:[],standalone:!0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"]}]}],ctorParameters:()=>[{type:i1.ChatService},{type:i2.AlertController},{type:i2.NavController}],propDecorators:{onItemClick:[{type:Input}]}});
|
|
8
|
+
import{CommonModule}from"@angular/common";import{Component,Input}from"@angular/core";import{AlertController,IonAvatar,IonButton,IonIcon,IonItem,IonLabel,IonList,IonNote,IonText,NavController}from"@ionic/angular/standalone";import{ChatService}from"../../service-fmai/service-chat/chat.service";import*as i0 from"@angular/core";import*as i1 from"../../service-fmai/service-chat/chat.service";import*as i2 from"@ionic/angular/standalone";import*as i3 from"@angular/common";export class ChatListComponent{constructor(t,e,n){this.chatServ=t,this.alertCtrl=e,this.navCtrl=n,this.chatList=[],this.onItemClick=(t,e)=>{e.stopPropagation(),this.goSession(t)},this.avatar="https://ionicframework.com/docs/img/demos/avatar.svg",this.isPreventGo=!1,this.chatServ.getChatSession().then((()=>{}))}async goSession(t){if(!this.isPreventGo)if(t?.rid||t?.sid)this.chatServ.restoreChatPanel(t);else{(await this.alertCtrl.create({header:"注意",subHeader:"请您选择右侧角色",message:"开始对话",buttons:[{role:"ok",text:"知道了",handler:()=>{}}]})).present(),this.navCtrl.navigateRoot("/chat/pro/mask")}}async presentEditTitle(t,e,n){n.stopPropagation(),this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const i=await this.alertCtrl.create({header:"修改会话标题",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:n=>{e.title=n.title,t?.set("title",n.title),t?.save()}}],inputs:[{placeholder:"会话标题",name:"title",value:e?.title||""}]});await i.present()}async presentDeleteTItle(t,e,n){n.stopPropagation(),this.isPreventGo=!0,setTimeout((()=>{this.isPreventGo=!1}),500),n.preventDefault();const i=await this.alertCtrl.create({header:"确认删除?",subHeader:"",message:"",buttons:[{text:"取消",role:"cancel",handler:()=>{}},{text:"确定",role:"confirm",handler:()=>{e.isHidden=!0,t?.set("isDeleted",!0),t?.save()}}]});await i.present()}truncateString(t){return t&&t.length>10?t.slice(0,10)+"...":t}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,deps:[{token:i1.ChatService},{token:i2.AlertController},{token:i2.NavController}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatListComponent,isStandalone:!0,selector:"app-chat-list",inputs:{onItemClick:"onItemClick"},providers:[],ngImport:i0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat,$event)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i3.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i3.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i3.DatePipe,name:"date"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonLabel,selector:"ion-label",inputs:["color","mode","position"]},{kind:"component",type:IonNote,selector:"ion-note",inputs:["color","mode"]},{kind:"component",type:IonAvatar,selector:"ion-avatar"},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonText,selector:"ion-text",inputs:["color","mode"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatListComponent,decorators:[{type:Component,args:[{selector:"app-chat-list",imports:[CommonModule,IonIcon,IonList,IonLabel,IonNote,IonButton,IonAvatar,IonItem,IonText],providers:[],standalone:!0,template:'<ion-list>\n <ng-container *ngFor="let chat of (chatServ?.chatList || chatList)">\n <ion-item [button]="true" detail="false" *ngIf="!chat?.isHidden" (click)="onItemClick(chat,$event)">\n <div class="unread-indicator-wrapper" slot="start">\n <div class="unread-indicator"></div>\n </div>\n <ion-label>\n <div style="display: flex;justify-content: space-between; align-items: center;">\n <div style="display: flex; flex-direction: row;align-items: center;">\n <strong style="display: flex;align-items: center;">\n <ion-avatar style="margin-right: 10px;">\n <img [src]="chat?.thumb||avatar" />\n </ion-avatar>\n <p style="max-width: 7rem;white-space: nowrap;">{{truncateString(chat?.title)}}</p>\n </strong>\n\n <ion-icon (click)="presentEditTitle(chat?.session,chat,$event)" name="brush-sharp" style="margin-left: 1rem;"></ion-icon>\n <ion-icon (click)="presentDeleteTItle(chat?.session,chat,$event)" name="trash-sharp" style="margin-left: 0.5rem;"></ion-icon>\n \n </div>\n <div class="metadata-end-wrapper" slot="end">\n <ion-note color="medium">{{chat?.latest | date:"HH:mm"}}</ion-note>\n <ion-icon color="medium" name="chevron-forward"></ion-icon>\n </div>\n </div>\n <ion-text></ion-text><br />\n <ion-note color="medium" class="ion-text-wrap">\n {{chat?.message}}\n </ion-note>\n </ion-label>\n </ion-item>\n </ng-container>\n </ion-list>',styles:["ion-icon{color:#fff}ion-list{margin:3px}ion-list ion-item{--inner-padding-bottom:0px;--inner-padding-end:0px;--inner-padding-start:0px;--inner-padding-to:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--padding-to:0px}ion-list ul{width:100%;list-style-type:none;padding:0;margin:0 0 10px;display:flex;flex-wrap:wrap;background-color:#fff;border-radius:10px}ion-list ul .active__{position:relative;padding:5px 15px;font-size:18px;font-weight:700;color:#535353;transition:.3s}ion-list ul .active{color:#2d8af7;background-color:#f2f4ff;border-radius:10px}ion-list ul li{flex:1 1 auto}ion-list ul li div{cursor:pointer;text-align:center}\n"]}]}],ctorParameters:()=>[{type:i1.ChatService},{type:i2.AlertController},{type:i2.NavController}],propDecorators:{onItemClick:[{type:Input}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1saXN0L2NoYXQtbGlzdC5jb21wb25lbnQubWpz`
|
|
10
10
|
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{CommonModule}from"@angular/common";import{Component,Input}from"@angular/core";import{ChatService,FmodeChat}from"../../service-fmai/service-chat";import{FmChatMessageCard}from"../chat-message-card/comp-message-card.component";import{CompRolePromptComponent}from"../comp-role-prompt/comp-role-prompt.component";import*as i0 from"@angular/core";import*as i1 from"../../service-fmai/service-chat";import*as i2 from"@angular/common";export class FmChatMesssageArea{get messageList(){return this.chatServ.chatMap[this.chatId]?.messageList}constructor(e){this.chatServ=e}ngDoCheck(){}ngAfterViewInit(){console.log("ng gogogo1"),console.log("ng gogogo2"),console.log(this.chat)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,deps:[{token:i1.ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"
|
|
8
|
+
import{CommonModule}from"@angular/common";import{Component,Input}from"@angular/core";import{ChatService,FmodeChat}from"../../service-fmai/service-chat";import{FmChatMessageCard}from"../chat-message-card/comp-message-card.component";import{CompRolePromptComponent}from"../comp-role-prompt/comp-role-prompt.component";import*as i0 from"@angular/core";import*as i1 from"../../service-fmai/service-chat";import*as i2 from"@angular/common";export class FmChatMesssageArea{get messageList(){return this.chatServ.chatMap[this.chatId]?.messageList}constructor(e){this.chatServ=e}ngDoCheck(){}ngAfterViewInit(){console.log("ng gogogo1"),console.log("ng gogogo2"),console.log(this.chat)}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,deps:[{token:i1.ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"17.3.12",type:FmChatMesssageArea,isStandalone:!0,selector:"fm-chat-message-area",inputs:{chatId:"chatId",chat:"chat"},ngImport:i0,template:'\n<div class="message-list">\n <app-comp-role-prompt [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList;let index=index;">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [index]="index" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n @if(!chat?.hideInputPreview){\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n \n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n }\n</div>',styles:[".message-list{padding:5px 20px}:host-context(body.dark) .message-list{background-color:#000!important}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatMessageCard,selector:"fm-chat-message-card",inputs:["index","message","role","chat"]},{kind:"component",type:CompRolePromptComponent,selector:"app-comp-role-prompt",inputs:["chat","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMesssageArea,decorators:[{type:Component,args:[{selector:"fm-chat-message-area",standalone:!0,imports:[CommonModule,FmChatMessageCard,CompRolePromptComponent],template:'\n<div class="message-list">\n <app-comp-role-prompt [chat]="chat" [role]="chat?.role?.id"></app-comp-role-prompt>\n <ng-container *ngFor="let message of chat?.messageList;let index=index;">\n \x3c!-- 内容格式化区域 --\x3e\n <fm-chat-message-card [chat]="chat" *ngIf="!message?.hidden" [index]="index" [message]="message" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n\n @if(!chat?.hideInputPreview){\n \x3c!-- 预览无图消息 --\x3e\n <ng-container *ngIf="chat?.userInput&&!chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:chat?.userInput}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n \n \x3c!-- 预览有图消息 --\x3e\n <ng-container *ngIf="chat?.userImage">\n <fm-chat-message-card [chat]="chat" [message]="{role:\'user\',content:[{type:\'text\',text:chat?.userInput},{type:\'image_url\',image_url:{url:chat?.userImage}}]}" [role]="chat?.role"></fm-chat-message-card>\n </ng-container>\n }\n</div>',styles:[".message-list{padding:5px 20px}:host-context(body.dark) .message-list{background-color:#000!important}\n"]}]}],ctorParameters:()=>[{type:i1.ChatService}],propDecorators:{chatId:[{type:Input}],chat:[{type:Input}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tZXNzYWdlLWFyZWEvY29tcC1tZXNzYWdlLWFyZWEuY29tcG9uZW50Lm1qcw==`
|
|
10
10
|
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{Component,Input}from"@angular/core";import{ChatContentPipe,FmodeChat,getMessageContentText}from"../../service-fmai/service-chat";import Parse from"parse";import{CommonModule}from"@angular/common";import{IonAvatar,IonItem}from"@ionic/angular/standalone";import{CompUserAvatarComponent}from"../../../user/comp-user-avatar/comp-user-avatar.component";import{NzAvatarModule}from"ng-zorro-antd/avatar";import{ClipboardService}from"../../comp-markdown-preview/clipboard.service";import{MarkdownPreviewModule}from"../../comp-markdown-preview/markdown-preview.module";import{NzSanitizerPipe}from"ng-zorro-antd/pipes";import{NzIconModule}from"ng-zorro-antd/icon";import*as i0 from"@angular/core";import*as i1 from"../../comp-markdown-preview/clipboard.service";import*as i2 from"@angular/common";import*as i3 from"../../comp-markdown-preview/markdown-preview.component";import*as i4 from"ng-zorro-antd/avatar";import*as i5 from"ng-zorro-antd/icon";export class FmChatMessageCard{constructor(e){this.copyServ=e,this.user=Parse.User.current()}async toggleVoicePlay(){if(this.message?.voice?.id&&(this.tts=this.chat.VoiceTTSMap[this.message?.voice?.id],console.log(this.message?.voice),console.log(this.tts,this.tts.isPlaying)),this.tts?.isPlaying)return void this.tts.stop();let e,t=!1;if(this.message?.voice?.id){let t=new Parse.Query("ChatVoice");t.include("voiceFile"),e=await t.get(this.message?.voice?.id)}if(!e?.id){let n=await this.chat.getVoiceByContentText(this.message?.content);e=this.chat.voiceMap[n?.id],this.message.voice={id:e?.id,duration:e?.get("duration")},t=!0}this.message?.voice?.duration||(this.message.voice.duration=e?.get("duration"),t=!0),t&&this.chat?.saveChatSession(),await this.chat.playChatVoice(e,{onStart:t=>{e?.id,t?.id},onLoaded:e=>{this.message.voice.duration=1e3*e.duration,this.updateVoiceDuration(1e3*e.duration)},onStop:t=>{e?.id,t?.id}}),this.tts=this.chat.VoiceTTSMap[e?.id]}updateVoiceDuration(e){this.message?.voice?.duration||(this.message.voice.duration=e,this.chat?.saveChatSession())}async copy(){this.copyServ.copyToClipboard(getMessageContentText(this.message?.content))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,deps:[{token:i1.ClipboardService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMessageCard,isStandalone:!0,selector:"fm-chat-message-card",inputs:{message:"message",role:"role",chat:"chat"},ngImport:i0,template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="message?.role==\'assistant\'||(message?.role==\'user\'&&message?.voice)" class="play-voice" (click)="toggleVoicePlay()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="tts?.isPlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000)|number:\'1.0-0\'}}"\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em;font-size:12px;font-weight:100;padding:5px 20px}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2.DecimalPipe,name:"number"},{kind:"pipe",type:i2.DatePipe,name:"date"},{kind:"component",type:CompUserAvatarComponent,selector:"app-comp-user-avatar",inputs:["user"]},{kind:"ngmodule",type:MarkdownPreviewModule},{kind:"component",type:i3.MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:["content","render"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i4.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]},{kind:"ngmodule",type:NzIconModule},{kind:"directive",type:i5.NzIconDirective,selector:"[nz-icon]",inputs:["nzSpin","nzRotate","nzType","nzTheme","nzTwotoneColor","nzIconfont"],exportAs:["nzIcon"]},{kind:"pipe",type:ChatContentPipe,name:"chatContent"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,decorators:[{type:Component,args:[{selector:"fm-chat-message-card",standalone:!0,imports:[CommonModule,IonItem,CompUserAvatarComponent,MarkdownPreviewModule,NzAvatarModule,IonAvatar,NzIconModule,ChatContentPipe,NzSanitizerPipe],template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="message?.role==\'assistant\'||(message?.role==\'user\'&&message?.voice)" class="play-voice" (click)="toggleVoicePlay()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="tts?.isPlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000)|number:\'1.0-0\'}}"\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em;font-size:12px;font-weight:100;padding:5px 20px}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n']}]}],ctorParameters:()=>[{type:i1.ClipboardService}],propDecorators:{message:[{type:Input}],role:[{type:Input}],chat:[{type:Input}]}});
|
|
8
|
+
import{Component,Input}from"@angular/core";import{ChatContentPipe,FmodeChat,getMessageContentText}from"../../service-fmai/service-chat";import Parse from"parse";import{CommonModule}from"@angular/common";import{IonAvatar,IonItem}from"@ionic/angular/standalone";import{CompUserAvatarComponent}from"../../../user/comp-user-avatar/comp-user-avatar.component";import{NzAvatarModule}from"ng-zorro-antd/avatar";import{ClipboardService}from"../../comp-markdown-preview/clipboard.service";import{MarkdownPreviewModule}from"../../comp-markdown-preview/markdown-preview.module";import{NzSanitizerPipe}from"ng-zorro-antd/pipes";import{NzIconModule}from"ng-zorro-antd/icon";import{DurationStrPipe}from"./duration-str.pipe";import*as i0 from"@angular/core";import*as i1 from"../../comp-markdown-preview/clipboard.service";import*as i2 from"@angular/common";import*as i3 from"../../comp-markdown-preview/markdown-preview.component";import*as i4 from"ng-zorro-antd/avatar";import*as i5 from"ng-zorro-antd/icon";export class FmChatMessageCard{constructor(e){this.copyServ=e,this.user=Parse.User.current()}async toggleVoicePlay(){if(this.message?.voice?.id&&this.chat.VoiceTTSMap[this.message?.voice?.id]&&(this.tts=this.chat.VoiceTTSMap[this.message?.voice?.id]),this.tts?.isPlaying)return void this.tts?.stop();let e,t=!1;if(this.message?.voice?.id){let t=new Parse.Query("ChatVoice");t.include("voiceFile"),e=await t.get(this.message?.voice?.id)}if(!e?.id){let n=await this.chat.getVoiceByContentText(this.message?.content);e=this.chat.voiceMap[n?.id],this.message.voice={id:e?.id,duration:e?.get("duration")},t=!0}this.message?.voice?.duration||(this.message.voice.duration=e?.get("duration"),t=!0),t&&this.saveSession(),await this.chat.playChatVoice(e,{onStart:t=>{e?.id,t?.id},onLoaded:e=>{this.message.voice.duration=1e3*e.duration,this.updateVoiceDuration(1e3*e.duration)},onStop:t=>{e?.id,t?.id}}),this.tts=this.chat.VoiceTTSMap[e?.id]}updateVoiceDuration(e){this.message?.voice?.duration||(this.message.voice.duration=e,this.saveSession())}saveSession(){(this.index>=2||void 0===this.index)&&this.chat?.saveChatSession()}async copy(){this.copyServ.copyToClipboard(getMessageContentText(this.message?.content))}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,deps:[{token:i1.ClipboardService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatMessageCard,isStandalone:!0,selector:"fm-chat-message-card",inputs:{index:"index",message:"message",role:"role",chat:"chat"},ngImport:i0,template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="((message?.role==\'assistant\' && chat?.role?.get(\'voiceConfig\')?.voice) || (message?.role==\'user\'&&message?.voice))" class="play-voice" (click)="toggleVoicePlay()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="tts?.isPlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000) | durationStr}}\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em;font-size:12px;font-weight:100;padding:5px 20px}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i2.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i2.DatePipe,name:"date"},{kind:"component",type:CompUserAvatarComponent,selector:"app-comp-user-avatar",inputs:["user"]},{kind:"ngmodule",type:MarkdownPreviewModule},{kind:"component",type:i3.MarkdownPreviewComponent,selector:"fm-markdown-preview",inputs:["content","render"]},{kind:"ngmodule",type:NzAvatarModule},{kind:"component",type:i4.NzAvatarComponent,selector:"nz-avatar",inputs:["nzShape","nzSize","nzGap","nzText","nzSrc","nzSrcSet","nzAlt","nzIcon"],outputs:["nzError"],exportAs:["nzAvatar"]},{kind:"ngmodule",type:NzIconModule},{kind:"directive",type:i5.NzIconDirective,selector:"[nz-icon]",inputs:["nzSpin","nzRotate","nzType","nzTheme","nzTwotoneColor","nzIconfont"],exportAs:["nzIcon"]},{kind:"pipe",type:ChatContentPipe,name:"chatContent"},{kind:"pipe",type:DurationStrPipe,name:"durationStr"}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatMessageCard,decorators:[{type:Component,args:[{selector:"fm-chat-message-card",standalone:!0,imports:[CommonModule,IonItem,CompUserAvatarComponent,MarkdownPreviewModule,NzAvatarModule,IonAvatar,NzIconModule,ChatContentPipe,NzSanitizerPipe,DurationStrPipe],template:'<div class="message-card" [class.right]="message?.role==\'user\'" [class.center]="message?.role==\'system\'">\n \x3c!-- 用户及操作区 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'"> \x3c!-- 系统消息不显示头像 --\x3e\n <div class="avatar-row">\n <div class="actions">\n \x3c!-- 刷新 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="refresh-outline"></ion-icon> \n </ion-button> --\x3e\n \x3c!-- 复制 --\x3e\n <ion-button size="small" fill="outline" slot="start" (click)="copy()">\n <ion-icon name="copy-outline"></ion-icon>\n </ion-button>\n \x3c!-- 编辑 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="create-outline"></ion-icon>\n </ion-button> --\x3e\n </div>\n \x3c!-- 音频消息区域 --\x3e\n <div *ngIf="((message?.role==\'assistant\' && chat?.role?.get(\'voiceConfig\')?.voice) || (message?.role==\'user\'&&message?.voice))" class="play-voice" (click)="toggleVoicePlay()">\n <div class="voice-button">\n <span nz-icon [nzRotate]="message?.role==\'user\'?-90:90" nzType="wifi" nzTheme="outline" [class.play-voice-playing]="tts?.isPlaying"></span>\n </div>\n <div class="voice-info">\n <span *ngIf="message?.voice?.duration">\n {{((message?.voice?.duration||0)/1000) | durationStr}}\n </span>\n <span *ngIf="!message?.voice?.duration">\n \x3c!-- --\x3e\n </span>\n </div>\n </div>\n \x3c!-- 头像区域 --\x3e\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'" ></nz-avatar>\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 附件:图片 --\x3e\n <div class="item-row images" *ngIf="message?.content | chatContent:\'image_url\'">\n <img [src]="message?.content | chatContent:\'image_url\'" alt="">\n </div>\n \x3c!-- 聊天气泡 --\x3e\n <div class="item-row bubble">\n <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content | chatContent" [render]="false"></fm-markdown-preview>\n <fm-markdown-preview *ngIf="message?.complete" [content]="message?.content | chatContent"></fm-markdown-preview>\n </div>\n \x3c!-- 时间显示 --\x3e\n <div class="item-row loading" *ngIf="message?.role!=\'system\' && !message?.complete">\n 正在输入<ion-spinner name="dots"></ion-spinner>\n </div>\n\n <div class="item-row created" *ngIf="message?.createdAt">\n <span>{{message?.createdAt | date:"dd/MM/yy HH:mm"}}</span>\n </div>\n</div>',styles:['@charset "UTF-8";:host-context(body.dark) .message-card .actions .item-native{background:none!important}:host-context(body.dark) .message-card .bubble{color:#0e101d}:host-context(body.dark) .message-card .bubble .content-style{filter:invert(1)!important}:host-context(body.dark) .message-card .bubble fm-markdown-preview{filter:invert(1)!important}:host-context(body.dark) .message-card .play-voice{background-color:#0e101d}:host-context(body.dark) .message-card .play-voice .voice-info{color:#fff}:host-context(body.dark) .message-card .right .bubble{color:#921f8a!important;background:#921f8a!important}:host-context(body.dark) .message-card .right .play-voice{background:#921f8a!important}:host-context(body.dark) .message-card .created span{color:#fff}@media screen and (max-width: 800px){.message-card:focus .actions{opacity:1!important}}.message-card:hover .actions{opacity:1;transition:opacity .3s ease-in-out}.message-card{display:flex;flex-wrap:wrap;justify-content:start;align-items:flex-start}.message-card .avatar-row{width:300px;height:32px;display:flex;flex-direction:row-reverse;justify-content:start;align-items:center}.message-card .actions{display:flex;opacity:0;padding-left:10px;padding-right:10px}.message-card .item-row{display:flex;flex:100%;justify-content:start;margin-bottom:5px}.message-card .images img{max-width:300px}.message-card .bubble{display:flex;justify-content:center;max-width:100%;padding-top:1rem;padding:.5rem;color:#333;flex:none;border-radius:0 1.5em 1.5em/0em 1.5em 1.5em;color:#fff;background-color:currentColor}.message-card .bubble .content-style{filter:grayscale(1) contrast(999) invert(1)}.message-card .loading{text-align:right;color:#101010}.message-card .created{display:flex}.message-card .created span{font-size:12px;opacity:.4;white-space:nowrap;transition:all .6s ease;color:var(--black);text-align:center;width:100%;box-sizing:border-box;padding-right:10px;pointer-events:none;z-index:1}.right{justify-content:end;align-items:flex-end}.right .avatar-row{flex-direction:row;justify-content:end;width:auto}.right .actions{position:relative;margin-left:0}.right .item-row{justify-content:end}.right .bubble{color:#bbdefb;border-top-left-radius:1.5em;border-top-right-radius:0}.right .play-voice{flex-direction:row-reverse;background-color:#bbdefb}.center{justify-content:center;align-items:center}.center .item-row{justify-content:center}.center .bubble{color:var(--gray-secondary);border-top-left-radius:1.5em;border-top-right-radius:1.5em;font-size:12px;font-weight:100;padding:5px 20px}.play-voice{min-width:100px;height:32px;display:flex;justify-content:space-around;align-items:center;background-color:#fff;border-radius:7px}.play-voice .voice-button{width:32px;height:32px;display:flex;justify-content:center;align-items:center}.play-voice .voice-button span{overflow:hidden;font-size:18px;color:#ff69b4}.play-voice .voice-info{height:32px;display:flex;padding:0 10px;justify-content:end;align-items:center;color:#333}.play-voice-playing{animation:play-voice-animation 1s infinite}@keyframes play-voice-animation{0%{width:0}to{width:32px}}\n']}]}],ctorParameters:()=>[{type:i1.ClipboardService}],propDecorators:{index:[{type:Input}],message:[{type:Input}],role:[{type:Input}],chat:[{type:Input}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tZXNzYWdlLWNhcmQvY29tcC1tZXNzYWdlLWNhcmQuY29tcG9uZW50Lm1qcw==`
|
|
10
10
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @copyright © 未来飞马 © 未来全栈 www.fmode.cn
|
|
4
|
+
* 版权所有 © 未来飞马 © 江西脑控科技有限公司 Copyright © Fmode Technology Co., Ltd.
|
|
5
|
+
* 保留所有权利 All Rights Reserved.
|
|
6
|
+
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-message-card/duration-str.pipe.mjs
|
|
7
|
+
*/
|
|
8
|
+
import{Pipe}from"@angular/core";import*as i0 from"@angular/core";export class DurationStrPipe{transform(r,...t){let i=String(parseInt(String(r/60))),e="";return r/60>1&&(e+=`${i}'`),e+=`${String((r%60).toFixed(0))}"`,e}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:DurationStrPipe,deps:[],target:i0.ɵɵFactoryTarget.Pipe})}static{this.ɵpipe=i0.ɵɵngDeclarePipe({minVersion:"14.0.0",version:"17.3.12",ngImport:i0,type:DurationStrPipe,isStandalone:!0,name:"durationStr"})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:DurationStrPipe,decorators:[{type:Pipe,args:[{name:"durationStr",standalone:!0}]}]});
|
|
9
|
+
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tZXNzYWdlLWNhcmQvZHVyYXRpb24tc3RyLnBpcGUubWpz`
|
|
10
|
+
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-message-card/index.mjs
|
|
7
7
|
*/
|
|
8
|
-
export*from"./comp-message-card.component";
|
|
8
|
+
export*from"./comp-message-card.component";export*from"./duration-str.pipe";
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tZXNzYWdlLWNhcmQvaW5kZXgubWpz`
|
|
10
10
|
|
package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs
CHANGED
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{Component,Input}from"@angular/core";import{IonButton,IonIcon,IonSpinner,ModalController,ToastController}from"@ionic/angular/standalone";import{FmodeVoiceService}from"../../../voice/fmode-voice.service";import{FmodeChat}from"../../../service-fmai/service-chat";import{CommonModule}from"@angular/common";import{NovaUploadService}from"../../../../storage/service-upload/nova-upload.service";import Parse from"parse";import*as i0 from"@angular/core";import*as i1 from"../../../voice/fmode-voice.service";import*as i2 from"@ionic/angular/standalone";import*as i3 from"../../../../storage/service-upload/nova-upload.service";import*as i4 from"@angular/common";export class ModalAudioMessageComponent{constructor(e,i,t){this.voiceServ=e,this.toastCtrl=i,this.uploadServ=t,this.isRecording=!1,this.player=new Audio,this.durationStr="0:00"}ngOnInit(){this.chat.userInput="",this.initVoiceSevice(),this.voiceServ.startTalk()}playMusic(e){this.player||(this.player=new Audio),this.player.src=`/assets/avatar/voice/${e}.mp3`;try{this.player?.play()}catch(e){}}initVoiceSevice(){this.chat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.chat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onAfterRecordStart=()=>{this.isRecording=!0},this.voiceServ.onDurationStrChange=e=>{this.durationStr=e},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.chat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{},this.voiceServ.onBeforeFinishTalk=()=>{this.chat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=async()=>{console.log("onAfterFinishTalk1",this.voiceServ?.resultText),console.log("onAfterFinishTalk2",this.voiceServ?.resultTextTemp),this.chat.userInput=""+(this.voiceServ?.resultTextTemp||this.voiceServ?.resultText),this.chat?.userInput&&await this.saveChatVoice(),this.sendMessage()}}async saveChatVoice(){let e=this.voiceServ.recordWavBlob,i=this.voiceServ.recordDuration;if(e){let t=Parse.Object.extend("ChatVoice");this.chatVoice=new t,this.chatVoice.set("content",this.chat.userInput),this.chatVoice.set("role","user"),this.chatVoice.set("duration",i);let n=localStorage.getItem("company");n&&this.chatVoice.set("company",{__type:"Pointer",className:"Company",objectId:n}),Parse.User.current()?.id&&this.chatVoice.set("user",Parse.User.current().toPointer());let o=this.chatVoice?.id||this.uploadServ?.genMd5(this.chatVoice?.get("content")||this.chatVoice?.get("ssml")),a=new Date,s=o+a.getFullYear()+(a.getMonth()+1)+a.getDate()+a.getHours()+a.getMinutes()+a.getSeconds()+".wav",r=new File([e],s,{type:"audio/wav"}),c=await this.uploadServ.upload(r,(e=>{console.log(e)})),l={__type:"Pointer",className:"Attachment",objectId:c?.id};l?.objectId&&(this.chatVoice.set("voiceFile",l),this.chatVoice=await this.chatVoice.save())}}async sendMessage(){if(this.chat.userInput)this.chat?.sendMessage(""+this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}},{id:this.chatVoice?.id,duration:this.chatVoice?.get("duration")});else{(await this.toastCtrl.create({message:"内容不能为空",position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}}cancel(){this.clear(),this.voiceServ.cancelTalk(),this.modal?.dismiss(null,"cancel")}send(){this.clear(),this.voiceServ.finishTalk(),this.modal?.dismiss(null,"send")}clear(){this.now=void 0,this.isRecording=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,deps:[{token:i1.FmodeVoiceService},{token:i2.ToastController},{token:i3.NovaUploadService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalAudioMessageComponent,isStandalone:!0,selector:"fm-modal-audio-message",inputs:{chat:"chat",modal:"modal"},providers:[ModalController],ngImport:i0,template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{durationStr || "00:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i4.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonSpinner,selector:"ion-spinner",inputs:["color","duration","name","paused"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,decorators:[{type:Component,args:[{selector:"fm-modal-audio-message",standalone:!0,imports:[CommonModule,IonButton,IonIcon,IonSpinner],providers:[ModalController],template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n <div class="timer row">\n {{durationStr || "00:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n <div class="actions row">\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.modal-area .row{margin:10px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"]}]}],ctorParameters:()=>[{type:i1.FmodeVoiceService},{type:i2.ToastController},{type:i3.NovaUploadService}],propDecorators:{chat:[{type:Input}],modal:[{type:Input}]}});
|
|
8
|
+
import{Component,Input}from"@angular/core";import{IonButton,IonIcon,IonSpinner,ModalController,ToastController}from"@ionic/angular/standalone";import{FmodeVoiceService}from"../../../voice/fmode-voice.service";import{FmodeChat}from"../../../service-fmai/service-chat";import{CommonModule}from"@angular/common";import{NovaUploadService}from"../../../../storage/service-upload/nova-upload.service";import Parse from"parse";import*as i0 from"@angular/core";import*as i1 from"../../../voice/fmode-voice.service";import*as i2 from"@ionic/angular/standalone";import*as i3 from"../../../../storage/service-upload/nova-upload.service";import*as i4 from"@angular/common";export class ModalAudioMessageComponent{constructor(e,i,t){this.voiceServ=e,this.toastCtrl=i,this.uploadServ=t,this.isRecording=!1,this.player=new Audio,this.durationStr="0:00"}ngOnInit(){this.chat.userInput="",this.initVoiceSevice(),this.voiceServ.startTalk()}playMusic(e){this.player||(this.player=new Audio),this.player.src=`/assets/avatar/voice/${e}.mp3`;try{this.player?.play()}catch(e){}}initVoiceSevice(){this.chat.userInput=this.voiceServ.resultText,this.voiceServ.requestPermission().then((()=>{this.voiceServ.openWithPriviledge()})),this.voiceServ.onBeforeStartTalk=()=>{this.chat.playAnimation("listening"),this.playMusic("start-talk")},this.voiceServ.onAfterRecordStart=()=>{this.isRecording=!0},this.voiceServ.onDurationStrChange=e=>{this.durationStr=e},this.voiceServ.onBeforeCancelTalk=()=>{this.playMusic("interupt-talk"),this.chat.playAnimation("waiting")},this.voiceServ.onAfterCancelTalk=()=>{},this.voiceServ.onBeforeFinishTalk=()=>{this.chat.playAnimation("thinking"),this.playMusic("stop-talk")},this.voiceServ.onAfterFinishTalk=async()=>{console.log("onAfterFinishTalk1",this.voiceServ?.resultText),console.log("onAfterFinishTalk2",this.voiceServ?.resultTextTemp),this.chat.userInput=""+(this.voiceServ?.resultTextTemp||this.voiceServ?.resultText),this.chat?.userInput&&await this.saveChatVoice(),this.sendMessage()}}async saveChatVoice(){let e=this.voiceServ.recordWavBlob,i=this.voiceServ.recordDuration;if(e){let t=Parse.Object.extend("ChatVoice");this.chatVoice=new t,this.chatVoice.set("content",this.chat.userInput),this.chatVoice.set("role","user"),this.chatVoice.set("duration",i);let n=localStorage.getItem("company");n&&this.chatVoice.set("company",{__type:"Pointer",className:"Company",objectId:n}),Parse.User.current()?.id&&this.chatVoice.set("user",Parse.User.current().toPointer());let o=this.chatVoice?.id||this.uploadServ?.genMd5(this.chatVoice?.get("content")||this.chatVoice?.get("ssml")),a=new Date,s=o+a.getFullYear()+(a.getMonth()+1)+a.getDate()+a.getHours()+a.getMinutes()+a.getSeconds()+".wav",r=new File([e],s,{type:"audio/wav"}),c=await this.uploadServ.upload(r,(e=>{console.log(e)})),d={__type:"Pointer",className:"Attachment",objectId:c?.id};d?.objectId&&(this.chatVoice.set("voiceFile",d),this.chatVoice=await this.chatVoice.save())}}async sendMessage(){if(this.chat.userInput)this.chat?.sendMessage(""+this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}},{id:this.chatVoice?.id,duration:this.chatVoice?.get("duration")});else{(await this.toastCtrl.create({message:"内容不能为空",position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}}cancel(){this.clear(),this.voiceServ.cancelTalk(),this.modal?.dismiss(null,"cancel")}send(){this.clear(),this.voiceServ.finishTalk(),this.modal?.dismiss(null,"send")}clear(){this.now=void 0,this.isRecording=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,deps:[{token:i1.FmodeVoiceService},{token:i2.ToastController},{token:i3.NovaUploadService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ModalAudioMessageComponent,isStandalone:!0,selector:"fm-modal-audio-message",inputs:{chat:"chat",modal:"modal"},providers:[ModalController],ngImport:i0,template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n\n \n <div class="actions row">\n \x3c!-- 取消 --\x3e\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n \x3c!-- 音频 --\x3e\n <div class="audio-input">\n <div class="timer row">\n {{durationStr || "00:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n </div>\n \x3c!-- 发送 --\x3e\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%}.modal-area .row{margin:10px}.modal-area .tips{padding-top:15px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio-input{display:flex;flex-direction:column;justify-content:center;align-items:center}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i4.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonSpinner,selector:"ion-spinner",inputs:["color","duration","name","paused"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ModalAudioMessageComponent,decorators:[{type:Component,args:[{selector:"fm-modal-audio-message",standalone:!0,imports:[CommonModule,IonButton,IonIcon,IonSpinner],providers:[ModalController],template:'\x3c!-- <div style="background:#FFFFFF;color:#000000;width:100%">\n {{this.chat.userInput}}\n</div> --\x3e\n<div class="modal-area">\n\n \x3c!-- 加载WebSockets动画 --\x3e\n <ng-container *ngIf="!isRecording">\n <div class="row">\n <ion-spinner name="crescent" color="success" style="width:80px;height:80px;"></ion-spinner>\n </div>\n </ng-container>\n \x3c!-- 录音中动画 --\x3e\n <ng-container *ngIf="isRecording">\n <div class="tips row">\n 请您讲话,AI会识别!\n </div>\n\n \n <div class="actions row">\n \x3c!-- 取消 --\x3e\n <ion-button (click)="cancel()" size="large" shape="round" color="light">\n <ion-icon name="close-outline"></ion-icon>\n </ion-button>\n \x3c!-- 音频 --\x3e\n <div class="audio-input">\n <div class="timer row">\n {{durationStr || "00:00"}}\n </div>\n <div class="audio-wave row">\n <div class="audio">\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n <div class="wave"></div>\n </div>\n </div>\n </div>\n \x3c!-- 发送 --\x3e\n <ion-button (click)="send()" size="large" shape="round" color="success">\n <ion-icon name="send-outline"></ion-icon>\n </ion-button>\n </div>\n </ng-container>\n</div>',styles:[":host-context(body.dark) .modal-area{color:#fff}.modal-area{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%}.modal-area .row{margin:10px}.modal-area .tips{padding-top:15px}.modal-area .timer{font-size:1.5rem;font-weight:700}.modal-area .actions{display:flex;justify-content:space-around;width:100%;height:86px}.audio-input{display:flex;flex-direction:column;justify-content:center;align-items:center}.audio{display:flex;justify-content:space-between;align-items:center;gap:8px;width:60px;height:40px}.audio .wave{height:40px;display:block;width:10px;height:6px;border-radius:8px;background:orange}.audio .wave{animation:audio-wave 2s ease-in-out infinite}.audio .wave:nth-child(1){animation-delay:.1s}.audio .wave:nth-child(2){animation-delay:.2s}.audio .wave:nth-child(3){animation-delay:.3s}.audio .wave:nth-child(4){animation-delay:.4s}.audio .wave:nth-child(5){animation-delay:.5s}@keyframes audio-wave{0%{height:6px;transform:translateY(0);background:#ff8e3a}25%{height:6px;transform:translateY(0);background:#9c73f8}50%{height:30px;transform:translateY(-5px) scaleY(1.5);background:#ed509e}75%{height:6px;transform:translateY(0);background:#9c73f8}to{height:6px;transform:translateY(0);background:#0fccce}}\n"]}]}],ctorParameters:()=>[{type:i1.FmodeVoiceService},{type:i2.ToastController},{type:i3.NovaUploadService}],propDecorators:{chat:[{type:Input}],modal:[{type:Input}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tb2RhbC1pbnB1dC9tb2RhbC1hdWRpby1tZXNzYWdlL21vZGFsLWF1ZGlvLW1lc3NhZ2UuY29tcG9uZW50Lm1qcw==`
|
|
10
10
|
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{Component,Input,ViewChild}from"@angular/core";import{ActivatedRoute,Router,RouterModule}from"@angular/router";import{AlertController,NavController,ToastController}from"@ionic/angular";import{FmodeChat}from"../../service-fmai/service-chat";import{ChatService}from"../../service-fmai/service-chat";import Parse from"parse";import{NzMessageService}from"ng-zorro-antd/message";import{ImagineService}from"../../service-fmai/service-imagine/imagine.service";import{IonButton,IonContent,IonIcon,IonInput,IonItem,IonList,IonModal,IonPopover,IonTextarea,IonToolbar}from"@ionic/angular/standalone";import{CommonModule}from"@angular/common";import{FormsModule,ReactiveFormsModule}from"@angular/forms";import{NzModalModule}from"ng-zorro-antd/modal";import{ModalAudioMessageComponent}from"./modal-audio-message/modal-audio-message.component";import*as i0 from"@angular/core";import*as i1 from"@ionic/angular";import*as i2 from"@angular/router";import*as i3 from"../../service-fmai/service-imagine/imagine.service";import*as i4 from"../../service-fmai/service-chat";import*as i5 from"ng-zorro-antd/message";import*as i6 from"@angular/common";import*as i7 from"@angular/forms";import*as i8 from"ng-zorro-antd/modal";export class FmChatModalInput{closeAudio(){this.audioComp?.cancel(),this.isAudioModal=!1}startTalk(){this.chat.stopPlayingVoice(),this.isAudioModal=!0}constructor(e,n,t,o,a,s,i,r){this.toastCtrl=e,this.alertCtrl=n,this.navCtrl=t,this.router=o,this.imagineServ=a,this.chatServ=s,this.route=i,this.messages=r,this.errorText="",this.isAudioModal=!1,this.isShare=!1,this.user=Parse.User.current()}ngOnInit(){this.loadModel()}async loadModel(){let e=this.chat?.role?.get("model");await this.chatServ.loadModelList(e)}async setMessageImage(){let e=await this.imagineServ.getimg();this.chat.userImage=e,console.log(this.chat?.userImage)}onKeyDown(e){e.ctrlKey&&"Enter"===e.key&&(console.log("Ctrl+Enter 被按下"),this.sendMessage())}async sendMessage(){if(!this.chat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.chat?.sendMessage(this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}}),this.chat.userInput="",this.chat.userImage=""}async checkBalance(){if(!this.chatServ?.currentModel?.get("payLimit"))return!0;let e=await this.account.getBilling();if(e?.credit?.balance<10){return(await this.alertCtrl.create({header:"注意",subHeader:"您的余额不足,请充值后解锁高级模型",buttons:[{role:"cancel",text:"取消"},{role:"destructive",text:"充值",handler:()=>{this.router.navigateByUrl("/account/billing")}}]})).present(),!1}return!0}async getChatShare(){this.user=Parse.User.current();let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("session",this.chat?.sessionId);await e.first()}async toggleChatShare(){let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("role",this.chat?.role.id),e.equalTo("session",this.chat?.sessionId),e.select("objectId");let n=await e.first();if(n?.id)n.set("messageList",this.chat?.messageList);else{n=new(Parse.Object.extend("ChatShare")),n.set("user",{__type:"Pointer",className:"_User",objectId:Parse.User.current()?.id}),n.set("session",{__type:"Pointer",className:"ChatSession",objectId:this.chat?.sessionId}),n.set("role",{__type:"Pointer",className:"AvatarRole",objectId:this.chat?.role.id}),n.set("company",{__type:"Pointer",className:"Company",objectId:"E4KpGvTEto"}),n.set("messageList",this.chat?.messageList)}await n.save(),this.getChatShare()}chatShareSuccessMessage(){this.messages.success("分享成功")}showShare(){this.isShare=!0}handleOkShare(){this.toggleChatShare(),this.chatShareSuccessMessage(),this.isShare=!1}handleCancelShare(){this.isShare=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,deps:[{token:i1.ToastController},{token:i1.AlertController},{token:i1.NavController},{token:i2.Router},{token:i3.ImagineService},{token:i4.ChatService},{token:i2.ActivatedRoute},{token:i5.NzMessageService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:FmChatModalInput,isStandalone:!0,selector:"fm-chat-modal-input",inputs:{chat:"chat",message:"message",role:"role"},viewQueries:[{propertyName:"audioComp",first:!0,predicate:ModalAudioMessageComponent,descendants:!0}],ngImport:i0,template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i6.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:i6.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i6.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i6.DatePipe,name:"date"},{kind:"ngmodule",type:FormsModule},{kind:"directive",type:i7.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i7.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:RouterModule},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonTextarea,selector:"ion-textarea",inputs:["autoGrow","autocapitalize","autofocus","clearOnEdit","color","cols","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","maxlength","minlength","mode","name","placeholder","readonly","required","rows","shape","spellcheck","value","wrap"]},{kind:"component",type:IonPopover,selector:"ion-popover"},{kind:"component",type:IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"ngmodule",type:NzModalModule},{kind:"component",type:i8.NzModalComponent,selector:"nz-modal",inputs:["nzMask","nzMaskClosable","nzCloseOnNavigation","nzVisible","nzClosable","nzOkLoading","nzOkDisabled","nzCancelDisabled","nzCancelLoading","nzKeyboard","nzNoAnimation","nzCentered","nzDraggable","nzContent","nzFooter","nzZIndex","nzWidth","nzWrapClassName","nzClassName","nzStyle","nzTitle","nzCloseIcon","nzMaskStyle","nzBodyStyle","nzOkText","nzCancelText","nzOkType","nzOkDanger","nzIconType","nzModalType","nzAutofocus","nzOnOk","nzOnCancel"],outputs:["nzOnOk","nzOnCancel","nzAfterOpen","nzAfterClose","nzVisibleChange"],exportAs:["nzModal"]},{kind:"directive",type:i8.NzModalContentDirective,selector:"[nzModalContent]",exportAs:["nzModalContent"]},{kind:"component",type:ModalAudioMessageComponent,selector:"fm-modal-audio-message",inputs:["chat","modal"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,decorators:[{type:Component,args:[{selector:"fm-chat-modal-input",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,RouterModule,IonToolbar,IonItem,IonButton,IonList,IonModal,IonInput,IonIcon,IonTextarea,IonPopover,IonContent,NzModalModule,ModalAudioMessageComponent],template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="chat.isTexting=true"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n<ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="0.35" [breakpoints]="[0, 0.35, 0.5]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal>',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n']}]}],ctorParameters:()=>[{type:i1.ToastController},{type:i1.AlertController},{type:i1.NavController},{type:i2.Router},{type:i3.ImagineService},{type:i4.ChatService},{type:i2.ActivatedRoute},{type:i5.NzMessageService}],propDecorators:{audioComp:[{type:ViewChild,args:[ModalAudioMessageComponent]}],chat:[{type:Input}],message:[{type:Input}],role:[{type:Input}]}});
|
|
8
|
+
import{Component,Input,ViewChild}from"@angular/core";import{ActivatedRoute,Router,RouterModule}from"@angular/router";import{AlertController,NavController,ToastController}from"@ionic/angular";import{FmodeChat}from"../../service-fmai/service-chat";import{ChatService}from"../../service-fmai/service-chat";import Parse from"parse";import{NzMessageService}from"ng-zorro-antd/message";import{ImagineService}from"../../service-fmai/service-imagine/imagine.service";import{IonButton,IonContent,IonIcon,IonInput,IonItem,IonList,IonModal,IonPopover,IonTextarea,IonToolbar,ModalController}from"@ionic/angular/standalone";import{CommonModule}from"@angular/common";import{FormsModule,ReactiveFormsModule}from"@angular/forms";import{NzModalModule}from"ng-zorro-antd/modal";import{ModalAudioMessageComponent}from"./modal-audio-message/modal-audio-message.component";import*as i0 from"@angular/core";import*as i1 from"@ionic/angular";import*as i2 from"@ionic/angular/standalone";import*as i3 from"@angular/router";import*as i4 from"../../service-fmai/service-imagine/imagine.service";import*as i5 from"../../service-fmai/service-chat";import*as i6 from"ng-zorro-antd/message";import*as i7 from"@angular/common";import*as i8 from"@angular/forms";import*as i9 from"ng-zorro-antd/modal";export class FmChatModalInput{closeAudio(){this.audioComp?.cancel(),this.isAudioModal=!1}async startTalk(){let e,n=document.body.clientHeight||960;this.audioModalHeightPoint=Number((240/n).toFixed(2)),this.chat.stopPlayingVoice(),e=await this.modalCtrl.create({component:ModalAudioMessageComponent,componentProps:{chat:this.chat,modal:e,onBreakPointSet:()=>{e?.setCurrentBreakpoint(this.audioModalHeightPoint)}},breakpoints:[this.audioModalHeightPoint],initialBreakpoint:this.audioModalHeightPoint}),e.present()}constructor(e,n,t,o,a,i,s,r,l){this.toastCtrl=e,this.alertCtrl=n,this.modalCtrl=t,this.navCtrl=o,this.router=a,this.imagineServ=i,this.chatServ=s,this.route=r,this.messages=l,this.errorText="",this.isAudioModal=!1,this.audioModalHeightPoint=.35,this.isShare=!1,this.user=Parse.User.current()}ngOnInit(){this.loadModel();let e=this;this.chat.focusUserInput=()=>{e.chat.isVoiceInputMode=!1,e.userInputComp.setFocus()}}async loadModel(){let e=this.chat?.role?.get("model");await this.chatServ.loadModelList(e)}async setMessageImage(){let e=await this.imagineServ.getimg();this.chat.userImage=e,console.log(this.chat?.userImage)}onInputFocus(){this.chat.isTexting=!0,this.chat.scrollToBottom&&this.chat.scrollToBottom()}onKeyDown(e){e.ctrlKey&&"Enter"===e.key&&(console.log("Ctrl+Enter 被按下"),this.sendMessage())}async sendMessage(){if(!this.chat.userInput){return this.errorText="内容不能为空",void(await this.toastCtrl.create({message:this.errorText,position:"top",icon:"alert",color:"warning-circle",duration:1e3})).present()}this.chat?.sendMessage(this.chat?.userInput,this.chat?.userImage,(e=>{}),{onSSMLComplete:e=>{console.log(e)}}),this.chat.userInput="",this.chat.userImage=""}async checkBalance(){if(!this.chatServ?.currentModel?.get("payLimit"))return!0;let e=await this.account.getBilling();if(e?.credit?.balance<10){return(await this.alertCtrl.create({header:"注意",subHeader:"您的余额不足,请充值后解锁高级模型",buttons:[{role:"cancel",text:"取消"},{role:"destructive",text:"充值",handler:()=>{this.router.navigateByUrl("/account/billing")}}]})).present(),!1}return!0}async getChatShare(){this.user=Parse.User.current();let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("session",this.chat?.sessionId);await e.first()}async toggleChatShare(){let e=new Parse.Query("ChatShare");e.equalTo("user",Parse.User.current().id),e.equalTo("role",this.chat?.role.id),e.equalTo("session",this.chat?.sessionId),e.select("objectId");let n=await e.first();if(n?.id)n.set("messageList",this.chat?.messageList);else{n=new(Parse.Object.extend("ChatShare")),n.set("user",{__type:"Pointer",className:"_User",objectId:Parse.User.current()?.id}),n.set("session",{__type:"Pointer",className:"ChatSession",objectId:this.chat?.sessionId}),n.set("role",{__type:"Pointer",className:"AvatarRole",objectId:this.chat?.role.id}),n.set("company",{__type:"Pointer",className:"Company",objectId:"E4KpGvTEto"}),n.set("messageList",this.chat?.messageList)}await n.save(),this.getChatShare()}chatShareSuccessMessage(){this.messages.success("分享成功")}showShare(){this.isShare=!0}handleOkShare(){this.toggleChatShare(),this.chatShareSuccessMessage(),this.isShare=!1}handleCancelShare(){this.isShare=!1}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,deps:[{token:i1.ToastController},{token:i1.AlertController},{token:i2.ModalController},{token:i1.NavController},{token:i3.Router},{token:i4.ImagineService},{token:i5.ChatService},{token:i3.ActivatedRoute},{token:i6.NzMessageService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"17.0.0",version:"17.3.12",type:FmChatModalInput,isStandalone:!0,selector:"fm-chat-modal-input",inputs:{chat:"chat",message:"message",role:"role"},viewQueries:[{propertyName:"audioComp",first:!0,predicate:ModalAudioMessageComponent,descendants:!0},{propertyName:"userInputComp",first:!0,predicate:["userInput"],descendants:!0}],ngImport:i0,template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n @if(!chat?.hideShare){\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n }\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n @if(!chat?.hideModalSelect){\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n }\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea\n #userInput\n *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="onInputFocus()"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n\x3c!-- <ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="audioModalHeightPoint" [breakpoints]="[0, audioModalHeightPoint]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal> --\x3e',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n'],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i7.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:i7.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:i7.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"pipe",type:i7.DatePipe,name:"date"},{kind:"ngmodule",type:FormsModule},{kind:"directive",type:i8.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:i8.NgModel,selector:"[ngModel]:not([formControlName]):not([formControl])",inputs:["name","disabled","ngModel","ngModelOptions"],outputs:["ngModelChange"],exportAs:["ngModel"]},{kind:"ngmodule",type:ReactiveFormsModule},{kind:"ngmodule",type:RouterModule},{kind:"component",type:IonToolbar,selector:"ion-toolbar",inputs:["color","mode"]},{kind:"component",type:IonItem,selector:"ion-item",inputs:["button","color","detail","detailIcon","disabled","download","href","lines","mode","rel","routerAnimation","routerDirection","target","type"]},{kind:"component",type:IonButton,selector:"ion-button",inputs:["buttonType","color","disabled","download","expand","fill","form","href","mode","rel","routerAnimation","routerDirection","shape","size","strong","target","type"]},{kind:"component",type:IonList,selector:"ion-list",inputs:["inset","lines","mode"]},{kind:"component",type:IonModal,selector:"ion-modal"},{kind:"component",type:IonIcon,selector:"ion-icon",inputs:["color","flipRtl","icon","ios","lazy","md","mode","name","sanitize","size","src"]},{kind:"component",type:IonTextarea,selector:"ion-textarea",inputs:["autoGrow","autocapitalize","autofocus","clearOnEdit","color","cols","counter","counterFormatter","debounce","disabled","enterkeyhint","errorText","fill","helperText","inputmode","label","labelPlacement","maxlength","minlength","mode","name","placeholder","readonly","required","rows","shape","spellcheck","value","wrap"]},{kind:"component",type:IonPopover,selector:"ion-popover"},{kind:"component",type:IonContent,selector:"ion-content",inputs:["color","fixedSlotPlacement","forceOverscroll","fullscreen","scrollEvents","scrollX","scrollY"]},{kind:"ngmodule",type:NzModalModule},{kind:"component",type:i9.NzModalComponent,selector:"nz-modal",inputs:["nzMask","nzMaskClosable","nzCloseOnNavigation","nzVisible","nzClosable","nzOkLoading","nzOkDisabled","nzCancelDisabled","nzCancelLoading","nzKeyboard","nzNoAnimation","nzCentered","nzDraggable","nzContent","nzFooter","nzZIndex","nzWidth","nzWrapClassName","nzClassName","nzStyle","nzTitle","nzCloseIcon","nzMaskStyle","nzBodyStyle","nzOkText","nzCancelText","nzOkType","nzOkDanger","nzIconType","nzModalType","nzAutofocus","nzOnOk","nzOnCancel"],outputs:["nzOnOk","nzOnCancel","nzAfterOpen","nzAfterClose","nzVisibleChange"],exportAs:["nzModal"]},{kind:"directive",type:i9.NzModalContentDirective,selector:"[nzModalContent]",exportAs:["nzModalContent"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:FmChatModalInput,decorators:[{type:Component,args:[{selector:"fm-chat-modal-input",standalone:!0,imports:[CommonModule,FormsModule,ReactiveFormsModule,RouterModule,IonToolbar,IonItem,IonButton,IonList,IonModal,IonInput,IonIcon,IonTextarea,IonPopover,IonContent,NzModalModule,ModalAudioMessageComponent],template:'<ion-toolbar>\n <ion-item class="button-item" lines="none">\n \x3c!-- 设置 --\x3e\n \x3c!-- <ion-button fill="outline" slot="start">\n <ion-icon name="settings-outline"></ion-icon> \n </ion-button> --\x3e\n <ng-container *ngFor="let button of chat?.leftButtons">\n <ion-button style="--padding-start:10px;--padding-end:10px;"\n shape="round" *ngIf="button.show()" fill="outline" [title]="button?.title" slot="start" (click)="button.onClick()">\n <ion-icon [name]="button?.icon" [slot]="button?.showTitle?\'start\':\'icon-only\'"></ion-icon>\n {{button?.showTitle&&button?.title}}\n </ion-button>\n </ng-container>\n\n <ng-container *ngFor="let button of chat?.role?.get(\'buttons\')">\n <ion-button shape="round" (click)="chatServ.doButtonAction(button)" fill="outline" slot="start">\n {{button?.name}}\n </ion-button>\n </ng-container>\n\n \x3c!--分享按钮--\x3e\n @if(!chat?.hideShare){\n <ion-button shape="round" *ngIf="chat?.messageList?.length>1" (click)="showShare()" fill="outline" title="分享" slot="end">\n <ion-icon name="share-social-outline"></ion-icon>\n </ion-button>\n }\n \x3c!-- <button nz-button *ngIf="chat?.messageList?.length>1"\n nzType="primary" title="分享" (click)="showShare()" style="width: 31.188px;height: 22px;box-shadow: none;background: #fff;border: 1px solid #4588ff;border-radius: 5px;"> <span class="iconfont icon-fenxiang" style="color: #4588ff;"></span></button>\n --\x3e\n <ion-modal [isOpen]="isShare">\n <ng-template>\n <ion-header>\n <ion-toolbar>\n <ion-buttons slot="start">\n <ion-button (click)="handleCancelShare()">取消</ion-button>\n </ion-buttons>\n <ion-title>对话分享</ion-title>\n <ion-buttons slot="end">\n <ion-button (click)="handleOkShare()">分享</ion-button>\n </ion-buttons>\n </ion-toolbar>\n </ion-header>\n <ion-content class="ion-padding">\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'avatar\') || chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ion-content>\n </ng-template>\n </ion-modal>\n\n <nz-modal *ngIf="false"\n [(nzVisible)]="isShare"\n nzTitle="问答分享"\n nzCentered\n nzOkText="分享"\n nzCancelText="取消"\n (nzOnCancel)="handleCancelShare()"\n (nzOnOk)="handleOkShare()"\n >\n <ng-container *nzModalContent>\n <div class="popup-content">\n <div *ngFor="let message of chat?.messageList">\n \x3c!-- 头像 --\x3e\n <div class="item-row user" *ngIf="message?.role!=\'system\'">\n <div>\n <nz-avatar *ngIf="message?.role!=\'user\'" [nzSrc]="(chat?.role?.get(\'thumb\') || \'https://file-cloud.fmode.cn/E4KpGvTEto/20230930/l413e6090731854.png\')+\'?\'+\'x-image-process=image/resize,m_fixed,w_100\'+\'&imageView2/1/w/32/h/32\'"></nz-avatar>\n </div>\n <div class="user-question">\n <app-comp-user-avatar [user]="user" *ngIf="message?.role==\'user\'"></app-comp-user-avatar>\n </div>\n </div>\n \x3c!-- 内容 --\x3e\n <div class="message-wrapper">\n <div class="message-content-user">\n <div class="user-message" *ngIf="message?.role === \'user\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-role">\n <div class="role-message" *ngIf="message?.role !== \'user\' && message?.role !== \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n <div class="message-content-system">\n <div class="system-message" *ngIf="message?.role === \'system\'">\n <div class="item-content">\n \x3c!-- <fm-markdown-preview *ngIf="!message?.complete" class="content-style" [content]="message?.content" [render]="false"></fm-markdown-preview> --\x3e\n <fm-markdown-preview *ngIf="message?.complete" class="content-style" [content]="message?.content"></fm-markdown-preview>\n </div>\n </div>\n </div>\n </div>\n <div class="chat-time" *ngIf="message?.createdAt" [ngClass]="{\'role-time\': message?.role !== \'user\'}">\n <span>{{message?.createdAt | date:"dd/MM/yyyy, HH/mm/ss a"}}</span>\n </div>\n </div>\n </div> \n </ng-container>\n </nz-modal>\n\n \x3c!-- 图片 --\x3e\n <ion-button shape="round" *ngIf="chatServ?.currentModel?.get(\'config\')?.imageEnabled" fill="outline" slot="end" (click)="setMessageImage()">\n <ion-icon name="image-outline"></ion-icon>\n </ion-button>\n \x3c!-- 模型 --\x3e\n @if(!chat?.hideModalSelect){\n <ion-button shape="round" fill="outline" slot="end" id="model-button">\n <ion-icon name="chevron-down-outline"></ion-icon>\n {{chatServ?.currentModel?.get&&chatServ?.currentModel?.get("name")||"飞码4.0"}}\n </ion-button>\n <ion-popover trigger="model-button" [dismissOnSelect]="true">\n <ng-template>\n <ion-content>\n <ion-list>\n <ng-container *ngFor="let model of chatServ.modelList">\n <ion-item (click)="chatServ.currentModel = model" [button]="true" [detail]="false">\n {{model?.get("name")}}\n <ion-note slot="end">{{model?.get("credit")}}/k</ion-note>\n </ion-item>\n </ng-container>\n </ion-list>\n </ion-content>\n </ng-template>\n </ion-popover>\n }\n\n </ion-item>\n\n <ion-item class="input-item" lines="none">\n \x3c!-- 语音消息输入 --\x3e\n <ng-container *ngIf="chat?.isVoiceInputMode">\n \x3c!-- 切换文本输入 --\x3e\n <ion-button class="btn-input-change" color="primary" (click)="chat.isVoiceInputMode=false" shape="round" size="large">\n <ion-icon name="chatbox-ellipses-outline" slot="icon-only"></ion-icon>\n </ion-button>\n \n <div class="btn-voice-start" (click)="startTalk()">\n <span>\n 点击讲话\n </span> \n </div>\n </ng-container>\n\n \x3c!-- 文本消息输入 --\x3e\n <ng-container *ngIf="!chat?.isVoiceInputMode">\n \x3c!-- 切换语音输入 --\x3e\n <ion-button [style.display]="chat.isTexting?\'none\':\'flex\'" class="btn-input-change" color="primary" *ngIf="chat?.role?.get(\'voiceConfig\')" (click)="chat.isVoiceInputMode=true" shape="round" size="large">\n <ion-icon name="mic-outline" slot="icon-only"></ion-icon>\n </ion-button>\n\n \x3c!-- 文本输入区域 --\x3e\n <ion-textarea\n #userInput\n *ngIf="chat" (keydown)="onKeyDown($event)"\n [errorText]="errorText"\n [(ngModel)]="chat.userInput"\n (ionFocus)="onInputFocus()"\n (ionBlur)="chat.isTexting=false"\n [autoGrow]="true" shape="round" fill="outline"\n label="Ctrl + Enter 发送消息" placeholder="请输入您的提示词"\n labelPlacement="floating"></ion-textarea>\n \n \x3c!-- 文本发送按钮 --\x3e\n <ion-button color="primary" shape="round" size="large" (click)="sendMessage()">\n <ion-icon name="paper-plane-outline" slot="icon-only"></ion-icon>\n </ion-button>\n </ng-container>\n </ion-item>\n</ion-toolbar>\n\n\n\x3c!-- 语音消息输入:弹出区域 --\x3e\n\x3c!-- <ion-modal #audioModal [isOpen]="isAudioModal" (willDismiss)="closeAudio()" [initialBreakpoint]="audioModalHeightPoint" [breakpoints]="[0, audioModalHeightPoint]">\n <ng-template>\n <fm-modal-audio-message #audioComp *ngIf="isAudioModal" [chat]="chat" [modal]="audioModal"></fm-modal-audio-message>\n </ng-template>\n</ion-modal> --\x3e',styles:['@charset "UTF-8";:host-context(body.dark) .btn-voice-start{background-color:#222428;color:#fff}:host-context(body.dark) ion-textarea{background-color:#222428;color:#fff}ion-toolbar{--background:none}ion-toolbar .button-item{--inner-padding-start:5px;--inner-padding-end:0px;--padding-start:5px;--padding-end:0px}ion-toolbar ion-item{--background:transparent}ion-textarea.custom{--background: #373737;--color: #fff;--padding-end: 10px;--padding-start: 10px;--placeholder-color: #ddd;--placeholder-opacity: .8}ion-textarea.custom textarea{width:calc(100% - 95px)}ion-textarea.custom ion-button{position:absolute;right:0}.input-item{display:flex;min-height:77px;align-items:center;border:none;--inner-padding-start:0px;--inner-padding-end:0px;--padding-start:0px;--padding-end:0px}.input-item ion-textarea{background-color:#fff;max-height:400px;padding:0 5px;margin:0 5px;border-radius:20px;overflow-y:auto}.input-item .btn-voice-start{display:flex;flex:1;justify-content:center;align-items:center;font-weight:700;background:#fff;border-radius:20px;min-height:50px}ion-textarea{transition:width .5s ease}ion-textarea:hover .btn-input-change,ion-textarea:focus-within .btn-input-change{display:none}.input-item:hover ion-textarea,.input-item:focus-within ion-textarea{border-color:var(--logo-color-primary)}::ng-deep .ant-modal-body{max-height:600px;overflow-y:auto}::ng-deep .ant-modal-footer{display:flex;justify-content:space-around}::ng-deep .ant-btn{width:40%}.popup-content{position:relative}.popup-content .message-content-user{display:flex;justify-content:flex-end}.popup-content .message-content-role{display:flex;justify-content:flex-start}.popup-content .message-content-system{display:flex;justify-content:center}.popup-content .user-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#e7f8ff}.popup-content .role-message{padding:10px 10px 0;border-radius:10px;width:fit-content;max-width:100%;background-color:#f6f6f6}.popup-content .user-question{margin-bottom:5px;display:flex;justify-content:flex-end}.popup-content .chat-time{margin-bottom:10px;display:flex;justify-content:flex-end;font-size:14px;color:#a3a3a3}.popup-content .role-time{justify-content:flex-start}\n']}]}],ctorParameters:()=>[{type:i1.ToastController},{type:i1.AlertController},{type:i2.ModalController},{type:i1.NavController},{type:i3.Router},{type:i4.ImagineService},{type:i5.ChatService},{type:i3.ActivatedRoute},{type:i6.NzMessageService}],propDecorators:{audioComp:[{type:ViewChild,args:[ModalAudioMessageComponent]}],userInputComp:[{type:ViewChild,args:["userInput"]}],chat:[{type:Input}],message:[{type:Input}],role:[{type:Input}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1tb2RhbC1pbnB1dC9tb2RhbC1pbnB1dC5jb21wb25lbnQubWpz`
|
|
10
10
|
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* 保留所有权利 All Rights Reserved.
|
|
6
6
|
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/chat/chat-panel/chat-panel.component.mjs
|
|
7
7
|
*/
|
|
8
|
-
import{CommonModule}from"@angular/common";import{Component,ElementRef,Input,ViewChild}from"@angular/core";import{ActivatedRoute,Router}from"@angular/router";import{ChatService}from"../../service-fmai/service-chat";import{combineLatest}from"rxjs";import{FmChatHeaderArea}from"../chat-header-area";import{FmChatMesssageArea}from"../chat-message-area";import{FmChatModalInput}from"../chat-modal-input";import*as i0 from"@angular/core";import*as i1 from"@angular/router";import*as i2 from"../../service-fmai/service-chat";import*as i3 from"@angular/common";export class ChatPanelComponent{constructor(t,
|
|
8
|
+
import{CommonModule}from"@angular/common";import{Component,ElementRef,Input,ViewChild}from"@angular/core";import{ActivatedRoute,Router}from"@angular/router";import{ChatService}from"../../service-fmai/service-chat";import{combineLatest}from"rxjs";import{FmChatHeaderArea}from"../chat-header-area";import{FmChatMesssageArea}from"../chat-message-area";import{FmChatModalInput}from"../chat-modal-input";import*as i0 from"@angular/core";import*as i1 from"@angular/router";import*as i2 from"../../service-fmai/service-chat";import*as i3 from"@angular/common";export class ChatPanelComponent{constructor(e,t,a){this.route=e,this.router=t,this.chatServ=a,this.isDirect=!1,this.showInputModal=!0,this.showMessageArea=!0,this.showHeaderArea=!0,this.hideShare=!1,this.hideModalSelect=!1,this.hideInputPreview=!1,window.location.pathname?.indexOf("chat/session")>-1&&document.body.classList.add("dark")}listenDivChange(){let e=new MutationObserver((()=>{this.fmodeChat.scrollComp=this.contentComp})),t={childList:!0,subtree:!0,attributes:!0};this.contentComp?.nativeElement&&e.observe(this.contentComp?.nativeElement,t)}ngAfterViewInit(){}ngOnInit(){combineLatest([this.route.params,this.route.queryParams]).subscribe((async e=>{let t=e[0];e[1];if(this.chatId=t?.chatId||this.chatId||null,this.chatId&&await this.chatServ.initChatMap(this.chatId),this.roleId=t?.roleId||this.roleId||null,this.roleId){let e=await this.chatServ.createNewRoleChat(this.roleId);this.fmodeChat=e}this.chatId&&(this.fmodeChat=this.chatServ.chatMap[this.chatId],this.fmodeChat||this.router.navigate(["/chat/pro/mask"],{queryParams:{type:"employee"}}),this.fmodeChat=this.chatServ.chatMap[this.chatId]),this.leftButtons&&(this.fmodeChat.leftButtons=this.leftButtons),window.location.pathname?.indexOf("chat/session")>-1?this.fmodeChat.isVoiceInputMode=!0:this.fmodeChat.isVoiceInputMode=!1,this.modelList&&(this.chatServ.modelList=this.modelList,this.chatServ.currentModel=this.modelList[0]),this.isDirect&&(this.fmodeChat.isDirect=this.isDirect),this.hideShare&&(this.fmodeChat.hideShare=this.hideShare),this.hideModalSelect&&(this.fmodeChat.hideModalSelect=this.hideModalSelect),this.hideInputPreview&&(this.fmodeChat.hideInputPreview=this.hideInputPreview),setTimeout((()=>{this.fmodeChat.scrollComp=this.contentComp,this.listenDivChange()}),1e3),this.sayWelcome()}))}sayWelcome(){this.fmodeChat.voiceConfig?.welcome?.enabled&&this.fmodeChat.welcome()}loadMask(){}static{this.ɵfac=i0.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,deps:[{token:i1.ActivatedRoute},{token:i1.Router},{token:i2.ChatService}],target:i0.ɵɵFactoryTarget.Component})}static{this.ɵcmp=i0.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"17.3.12",type:ChatPanelComponent,isStandalone:!0,selector:"app-chat-panel",inputs:{chatId:"chatId",maskId:"maskId",roleId:"roleId",leftButtons:"leftButtons",modelList:"modelList",isDirect:"isDirect",showInputModal:"showInputModal",showMessageArea:"showMessageArea",showHeaderArea:"showHeaderArea",hideShare:"hideShare",hideModalSelect:"hideModalSelect",hideInputPreview:"hideInputPreview"},viewQueries:[{propertyName:"contentComp",first:!0,predicate:["contentComp"],descendants:!0}],ngImport:i0,template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <ng-content select="[chat-header]"></ng-content>\n <fm-chat-header-area *ngIf="showHeaderArea" [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <ng-content select="[chat-content]"></ng-content>\n <fm-chat-message-area *ngIf="showMessageArea" [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <ng-content select="[chat-footer]"></ng-content>\n <fm-chat-modal-input *ngIf="showInputModal" [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"],dependencies:[{kind:"ngmodule",type:CommonModule},{kind:"directive",type:i3.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:FmChatHeaderArea,selector:"fm-chat-header-area",inputs:["chat"]},{kind:"component",type:FmChatMesssageArea,selector:"fm-chat-message-area",inputs:["chatId","chat"]},{kind:"component",type:FmChatModalInput,selector:"fm-chat-modal-input",inputs:["chat","message","role"]}]})}}i0.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"17.3.12",ngImport:i0,type:ChatPanelComponent,decorators:[{type:Component,args:[{selector:"app-chat-panel",standalone:!0,imports:[CommonModule,FmChatHeaderArea,FmChatMesssageArea,FmChatModalInput],template:'\n\x3c!-- <ion-header></ion-header> --\x3e\n\x3c!-- <ion-content class="ion-padding"> --\x3e\n <div class="chat-page" *ngIf="fmodeChat">\n <div class="header" [class.avatarHeader]="fmodeChat?.isAvatarShow">\n <ng-content select="[chat-header]"></ng-content>\n <fm-chat-header-area *ngIf="showHeaderArea" [chat]="fmodeChat"></fm-chat-header-area>\n </div>\n \n <div class="content" #contentComp>\n <ng-content select="[chat-content]"></ng-content>\n <fm-chat-message-area *ngIf="showMessageArea" [chat]="fmodeChat"></fm-chat-message-area>\n </div>\n \n <div class="footer">\n <ng-content select="[chat-footer]"></ng-content>\n <fm-chat-modal-input *ngIf="showInputModal" [chat]="fmodeChat"></fm-chat-modal-input>\n </div>\n </div>\n\n\x3c!-- </ion-content> --\x3e',styles:[".chat-page{display:flex;flex-direction:column;height:100%;background:#f3f3f3}.chat-page .content,.chat-page .header,.chat-page .footer{justify-content:center;align-items:center}.chat-page .content{flex-grow:1;flex:1;overflow-y:auto}.chat-page .avatarHeader{height:35vh!important;overflow:hidden}.chat-page .header{height:44px;margin-bottom:-1px}.chat-page .footer{height:auto;min-height:130px}:host-context(body.dark) .chat-page{background:#000}\n"]}]}],ctorParameters:()=>[{type:i1.ActivatedRoute},{type:i1.Router},{type:i2.ChatService}],propDecorators:{chatId:[{type:Input}],maskId:[{type:Input}],roleId:[{type:Input}],leftButtons:[{type:Input}],modelList:[{type:Input}],isDirect:[{type:Input}],showInputModal:[{type:Input}],showMessageArea:[{type:Input}],showHeaderArea:[{type:Input}],hideShare:[{type:Input}],hideModalSelect:[{type:Input}],hideInputPreview:[{type:Input}],contentComp:[{type:ViewChild,args:["contentComp"]}]}});
|
|
9
9
|
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL2NoYXQvY2hhdC1wYW5lbC9jaGF0LXBhbmVsLmNvbXBvbmVudC5tanM=`
|
|
10
10
|
|