浏览代码

feat: new ailearning page with aigc

未来全栈 6 月之前
父节点
当前提交
59b102def4

+ 4 - 1
interestCourses-app/angular.json

@@ -126,7 +126,10 @@
     }
   },
   "cli": {
-    "schematicCollections": ["@ionic/angular-toolkit"]
+    "schematicCollections": [
+      "@ionic/angular-toolkit"
+    ],
+    "analytics": "abb61b0c-b5d2-4d96-8437-5c7ca6cb08b9"
   },
   "schematics": {
     "@ionic/angular-toolkit:component": {

文件差异内容过多而无法显示
+ 641 - 14
interestCourses-app/package-lock.json


+ 1 - 0
interestCourses-app/package.json

@@ -27,6 +27,7 @@
     "@capacitor/keyboard": "6.0.3",
     "@capacitor/status-bar": "6.0.2",
     "@ionic/angular": "^8.0.0",
+    "fmode-ng": "^0.0.62",
     "ionicons": "^7.2.1",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",

+ 1 - 0
interestCourses-app/src/app/app.routes.ts

@@ -5,4 +5,5 @@ export const routes: Routes = [
     path: '',
     loadChildren: () => import('./tabs/tabs.routes').then((m) => m.routes),
   },
+
 ];

+ 24 - 0
interestCourses-app/src/app/page-ailearning/page-ailearning.component.html

@@ -0,0 +1,24 @@
+<ion-content>
+
+  <h1>课程</h1>
+  <ion-input [value]="course" (ionInput)="courseInput($event)"></ion-input>
+
+
+  <h1>学习内容的描述</h1>
+  <ion-textarea [value]="userPrompt" (ionInput)="promptInput($event)" placeholder="文本提示词"
+    autoGrow="true"></ion-textarea>
+  <!-- 按钮:执行消息生成函数 -->
+  <ion-button (click)="sendMessage()" expand="block">学习建议</ion-button>
+
+  <!-- 展示:返回消息内容 -->
+  <!-- 展示:返回消息内容 -->
+  <!-- 消息传输过程中,实时预览 -->
+  @if(!isComplete){
+  <div>{{responseMsg}}</div>
+  }
+  <!-- 消息传输完成后,实时预览Markdown格式 -->
+  @if(isComplete){
+  <fm-markdown-preview class="content-style" [content]="responseMsg"></fm-markdown-preview>
+  }
+
+</ion-content>

+ 0 - 0
interestCourses-app/src/app/page-ailearning/page-ailearning.component.scss


+ 22 - 0
interestCourses-app/src/app/page-ailearning/page-ailearning.component.spec.ts

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

+ 58 - 0
interestCourses-app/src/app/page-ailearning/page-ailearning.component.ts

@@ -0,0 +1,58 @@
+import { Component, OnInit } from '@angular/core';
+import { IonButton, IonContent, IonHeader, IonInput, IonTitle, IonToolbar } from '@ionic/angular/standalone';
+import { IonTextarea } from '@ionic/angular/standalone';
+import { FmodeChatCompletion, MarkdownPreviewModule } from 'fmode-ng';
+
+@Component({
+  selector: 'app-page-ailearning',
+  templateUrl: './page-ailearning.component.html',
+  styleUrls: ['./page-ailearning.component.scss'],
+  standalone: true,
+  imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButton,
+    IonTextarea, IonInput, MarkdownPreviewModule
+  ],
+})
+export class PageAIlearningComponent implements OnInit {
+  constructor() { }
+
+  ngOnInit() { }
+
+  // 用户输入提示词
+  course: string = "课程名称"
+  courseInput(ev: any) {
+    this.course = ev.detail.value;
+  }
+  // 用户输入提示词
+  userPrompt: string = "请描述你想学习的内容。"
+  promptInput(ev: any) {
+    this.userPrompt = ev.detail.value;
+  }
+  // 属性:组件内用于展示消息内容的变量
+  responseMsg: any = ""
+  // 方法:实例化completion对象,传入消息数组,并订阅生成的可观察对象。
+  isComplete: boolean = false; // 定义完成状态属性,用来标记是否补全完成
+  sendMessage() {
+    console.log("create")
+
+    let PromptTemplate = `
+    您作为一名专业的${this.courseInput}老师,请您根据用户描述的学习内容,给出知识点的解析,并给出一些建议。以下是用户的口述:${this.userPrompt}
+    `
+    let completion = new FmodeChatCompletion([
+      { role: "system", content: "" },
+      { role: "user", content: this.userPrompt }
+    ])
+    completion.sendCompletion().subscribe((message: any) => {
+      // 打印消息体
+      console.log(message.content)
+      // 赋值消息内容给组件内属性
+      this.responseMsg = message.content
+      if (message?.complete) { // 判断message为完成状态,则设置isComplete为完成
+        this.isComplete = true
+      }
+    })
+
+    this.isComplete = false
+  }
+}
+
+

+ 10 - 5
interestCourses-app/src/app/tab2/tab2.page.html

@@ -1,7 +1,7 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
     <ion-title>
-      Tab 2
+      开始今天的学习吧
     </ion-title>
   </ion-toolbar>
 </ion-header>
@@ -9,9 +9,14 @@
 <ion-content [fullscreen]="true">
   <ion-header collapse="condense">
     <ion-toolbar>
-      <ion-title size="large">Tab 2</ion-title>
+      <ion-title size="large">开始学习</ion-title>
     </ion-toolbar>
   </ion-header>
-
-  <app-explore-container name="Tab 2 page"></app-explore-container>
-</ion-content>
+  <div class="learning" style="margin-top: 10px">
+    <div class="learningy-ai">
+      <ion-button color="primary" size="large" (click)="goToPageailearning()">
+        AI兴趣学习
+      </ion-button>
+    </div>
+  </div>
+</ion-content>

+ 16 - 0
interestCourses-app/src/app/tab2/tab2.page.scss

@@ -0,0 +1,16 @@
+.learning {
+    width: 100%;
+    height: 100px;
+    // background-color: #fd0000;
+    padding: 5px 0px;
+    box-sizing: border-box;
+    margin: 0px 0px;
+
+    ion-button {
+        width: 100%;
+        height: 100%;
+        background-color: crimson;
+        display: inline-block;
+    }
+
+}

+ 11 - 2
interestCourses-app/src/app/tab2/tab2.page.ts

@@ -1,16 +1,25 @@
 import { Component } from '@angular/core';
 import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
 import { ExploreContainerComponent } from '../explore-container/explore-container.component';
+import { Router } from '@angular/router';
+import { IonButton } from '@ionic/angular/standalone';
 
 @Component({
   selector: 'app-tab2',
   templateUrl: 'tab2.page.html',
   styleUrls: ['tab2.page.scss'],
   standalone: true,
-  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent]
+  imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent, IonButton]
 })
 export class Tab2Page {
 
-  constructor() {}
+  constructor(private router: Router) { }
+
+  /**
+   * Go to the ai page
+   */
+  goToPageailearning() {
+    this.router.navigate(['/tabs/ailearning'])
+  }
 
 }

+ 13 - 0
interestCourses-app/src/app/tab4/tab4.page.html

@@ -0,0 +1,13 @@
+<ion-header [translucent]="true">
+  <ion-toolbar>
+    <ion-title>tab4</ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content [fullscreen]="true">
+  <ion-header collapse="condense">
+    <ion-toolbar>
+      <ion-title size="large">tab4</ion-title>
+    </ion-toolbar>
+  </ion-header>
+</ion-content>

+ 0 - 0
interestCourses-app/src/app/tab4/tab4.page.scss


+ 17 - 0
interestCourses-app/src/app/tab4/tab4.page.spec.ts

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

+ 20 - 0
interestCourses-app/src/app/tab4/tab4.page.ts

@@ -0,0 +1,20 @@
+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';
+
+@Component({
+  selector: 'app-tab4',
+  templateUrl: './tab4.page.html',
+  styleUrls: ['./tab4.page.scss'],
+  standalone: true,
+  imports: [IonContent, IonHeader, IonTitle, IonToolbar, CommonModule, FormsModule]
+})
+export class Tab4Page implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}

+ 7 - 0
interestCourses-app/src/app/tabs/tabs.page.html

@@ -10,9 +10,16 @@
       <ion-label>学习</ion-label>
     </ion-tab-button>
 
+    <ion-tab-button tab="tab4" href="/tabs/tab4">
+      <ion-icon aria-hidden="true" name="planet"></ion-icon>
+      <ion-label>广场</ion-label>
+    </ion-tab-button>
+
     <ion-tab-button tab="tab3" href="/tabs/tab3">
       <ion-icon aria-hidden="true" name="person"></ion-icon>
       <ion-label>我的</ion-label>
     </ion-tab-button>
+
+
   </ion-tab-bar>
 </ion-tabs>

+ 2 - 2
interestCourses-app/src/app/tabs/tabs.page.ts

@@ -1,7 +1,7 @@
 import { Component, EnvironmentInjector, inject } from '@angular/core';
 import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
 import { addIcons } from 'ionicons';
-import { home, book, person } from 'ionicons/icons';
+import { home, book, planet, person } from 'ionicons/icons';
 
 @Component({
   selector: 'app-tabs',
@@ -14,6 +14,6 @@ export class TabsPage {
   public environmentInjector = inject(EnvironmentInjector);
 
   constructor() {
-    addIcons({ home, book, person });
+    addIcons({ home, book, planet, person });
   }
 }

+ 11 - 0
interestCourses-app/src/app/tabs/tabs.routes.ts

@@ -21,6 +21,17 @@ export const routes: Routes = [
         loadComponent: () =>
           import('../tab3/tab3.page').then((m) => m.Tab3Page),
       },
+      {
+        path: 'tab4',
+        loadComponent: () =>
+          import('../tab4/tab4.page').then((m) => m.Tab4Page),
+      },
+      {
+        path: 'ailearning',
+        loadComponent: () =>
+          import('../page-ailearning/page-ailearning.component').then((m) => m.PageAIlearningComponent),
+
+      },
       {
         path: '',
         redirectTo: '/tabs/tab1',

+ 22 - 0
interestCourses-app/src/main.ts

@@ -5,10 +5,32 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalo
 import { routes } from './app/app.routes';
 import { AppComponent } from './app/app.component';
 
+//
+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:E4KpGvTEto-138035029591732374992')
+
+
 bootstrapApplication(AppComponent, {
   providers: [
     { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
     provideIonicAngular(),
     provideRouter(routes, withPreloading(PreloadAllModules)),
+    // ...
+    // 添加HttpClient供应器
+    provideHttpClient(),
+    // 添加Diagnostic
+    Diagnostic,
+    // ...
   ],
 });
+

+ 6 - 2
interestCourses-app/tsconfig.json

@@ -18,7 +18,11 @@
     "importHelpers": true,
     "target": "es2022",
     "module": "es2020",
-    "lib": ["es2018", "dom"],
+    "lib": [
+      "es2018",
+      "dom"
+    ],
+    "allowSyntheticDefaultImports": true,
     "useDefineForClassFields": false
   },
   "angularCompilerOptions": {
@@ -27,4 +31,4 @@
     "strictInputAccessModifiers": true,
     "strictTemplates": true
   }
-}
+}

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