Browse Source

feat: poem picture task

未来全栈 4 months ago
parent
commit
078fbc74c2

+ 18 - 0
src/agent/agent-user-input/agent-user-input.component.html

@@ -0,0 +1,18 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-buttons slot="start">
+      <ion-button color="medium" (click)="cancel()">取消</ion-button>
+    </ion-buttons>
+    <ion-title>用户输入</ion-title>
+    <ion-buttons slot="end">
+      <ion-button (click)="confirm()" [strong]="true">确认</ion-button>
+    </ion-buttons>
+  </ion-toolbar>
+</ion-header>
+<ion-content class="ion-padding">
+  @for(field of fieldsArray;track field.name){
+    <ion-item>
+      <ion-input labelPlacement="stacked" label="请输入 {{field.name}}" [(ngModel)]="inputData[field.name]" placeholder="{{field.desc}}"></ion-input>
+    </ion-item>
+  }
+</ion-content>

+ 0 - 0
src/agent/agent-user-input/agent-user-input.component.scss


+ 22 - 0
src/agent/agent-user-input/agent-user-input.component.spec.ts

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

+ 38 - 0
src/agent/agent-user-input/agent-user-input.component.ts

@@ -0,0 +1,38 @@
+import { Component, OnInit, Input } from '@angular/core';
+import { ModalController, IonHeader, IonContent, IonInput, IonToolbar, IonItem, IonButtons, IonButton, IonTitle } from '@ionic/angular/standalone';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+export interface AgentUserInputField{
+  name:string, // 字段名称
+  type:string, // 输入类型
+  desc:string, // 字段说明
+}
+@Component({
+  selector: 'agent-user-input',
+  templateUrl: './agent-user-input.component.html',
+  styleUrls: ['./agent-user-input.component.scss'],
+  standalone: true,
+  imports:[
+    IonHeader,IonContent,IonInput,IonToolbar,IonItem,IonButtons,IonButton,
+    IonTitle,
+    FormsModule,ReactiveFormsModule,
+  ]
+})
+export class AgentUserInputComponent  implements OnInit {
+
+  @Input()
+  fieldsArray:AgentUserInputField[]=[]
+
+  @Input()
+  inputData:any = {}
+
+  constructor(private modalCtrl: ModalController) {}
+  ngOnInit(){
+  }
+  cancel() {
+    return this.modalCtrl.dismiss(null, 'cancel');
+  }
+
+  confirm() {
+    return this.modalCtrl.dismiss(this.inputData, 'confirm');
+  }
+}

+ 23 - 0
src/agent/agent.input.ts

@@ -0,0 +1,23 @@
+import { ModalController } from '@ionic/angular/standalone';
+import { AgentUserInputComponent } from './agent-user-input/agent-user-input.component';
+
+/**
+ * 数据搜集Modal
+ * @description
+ * https://ionicframework.com/docs/api/modal#controller-modals
+ */
+export async function getUserInput(modalCtrl:ModalController,options:{fieldsArray:any}){
+  const modal = await modalCtrl.create({
+    component: AgentUserInputComponent,
+    componentProps:{
+      fieldsArray:options.fieldsArray
+    }
+  });
+  modal.present();
+
+  const { data, role } = await modal.onWillDismiss();
+
+  if (role === 'confirm') {
+    return data;
+  }
+}

+ 39 - 0
src/agent/tasks/poem/poem-desc.ts

@@ -0,0 +1,39 @@
+import { AgentTaskStep } from 'src/agent/agent.task';
+import { getUserInput } from 'src/agent/agent.input';
+import { ModalController } from '@ionic/angular/standalone';
+import { FmodeChatCompletion } from 'fmode-ng';
+
+export function TaskPoemPictureDesc(options:{
+    modalCtrl:ModalController
+    shareData:any}
+    ):AgentTaskStep{
+        let task1 = new AgentTaskStep({title:"意境分析",shareData:options.shareData})
+        task1.handle = async ()=>{
+        // 获取用户输入的诗词
+        let userInput = await getUserInput(options.modalCtrl,{fieldsArray:[
+            {name:"诗文内容",type:"text",desc:"诗文句子或段落"}
+        ]});
+        console.log("已获取用户输入:",userInput)
+        console.log("已获取诗文内容:",userInput['诗文内容'])
+
+            // 文本生成
+        let PromptTemplate = `您是一名专业的美术画家,请您根据古诗文的内容,将其描述的画面、场景、人物、物品等用最简短的语言表达,直接写出画面,并且以中国的古风意境为主
+        诗文如下:
+        ${userInput['诗文内容']}
+        `
+        let completion = new FmodeChatCompletion([
+            {role:"system",content:""},
+            {role:"user",content:PromptTemplate}
+            ])
+            completion.sendCompletion().subscribe((message:any)=>{
+            // 打印消息体
+            console.log(message.content)
+            // 赋值消息内容给组件内属性
+            options.shareData.PictureDescResult = message.content
+            if(message.complete){ // 判断message为完成状态,则设置isComplete为完成
+                task1.progress = 1
+            }
+            })
+        }
+        return task1
+}

+ 32 - 0
src/agent/tasks/poem/poem-picture.ts

@@ -0,0 +1,32 @@
+import { ModalController } from '@ionic/angular/standalone';
+import { AgentTaskStep } from 'src/agent/agent.task';
+import { ImagineWork, DalleOptions } from 'fmode-ng';
+
+
+export function TaskPoemPictureCreate(options:{
+    modalCtrl:ModalController
+    shareData:any}):AgentTaskStep{
+    let task2 = new AgentTaskStep({title:"意境绘制",shareData:options.shareData})
+    task2.handle = async ()=>{
+      // let userInput = await getUserInput(options.modalCtrl,{fieldsArray:[
+      //   {name:"绘图要求",type:"text",desc:"画风、构图等等"}
+      // ]});
+      // console.log(userInput)
+      console.log("意境绘制:执行过程")
+
+      options.shareData.PictureDescResult
+      let imagineWork = new ImagineWork();
+      // 图片生成
+      let PicturePrompt = `${options.shareData.PictureDescResult}\n风格:中国古风。画面不带任何文字。`
+      let imgOptions:DalleOptions = {prompt:PicturePrompt}
+      imagineWork?.draw(imgOptions).subscribe((work:any)=>{
+          console.log("imagineWork",work?.toJSON())
+          console.log("images",work?.get("images"))
+          if(work?.get("images")?.length){
+            options.shareData.images = work?.get("images");
+            task2.progress = 1
+          }
+      })
+    }
+    return task2
+}

+ 8 - 0
src/app/tab1/tab1.page.html

@@ -7,6 +7,7 @@
 </ion-header>
 
 <ion-content [fullscreen]="true">
+ <ion-button (click)="doPoemTask()">执行诗文意境绘制任务集</ion-button>
  <ion-button (click)="doInqueryTask()">执行问诊任务集</ion-button>
 
  <ul>
@@ -32,4 +33,11 @@
     </div>   
   }
   </ul>
+
+  <!-- 生成结果 -->
+  @if(shareData.images) {
+    @for(imageUrl of shareData.images;track imageUrl){
+      <img [src]="imageUrl" alt="" srcset="">
+    }
+  }
 </ion-content>

+ 12 - 14
src/app/tab1/tab1.page.ts

@@ -1,9 +1,14 @@
 import { Component,OnInit } from '@angular/core';
-import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonIcon } from '@ionic/angular/standalone';
+import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton,IonIcon, ModalController } from '@ionic/angular/standalone';
 import { AgentTaskStep } from 'src/agent/agent.task';
 import { addIcons } from 'ionicons';
 import { radioButtonOffOutline, reloadOutline, checkmarkCircleOutline, closeCircleOutline } from 'ionicons/icons';
 import { startTask } from 'src/agent/agent.start';
+import { AgentUserInputComponent } from 'src/agent/agent-user-input/agent-user-input.component';
+import { getUserInput } from 'src/agent/agent.input';
+import { FmodeChatCompletion, ImagineWork, DalleOptions } from "fmode-ng";
+import { TaskPoemPictureDesc } from 'src/agent/tasks/poem/poem-desc';
+import { TaskPoemPictureCreate } from 'src/agent/tasks/poem/poem-picture';
 addIcons({radioButtonOffOutline,reloadOutline,checkmarkCircleOutline,closeCircleOutline})
 @Component({
   selector: 'app-tab1',
@@ -17,7 +22,7 @@ addIcons({radioButtonOffOutline,reloadOutline,checkmarkCircleOutline,closeCircle
 export class Tab1Page  {
 
 
-  constructor() {
+  constructor(private modalCtrl:ModalController) {
 
 
   }
@@ -34,19 +39,12 @@ export class Tab1Page  {
 
   shareData:any = {}
 
+  // 任务:完成故事意境描述及图像绘制
   doPoemTask(){
-    let task1 = new AgentTaskStep({title:"意境分析",shareData:this.shareData})
-    task1.handle = async ()=>{
-      await this.wait(1000)
-      console.log("意境分析:执行过程")
-      task1.progress = 1
-    }
-    let task2 = new AgentTaskStep({title:"意境绘制",shareData:this.shareData})
-    task2.handle = async ()=>{
-      await this.wait(1000)
-      console.log("意境绘制:执行过程")
-      task2.progress = 1
-    }
+    // 产生: shareData.PictureDescResult 生成后描述
+    let task1 = TaskPoemPictureDesc({shareData:this.shareData,modalCtrl:this.modalCtrl});
+    // 产生: shareData.images 渲染后图片
+    let task2 = TaskPoemPictureCreate({shareData:this.shareData,modalCtrl:this.modalCtrl});
     
     // 定义任务集
     let PoemTaskList = [task1,task2]

+ 18 - 0
src/main.ts

@@ -5,10 +5,28 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalo
 import { routes } from './app/app.routes';
 import { AppComponent } from './app/app.component';
 
+// 引用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')
+
+// 注意:替换Token 根据Token设置Parse服务帐套权限
+Parse.User.become('r:21b53aad9b769d6e0e1a1e23db0e0a7b')
+
 bootstrapApplication(AppComponent, {
   providers: [
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
     provideIonicAngular(),
     provideRouter(routes, withPreloading(PreloadAllModules)),
+     // 添加HttpClient供应器
+     provideHttpClient(),
+     // 添加Diagnostic
+     Diagnostic,
+    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
   ],
 });

+ 1 - 0
tsconfig.json

@@ -4,6 +4,7 @@
   "compilerOptions": {
     "baseUrl": "./",
     "outDir": "./dist/out-tsc",
+    "allowSyntheticDefaultImports":true,
     "forceConsistentCasingInFileNames": true,
     "strict": true,
     "noImplicitOverride": true,