Browse Source

feat:prompt to image

202226701053 7 months ago
parent
commit
3cb8f8bd4a

+ 10 - 0
E-Cover-app/src/app/app.routes.ts

@@ -5,4 +5,14 @@ export const routes: Routes = [
     path: '',
     loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
   },
+  {
+    path: 'generateOption',
+    loadComponent: () =>
+      import('./generate-option/generate-option.component').then((m) => m.GenerateOptionComponent),
+  },
+  {
+    path: 'generateResult',
+    loadComponent: () =>
+      import('./generate-result/generate-result.component').then((m) => m.GenerateResultComponent),
+  },
 ];

+ 192 - 24
E-Cover-app/src/app/generate-option/generate-option.component.ts

@@ -5,7 +5,7 @@ import { IonicModule, NavController } from '@ionic/angular';
 import { addIcons } from 'ionicons';
 import { arrowBackOutline } from 'ionicons/icons';
 import { FormsModule } from '@angular/forms';
-addIcons({ 'arrow-back-outline':arrowBackOutline });
+addIcons({ 'arrow-back-outline': arrowBackOutline });
 @Component({
   selector: 'app-generate-option',
   templateUrl: './generate-option.component.html',
@@ -13,9 +13,33 @@ addIcons({ 'arrow-back-outline':arrowBackOutline });
   standalone: true,
   imports: [IonicModule, CommonModule, FormsModule],
 })
+
 export class GenerateOptionComponent implements OnInit {
+  userProfile: {
+    gender: string;
+    age: string;
+    height: string;
+    weight: string;
+    season: string;
+    regStyle: string;
+    sceFunction: string;
+    dsgPhilosophy: string;
+    artStyle: string;
+    color: string;
+  } = {
+      gender: '不限制',
+      age: '不限制',
+      height: '不限制',
+      weight: '不限制',
+      season: '不限制',
+      regStyle: '不限制',
+      sceFunction: '不限制',
+      dsgPhilosophy: '不限制',
+      artStyle: '不限制',
+      color: '不限制',
+    }
   //构造器
-  constructor(private router:Router,private navCtrl:NavController) { }
+  constructor(private router: Router, private navCtrl: NavController) { }
   //初始化
   ngOnInit() {
   }
@@ -32,6 +56,35 @@ export class GenerateOptionComponent implements OnInit {
         { id: 2, isElected: false, label: '女' },
       ],
     },
+    {
+      id: '年龄',
+      chips: [
+        { id: 1, isElected: false, label: '20岁以下' },
+        { id: 2, isElected: false, label: '20-30岁' },
+        { id: 3, isElected: false, label: '30-40岁' },
+        { id: 4, isElected: false, label: '40岁以上' },
+      ],
+    },
+    {
+      id: '身高',
+      chips: [
+        { id: 1, isElected: false, label: '160以下' },
+        { id: 2, isElected: false, label: '160-170cm' },
+        { id: 3, isElected: false, label: '170-180cm' },
+        { id: 4, isElected: false, label: '180-190cm' },
+        { id: 5, isElected: false, label: '190以上' },
+      ],
+    },
+    {
+      id: '体重',
+      chips: [
+        { id: 1, isElected: false, label: '50kg以下' },
+        { id: 2, isElected: false, label: '50-55kg' },
+        { id: 3, isElected: false, label: '55-60kg' },
+        { id: 4, isElected: false, label: '60-70kg' },
+        { id: 5, isElected: false, label: '70kg以上' },
+      ],
+    },
     {
       id: '季节',
       chips: [
@@ -41,57 +94,172 @@ export class GenerateOptionComponent implements OnInit {
         { id: 4, isElected: false, label: '冬季' },
       ],
     },
+    {
+      id: '区域风格',
+      chips: [
+        { id: 1, isElected: false, label: '中国风' },
+        { id: 2, isElected: false, label: '日系' },
+        { id: 3, isElected: false, label: '韩系' },
+        { id: 4, isElected: false, label: '欧美风' },
+        { id: 5, isElected: false, label: '英伦风' },
+        { id: 6, isElected: false, label: '法式' },
+        { id: 7, isElected: false, label: '波西米亚风' },
+      ],
+    },
+    {
+      id: '场景功能',
+      chips: [
+        { id: 1, isElected: false, label: '通勤风' },
+        { id: 2, isElected: false, label: '休闲风' },
+        { id: 3, isElected: false, label: '田园风' },
+        { id: 4, isElected: false, label: '校园风' },
+        { id: 5, isElected: false, label: 'Party风' },
+        { id: 6, isElected: false, label: '约会装' },
+        { id: 7, isElected: false, label: '度假风' },
+      ],
+    },
+    {
+      id: '设计理念',
+      chips: [
+        { id: 1, isElected: false, label: '新中式' },
+        { id: 2, isElected: false, label: '淑女风' },
+        { id: 3, isElected: false, label: '名媛风' },
+        { id: 4, isElected: false, label: '瑞丽风' },
+        { id: 5, isElected: false, label: '简约风' },
+        { id: 6, isElected: false, label: '极简风' },
+        { id: 7, isElected: false, label: '中性风' },
+        { id: 8, isElected: false, label: '性冷淡风' },
+        { id: 9, isElected: false, label: '民族风' },
+        { id: 10, isElected: false, label: '戏剧风' },
+        { id: 11, isElected: false, label: '复古风' },
+        { id: 12, isElected: false, label: 'Y2K' },
+        { id: 13, isElected: false, label: '嘻哈风' },
+        { id: 14, isElected: false, label: '朋克风' },
+        { id: 15, isElected: false, label: '嬉皮风' },
+        { id: 16, isElected: false, label: '甜酷风' },
+      ],
+    },
+    {
+      id: '艺术风格',
+      chips: [
+        { id: 1, isElected: false, label: '拜占庭艺术' },
+        { id: 2, isElected: false, label: '哥特风格' },
+        { id: 3, isElected: false, label: '浪漫主义' },
+        { id: 4, isElected: false, label: '巴洛克风格' },
+        { id: 5, isElected: false, label: '洛可可风格' },
+        { id: 6, isElected: false, label: '洛丽塔风格' },
+        { id: 7, isElected: false, label: '维多利亚风' },
+        { id: 8, isElected: false, label: '欧普风格' },
+        { id: 9, isElected: false, label: '未来主义' },
+        { id: 10, isElected: false, label: '极简主义' },
+        { id: 11, isElected: false, label: '新古典主义' },
+      ],
+    },
+    {
+      id: '色彩搭配',
+      chips: [
+        { id: 1, isElected: false, label: '多巴胺穿搭' },
+        { id: 2, isElected: false, label: '美拉德穿搭' },
+      ],
+    },
   ];
-  //变量初始化
-  //性别
-  gender: string = '';
-  setGender(gender: string) {
-    this.gender = gender;
-  }
-  //季节
-  season: string = '';
-  setSeason(season: string) {
-    this.season = season;
-  }
+  /*变量初始化*/
+
+
   //补充说明
   suppleInput: string = '';
   //用户提示词
   userPrompt: string = '';
+  
   //点击选项卡事件
   toggleChip(cardId: string, chipId: number): void {
     this.cards.forEach((card) => {
       if (card.id === cardId) {
         card.chips.forEach((chip) => {
           chip.isElected = chip.id === chipId; // 当前点击的 chip 设为 active,其他设为 false
-
         });
-        switch (cardId) {
+
+        switch (card.id) {
           case '性别':
-            this.setGender(card.chips[chipId - 1].label)
+            this.userProfile.gender = card.chips[chipId - 1].label;
+            break;
+          case '年龄':
+            this.userProfile.age = card.chips[chipId - 1].label;
+            break;
+          case '身高':
+            this.userProfile.height = card.chips[chipId - 1].label;
+            break;
+          case '体重':
+            this.userProfile.weight = card.chips[chipId - 1].label;
             break;
           case '季节':
-            this.setSeason(card.chips[chipId - 1].label)
+            this.userProfile.season = card.chips[chipId - 1].label;
+            break;
+          case '区域风格':
+            this.userProfile.regStyle = card.chips[chipId - 1].label;
+            break;
+          case '场景功能':
+            this.userProfile.sceFunction = card.chips[chipId - 1].label;
+            break;
+          case '设计理念':
+            this.userProfile.dsgPhilosophy = card.chips[chipId - 1].label;
+            break;
+          case '艺术风格':
+            this.userProfile.artStyle = card.chips[chipId - 1].label;
+            break;
+          case '色彩搭配':
+            this.userProfile.color = card.chips[chipId - 1].label;
             break;
         }
       }
-    });
-  }
+    })
+  };
 
   //生成传递提示词事件
   sendMsg() {
-    this.userPrompt = "生成一位" + this.gender + "的" + this.season + "休闲穿搭图像,场景设定在公园的步道上。" +
-      "她穿着一件宽松的针织毛衣,搭配修身的黑色打底裤和白色运动鞋。配饰包括一条简约的手链和一顶时尚的帽子。" +
-      "背景是绿树成荫的公园,体现出轻松愉快的氛围。请注意色彩搭配和整体风格的协调。\n"+
-      "补充:"+this.suppleInput;
+    this.userPrompt = "请生成一个穿搭照片绘画提示词:模板如下:\n" +
+      "穿搭主题:夏季通勤风格\n" +
+      "性别:男性\n" +
+      "体重:70kg\n" +
+      "年龄:约40-45岁\n" +
+      "整体风格:简约、舒适、专业\n" +
+      "上装:\n" +
+      "衬衫:选择一款轻薄透气的短袖衬衫,颜色可以是浅蓝色或淡灰色,搭配细条纹或小格纹图案,以增加层次感。衬衫的剪裁要稍微宽松,以便于活动,适合办公室环境。\n" +
+      "外套(可选):如果需要在空调环境中,搭配一件轻便的深色西装外套,面料应为透气的棉麻混纺,能够增添正式感。\n" +
+      "下装:\n" +
+      "裤子:选择一条修身但不紧身的深色休闲裤(如海军蓝或深灰色),采用轻便的面料,保持通勤的舒适性。裤子长度适中,裤脚可微微收口,展现干练的形象。\n" +
+      "鞋子:\n" +
+      "鞋款:搭配一双经典的休闲皮鞋或轻便的商务休闲鞋,颜色可以选择黑色或深棕色,鞋面光滑,适合正式场合,同时也提供舒适的步行体验。\n" +
+      "配饰:" +
+      "腰带:搭配一条与鞋子颜色一致的皮质腰带,简约设计,增加整体协调感。\n" +
+      "手表:佩戴一款简约风格的手表,金属表带或皮表带均可,展现成熟稳重的气质。\n" +
+      "公文包:选择一款深色的公文包,材质为皮革或优质帆布,既实用又具有商务气息。\n" +
+      "场景功能:适合在办公室、商务会议、午餐约会等场合穿着,整体搭配既显得专业又不失时尚感,适合夏季通勤的需求。\n" +
+      "以上模板仅供参考,可以写的更详细一些,但不要过于繁琐和冗长。\n"+
+      "以下内容为用户需求:\n" +
+      "性别:" + this.userProfile.gender + "\n" +
+      "年龄:" + this.userProfile.age + "\n" +
+      "身高:" + this.userProfile.height + "\n" +
+      "体重:" + this.userProfile.weight + "\n" +
+      "季节:" + this.userProfile.season + "\n" +
+      "区域风格:" + this.userProfile.regStyle + "\n" +
+      "场景功能:" + this.userProfile.sceFunction + "\n" +
+      "设计理念:" + this.userProfile.dsgPhilosophy + "\n" +
+      "艺术风格:" + this.userProfile.artStyle + "\n" +
+      "色彩搭配:" + this.userProfile.color + "\n" +
+      "补充说明:" + this.suppleInput + "\n";
     console.log(this.userPrompt)
   }
 
   goGenerateResult() {
-    this.router.navigate(['/generate-result']);
+    this.router.navigate(['/generateResult'], {
+      queryParams: { userPrompt: this.userPrompt }
+    });
   }
 
   sendMsgAndGoGenerateResult() {
     this.sendMsg();
+    this.goGenerateResult();
   }
 }
 

+ 30 - 5
E-Cover-app/src/app/generate-result/generate-result.component.html

@@ -1,5 +1,30 @@
-<!-- 文本域:生成提示词 -->
-<ion-textarea [value]="userPrompt" (ionInput)="promptInput($event)" placeholder="文本提示词" [autoGrow]="true"></ion-textarea>
-  
-<!-- 展示:返回消息内容 -->
-<div>{{responseMsg}}</div>
+<div id="banner">
+    <ion-header>
+        <div class="header-container">
+            <ion-icon name="arrow-back-outline" size="large" class="back-icon" (click)="goBack()"></ion-icon>
+            <p class="header-title">生成结果{{imagineWork?.progress || 0}}</p>
+        </div>
+    </ion-header>
+</div>
+<ion-content>
+    @if(images.length) {
+    @for(imageUrl of images;track imageUrl){
+    <img [src]="imageUrl" alt="" srcset="">
+    }
+    }
+    <!-- 生成状态 -->
+    @if(!images.length){
+    @if(imagineWork){
+    <h1>生成中</h1>
+    }
+    @if(!imagineWork){
+    <h1>未开始</h1>
+    }
+    }
+    <ion-card>
+        <ion-card-header>
+            <ion-card-title>生成思路</ion-card-title>
+        </ion-card-header>
+        <ion-card-content>{{responseMsg}}</ion-card-content>
+    </ion-card>
+</ion-content>

+ 47 - 0
E-Cover-app/src/app/generate-result/generate-result.component.scss

@@ -0,0 +1,47 @@
+#banner {
+    height: 300px;
+    background-image: url("style-img/banner-color1.png");
+    background-position: 100% 100%;
+    background-size: cover;
+    background-repeat: no-repeat;
+    background-color: none;
+    padding: 10px;
+    padding-top: 20px;
+    margin-bottom: -35px;
+    color: black;
+}
+
+ion-header {
+    background-color: none;
+    padding: 10px;
+    color: black;
+    height: 50px;
+    box-shadow: none;
+    .header-container {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        position: relative;
+        height: 100%; /* 确保容器占满整个 header 高度 */
+      }
+      
+      .back-icon {
+        position: absolute;
+        left: 10px; /* 图标距左侧的距离 */
+        cursor: pointer;
+      }
+      
+      .header-title {
+        font-size: 18px; /* 根据需要调整字体大小 */
+        font-weight: bold; /* 可选,加粗字体 */
+        margin: 0;
+      }
+}
+
+ion-content {
+    --background:#f8f8f8;
+    --color:black;
+    background-color: #f8f8f8;
+    z-index: -1;
+    height: 100vh;
+}

+ 52 - 19
E-Cover-app/src/app/generate-result/generate-result.component.ts

@@ -1,40 +1,73 @@
 import { Component, OnInit } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
-import { IonHeader, IonToolbar, IonTitle, IonContent,IonButton,IonTextarea } from '@ionic/angular/standalone';
+import { ActivatedRoute, Router } from '@angular/router';
+import { IonicModule } from '@ionic/angular';
+import { NavController } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { arrowBackOutline } from 'ionicons/icons';
+addIcons({ arrowBackOutline });
 /** 引用:从fmode-ng库引用FmodeChatCompletion类 */
-import { FmodeChatCompletion } from 'fmode-ng';
+import { ChatImageContentItem, FmodeChatCompletion } from 'fmode-ng';
+import { DalleOptions, ImagineWork } from 'fmode-ng';
 @Component({
   selector: 'app-generate-result',
   templateUrl: './generate-result.component.html',
   styleUrls: ['./generate-result.component.scss'],
   standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonTextarea],
+  imports: [IonicModule],
 })
-export class GenerateResultComponent  implements OnInit {
-  userPrompt:string = this.route.snapshot.paramMap.get('prompt') || '你好';
-  responseMsg:any = "";
 
-  constructor(private route:ActivatedRoute) { }
+export class GenerateResultComponent implements OnInit {
+  constructor(private route: ActivatedRoute, private router: Router, private navCtrl: NavController) {
+    // 示例任务,自己生成图片后请存储新的ID
+    this.imagineWork = new ImagineWork("lpJGiFwWeA");
+    this.imagineWork.fetchTask().then(work => {
+      this.images = this.imagineWork?.images || [];
+    });
+  }
+  userPrompt: string = "";
+  responseMsg: any = "";
+  imagineWork: ImagineWork | undefined;
+  images: Array<string> = [];
 
-  promptInput(ev:any){
-    this.userPrompt = ev.detail.value;
+  ngOnInit() {
+    this.route.queryParams.subscribe(params => {
+      this.userPrompt = params['userPrompt'] || "";
+    });
+    console.log(this.userPrompt)
+    this.createImage()
+  }
+  goBack() {
+    this.navCtrl.back();
   }
-  // 属性:组件内用于展示消息内容的变量
-  // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
-  fetchAIResponse(){
-    console.log("create")
+
+  async createImage() {
+    this.imagineWork = new ImagineWork();
+    // 文本生成
+    let PromptTemplate = `${this.userPrompt}`
     let completion = new FmodeChatCompletion([
-      {role:"system",content:""},
-      {role:"user",content:this.userPrompt}
+      { role: "system", content: "" },
+      { role: "user", content: PromptTemplate }
     ])
-    completion.sendCompletion().subscribe(message=>{
+    completion.sendCompletion().subscribe((message: any) => {
       // 打印消息体
       console.log(message.content)
       // 赋值消息内容给组件内属性
       this.responseMsg = message.content
+      if (message?.complete) { // 判断message为完成状态,则设置isComplete为完成
+        // 图片生成
+        let PicturePrompt = `${this.responseMsg}`
+        let options: DalleOptions = { prompt: PicturePrompt }
+        this.imagineWork?.draw(options).subscribe(work => {
+          console.log("imagineWork", work?.toJSON())
+          console.log("images", work?.get("images"))
+          if (work?.get("images")?.length) {
+            this.images = work?.get("images");
+          }
+        })
+      }
     })
-  }
 
-  ngOnInit() {}
+
+  }
 
 }

BIN
E-Cover-app/src/app/generate-result/style-img/banner-color1.png


BIN
E-Cover-app/src/app/generate-result/style-img/test.png


+ 0 - 10
E-Cover-app/src/app/tabs/tabs.routes.ts

@@ -21,11 +21,6 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../tab3/tab3.page').then((m) => m.Tab3Page),
       },
-      {
-        path: 'generateResult',
-        loadComponent: () =>
-          import('../generate-result/generate-result.component').then((m) => m.GenerateResultComponent),
-      },
       {
         path: '',
         redirectTo: '/tabs/tab1',
@@ -33,11 +28,6 @@ export const routes: Routes = [
       },
     ],
   },
-  {
-    path: 'generateOption',
-    loadComponent: () =>
-      import('../generate-option/generate-option.component').then((m) => m.GenerateOptionComponent),
-  },
   {
     path: '',
     redirectTo: '/tabs/tab1',

BIN
Ecover-app/src/app/tabs/style-img/tab1-logo.png