浏览代码

完成了gpt对话和文生图功能

itcast 4 月之前
父节点
当前提交
451f3c39a4
共有 25 个文件被更改,包括 1728 次插入116 次删除
  1. 630 48
      tailor-app/myapp/package-lock.json
  2. 6 0
      tailor-app/myapp/package.json
  3. 50 5
      tailor-app/myapp/src/app/customization/customization.page.html
  4. 172 4
      tailor-app/myapp/src/app/customization/customization.page.ts
  5. 99 0
      tailor-app/myapp/src/app/customization/test-chat-completion.ts
  6. 11 0
      tailor-app/myapp/src/app/edit-tag/edit-tag.component.html
  7. 0 0
      tailor-app/myapp/src/app/edit-tag/edit-tag.component.scss
  8. 24 0
      tailor-app/myapp/src/app/edit-tag/edit-tag.component.spec.ts
  9. 43 0
      tailor-app/myapp/src/app/edit-tag/edit-tag.component.ts
  10. 二进制
      tailor-app/myapp/src/app/me/img/绘图1.jpg
  11. 233 7
      tailor-app/myapp/src/app/me/me.page.html
  12. 109 5
      tailor-app/myapp/src/app/me/me.page.ts
  13. 99 0
      tailor-app/myapp/src/app/me/test-chat-completion.ts
  14. 3 0
      tailor-app/myapp/src/app/module/slide/slide.component.html
  15. 0 0
      tailor-app/myapp/src/app/module/slide/slide.component.scss
  16. 24 0
      tailor-app/myapp/src/app/module/slide/slide.component.spec.ts
  17. 14 0
      tailor-app/myapp/src/app/module/slide/slide.component.ts
  18. 13 0
      tailor-app/myapp/src/app/module/slide/slide.module.ts
  19. 122 15
      tailor-app/myapp/src/app/yiyun/yiyun.page.html
  20. 41 0
      tailor-app/myapp/src/app/yiyun/yiyun.page.scss
  21. 19 30
      tailor-app/myapp/src/app/yiyun/yiyun.page.ts
  22. 二进制
      tailor-app/myapp/src/assets/img/3d.png
  23. 二进制
      tailor-app/myapp/src/assets/img/ding.png
  24. 14 1
      tailor-app/myapp/src/main.ts
  25. 2 1
      tailor-app/myapp/tsconfig.json

文件差异内容过多而无法显示
+ 630 - 48
tailor-app/myapp/package-lock.json


+ 6 - 0
tailor-app/myapp/package.json

@@ -27,9 +27,15 @@
     "@capacitor/keyboard": "6.0.3",
     "@capacitor/status-bar": "6.0.2",
     "@ionic/angular": "^8.0.0",
+    "@ionic/vue": "^8.4.0",
+    "@ionic/vue-router": "^8.4.0",
+    "fmode-ng": "^0.0.62",
     "ionicons": "^7.2.1",
+    "parse": "^5.3.0",
     "rxjs": "~7.8.0",
+    "swiper": "^11.1.15",
     "tslib": "^2.3.0",
+    "vue": "^3.5.13",
     "zone.js": "~0.14.2"
   },
   "devDependencies": {

+ 50 - 5
tailor-app/myapp/src/app/customization/customization.page.html

@@ -5,9 +5,54 @@
 </ion-header>
 
 <ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">customization</ion-title>
-    </ion-toolbar>
-  </ion-header>
+  
+  
+
+
+    <ion-list >
+      <ion-item  >
+        <app-edit-tag (onTagChange)="setTags($event)"></app-edit-tag>
+      </ion-item>
+
+      <ion-item  >
+        <ion-textarea (ionInput)="onInputarea($event)" label="服装描述" placeholder="请尽可能描述衣服需要的功能" [autoGrow]="true"></ion-textarea>
+      </ion-item>
+
+    </ion-list>    
+    <!-- <h1>父级页面传参</h1>
+    @for(tag of editTags;track tag;){
+      <p>{{tag}}</p>
+    } -->
+    <!-- GPT组件 -->
+    <!-- <h1>GPT组件</h1>
+     <ion-input type="" [(ngModel)]="inputValue"  ></ion-input> -->
+    <ion-button (click)="printInputValue()">提交</ion-button>
+    @if(!isComplete){
+      <div>{{gptre}}</div>
+    }
+   
+   @if(isComplete){
+    <fm-markdown-preview class="content-style" [content]="gptre" ></fm-markdown-preview>
+   }
+
+
+   <ion-title>服装生成{{imagineWork?.progress || 0}}</ion-title>
+   <!-- <ion-textarea [value]="userPrompt" (ionInput)="promptInput($event)" placeholder="服装填写" autoGrow="true"></ion-textarea> -->
+  <ion-button (click)="createImage()" expand="block">生成图片</ion-button>
+  <!-- 生成结果 -->
+  @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>
+    }
+  }
+  {{   picdetail}}
 </ion-content>

+ 172 - 4
tailor-app/myapp/src/app/customization/customization.page.ts

@@ -1,20 +1,188 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
-
+import { IonContent, IonHeader, IonTitle, IonToolbar, IonButton, IonInput, IonTextarea, IonItem, IonList } from '@ionic/angular/standalone';
+import { TestChatCompletion } from './test-chat-completion';
+import { EditTagComponent } from '../edit-tag/edit-tag.component';
+import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
+import { DalleOptions, ImagineWork } from 'fmode-ng';
 @Component({
   selector: 'app-customization',
   templateUrl: './customization.page.html',
   styleUrls: ['./customization.page.scss'],
   standalone: true,
-  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule, IonButton, IonInput, EditTagComponent, IonTextarea, IonItem, IonList, MarkdownPreviewModule,]
 })
 export class CustomizationPage implements OnInit {
+  public isComplete: boolean = false;
+  public inputValue = ""
+  public gptre = ""
+  area: string = ""
+  editTags: Array<string> = []
+  onInput(event: any) {
+    console.log(event.detail.value);
 
-  constructor() { }
+  }
+  setTags(ev: any) {
+    console.log(ev);
+    this.editTags = ev
+  }
+  onInputarea(event: any) {
+    this.area = event.detail.value;
+    console.log(this.area);
 
+  }
   ngOnInit() {
   }
 
+
+  async printInputValue() {
+    console.log("create")
+    let promt = `您作为一名专业的服装推荐师,请帮我推荐具体的某件衣服,不要鞋子裤子,帽子,我只要你推荐某个具体服装,风格是:${this.editTags.join(",")},需要的衣服功能是:${this.area}`
+    let completion = new FmodeChatCompletion([
+      { role: "system", content: "" },
+      { role: "user", content: promt }
+    ])
+    completion.sendCompletion().subscribe((message: any) => {
+      // 打印消息体
+      console.log(message.content)
+      // 赋值消息内容给组件内属性
+      this.gptre = message.content
+      if (message?.complete) {
+        this.isComplete = true
+      }
+    })
+
+
+
+
+
+
+
+
+    // console.log("开始解析");
+    // console.log(this.inputValue);
+
+    // let token = "r:16cd8f27084ff647fcdb5308a6783c4c"
+    // localStorage.setItem("token",token)
+    // let promt=`您作为一名专业的服装推荐师,请帮我推荐具体的某件衣服,风格是:${this.editTags.join(",")},需要的衣服功能是:${this.area}`
+    // let messageList: any = [
+    //   {
+    //     role: "system", content: `${new Date().toLocaleString}`
+    //   },
+    //   {
+    //     role: "user", content: promt
+    //   }
+    // ]
+
+    // let completion=new TestChatCompletion(messageList)
+    // completion.createCompletionByStream()
+    // setInterval(()=>{
+    //   console.log(messageList);
+    //   if(messageList.length!=1){
+    //     this.gptre=messageList[messageList.length-1].content
+
+    //   }
+    // },2000)
+
+
+    // let bodyJson = {
+    //   "token": `Bearer ${token}`,
+    //   "messages": messageList,
+    //   "model": "fmode-4.5-128k",
+    //   "temperature": 0.5,
+    //   "presence_penalty": 0,
+    //   "frequency_penalty": 0,
+    //   "top_p": 1,
+    //   "stream": true
+    // };
+
+    // let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+    //   "headers": {
+    //     "accept": "text/event-stream",
+    //   },
+    //   "body": JSON.stringify(bodyJson),
+    //   "method": "POST",
+    //   "mode": "cors",
+    //   "credentials": "omit"
+    // });
+    // let reader = response.body?.getReader()
+    // if (!reader) {
+    //   throw new Error("Failed to get the response reader.");
+    // }
+
+    // let decoder = new TextDecoder();
+    // let buffer = "";
+
+    // while (true) {
+    //   let { done, value } = await reader.read();
+    //   if (done) {
+    //     break;
+    //   }
+    //   let data = decoder.decode(value);
+    //   let messages = data.split("\n");
+    //   console.log(messages);
+
+    //   for (let i = 0; i < messages.length - 1; i++) {
+    //     let message = messages[i];
+    //     console.log(message);
+    //     let dataStr: string = message.split("data: ")[1]
+    //     if (dataStr && dataStr.startsWith("{")) {
+    //       try {
+    //         let json = JSON.parse(dataStr);
+    //         let content = json.choices[0].delta.content
+    //         this.gptre = this.gptre + content
+    //       } catch (err) { }
+    //     }
+
+
+    //   }
+    // }
+
+
+  }
+
+  userPrompt: string = "飞码产品LOGO,独角兽头部形象,极简风格,棱角分明,线条勾勒,蓝色紫色搭配。"
+  promptInput(ev: any) {
+    this.userPrompt = ev.detail.value;
+  }
+  imagineWork: ImagineWork | undefined
+  images: Array<string> = []
+  constructor(
+  ) {
+    // 示例任务,自己生成图片后请存储新的ID
+    this.imagineWork = new ImagineWork("lpJGiFwWeA");
+    this.imagineWork.fetchTask().then(work => {
+      this.images = this.imagineWork?.images || [];
+    })
+  }
+  picdetail: string = ""
+  async createImage() {
+    let promotTemplate = `您是一名专业的没事画家,请您根据服装描述内容,将其描述的服装细节描述出来,服装描述如下:${this.gptre}`
+    let completion = new FmodeChatCompletion([
+      { role: "system", content: "" },
+      { role: "user", content: promotTemplate }
+    ])
+
+    completion.sendCompletion().subscribe((message: any) => {
+      // 打印消息体
+      console.log(message.content)
+      // 赋值消息内容给组件内属性
+      this.picdetail = message.content
+      if (message?.complete) {
+        this.imagineWork = new ImagineWork();
+        let options: DalleOptions = { prompt: this.picdetail }
+        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");
+          }
+        })
+      }
+    })
+
+
+
+  }
 }

+ 99 - 0
tailor-app/myapp/src/app/customization/test-chat-completion.ts

@@ -0,0 +1,99 @@
+export interface TestChatMessage{
+    role:string
+    content:string
+}
+export class TestChatCompletion{
+messageList:Array<TestChatMessage>
+constructor(messageList:Array<TestChatMessage>){
+    this.messageList = messageList
+}
+async createCompletionByStream() {
+
+let token = localStorage.getItem("token");
+let bodyJson = {
+  "token": `Bearer ${token}`,
+  "messages": this.messageList,
+  "model": "fmode-4.5-128k",
+  "temperature": 0.5,
+  "presence_penalty": 0,
+  "frequency_penalty": 0,
+  "top_p": 1,
+  "stream":true
+};
+
+let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+  "headers": {
+    "accept": "text/event-stream",
+    "sec-fetch-dest": "empty",
+    "sec-fetch-mode": "cors",
+    "sec-fetch-site": "same-site"
+  },
+  "referrer": "https://ai.fmode.cn/",
+  "referrerPolicy": "strict-origin-when-cross-origin",
+  "body": JSON.stringify(bodyJson),
+  "method": "POST",
+  "mode": "cors",
+  "credentials": "omit"
+});
+
+let messageAiReply = ""
+let messageIndex = this.messageList.length
+let reader = response.body?.getReader();
+if (!reader) {
+  throw new Error("Failed to get the response reader.");
+}
+
+let decoder = new TextDecoder();
+let buffer = "";
+
+while (true) {
+  let { done, value } = await reader.read();
+  if (done) {
+    break;
+  }
+
+  buffer += decoder.decode(value);
+
+  // Split the buffer by newlines to get individual messages
+  let messages = buffer.split("\n");
+
+  // Process each message
+  for (let i = 0; i < messages.length - 1; i++) {
+    let message = messages[i];
+
+    // Process the message as needed
+    /**
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"fmode-4.5-128k","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"fmode-4.5-128k","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
+     * data: [DONE]
+     */
+    let dataText = message.replace("data:\ ","")
+    if(dataText.startsWith("{")){
+      try{
+        let dataJson = JSON.parse(dataText)
+        console.log(dataJson)
+        messageAiReply += dataJson?.choices?.[0]?.delta?.content || ""
+        this.messageList[messageIndex] = {
+          role:"assistant",
+          content:messageAiReply
+        }
+      }catch(err){}
+    }
+    if(dataText.startsWith("[")){
+      console.log(message)
+      console.log("完成")
+      this.messageList[messageIndex] = {
+        role:"assistant",
+        content:messageAiReply
+      }
+      messageAiReply = ""
+    }
+    // Parse the message as JSON
+    // let data = JSON.parse(message);
+
+    // Clear the processed message from the buffer
+    buffer = buffer.slice(message.length + 1);
+  }
+}
+}
+}

+ 11 - 0
tailor-app/myapp/src/app/edit-tag/edit-tag.component.html

@@ -0,0 +1,11 @@
+
+
+  
+  
+    <ion-input [value]="userInputText" (ionInput)="onInput($event)" type="" ></ion-input>
+    <!-- <p>当前输入{{userInputText}}</p> -->
+    <ion-button (click)="addtag()">添加标签</ion-button>
+    @for(tag of tags;track tag;){
+      <ion-chip>{{tag}} <span (click)="deleteTag(tag)">x</span></ion-chip>
+    }
+    

+ 0 - 0
tailor-app/myapp/src/app/edit-tag/edit-tag.component.scss


+ 24 - 0
tailor-app/myapp/src/app/edit-tag/edit-tag.component.spec.ts

@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { IonicModule } from '@ionic/angular';
+
+import { EditTagComponent } from './edit-tag.component';
+
+describe('EditTagComponent', () => {
+  let component: EditTagComponent;
+  let fixture: ComponentFixture<EditTagComponent>;
+
+  beforeEach(waitForAsync(() => {
+    TestBed.configureTestingModule({
+      declarations: [ EditTagComponent ],
+      imports: [IonicModule.forRoot()]
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(EditTagComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  }));
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 43 - 0
tailor-app/myapp/src/app/edit-tag/edit-tag.component.ts

@@ -0,0 +1,43 @@
+import { Component, EventEmitter, OnInit, Output } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonContent, IonHeader, IonTitle, IonToolbar, IonButton, IonInput, IonChip, IonItem, IonList } from '@ionic/angular/standalone';
+
+@Component({
+  selector: 'app-edit-tag',
+  templateUrl: './edit-tag.component.html',
+  styleUrls: ['./edit-tag.component.scss'],
+  standalone: true,
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule,IonButton,IonInput,IonChip,IonItem,IonList]
+
+})
+export class EditTagComponent  implements OnInit {
+  public inputValue = ""
+  public gptre = ""
+  tags:Array<string>=[]
+
+  userInputText:string=""
+  onInput(event:any){
+  this.userInputText=  event.detail.value
+    
+  }
+  deleteTag(tag:string){
+    let idx=this.tags.findIndex(item=>item==tag)
+    this.tags.splice(idx,1)
+
+  }
+  addtag(){
+    this.tags.push(this.userInputText);
+    this.userInputText=""
+    this.onTagChange.emit(this.tags)
+  }
+  @Output()
+  onTagChange:EventEmitter<Array<string>>=new EventEmitter<Array<string>>()
+  constructor() { }
+
+  ngOnInit() {
+  }
+  
+
+  
+}

二进制
tailor-app/myapp/src/app/me/img/绘图1.jpg


+ 233 - 7
tailor-app/myapp/src/app/me/me.page.html

@@ -1,13 +1,239 @@
 <ion-header [translucent]="true">
-  <ion-toolbar>
+  <ion-toolbar color="success">
     <ion-title>me</ion-title>
   </ion-toolbar>
 </ion-header>
 
 <ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">me</ion-title>
-    </ion-toolbar>
-  </ion-header>
-</ion-content>
+
+    <!-- GPT组件 -->
+    <h1>GPT组件</h1>
+     <ion-input type="" [(ngModel)]="inputValue"  ></ion-input>
+    <ion-button (click)="printInputValue()">提交</ion-button>
+   {{gptre}}
+
+
+  <h1>页面跳转和组件使用</h1>
+  <!-- 页面跳转和组件使用 -->
+  <ion-button [routerLink]="[ '/yiyun' ]">
+    跳转到yiyun
+  </ion-button>
+
+  <app-slide></app-slide>
+  <h1>button组件调用</h1>
+  <!-- button组件调用 -->
+  <ion-button [routerLink]="[ '/yiyun' ]" color="warning">
+    修改按钮颜色
+  </ion-button>
+ 
+  <ion-buttons slot="start">
+    <ion-back-button>返回i按钮</ion-back-button>
+  </ion-buttons>
+
+  <ion-button expand="block">
+    按钮可以block
+  </ion-button>
+
+  <ion-button expand="full">
+    按钮可以直角
+  </ion-button>
+
+  <ion-button fill="clear" expand="block">
+    按钮可以透明背景填充
+  </ion-button>
+
+  <ion-button>
+    <ion-icon slot="icon-only" name="add"></ion-icon>
+  </ion-button>
+  <ion-button fill="clear">
+    <ion-icon slot="icon-only" name="add"></ion-icon>
+  </ion-button>
+
+  <ion-button size="small">
+    小按钮
+  </ion-button>
+  <ion-button size="large">
+    大按钮
+  </ion-button>
+
+  <ion-button mode="ios" color="primary">
+    ios按钮
+  </ion-button>
+  <ion-button mode="md" color="primary">
+    android按钮
+  </ion-button>
+
+  <ion-button>
+    <ion-icon name="add" slot="start"></ion-icon>
+    图片在左侧文字在右侧按钮
+  </ion-button>
+  <ion-button>
+    <ion-icon name="add" slot="end"></ion-icon>
+    图片在右侧文字在右侧按钮
+  </ion-button>
+
+  <!-- List组件调用 -->
+  <h1>List组件调用 </h1>
+  <ion-list lines="full">
+    <ion-item *ngFor="let item of list" [routerLink]="[ '/yiyun' ]">
+      {{item}}
+    </ion-item>
+  </ion-list>
+
+  <ion-list>
+    <ion-item-divider>
+      <ion-label>分组列表A</ion-label>
+    </ion-item-divider>
+    <ion-item>
+      a
+    </ion-item>
+    <ion-item>
+      aaa
+    </ion-item>
+
+    <ion-item-divider>
+      <ion-label>B</ion-label>
+    </ion-item-divider>
+    <ion-item>
+      b
+    </ion-item>
+    <ion-item>
+      bbb
+    </ion-item>
+  </ion-list>
+
+  <ion-list lines="full">
+    <ion-item *ngFor="let item of list">
+      <ion-icon slot="start" name="add"></ion-icon>
+      带图标列表{{item}}
+    </ion-item>
+  </ion-list>
+
+  <ion-list>
+    <ion-item *ngFor="let item of list">
+      <ion-avatar item-left>
+        <img src="assets/shapes.svg">
+      </ion-avatar>
+      <ion-label>列表中的头像</ion-label>
+    </ion-item>
+  </ion-list>
+
+  <ion-list>
+    <ion-item *ngFor="let item of list">
+      <ion-thumbnail item-left>
+        <img src="assets/shapes.svg">
+      </ion-thumbnail>
+      <div>
+        <h2>我是标题</h2>
+        <p>我是新闻</p>
+      </div>
+      <button ion-button clear item-right></button>
+    </ion-item>
+  </ion-list>
+
+  <ion-list>
+    <ion-item-sliding>
+      <ion-item>
+        <ion-label>滑动列表1</ion-label>
+      </ion-item>
+      <ion-item-options side="start">
+        <ion-item-option>Favorite</ion-item-option>
+        <ion-item-option color="primary">Share</ion-item-option>
+      </ion-item-options>
+
+      <ion-item-options side="end">
+        <ion-item-option>Unread</ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+
+    <ion-item-sliding>
+      <ion-item>
+        <ion-label>滑动列表2</ion-label>
+      </ion-item>
+      <ion-item-options side="start">
+        <ion-item-option>Favorite</ion-item-option>
+        <ion-item-option color="primary">Share</ion-item-option>
+      </ion-item-options>
+
+      <ion-item-options side="end">
+        <ion-item-option>Unread</ion-item-option>
+      </ion-item-options>
+    </ion-item-sliding>
+  </ion-list>
+  <!-- 表单组件 -->
+  <h1>表单组件</h1>
+
+  <ion-list>
+    <ion-item>
+      <ion-label>用户名</ion-label>
+      <ion-input [(ngModel)]="peopleInfo.username"></ion-input>
+    </ion-item>
+
+    <ion-item>
+      <ion-label>是否本科</ion-label>
+      <ion-toggle slot="end" [(ngModel)]="peopleInfo.flag"></ion-toggle>
+    </ion-item>
+
+    <ion-radio-group [(ngModel)]="peopleInfo.payType">
+      <ion-item>
+        <ion-avatar item-left>
+          <img src="assets/shapes.svg">
+        </ion-avatar>
+        <ion-label>支付宝支付</ion-label>
+        <ion-radio value="1"></ion-radio>
+      </ion-item>
+
+      <ion-item>
+        <ion-avatar item-left>
+          <img src="assets/shapes.svg">
+        </ion-avatar>
+        <ion-label>微信支付</ion-label>
+        <ion-radio value="2"></ion-radio>
+      </ion-item>
+
+    </ion-radio-group>
+
+    <ion-item>
+      <ion-label>checkbox</ion-label>
+      <ion-checkbox></ion-checkbox>
+    </ion-item>
+  </ion-list>
+  {{peopleInfo|json}}
+
+  <!-- 搜索框 -->
+  <h1>搜索框</h1>
+  <ion-searchbar animated="true" placeholder="Animated"></ion-searchbar>
+  <ion-searchbar placeholder="Filter Pizza" (ionInput)="onSearchInput($event)" animated></ion-searchbar>
+
+  <!-- segment演示 -->
+  <h1>segment演示</h1>
+  <ion-segment [(ngModel)]="tab">
+    <ion-segment-button value="tab1">
+      <ion-label>详情</ion-label>
+    </ion-segment-button>
+    <ion-segment-button value="tab2">
+      <ion-label>评论</ion-label>
+    </ion-segment-button>
+
+    <div class="info" [ngSwitch]="tab">
+      <div *ngSwitchCase="'tab1'">商品简介</div>
+      <div *ngSwitchCase="'tab2'">商品评论</div>
+
+    </div>
+
+
+    {{tab}}
+
+    <!-- 日期组件 -->
+    <h1>日期组件</h1>
+    <ion-list>
+
+      <ion-item>
+        <ion-label>Date</ion-label>
+        <ion-datetime display-format="DD.MM.YYYY HH:mm"></ion-datetime>
+      </ion-item>
+    </ion-list>
+  </ion-segment>
+
+
+</ion-content>

+ 109 - 5
tailor-app/myapp/src/app/me/me.page.ts

@@ -1,20 +1,124 @@
 import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { IonContent, IonHeader, IonTitle, IonToolbar, IonButton, IonLabel, IonItem, IonList, IonBackButton, IonButtons, IonIcon, IonItemDivider, IonAvatar, IonThumbnail, IonItemOptions, IonItemOption, IonItemSliding, IonInput, IonCheckbox, IonRadio, IonToggle, IonRadioGroup, IonSearchbar, IonSegment, IonSegmentButton, IonDatetime } from '@ionic/angular/standalone';
+import { RouterModule } from '@angular/router';
+import { SlideModule } from '../module/slide/slide.module';
+import { addIcons } from 'ionicons';
+import { add } from 'ionicons/icons';
+// import {FmodeChatCompletion} from "fmode-ng"
+import { TestChatCompletion } from './test-chat-completion';
 
+addIcons({ add })
 @Component({
   selector: 'app-me',
   templateUrl: './me.page.html',
   styleUrls: ['./me.page.scss'],
   standalone: true,
-  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule, IonButton, RouterModule, IonLabel, IonLabel, IonList, IonItem, SlideModule, IonBackButton, IonButtons, IonIcon, IonItemDivider, IonAvatar, IonThumbnail, IonItemOptions, IonItemSliding, IonItemOption, IonItemOptions, IonInput, IonCheckbox, IonRadio, IonToggle, IonRadioGroup, IonSearchbar, IonSegment, IonSegmentButton, IonDatetime]
 })
 export class MePage implements OnInit {
-
+  public list: any = []
+  public tab = "tab1"
   constructor() { }
-
+  public inputValue = ""
+  public gptre = ""
+  public peopleInfo: any = {
+    username: '',
+    age: 20,
+    flag: true,
+    payType: '1',
+    checkBoxList: [
+      { val: '吃饭', ischecked: true },
+      { val: '睡觉', ischecked: false },
+      { val: '敲代码', ischecked: false }
+    ],
+    cityList: ['北京', '上海', '深圳'],
+    city: '北京'
+  }
   ngOnInit() {
+    for (var i = 0; i < 5; i++) {
+      this.list.push(`aaaaaaa${i}`);
+    }
+  }
+  onSearchInput(event: any) {
+    console.log(event.target.value);
   }
+  async printInputValue() {
+    console.log("开始解析");
+
+    let token = "r:16cd8f27084ff647fcdb5308a6783c4c"
+    localStorage.setItem("token",token)
+    let messageList: any = [
+      {
+        role: "system", content: `${new Date().toLocaleString}`
+      },
+      {
+        role: "user", content: this.inputValue
+      }
+    ]
+
+    let completion=new TestChatCompletion(messageList)
+    completion.createCompletionByStream()
+    setInterval(()=>{
+      console.log(messageList);
+      this.gptre=messageList[messageList.length-1].content
+    },1000)
+
+
+    // let bodyJson = {
+    //   "token": `Bearer ${token}`,
+    //   "messages": messageList,
+    //   "model": "fmode-4.5-128k",
+    //   "temperature": 0.5,
+    //   "presence_penalty": 0,
+    //   "frequency_penalty": 0,
+    //   "top_p": 1,
+    //   "stream": true
+    // };
 
-}
+    // let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+    //   "headers": {
+    //     "accept": "text/event-stream",
+    //   },
+    //   "body": JSON.stringify(bodyJson),
+    //   "method": "POST",
+    //   "mode": "cors",
+    //   "credentials": "omit"
+    // });
+    // let reader = response.body?.getReader()
+    // if (!reader) {
+    //   throw new Error("Failed to get the response reader.");
+    // }
+
+    // let decoder = new TextDecoder();
+    // let buffer = "";
+
+    // while (true) {
+    //   let { done, value } = await reader.read();
+    //   if (done) {
+    //     break;
+    //   }
+    //   let data = decoder.decode(value);
+    //   let messages = data.split("\n");
+    //   console.log(messages);
+
+    //   for (let i = 0; i < messages.length - 1; i++) {
+    //     let message = messages[i];
+    //     console.log(message);
+    //     let dataStr: string = message.split("data: ")[1]
+    //     if (dataStr && dataStr.startsWith("{")) {
+    //       try {
+    //         let json = JSON.parse(dataStr);
+    //         let content = json.choices[0].delta.content
+    //         this.gptre = this.gptre + content
+    //       } catch (err) { }
+    //     }
+
+
+    //   }
+    // }
+
+
+  }
+}

+ 99 - 0
tailor-app/myapp/src/app/me/test-chat-completion.ts

@@ -0,0 +1,99 @@
+export interface TestChatMessage{
+    role:string
+    content:string
+}
+export class TestChatCompletion{
+messageList:Array<TestChatMessage>
+constructor(messageList:Array<TestChatMessage>){
+    this.messageList = messageList
+}
+async createCompletionByStream() {
+
+let token = localStorage.getItem("token");
+let bodyJson = {
+  "token": `Bearer ${token}`,
+  "messages": this.messageList,
+  "model": "fmode-4.5-128k",
+  "temperature": 0.5,
+  "presence_penalty": 0,
+  "frequency_penalty": 0,
+  "top_p": 1,
+  "stream":true
+};
+
+let response = await fetch("https://test.fmode.cn/api/apig/aigc/gpt/v1/chat/completions", {
+  "headers": {
+    "accept": "text/event-stream",
+    "sec-fetch-dest": "empty",
+    "sec-fetch-mode": "cors",
+    "sec-fetch-site": "same-site"
+  },
+  "referrer": "https://ai.fmode.cn/",
+  "referrerPolicy": "strict-origin-when-cross-origin",
+  "body": JSON.stringify(bodyJson),
+  "method": "POST",
+  "mode": "cors",
+  "credentials": "omit"
+});
+
+let messageAiReply = ""
+let messageIndex = this.messageList.length
+let reader = response.body?.getReader();
+if (!reader) {
+  throw new Error("Failed to get the response reader.");
+}
+
+let decoder = new TextDecoder();
+let buffer = "";
+
+while (true) {
+  let { done, value } = await reader.read();
+  if (done) {
+    break;
+  }
+
+  buffer += decoder.decode(value);
+
+  // Split the buffer by newlines to get individual messages
+  let messages = buffer.split("\n");
+
+  // Process each message
+  for (let i = 0; i < messages.length - 1; i++) {
+    let message = messages[i];
+
+    // Process the message as needed
+    /**
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"fmode-4.5-128k","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
+     * data: {"id":"chatcmpl-y2PLKqPDnwAFJIj2L5aqdH5TWK9Yv","object":"chat.completion.chunk","created":1696770162,"model":"fmode-4.5-128k","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
+     * data: [DONE]
+     */
+    let dataText = message.replace("data:\ ","")
+    if(dataText.startsWith("{")){
+      try{
+        let dataJson = JSON.parse(dataText)
+        console.log(dataJson)
+        messageAiReply += dataJson?.choices?.[0]?.delta?.content || ""
+        this.messageList[messageIndex] = {
+          role:"assistant",
+          content:messageAiReply
+        }
+      }catch(err){}
+    }
+    if(dataText.startsWith("[")){
+      console.log(message)
+      console.log("完成")
+      this.messageList[messageIndex] = {
+        role:"assistant",
+        content:messageAiReply
+      }
+      messageAiReply = ""
+    }
+    // Parse the message as JSON
+    // let data = JSON.parse(message);
+
+    // Clear the processed message from the buffer
+    buffer = buffer.slice(message.length + 1);
+  }
+}
+}
+}

+ 3 - 0
tailor-app/myapp/src/app/module/slide/slide.component.html

@@ -0,0 +1,3 @@
+<p>
+  slide works!
+</p>

+ 0 - 0
tailor-app/myapp/src/app/module/slide/slide.component.scss


+ 24 - 0
tailor-app/myapp/src/app/module/slide/slide.component.spec.ts

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

+ 14 - 0
tailor-app/myapp/src/app/module/slide/slide.component.ts

@@ -0,0 +1,14 @@
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-slide',
+  templateUrl: './slide.component.html',
+  styleUrls: ['./slide.component.scss'],
+})
+export class SlideComponent  implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {}
+
+}

+ 13 - 0
tailor-app/myapp/src/app/module/slide/slide.module.ts

@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SlideComponent } from './slide.component';
+
+
+@NgModule({
+  declarations: [SlideComponent],
+  imports: [
+    CommonModule,
+  ],
+  exports:[SlideComponent]
+})
+export class SlideModule { }

+ 122 - 15
tailor-app/myapp/src/app/yiyun/yiyun.page.html

@@ -1,16 +1,123 @@
-<ion-header>
-  <ion-toolbar>
-    <ion-title>
-      搜索栏示例
-    </ion-title>
-    <ion-searchbar (ionInput)="onSearchInput($event)" placeholder="搜索..."></ion-searchbar>
-  </ion-toolbar>
-</ion-header>
+  <!-- 页面顶部导航栏 -->
+  <ion-header class="ion-no-border" style="background-color: rgb(231, 244, 247);;" >
+    <ion-toolbar  >
+      <ion-searchbar  animated="true" placeholder="Animated"></ion-searchbar>
+      <ion-buttons slot="end">
+        <!-- <ion-button size="small">登录/注册</ion-button> -->
+        <!-- <ion-button size="small">商家后台入口</ion-button> -->
+      </ion-buttons>
+    </ion-toolbar>
+  </ion-header>
 
-<ion-content>
-  <ion-list>
-    <ion-item *ngFor="let item of filteredItems">
-      {{ item }}
-    </ion-item>
-  </ion-list>
-</ion-content>
+  <!-- 品牌展示区 -->
+  <ion-content>
+    <!-- <ion-slides>
+      <ion-slide>
+        <img src="最新服装定制案例图片路径" alt="服装定制案例">
+      </ion-slide>
+      <ion-slide>
+        <img src="时尚活动照片路径" alt="时尚活动">
+      </ion-slide>
+    </ion-slides> -->
+    <ion-grid>
+      <ion-row >
+        <ion-col *ngFor="let item of items; let i = index" class="custom-padding" >
+          <div class="button-container">
+            <ion-icon size="large" [name]="item.image"></ion-icon>
+            <p class="item-text">{{ item.text }}</p>
+          </div>
+        </ion-col>
+      </ion-row>
+    </ion-grid>
+
+    <ion-grid style="justify-content: center;display: flex;">
+      <ion-row style="background-color: white;width: 90%;border-radius: 10px;" >
+        <ion-card style="width: 44%;box-shadow: none;">
+          <ion-card-header>
+            <img src="assets/img/ding.png" alt="">
+            <ion-card-title style="font-size: 17px;font-weight:bolder;">定制服务</ion-card-title>
+          </ion-card-header>
+          <!-- <ion-card-content>
+            <ion-button expand="block">点击参与最新定制活动</ion-button>
+          </ion-card-content> -->
+        </ion-card>
+    
+        <!-- 用户定制入口 -->
+        <ion-card style="width: 44%;box-shadow: none;">
+          <ion-card-header>
+            <img src="assets/img/3d.png" alt="">
+            <ion-card-title style="font-size: 17px;font-weight:bolder;">3D试衣服务</ion-card-title>
+          </ion-card-header>
+          
+        </ion-card>
+      </ion-row>
+    </ion-grid>
+
+    <!-- 商家管理入口 -->
+    <ion-card>
+      <ion-card-content>
+        
+        <ion-button expand="block"><ion-icon name="camera"></ion-icon> 一键入库</ion-button>
+        <p>智能库存管理,让生意更简单</p>
+      </ion-card-content>
+    </ion-card>
+
+    <!-- 特色服务展示
+    <ion-grid>
+      <ion-row>
+        <ion-col size="6">
+          <ion-card>
+            <ion-icon name="camera"></ion-icon> 假设AI定制对应的ion-icon名称为ai-outline,需替换准确图标名
+            <ion-card-header>
+              <ion-card-title>AI智能推荐,精准匹配</ion-card-title>
+            </ion-card-header>
+          </ion-card>
+        </ion-col>
+        <ion-col size="6">
+          <ion-card>
+            <ion-icon name="camera"></ion-icon> 假设虚拟试衣对应的ion-icon名称为body-outline,需替换准确图标名
+            <ion-card-header>
+              <ion-card-title>虚拟试衣体验,先试后买</ion-card-title>
+            </ion-card-header>
+          </ion-card>
+        </ion-col>
+      </ion-row>
+    </ion-grid> -->
+
+    <!-- 用户评价和案例展示 -->
+    <!-- <ion-list>
+      <ion-item>
+        <ion-avatar slot="start">
+          <img src="示例用户照片路径" alt="用户头像">
+        </ion-avatar>
+        <ion-label>
+          <h2>衣服非常合身,面料舒适,非常满意!</h2>
+          <img src="用户定制的服装照片路径" alt="定制案例">
+        </ion-label>
+      </ion-item>
+    </ion-list> -->
+
+    <!-- 最新时尚资讯 -->
+    <ion-card>
+      <ion-card-header>
+        <ion-card-title>2024年春季流行趋势</ion-card-title>
+      </ion-card-header>
+      <ion-card-content>
+        <p>本季流行色、面料及搭配建议一览</p>
+        <ion-button expand="block">了解更多</ion-button>
+      </ion-card-content>
+    </ion-card>
+
+    <!-- 页面底部 -->
+    <!-- <ion-footer>
+      <ion-toolbar>
+        <ion-label>© 2024 个性化定制服装平台</ion-label>
+        <ion-buttons slot="end">
+          <ion-button>客服热线:400-xxx-xxxx</ion-button>
+          <ion-button>关于我们</ion-button>
+          <ion-button>合作伙伴</ion-button>
+          <ion-button>隐私政策</ion-button>
+        </ion-buttons>
+      </ion-toolbar>
+    </ion-footer> -->
+  </ion-content>

+ 41 - 0
tailor-app/myapp/src/app/yiyun/yiyun.page.scss

@@ -0,0 +1,41 @@
+ion-searchbar {
+    --background: #ffffff; // 背景颜色
+    --placeholder-color: #aaaaaa; // 占位符颜色
+    --text-color: #000000; // 文本颜色
+    --border-color: #cccccc; // 边框颜色
+    --border-radius: 15px; // 边框圆角
+    --box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); // 阴影效果
+    // 你可以添加更多的CSS变量来定制样式
+  }
+  .button-container {
+    text-align: center;
+    padding: 16px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    transition: all 0.3s ease;
+  }
+   
+  .button-container:hover {
+    transform: translateY(-4px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+  }
+   
+  .item-image {
+    width: 100%;
+    height: auto;
+    border-radius: 8px 8px 0 0;
+  }
+   
+  .item-text {
+    margin-top: 0px;
+    font-size: 14px;
+    color: #333;
+  }
+  .custom-padding .button-container {
+    padding: 0px;
+    box-shadow: none;
+  }
+  ion-content {
+    --background: rgb(231, 244, 247);
+  }
+  

+ 19 - 30
tailor-app/myapp/src/app/yiyun/yiyun.page.ts

@@ -1,48 +1,37 @@
 import { Component, NgModule, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
-import { IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular/standalone';
-import { IonItem } from '@ionic/angular/standalone';
-import { IonList } from '@ionic/angular/standalone';
-import { IonSearchbar } from '@ionic/angular/standalone';
+import { ItemReorderEventDetail } from '@ionic/angular/standalone';
+import { addIcons } from 'ionicons';
+import { camera} from 'ionicons/icons';
+import { IonContent, IonHeader, IonTitle, IonToolbar, IonButton, IonLabel, IonItem, IonList, IonBackButton, IonButtons, IonIcon, IonItemDivider, IonAvatar, IonThumbnail, IonItemOptions, IonItemOption, IonItemSliding, IonInput, IonCheckbox, IonRadio, IonToggle, IonRadioGroup, IonSearchbar,IonSegment,IonSegmentButton,IonDatetime,IonFooter,IonCardContent,IonCardTitle,IonCardHeader,IonCard,IonCol,IonRow,IonGrid } from '@ionic/angular/standalone';
+addIcons({camera})
+
 @Component({
   selector: 'app-yiyun',
   templateUrl: './yiyun.page.html',
   styleUrls: ['./yiyun.page.scss'],
   standalone: true,
-  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule,IonItem,IonList,IonSearchbar]
-})
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule, IonButton,  IonLabel, IonLabel, IonList, IonItem, IonBackButton, IonButtons, IonIcon, IonItemDivider, IonAvatar, IonThumbnail, IonItemOptions, IonItemSliding, IonItemOption, IonItemOptions,IonInput,IonCheckbox,IonRadio,IonToggle,IonRadioGroup,IonSearchbar,IonSegment,IonSegmentButton,IonDatetime,IonFooter,IonCardContent,IonCardTitle,IonCardHeader,IonCard,IonCol,IonRow,IonGrid ]
 
+})
 export class YiyunPage implements OnInit {
 
   constructor() { }
 
   ngOnInit() {
   }
-  items: string[] = [
-    'Apple',
-    'Banana',
-    'Cherry',
-    'Date',
-    'Elderberry',
-    'Fig',
-    'Grape',
-    'Honeydew',
-    'Kiwi',
-    'Lemon'
+  
+  public items = [
+    { image: 'camera', text: 'Button 1', page: '/page1' },
+    { image: 'camera', text: 'Button 2', page: '/page2' },
+    { image: 'camera', text: 'Button 3', page: '/page3' },
+    { image: 'camera', text: 'Button 4', page: '/page4' },
+    
   ];
- 
-  filteredItems: string[] = [...this.items];
- 
- 
-  onSearchInput(event: CustomEvent<any>) {
-    const searchValue = event.detail.value.toLowerCase();
-    if (!searchValue) {
-      this.filteredItems = [...this.items];
-    } else {
-      this.filteredItems = this.items.filter(item =>
-        item.toLowerCase().includes(searchValue)
-      );
-    }
+  // 打开登陆页面
+  openLoginModal(){
+    console.log("打开登陆页面");
+    
   }
 }

二进制
tailor-app/myapp/src/assets/img/3d.png


二进制
tailor-app/myapp/src/assets/img/ding.png


+ 14 - 1
tailor-app/myapp/src/main.ts

@@ -4,11 +4,24 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalo
 
 import { routes } from './app/app.routes';
 import { AppComponent } from './app/app.component';
-
+// let token = "r:16cd8f27084ff647fcdb5308a6783c4c"
+// 引用HttpClient方法
+import { provideHttpClient } from '@angular/common/http';
+// 引用移动端授权检测供应器
+import { Diagnostic } from '@awesome-cordova-plugins/diagnostic/ngx';
+// 设置Parse服务属性
+import Parse from "parse";
+Parse.initialize("ncloudmaster");
+Parse.serverURL = "https://server.fmode.cn/parse";
+localStorage.setItem("NOVA_APIG_SERVER", 'aHR0cHMlM0ElMkYlMkZzZXJ2ZXIuZm1vZGUuY24lMkZhcGklMkZhcGlnJTJG')
+Parse.User.become("r:16cd8f27084ff647fcdb5308a6783c4c")
 bootstrapApplication(AppComponent, {
   providers: [
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
     provideIonicAngular(),
     provideRouter(routes, withPreloading(PreloadAllModules)),
+    provideHttpClient(),
+    // 添加Diagnostic
+    Diagnostic,
   ],
 });

+ 2 - 1
tailor-app/myapp/tsconfig.json

@@ -19,7 +19,8 @@
     "target": "es2022",
     "module": "es2020",
     "lib": ["es2018", "dom"],
-    "useDefineForClassFields": false
+    "useDefineForClassFields": false,
+    "allowSyntheticDefaultImports":true
   },
   "angularCompilerOptions": {
     "enableI18nLegacyMessageIdFormat": false,

部分文件因为文件数量过多而无法显示