15207938132 2 mesiacov pred
rodič
commit
e79eae2859

+ 48 - 12
fashion-app/src/app/ai-chat-component/ai-chat-component.component.html

@@ -2,26 +2,60 @@
 <ion-header>
   <ion-toolbar class="custom-toolbar" >
     <ion-buttons slot="start">
-      <ion-button (click)="goBack()">
+      <ion-button (click)="goBack()">  <!--返回按钮-->
         <ion-icon name="chevron-back-sharp" style="color: black; font-size:27px"></ion-icon>
       </ion-button>
     </ion-buttons>
-    <ion-title>hcx</ion-title>
+    <ion-title>hcx</ion-title>  <!--AI名称-->
     <ion-buttons slot="end">
-      <ion-button (click)="openOptions()">
+      <ion-button (click)="openOptions()">   <!--更多按钮-->
         <ion-icon name="ellipsis-horizontal" style="color: black; font-size:27px"></ion-icon>
       </ion-button>
     </ion-buttons>
   </ion-toolbar>
 </ion-header>
 
-<!--聊天区域-->
+<!--聊天区域:聊天内容保存在messages-->
 <ion-content>
   <div class="chat-container">
-    <div *ngFor="let message of messages" [ngClass]="{'user-message': message.sender === 'user', 'ai-message': message.sender === 'ai'}" class="message-bubble">
-      {{ message.text }}
+    <div *ngFor="let message of messages" class="message-container">
+      <!-- 如果是用户消息,头像和消息都在右边 -->
+      <div *ngIf="message.sender === 'user'" class="message-content user-message-content">
+        <div class="message-bubble user-message">
+          {{ message.text }}
+        </div>
+        <div class="user-avatar">
+          <img src="../../assets/images/touxiang.jpg" alt="用户头像" />
+        </div>
+      </div>
+      
+      <!-- 如果是 AI 消息,头像和消息都在左边 -->
+      <div *ngIf="message.sender === 'ai'" class="message-content ai-message-content">
+        <div class="ai-avatar">
+          <img src="../../assets/images/cxtouxiang.jpg" alt="AI头像" />
+        </div>
+        <div class="message-bubble ai-message">
+          {{ message.text }}
+        </div>
+      </div>
+
+    </div>
+
+<!--当AI正在生成内容时显示加载动画-->
+    <div *ngIf="isLoading" class="message-content ai-message-content">
+      <div class="ai-avatar">
+        <img src="../../assets/images/cxtouxiang.jpg" alt="AI头像" />
+      </div>
+      <div class="message-bubble ai-message">
+      <div class="loading-dots">
+        <div class="loading-dot"></div>
+        <div class="loading-dot"></div>
+        <div class="loading-dot"></div>
+      </div>
     </div>
   </div>
+
+  </div>
 </ion-content>
 
 <!--底部内容-->
@@ -34,17 +68,19 @@
           <ion-icon name="mic-circle-outline" style="color: white; font-size: 40px;"></ion-icon>
         </ion-button>
         
-     <!-- 修改后的语音输入模态框 -->
+     <!--语音输入模态框 -->
 <ion-modal trigger="open-modal" [initialBreakpoint]="0.25" [breakpoints]="[0, 0.25, 0.5, 0.75]" handleBehavior="cycle">
   <ng-template>
     <ion-content class="yuyinframe">
       <div class="modal-content">
+        <!--取消按钮-->
         <ion-icon name="close-circle-outline" (click)="cancelVoiceInput()" class="cancle-button"></ion-icon>
         
         <div class="timer-container">
+          <!--计时器-->
           <div style="color: black; font-size: 24px;" id="timer">{{ timer }}</div>
          
-          
+          <!--音律跳动-->
               <div class="light">
                   <span></span>
                   <span></span>
@@ -54,7 +90,7 @@
               </div>
           
         </div>
-        
+        <!--提交语音内容按钮-->
         <div class="send-button">
           <ion-icon name="send-outline" style="font-size: 40px;" (click)="sendVoiceInput()"> </ion-icon>
         </div>
@@ -64,15 +100,15 @@
 </ion-modal>
         
       </ion-buttons>
-
+<!--文本输入框-->
       <ion-input placeholder="输入消息..." class="input-box" [(ngModel)]="userMessage">
         <ion-button (click)="openEmojiPicker()" fill="clear" slot="end">
-          <ion-icon name="happy-outline" style="color:#99d75c; font-size: 30px;" ></ion-icon> 
+          <ion-icon name="happy-outline" style="color:#99d75c; font-size: 30px;" ></ion-icon> <!--表情符号-->
         </ion-button>
       </ion-input>
 
       <ion-buttons>
-        <ion-button (click)="sendMessage()" fill="clear">
+        <ion-button (click)="sendMessage()" fill="clear">  <!--发送按钮-->
           <div class="circle">
           <ion-icon name="paper-plane" style="color: white; font-size: 27px;"></ion-icon>
         </div>

+ 114 - 27
fashion-app/src/app/ai-chat-component/ai-chat-component.component.scss

@@ -6,11 +6,12 @@ ion-toolbar {
     align-items: center; /* 垂直居中对齐 */
     --background: transparent; /* 去除背景色 */
   }
+  //头部样式
   ion-header{
     background-color: #99d75c ;
     --background: transparent; /* 去除背景色 */
   }
-  
+  //头部标题
   ion-title {
     margin: 0; /* 去掉默认的外边距 */
     flex: 1; /* 让标题占据剩余空间 */
@@ -18,7 +19,7 @@ ion-toolbar {
     font-size: 24px;
   }
 
-/* 输入框样式 */
+/* 文本输入框样式 */
 .input-box {
   background-color: white; /* 设置输入框背景为白色 */
   border-radius: 8px; /* 圆角 */
@@ -34,11 +35,11 @@ ion-toolbar {
   justify-content: center; /* 水平居中对齐 */
   width: 100%; /* 宽度100% */
 }
-
+//底部按钮样式
 ion-buttons {
   margin: 0 5px; /* 按钮之间的间距 */
 }
-
+//底部发送按钮圆圈样式
 .circle{
 width: 35px;
 height: 35px;
@@ -49,41 +50,91 @@ align-items: center; /* 垂直居中对齐 */
 justify-content: center; /* 水平居中对齐 */
 }
 
-
-//聊天样式
+//聊天内容容器样式
 .chat-container {
-  padding: 10px;
   display: flex;
   flex-direction: column;
+  padding-top: 10px;
 }
-
+//聊天内容样式
+.message-container {
+  display: flex; /* 使用Flexbox布局 */
+  justify-content: flex-end; /* 用户消息在右边,AI消息在左边 */
+  margin: 10px 0; /* 消息之间的间距 */
+}
+//消息内容样式
+.message-content {
+  display: flex; /* 使用Flexbox布局 */
+  align-items: center; /* 垂直居中对齐 */
+}
+//用户消息和头像样式
+.user-message-content {
+  justify-content: flex-end; /* 用户消息和头像在右边 */
+}
+//AI消息和头像样式
+.ai-message-content {
+  justify-content: flex-start; /* AI消息和头像在左边 */
+}
+//气泡样式
 .message-bubble {
   background-color: #99d75c; /* 绿色气泡的背景色 */
   color: white; /* 字体颜色 */
   border-radius: 15px; /* 圆角 */
   padding: 10px 15px; /* 内边距 */
-  margin: 5px 0; /* 外边距 */
-  max-width: 80%; /* 最大宽度 */
-  align-self: flex-end; /* 右侧对齐 */
+  max-width: 60%; /* 最大宽度 */
 }
-
+//用户消息样式
 .user-message {
   background-color: #99d75c; /* 用户消息的颜色 */
+  margin-left: 10px; /* 与头像之间的间距 */
 }
-
+//AI消息样式
 .ai-message {
   background-color: white; /* AI消息的气泡颜色 */
   color: black; /* 字体颜色 */
-  align-self: flex-start; /* 左侧对齐 */
   border: 1px solid black; /* 添加黑色边框 */
   box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); /* 添加阴影效果 */
-  border-radius: 15px; /* 圆角 */
-  padding: 10px 15px; /* 内边距 */
-  margin: 5px 0; /* 外边距 */
-  max-width: 80%; /* 最大宽度 */
-  word-wrap: break-word; /* 自动换行 */
+  margin-right: 10px; /* 与头像之间的间距 */
 }
-
+//用户头像样式
+.user-avatar {
+  width: 40px; /* 头像宽度 */
+  height: 40px; /* 头像高度 */
+  border-radius: 50%; /* 圆形 */
+  overflow: hidden; /* 超出部分隐藏 */
+  display: flex; /* 使用Flexbox布局 */
+  align-items: center; /* 垂直居中对齐 */
+  justify-content: center; /* 水平居中对齐 */
+  background-color: #f0f0f0; /* 背景色 */
+  border: 2px solid #99d75c; /* 边框颜色 */
+  margin-left: 5px; /* 与消息之间的间距 */
+}
+//AI头像样式
+.ai-avatar {
+  width: 40px; /* 头像宽度 */
+  height: 40px; /* 头像高度 */
+  border-radius: 50%; /* 圆形 */
+  overflow: hidden; /* 超出部分隐藏 */
+  display: flex; /* 使用Flexbox布局 */
+  align-items: center; /* 垂直居中对齐 */
+  justify-content: center; /* 水平居中对齐 */
+  background-color: #f0f0f0; /* 背景色 */
+  border: 2px solid #99d75c; /* 边框颜色 */
+  margin-right: 5px; /* 与消息之间的间距 */
+}
+//用户头像图片样式
+.user-avatar img {
+  width: 100%; /* 使图片适应头像框 */
+  height: 100%; /* 使图片适应头像框 */
+  object-fit: cover; /* 保持图片比例,裁剪多余部分 */
+}
+//AI头像图片样式
+.ai-avatar img {
+  width: 100%; /* 使图片适应头像框 */
+  height: 100%; /* 使图片适应头像框 */
+  object-fit: cover; /* 保持图片比例,裁剪多余部分 */
+}
+//语音框
 .yuyinframe{
   --background: transparent; 
   background-color: #99d75c; 
@@ -99,7 +150,7 @@ justify-content: center; /* 水平居中对齐 */
   width: 100%; /* 宽度100% */
   height: 25%;
 }
-
+//语音框中间内容框
 .timer-container {
   height: 100%;
   flex-direction: column; /* 垂直排列 */
@@ -107,7 +158,7 @@ justify-content: center; /* 水平居中对齐 */
   justify-content: center; /* 水平居中对齐 */
 
 }
-
+//计时器样式
 #timer{
   width: 100%;
   margin-top: 30px; /* 可根据需要调整这个值 */
@@ -189,7 +240,7 @@ justify-content: center; /* 水平居中对齐 */
 .light span:nth-child(9) {
   animation: bar9 2s 1.8s infinite linear;
 }
-
+//第一条音律加载动画
 @keyframes bar1 {
   0% {
       background: #f677b0;
@@ -209,7 +260,7 @@ justify-content: center; /* 水平居中对齐 */
       margin-top: 25%;
   }
 }
-
+//第二条音律加载动画
 @keyframes bar2 {
   0% {
       background: #df7ff2;
@@ -229,7 +280,7 @@ justify-content: center; /* 水平居中对齐 */
       margin-top: 25%;
   }
 }
-
+//第三条音律加载动画
 @keyframes bar3 {
   0% {
       background: #8c7ff2;
@@ -249,7 +300,7 @@ justify-content: center; /* 水平居中对齐 */
       margin-top: 25%;
   }
 }
-
+//第四条音律加载动画
 @keyframes bar4 {
   0% {
       background: #024b6a;
@@ -269,7 +320,7 @@ justify-content: center; /* 水平居中对齐 */
       margin-top: 25%;
   }
 }
-
+//第五条音律加载动画
 @keyframes bar5 {
   0% {
       background: #7ff2d3;
@@ -289,4 +340,40 @@ justify-content: center; /* 水平居中对齐 */
       margin-top: 25%;
   }
 }
+//三个点的加载动画
+.loading-dots {
+  display: flex;
+  align-items: center;
+  margin-left: 10px; /* 气泡与点之间的间距 */
+}
+
+.loading-dot {
+  width: 8px;
+  height: 8px;
+  border-radius: 50%;
+  background-color: #99d75c; /* 点的颜色 */
+  margin: 0 2px; /* 点之间的间距 */
+  animation: loading 1s infinite; /* 加载动画 */
+}
+//第一个点
+.loading-dot:nth-child(1) {
+  animation-delay: 0s;
+}
+//第二个点
+.loading-dot:nth-child(2) {
+  animation-delay: 0.2s;
+}
+//第三个点
+.loading-dot:nth-child(3) {
+  animation-delay: 0.4s;
+}
+//加载动画
+@keyframes loading {
+  0%, 100% {
+    opacity: 0.5;
+  }
+  50% {
+    opacity: 1;
+  }
+}
 

+ 18 - 22
fashion-app/src/app/ai-chat-component/ai-chat-component.component.ts

@@ -37,16 +37,13 @@ export class AiChatComponentComponent  implements OnInit {
   timer: string = '00:00'; // 用于显示计时器
   interval: any; // 用于存储定时器的引用
   elapsedSeconds: number = 0; // 计时器的秒数
-  isVoiceInputVisible: boolean = false; // 控制语音输入框的显示状态
+  isLoading: boolean = true; // AI生成文本加载状态,刚开始AI向你打招呼,所以处于加载状态
  
 
   constructor(private navCtrl: NavController,private alertController: AlertController) {
     // 初始化语音识别
     this.initSpeechRecognition();
    }
-
-
-
    
   // 初始化语音识别
 initSpeechRecognition() {
@@ -60,10 +57,11 @@ initSpeechRecognition() {
     
 
     // 处理识别结果
-    this.recognition.onresult = (event: any) => {
-      this.recognizedContent += event.results[event.results.length - 1][0].transcript; // 追加识别结果
-      console.log("识别到的内容:", this.recognizedContent); // 打印识别到的内容
-    };
+this.recognition.onresult = (event: any) => {
+  this.recognizedContent += event.results[event.results.length - 1][0].transcript; // 追加识别结果
+  this.userMessage = this.recognizedContent; // 实时更新 userMessage
+  console.log("识别到的内容:", this.recognizedContent); // 打印识别到的内容
+};
 
     // 处理识别错误
     this.recognition.onerror = (event: any) => {
@@ -78,13 +76,12 @@ initSpeechRecognition() {
   }
 }
 
-
+// 启动语音识别
 startVoice() {
   if (this.recognition && this.recognition.state !== 'active') { // 检查识别状态
     this.recognition.start(); // 启动语音识别
     console.log('语音识别启动...');
     this.startTimer(); // 启动计时器
-    this.isVoiceInputVisible = true; // 显示语音输入框
   } else {
     console.warn('语音识别已经在运行中'); // 提示用户语音识别已在运行
   }
@@ -115,7 +112,6 @@ cancelVoiceInput() {
     this.timer = '00:00'; // 重置计时器显示
     this.recognizedContent = ''; // 清空识别内容
   }
-  this.isVoiceInputVisible = false; // 隐藏语音输入框
 
 }
 
@@ -126,12 +122,12 @@ sendVoiceInput() {
     console.log('语音识别已停止');
     clearInterval(this.interval); // 清除计时器
     this.timer = '00:00'; // 重置计时器显示
+
     // 将识别到的内容传到输入框中
     this.userMessage = this.recognizedContent.trim(); // 将识别内容赋值给输入框,并去除多余空格
+
     this.recognizedContent = ''; // 清空识别内容
   }
-  this.isVoiceInputVisible = false; // 隐藏语音输入框
-
 }
   goBack() {
     this.navCtrl.back(); // 返回上一页
@@ -183,6 +179,7 @@ sendVoiceInput() {
     // 发送初始化消息
     completion.sendCompletion().subscribe((message: any) => {
       if (message?.complete) {
+        this.isLoading = false; // 加载完成,设置状态为 false
         console.log("AI初始化回复:", message.content);
         this.messages.push({ text: message.content, sender: 'ai' }); // 添加AI的初始化回复
       }
@@ -190,14 +187,6 @@ sendVoiceInput() {
   }
 
 
-
-
-
-  openEmojiPicker() {
-    // 打开表情选择器的逻辑
-    console.log("打开表情选择器");
-  }
-
   sendMessage() {
     // 发送消息的逻辑
     if (this.userMessage.trim()) { // 确保消息不为空
@@ -209,7 +198,7 @@ sendVoiceInput() {
 
       // 将提示词直接添加到对话历史
     conversationHistory.unshift({ role: 'user', content: this.initialPrompt }); // 添加系统消息到历史
-
+    this.isLoading = true; // 设置加载状态为 true
       this.messages.push({ text: this.userMessage, sender: 'user' }); // 添加用户消息到数组
       console.log("发送消息:", this.messages); // 调试输出
   
@@ -227,6 +216,7 @@ sendVoiceInput() {
         
         if (message?.complete) { // 判断message为完成状态,则设置ai内容
           this.aiMessage = message.content;
+          this.isLoading = false; // 加载完成,设置状态为 false
         }
   
         if (this.aiMessage) { // 判断ai内容不为空
@@ -239,4 +229,10 @@ sendVoiceInput() {
       });
     }
   }
+// 打开表情选择器
+  openEmojiPicker() {
+    console.log("打开表情选择器");
+    
+  }
+
 }

+ 1 - 1
fashion-app/src/app/page-ai-chat/page-ai-chat.component.html

@@ -1,7 +1,7 @@
 <div class="button-container">
   <ion-button fill="clear" (click)="openFashionChat()" class="chat-button">开始新聊天</ion-button>
   <ion-button fill="clear" (click)="restoreChat(chatId)" class="chat-button">继续上次聊天</ion-button>
-
+  <ion-button fill="clear" (click)="goaichat()" class="chat-button">聊天</ion-button>
 </div>
 
 

+ 6 - 0
fashion-app/src/app/page-ai-chat/page-ai-chat.component.ts

@@ -123,4 +123,10 @@ async loadUserProfileList(){
   this.UserProfileList = await query.find();
   console.log("UserProfileList",this.UserProfileList)
 }
+
+
+//跳转到自己写的AI聊天页面
+goaichat(){
+  this.router.navigate(['/tabs/chat'])
+}
 }

+ 0 - 7
fashion-app/src/app/page-yuyin/page-yuyin.component.html

@@ -1,7 +0,0 @@
-<ion-content style="background-color: #99d75c; display: flex; flex-direction: column; justify-content: center; align-items: center;">
-  <div style="display: flex; justify-content: space-between; width: 100%; padding: 10px;">
-    <ion-button (click)="cancelVoiceInput()" fill="clear" style="color: black;">取消</ion-button>
-    <div style="color: black; font-size: 24px;" id="timer">{{ timer }}</div>
-    <ion-button (click)="sendVoiceInput()" fill="clear" style="color: black;">发送</ion-button>
-  </div> 
-</ion-content>

+ 0 - 0
fashion-app/src/app/page-yuyin/page-yuyin.component.scss


+ 0 - 22
fashion-app/src/app/page-yuyin/page-yuyin.component.spec.ts

@@ -1,22 +0,0 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
-
-import { PageYuyinComponent } from './page-yuyin.component';
-
-describe('PageYuyinComponent', () => {
-  let component: PageYuyinComponent;
-  let fixture: ComponentFixture<PageYuyinComponent>;
-
-  beforeEach(waitForAsync(() => {
-    TestBed.configureTestingModule({
-      imports: [PageYuyinComponent],
-    }).compileComponents();
-
-    fixture = TestBed.createComponent(PageYuyinComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  }));
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 115
fashion-app/src/app/page-yuyin/page-yuyin.component.ts

@@ -1,115 +0,0 @@
-import { Component, OnInit } from '@angular/core';
-import { ModalController } from '@ionic/angular';
-
-@Component({
-  selector: 'app-page-yuyin',
-  templateUrl: './page-yuyin.component.html',
-  styleUrls: ['./page-yuyin.component.scss'],
-  standalone: true,
-})
-export class PageYuyinComponent  implements OnInit {
-
-  ngOnInit() {}
-
-   recognition: any; // 用于存储语音识别实例
-    recognizedContent: string = ''; // 用于存储识别到的语音内容
-    timer: string = '00:00'; // 用于显示计时器
-    interval: any; // 用于存储定时器的引用
-    elapsedSeconds: number = 0; // 计时器的秒数
-    isVoiceInputVisible: boolean = false; // 控制语音输入框的显示状态
-   
-  
-    constructor() {
-      // 初始化语音识别
-      this.initSpeechRecognition();
-     }
-  
-  
-  
-     
-    // 初始化语音识别
-  initSpeechRecognition() {
-    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
-    if (SpeechRecognition) {
-      this.recognition = new SpeechRecognition();
-      this.recognition.lang = 'zh-CN'; // 设置语言为中文
-      this.recognition.interimResults = false; // 不返回中间结果
-      this.recognition.maxAlternatives = 1; // 最大替代结果数
-      this.recognition.continuous = true; // 设置为连续识别
-      
-  
-      // 处理识别结果
-      this.recognition.onresult = (event: any) => {
-        this.recognizedContent += event.results[event.results.length - 1][0].transcript; // 追加识别结果
-        console.log("识别到的内容:", this.recognizedContent); // 打印识别到的内容
-      };
-  
-      // 处理识别错误
-      this.recognition.onerror = (event: any) => {
-        if (event.error === 'no-speech') {
-          console.warn('没有检测到语音,继续监听...');
-        } else {
-          console.error('语音识别错误:', event.error);
-        }
-      };
-    } else {
-      console.log('该浏览器不支持语音识别');
-    }
-  }
-  
-  
-  startVoice() {
-    if (this.recognition && this.recognition.state !== 'active') { // 检查识别状态
-      this.recognition.start(); // 启动语音识别
-      console.log('语音识别启动...');
-      this.startTimer(); // 启动计时器
-      this.isVoiceInputVisible = true; // 显示语音输入框
-    } else {
-      console.warn('语音识别已经在运行中'); // 提示用户语音识别已在运行
-    }
-  }
-  
-    // 启动计时器
-    startTimer() {
-      this.elapsedSeconds = 0; // 重置秒数
-      this.timer = '00:00'; // 重置计时器显示
-      this.interval = setInterval(() => {
-        this.elapsedSeconds++;
-        const minutes = Math.floor(this.elapsedSeconds / 60);
-        const seconds = this.elapsedSeconds % 60;
-        this.timer = `${this.padZero(minutes)}:${this.padZero(seconds)}`; // 更新计时器显示
-      }, 1000);
-    }
-  
-    // 格式化数字为两位数
-    padZero(num: number): string {
-      return num < 10 ? '0' + num : num.toString();
-    }
-  // 取消语音输入
-  cancelVoiceInput() {
-    if (this.recognition) {
-      this.recognition.stop(); // 停止语音识别
-      console.log('语音识别已停止');
-      clearInterval(this.interval); // 清除计时器
-      this.timer = '00:00'; // 重置计时器显示
-      this.recognizedContent = ''; // 清空识别内容
-    }
-    this.isVoiceInputVisible = false; // 隐藏语音输入框
-  
-  }
-  
-  // 发送语音输入
-  sendVoiceInput() {
-    if (this.recognition) {
-      this.recognition.stop(); // 停止语音识别
-      console.log('语音识别已停止');
-      clearInterval(this.interval); // 清除计时器
-      this.timer = '00:00'; // 重置计时器显示
-      // 将识别到的内容传到输入框中
-return this.recognizedContent;
-    }
-    this.isVoiceInputVisible = false; // 隐藏语音输入框
-  
-  }
-
-}

+ 3 - 0
fashion-app/src/app/tab2/tab2.page.html

@@ -60,3 +60,6 @@
   </ion-card>
 
 </ion-content>
+
+
+

+ 2 - 0
fashion-app/src/app/tab3/tab3.page.html

@@ -125,6 +125,8 @@
   <!--AI聊天-->
   <div *ngIf="selectedSegment === 'ai-chat'">
 <app-page-ai-chat></app-page-ai-chat>
+
+
   </div>
   
   <!--测试-->

+ 0 - 1
fashion-app/src/app/tab3/tab3.page.ts

@@ -211,5 +211,4 @@ alertButtons = ['退出'];
 
 
 
-
 }

BIN
fashion-app/src/assets/images/cxtouxiang.jpg