Переглянути джерело

Merge branch 'master' of http://git.fmode.cn:3000/lzy/S202226701025

yi 1 рік тому
батько
коміт
a59b29ad07

+ 0 - 4
FilmDraw-app/src/app/app.routes.ts

@@ -5,10 +5,6 @@ export const routes: Routes = [
     path: '',
     loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
   },
-  {
-    path: 'interact',
-    loadComponent: () => import('./interact/interact.page').then( m => m.InteractPage)
-  },
   {
     path: 'help',
     loadComponent: () => import('./homepage/help/help.page').then( m => m.HelpPage)

+ 0 - 52
FilmDraw-app/src/app/interact/interact.page.html

@@ -1,52 +0,0 @@
-<ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title size="large">角色互动</ion-title>
-  </ion-toolbar>
-</ion-header>
-
-<ion-content [fullscreen]="true">
-
-    <!-- 角色选择区 -->
-    <section>
-      <ion-card>
-        <ion-card-header>
-          <ion-card-title>选择角色</ion-card-title>
-        </ion-card-header>
-        <ion-card-content>
-          <ion-list>
-            <ion-item *ngFor="let character of characters" (click)="selectCharacter(character)">
-              <ion-avatar slot="start">
-                <img [src]="character.avatar" alt="{{ character.name }} 头像">
-              </ion-avatar>
-              <ion-label>
-                <h2>{{ character.name }}</h2>
-                <p>{{ character.description }}</p>
-              </ion-label>
-            </ion-item>
-          </ion-list>
-        </ion-card-content>
-      </ion-card>
-    </section>
-  
-    <!-- 角色对话区 -->
-    <section *ngIf="selectedCharacter">
-      <ion-card>
-        <ion-card-header>
-          <ion-card-title>与 {{ selectedCharacter.name }} 对话</ion-card-title>
-        </ion-card-header>
-        <ion-card-content>
-          <div class="chat-area">
-            <div *ngFor="let message of chatMessages" class="message">
-              <strong>{{ message.sender }}:</strong> {{ message.text }}
-            </div>
-          </div>
-          <ion-item>
-            <ion-input [(ngModel)]="userMessage" placeholder="输入您的消息..."></ion-input>
-            <ion-button (click)="sendMessage()" slot="end">
-              <ion-icon name="send"></ion-icon>
-            </ion-button>
-          </ion-item>
-        </ion-card-content>
-      </ion-card>
-    </section>
-</ion-content>

+ 0 - 50
FilmDraw-app/src/app/interact/interact.page.scss

@@ -1,50 +0,0 @@
-ion-title {
-    flex: 1; // 使标题占据可用空间
-    text-align: left; // 确保文字左对齐
-    margin-left: 16px; // 左侧边距,可以根据需要调整
-    margin-top: 5px;
-  }
-
-ion-header {
-    background-color: #3880ff; // 设置头部背景色
-  }
-  
-  ion-card {
-    margin: 10px; // 设置卡片之间的间距
-    border-radius: 10px; // 设置卡片圆角
-    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); // 添加阴影效果
-  }
-  
-  ion-card-header {
-    background-color: #f0f0f0; // 设置卡片头部背景色
-  }
-  
-  ion-card-title {
-    font-size: 1.2em; // 设置卡片标题字体大小
-    font-weight: bold; // 设置卡片标题字体加粗
-  }
-  
-  ion-item {
-    --ion-item-background: transparent; // 设置列表项背景透明
-  }
-  
-  ion-avatar {
-    border-radius: 50%; // 设置头像圆形
-    width: 50px; // 设置头像宽度
-    height: 50px; // 设置头像高度
-  }
-  
-  h2 {
-    font-size: 1em; // 设置二级标题字体大小
-    margin: 0; // 去掉默认外边距
-  }
-  
-  p {
-    font-size: 0.9em; // 设置段落字体大小
-    color: #666; // 设置段落文字颜色
-  }
-  
-  ion-thumbnail {
-    width: 100px; // 设置封面图宽度
-    height: 150px; // 设置封面图高度
-  }

+ 0 - 17
FilmDraw-app/src/app/interact/interact.page.spec.ts

@@ -1,17 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { InteractPage } from './interact.page';
-
-describe('InteractPage', () => {
-  let component: InteractPage;
-  let fixture: ComponentFixture<InteractPage>;
-
-  beforeEach(() => {
-    fixture = TestBed.createComponent(InteractPage);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});

+ 0 - 80
FilmDraw-app/src/app/interact/interact.page.ts

@@ -1,80 +0,0 @@
-import { Component, OnInit, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { FormsModule } from '@angular/forms';
-import { 
-  IonContent, IonHeader, IonTitle, IonToolbar,
-  IonCard, IonCardHeader, IonCardTitle, IonCardContent,
-  IonList, IonItem, IonLabel, IonAvatar, IonInput, IonButton, IonIcon
- } from '@ionic/angular/standalone';
- import { ExploreContainerComponent } from '../explore-container/explore-container.component';
-
- interface Character {
-  name: string;
-  avatar: string;
-  description: string;
-}
-
-interface Message {
-  sender: string;
-  text: string;
-}
-
-
-@Component({
-  selector: 'app-interact',
-  templateUrl: './interact.page.html',
-  styleUrls: ['./interact.page.scss'],
-  standalone: true,
-  imports: [
-    IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule, ExploreContainerComponent,
-    IonCard, IonCardHeader, IonCardTitle, IonCardContent,
-    IonList, IonItem, IonLabel, IonAvatar, IonInput, IonButton, IonIcon,
-  ],
-  schemas: [CUSTOM_ELEMENTS_SCHEMA], 
-})
-export class InteractPage {
-  characters: Character[] = [
-    {
-      name: '角色A',
-      avatar: 'assets/character-a.png',
-      description: '角色A的简介...',
-    },
-    {
-      name: '角色B',
-      avatar: 'assets/character-b.png',
-      description: '角色B的简介...',
-    },
-    {
-      name: '角色C',
-      avatar: 'assets/character-c.png',
-      description: '角色C的简介...',
-    },
-  ];
-
-  selectedCharacter: Character | null = null; // 当前选择的角色
-  chatMessages: Message[] = []; // 聊天消息列表
-  userMessage: string = ''; // 用户输入的消息
-
-  selectCharacter(character: Character) {
-    this.selectedCharacter = character;
-    this.chatMessages = []; // 清空聊天记录
-  }
-
-  sendMessage() {
-    if (this.userMessage.trim()) {
-      this.chatMessages.push({
-        sender: '您',
-        text: this.userMessage,
-      });
-      this.userMessage = ''; // 清空输入框
-      // 模拟角色的回复
-      setTimeout(() => {
-        this.chatMessages.push({
-          sender: this.selectedCharacter?.name || '角色',
-          text: '这是角色的回复。',
-        });
-      }, 1000);
-    }
-  }
-
-}

+ 7 - 24
FilmDraw-app/src/app/tab2/tab2.page.html

@@ -34,26 +34,10 @@
             </ion-label>
           }
         </ion-item>
-        <ion-button (click)="goToPage()">
-          生成用户画像
-        </ion-button>
         </ion-card-content>
       </ion-card>
     </section>
-  
-    <!-- AI智能推荐
-    <section>
-      <ion-card>
-        <ion-card-header>
-          <ion-card-title>AI智能推荐</ion-card-title>
-        </ion-card-header>
-        <ion-card-content>
-          <ion-button expand="full" color="primary" size="large" (click)="goToPage()">
-            AI推荐
-          </ion-button>
-        </ion-card-content>
-      </ion-card>
-    </section> -->
+
 
     <!-- 推荐影视剧列表 -->
     <section>
@@ -62,15 +46,14 @@
           <ion-card-title>为您推荐</ion-card-title>
         </ion-card-header>
         <ion-card-content>
+          <ion-button (click)="sendMessage()" expand="block">推荐生成</ion-button>
           <ion-list>
-            <ion-item *ngFor="let movie of recommendedMovies">
-              <ion-thumbnail slot="start">
-                <img [src]="movie.coverImage" alt="{{ movie.title }} 封面">
-              </ion-thumbnail>
+            <ion-item *ngFor="let film of filmList">
               <ion-label>
-                <h2>{{ movie.title }}</h2>
-                <p>评分: {{ movie.rating }}</p>
-                <p>{{ movie.description }}</p>
+                <h2>{{ film.get('title') }}</h2>
+                <p>题材: {{ film.get('genre') }}</p>
+                <p>评分: {{ film.get('grade') }}</p>
+                <p>{{ film.get('desc') }}</p>
               </ion-label>
             </ion-item>
           </ion-list>

+ 144 - 20
FilmDraw-app/src/app/tab2/tab2.page.ts

@@ -7,9 +7,14 @@ import { IonHeader, IonToolbar, IonTitle, IonContent,
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
 import { CommonModule } from '@angular/common';
 import { Router } from '@angular/router';
-import { CloudObject, CloudUser } from 'src/lib/ncloud';
+import { CloudObject, CloudUser, CloudQuery } from 'src/lib/ncloud';
 import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-login.component';
+import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
 
+interface DialogueItem {
+  role: string;
+  content: string;
+}
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
@@ -42,24 +47,143 @@ export class Tab2Page {
     private modalCtrl:ModalController,
     private router: Router) {}
   
-  goToPage(){
-    this.router.navigate(['/tabs/AIimagery'])
-  }
-
-  recommendedMovies = [
-    {
-      title: '某某剧名1',
-      rating: '9.0',
-      description: '这是一部精彩的剧集,讲述了...',
-      coverImage: 'assets/movie1.jpg',
-    },
-    {
-      title: '某某剧名2',
-      rating: '8.5',
-      description: '这部剧集以其独特的视角吸引了观众...',
-      coverImage: 'assets/movie2.jpg',
-    },
-    // 其他推荐影视剧...
-  ];
+    filmList:Array<CloudObject> = []
+    async loadFilmList(){
+      const currentUser = new CloudUser();
+      await currentUser.current(); // 确保用户信息已加载
+      const userId = currentUser.id; // 获取当前用户的 ObjectId
+      let query = new CloudQuery("FilmRecommendation");
+      query.equalTo("user", currentUser.toPointer()); // 只获取当前用户的记录
+      this.filmList = await query.find()
+    }
 
+    async ngOnInit() {
+      await this.ChatList();
+      this.loadFilmList()
+    }
+  
+    responseMsg: any = "";
+    isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
+    chatList: Array<CloudObject> = [];
+  
+    async ChatList() {
+      const currentUser = new CloudUser();
+      await currentUser.current(); // 确保用户信息已加载
+      const userId = currentUser.id; // 获取当前用户的 ObjectId
+  
+      let query = new CloudQuery("FilmChat");
+      query.equalTo("user", currentUser.toPointer()); // 只获取当前用户的记录
+      this.chatList = await query.find();
+  
+      this.chatList.forEach(chat => {
+        const dialogueArray = chat.get('dialogue');
+        if (dialogueArray && dialogueArray.length > 0) {
+          const userIndex = dialogueArray.findIndex((item: DialogueItem) => item.role === 'user');
+          if (userIndex !== -1) {
+            dialogueArray.splice(userIndex, 1); // 移除第一条 user 内容
+          }
+        }
+      });
+    }
+    
+    sendMessage() {
+      console.log("create");
+    
+      let dialogues = this.chatList.map(chat => {
+        const dialogueArray = chat.get('dialogue');
+        return dialogueArray.map((item: DialogueItem) => `${item.role}: ${item.content}`).join('\n');
+      }).join('\n');
+    
+      let PromptTemplate = `
+      请根据以下的用户聊天记录生成该用户的影视剧推荐列表。
+    
+      ${dialogues}
+    
+      请生成推荐列表,包括剧名、题材、评分和描述。
+      严格按照下面的格式生成:
+      剧名:
+      题材:
+      评分:
+      描述:
+      `;
+    
+      let completion = new FmodeChatCompletion([
+        { role: "system", content: "" },
+        { role: "user", content: PromptTemplate }
+      ]);
+    
+      completion.sendCompletion().subscribe(async (message: any) => {
+        console.log(message.content);
+        this.responseMsg = message.content;
+    
+        if (message?.complete) {
+          this.isComplete = true;
+    
+          // 假设 message.content 是自然语言文本而不是 JSON
+          try {
+            const recommendations = this.parseRecommendations(message.content);
+            
+            // 获取当前用户的 ObjectId
+            const currentUser = new CloudUser();
+            await currentUser.current(); // 确保用户信息已加载
+    
+            // 遍历推荐列表并保存到 FilmRecommendation 表
+            for (const rec of recommendations) {
+              const recommendation = new CloudObject("FilmRecommendation");
+              recommendation.set({
+                user: currentUser.toPointer(), // 设置用户指针
+                title: rec.title,
+                genre: rec.genre,
+                grade: rec.grade,
+                desc: rec.desc
+              });
+    
+              try {
+                await recommendation.save(); // 保存推荐到数据库
+                console.log('推荐已保存:', recommendation);
+              } catch (error) {
+                console.error('保存推荐失败:', error);
+              }
+            }
+          } catch (error) {
+            console.error('解析推荐内容失败:', error);
+          }
+        }
+      });
+    }
+    
+    // 解析推荐内容的辅助方法
+    private parseRecommendations(content: string): Array<{ title: string, genre: string, grade: string, desc: string }> {
+    const recommendations: Array<{ title: string, genre: string, grade: string, desc: string }> = [];
+      
+      // 按照空行分割每条推荐
+      const blocks = content.split('\n\n');
+      for (const block of blocks) {
+        const lines = block.split('\n').map(line => line.trim()).filter(line => line.length > 0);
+        
+        if (lines.length >= 4) {
+          const titleLine = lines[0];
+          const genreLine = lines[1];
+          const gradeLine = lines[2];
+          const descLine = lines[3];
+    
+          // 提取信息并去掉前缀和冒号
+          const title = titleLine.replace(/.*?剧名:\s*《(.*?)》$/, '$1').trim(); // 提取剧名
+          const genre = genreLine.replace(/.*?题材:\s*/, '').trim(); // 提取题材
+          const grade = gradeLine.replace(/.*?评分:\s*/, '').trim(); // 提取评分
+          const desc = descLine.replace(/.*?描述:\s*/, '').trim(); // 提取描述
+    
+          recommendations.push({
+            title: title,
+            genre: genre,
+            grade: grade,
+            desc: desc
+          });
+        } else {
+          console.warn('推荐内容格式不正确:', block); // 打印格式不正确的块
+        }
+      }
+      
+      return recommendations;
+    }
 }

+ 1 - 20
FilmDraw-app/src/app/tab3/tab3.page.html

@@ -53,23 +53,4 @@
       </ion-card-content>
     </ion-card>
   </section>
-
-  
-
-
-<!-- <ion-header [translucent]="true">
-  <ion-toolbar>
-    <ion-title size="large">AI追剧搭子</ion-title>
-  </ion-toolbar>
-</ion-header>
-
-<ion-content [fullscreen]="true">
-  <h1>页面:配置路由和参数的聊天页</h1>
-  <ion-button (click)="goChat()">开始页面聊天</ion-button>
-  <h1>组件:直接弹出的聊天组件</h1>
-  <ion-button (click)="openChat()">开始新聊天</ion-button>
-  <ion-button (click)="restoreChat('2DXJkRsjXK')">恢复会话</ion-button>
-  <h1>示例:门诊问诊的智能体示例(ChatPanel组件)</h1>
-  <ion-button (click)="opendazi()">追剧搭子</ion-button>
-
-</ion-content> -->
+</ion-content>

+ 3 - 59
FilmDraw-app/src/app/tab3/tab3.page.ts

@@ -1,4 +1,4 @@
-import { Component, contentChild } from '@angular/core';
+import { Component} from '@angular/core';
 import { Router } from '@angular/router';
 import { CommonModule } from '@angular/common';
 import { IonHeader, IonToolbar, IonTitle, IonContent, ModalController, IonButton,
@@ -25,11 +25,10 @@ import { openUserLoginModal } from 'src/lib/user/modal-user-login/modal-user-log
     FmChatModalInput, 
     // ModalAudioMessageComponent
     CommonModule, IonCard, IonCardHeader, IonCardTitle, IonCardContent,
-  IonList, IonItem, IonLabel, IonAvatar, IonInput, IonIcon, IonThumbnail,
-
+    IonList, IonItem, IonLabel, IonAvatar, IonInput, IonIcon, IonThumbnail,
   ]
 })
-export class Tab3Page {
+export class Tab3Page{
 
   constructor(
     private modalCtrl:ModalController,
@@ -38,7 +37,6 @@ export class Tab3Page {
 
   }
 
-
   /** 示例:搭子聊天面板 */
   async opendazi(filmpartner:CloudObject){
     //验证用户登录
@@ -198,60 +196,6 @@ export class Tab3Page {
   }
 
 
-
-
-//   openChat(){
-//     let options:ChatPanelOptions = {
-//       roleId:"2DXJkRsjXK",
-//       onChatSaved:(chat:FmodeChat)=>{
-//         // chat?.chatSession?.id 本次会话的 chatId
-      
-// console.log("onChatSaved",chat,chat?.chatSession,chat?.chatSession?.id)
-
-//       },
-
-//     }
-//     openChatPanelModal(this.modalCtrl,options)
-//   }
-
-//   restoreChat(chatId:string){
-//     let options:ChatPanelOptions = {
-//       roleId:"2DXJkRsjXK",
-//       chatId:chatId
-//     }
-//     openChatPanelModal(this.modalCtrl,options)
-//   }
-
-//   goChat(){
-//     this.router.navigateByUrl("/chat/session/role/2DXJkRsjXK")
-//   }
-
-
-
-  // audioModalHeightPoint:number = 0.35;
-  // async startTalk(){
-  //   // 根据手机兼容性,适配组件弹出高度
-  //   let height = document.body.clientHeight || 960;
-  //   this.audioModalHeightPoint = Number((165/height).toFixed(2));
-
-  //   // 弹出组件
-  //   let modal:any
-  //   let chat:any
-  //   modal = await this.modalCtrl.create({
-  //     component:ModalAudioMessageComponent,
-  //     componentProps:{
-  //       chat:chat,
-  //       modal:modal,
-  //       onBreakPointSet:()=>{
-  //         modal?.setCurrentBreakpoint(this.audioModalHeightPoint)
-  //       }
-  //     }
-  //   })
-  //   modal.present();
-  // }
-
-
-
   ngOnInit() {
     // 生命周期:页面加载后,运行搭子和角色列表,加载函数
     this.loadFilmPartnerList()

+ 1 - 2
FilmDraw-app/src/lib/ncloud.ts

@@ -1,4 +1,3 @@
-
 //CloudObject.ts
 export class CloudObject {
     className: string;
@@ -556,4 +555,4 @@ export class CloudFeedback extends CloudObject {
     async deleteFeedback() {
         return await this.destroy(); // 调用父类的 destroy 方法
     }
-}
+}