3 Commitit 9909e3313c ... 59b3b455ce

Tekijä SHA1 Viesti Päivämäärä
  0210225 59b3b455ce feat: bole job aigc 4 kuukautta sitten
  0210225 d6fc251547 feat: bolejob in agent 4 kuukautta sitten
  0210225 1bceca214e animation update 4 kuukautta sitten

+ 1 - 0
angular.json

@@ -13,6 +13,7 @@
         "build": {
           "builder": "@angular-devkit/build-angular:browser",
           "options": {
+            "allowedCommonJsDependencies":["markdown-it"],
             "outputPath": "www",
             "index": "src/index.html",
             "main": "src/main.ts",

+ 39 - 0
docs/job.mm.md

@@ -0,0 +1,39 @@
+    下面是每个能力需要的专业知识的具体细分:
+
+1. 沟通能力:
+   - 口才训练:学习如何清晰、流畅地表达自己的思想和情感,包括掌握语言表达技巧、声音控制等。
+   - 非语言沟通:了解身体语言、面部表情、姿势等非语言沟通的重要性,学习如何运用非语言沟通增强沟通效果。
+   - 情绪管理:学习如何管理自己的情绪,以及如何理解和应对他人的情绪,确保沟通效果更加顺畅。
+
+2. 主持能力:
+   - 节目设计:了解节目设计的基本原则和流程,包括节目结构、节目内容安排等。
+   - 现场控制:学习如何掌控现场气氛,处理突发情况,保持节目的顺利进行。
+   - 互动技巧:掌握与来宾和观众进行有效互动的技巧,包括提问技巧、引导对话等。
+
+3. 自信和魅力:
+   - 自我形象管理:学习如何塑造自己的形象,包括服装搭配、仪态举止等。
+   - 自信训练:进行自信心理训练,提升自我认知和自信水平。
+   - 魅力表现:学习如何展现个人魅力,吸引观众的注意和喜爱。
+
+4. 知识和素养:
+   - 广泛阅读:保持对各种话题的广泛了解,不断扩展自己的知识面。
+   - 社交礼仪:学习社交礼仪和文化知识,确保在不同场合表现得体。
+   - 文化素养:培养对艺术、历史、文学等方面的兴趣和了解,提升自己的文化素养。
+
+5. 适应能力:
+   - 灵活性训练:学习如何灵活适应不同情况和环境,调整自己的表现和态度。
+   - 压力管理:掌握有效的压力管理技巧,确保在压力下依然能够表现出色。
+
+6. 团队合作能力:
+   - 团队协作:学习如何与团队成员有效沟通、协作,共同完成节目制作和表演任务。
+   - 领导能力:了解如何在团队中发挥领导作用,引导团队成员共同实现共同目标。
+
+7. 幽默感:
+   - 幽默技巧:学习如何运用幽默元素,制造笑点,增加节目趣味性。
+   - 观众互动:掌握与观众进行幽默互动的技巧,拉近与观众的距离。
+
+8. 专业知识和技能:
+   - 主持培训:参加专业的主持培训课程,学习主持技巧和经验。
+   - 节目制作:了解节目制作的流程和技术,包括摄影、灯光、音响等方面的知识。
+
+以上是每个能力所需要的专业知识的一些细分,希望对你有所帮助。

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 34 - 0
docs/text.html


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 886 - 15
package-lock.json


+ 7 - 0
package.json

@@ -22,7 +22,12 @@
     "@angular/platform-browser-dynamic": "^17.0.2",
     "@angular/router": "^17.0.2",
     "@ionic/angular": "^8.2.5",
+    "d3-flextree": "^2.1.2",
     "ionicons": "^7.0.0",
+    "markdown-it": "^14.1.0",
+    "markmap-lib": "^0.17.0",
+    "markmap-render": "^0.17.0",
+    "markmap-view": "^0.17.0",
     "parse": "^5.1.0",
     "rxjs": "~7.8.0",
     "swiper": "^11.1.4",
@@ -41,7 +46,9 @@
     "@angular/language-service": "^17.0.2",
     "@compodoc/compodoc": "^1.1.25",
     "@ionic/angular-toolkit": "^11.0.1",
+    "@types/d3-flextree": "^2.1.4",
     "@types/jasmine": "~5.1.0",
+    "@types/markdown-it": "^14.1.1",
     "@types/parse": "^3.0.9",
     "@typescript-eslint/eslint-plugin": "^6.0.0",
     "@typescript-eslint/parser": "^6.0.0",

+ 2 - 0
src/app/app.component.ts

@@ -6,10 +6,12 @@ Parse.initialize("dev");
 import { register } from 'swiper/element/bundle';
 
 register();
+
 @Component({
   selector: 'app-root',
   templateUrl: 'app.component.html',
   styleUrls: ['app.component.scss'],
+  
 })
 export class AppComponent {
   constructor() {}

+ 17 - 0
src/modules/aigc/agent/agent-shige/agent-shige-routing.module.ts

@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { AgentShigePage } from './agent-shige.page';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: AgentShigePage
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule],
+})
+export class AgentShigePageRoutingModule {}

+ 20 - 0
src/modules/aigc/agent/agent-shige/agent-shige.module.ts

@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { IonicModule } from '@ionic/angular';
+
+import { AgentShigePageRoutingModule } from './agent-shige-routing.module';
+
+import { AgentShigePage } from './agent-shige.page';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    IonicModule,
+    AgentShigePageRoutingModule
+  ],
+  declarations: [AgentShigePage]
+})
+export class AgentShigePageModule {}

+ 23 - 0
src/modules/aigc/agent/agent-shige/agent-shige.page.html

@@ -0,0 +1,23 @@
+<ion-header>
+  <ion-toolbar>
+    <ion-title>
+      职业建议
+    </ion-title>
+  </ion-toolbar>
+</ion-header>
+
+<ion-content>
+  <ion-item>
+    <ion-input placeholder="关键词" [(ngModel)]="jobTitle"></ion-input>
+  </ion-item>
+  <ion-button *ngIf="!jobTitle" expand="block" (click)="sendMessage()">发送</ion-button>
+
+  <ion-card *ngFor="let message of messageList">
+    <ion-card-header>
+      {{message?.role}}
+    </ion-card-header>
+    <ion-card-content>
+      {{ message?.content }}
+    </ion-card-content>
+  </ion-card>
+</ion-content>

+ 0 - 0
src/modules/aigc/agent/agent-shige/agent-shige.page.scss


+ 17 - 0
src/modules/aigc/agent/agent-shige/agent-shige.page.spec.ts

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

+ 115 - 0
src/modules/aigc/agent/agent-shige/agent-shige.page.ts

@@ -0,0 +1,115 @@
+import { Component, OnInit } from '@angular/core';
+// 引用FmodeChatCompletion类
+import { TestRxjsChatCompletion,TestRxjsChatMessage } from '../../chat/class-rxjs-chat-completion';
+import Parse from "parse";
+import { ActivatedRoute, Router } from '@angular/router';
+@Component({
+  selector: 'app-agent-shige',
+  templateUrl: './agent-shige.page.html',
+  styleUrls: ['./agent-shige.page.scss'],
+})
+export class AgentShigePage implements OnInit {
+  messageList:Array<TestRxjsChatMessage> = []
+  jobTitle:string | undefined |null
+
+  constructor(
+    private route:ActivatedRoute,
+    private router:Router,
+  ) { 
+  }
+
+  ngOnInit() {
+    this.loadAndGenJobMarkmind()
+  }
+
+  boleJob:Parse.Object | undefined
+  async loadAndGenJobMarkmind(){
+    let user = Parse.User.current();
+    if(!user?.id) return
+    this.jobTitle = this.route.snapshot.paramMap.get("keyword");
+    if(!this.jobTitle) return
+    let query = new Parse.Query("BoleJob");
+    query.equalTo("user",user?.id);
+    query.equalTo("title",this.jobTitle);
+    this.boleJob = await query.first();
+
+    if(!this.boleJob?.id){
+      // 生成
+      this.sendMessage();
+    }else{
+      
+      if(this.boleJob?.get("markmind")){
+        this.router.navigate(["/test","skill-tree",this.boleJob?.id])
+      }
+    }
+  }
+
+  sendMessage(){
+    /*
+4. 风格:选择风格,例如“豪放”或“婉约”。
+5. 情感:描述诗中应表达的情感,例如“喜悦”、“忧愁”、“思念”等。
+
+    */
+    let GuhiPromoptTemplate = `
+你是一位资深职业教育者,擅长对职业前景评估,了解职业所需技能,和职业所需技能的具体的学科课程:
+1. 职业:${this.jobTitle}。
+请根据要求给出职业学习建议,并且格式要严格,符合markmind语法
+请开始创作:
+    `
+    this.messageList.push({
+      role:"user",
+      content: GuhiPromoptTemplate
+    })
+    
+    // messageList在competion内部,已经赋予了完整的message
+    // 下方暴露出来的可订阅内容,主要是用于关键字过滤,或者其他开发逻辑的续写
+    let resultStr = ""
+    let testChatCompletion = new TestRxjsChatCompletion(this.messageList);
+    testChatCompletion.createCompletionByStream({model:"fmode-3.6-16k"}).subscribe({
+        next: ({ content, cumulativeContent, done }) => {
+          resultStr = cumulativeContent
+            console.log(`Content: ${content}`);
+            console.log(`Cumulative Content: ${cumulativeContent}`);
+            if (done) {
+                console.log('Stream completed');
+            }
+        },
+        error: err => console.error(err),
+        complete: async () => {
+          // 诗歌创建完成:正则表达式,匹配诗歌json内容
+          console.log("结果",resultStr)
+          let BoleJob = Parse.Object.extend("BoleJob");
+          let job = new BoleJob();
+          job.set("title",this.jobTitle);
+          job.set("user",Parse.User.current()?.toPointer());
+          job.set("markmind",resultStr);
+          job = await job.save();
+          if(job?.id){
+            if(job?.get("markmind")){
+              this.router.navigate(["/test","skill-tree",job?.id])
+            }
+          }
+          let pattern = /前景:\s*(.*?)\s*内容:\s*(.*?)/;
+          let match = resultStr.match(pattern);
+
+          if (match) {
+            let suggest:any = {}
+              suggest.title = match[1];
+              suggest.content = match[2];
+              suggest.source = "AI创作";
+              console.log(`前景: ${suggest.title}`);
+              console.log(`内容: ${suggest.content}`);
+              console.log(suggest);
+              //let Shige = Parse.Object.extend("Shige");
+              //let sg = new Shige();
+              //sg.set(suggest);
+              //sg.save();
+          } else {
+              console.log("未能匹配到任何内容");
+          }
+        }
+    });
+
+  }
+
+}

+ 2 - 0
src/modules/aigc/aigc-routing.module.ts

@@ -3,6 +3,8 @@ import { RouterModule, Routes } from '@angular/router';
 
 const routes: Routes = [
   {path: 'chat', loadChildren: () => import('./chat/chat.module').then(mod => mod.ChatPageModule)},
+  {path: 'agent', loadChildren: () => import('./agent/agent-shige/agent-shige.module').then(mod => mod.AgentShigePageModule)},
+  {path: 'agent/:keyword', loadChildren: () => import('./agent/agent-shige/agent-shige.module').then(mod => mod.AgentShigePageModule)}
 ];
 
 @NgModule({

+ 111 - 0
src/modules/aigc/chat/class-rxjs-chat-completion.ts

@@ -0,0 +1,111 @@
+import { Observable, from, of } from 'rxjs';
+import { switchMap, map, catchError, finalize } from 'rxjs/operators';
+
+export interface TestRxjsChatMessage {
+    role: string;
+    content: string;
+}
+
+export class TestRxjsChatCompletion {
+    messageList: Array<TestRxjsChatMessage>;
+
+    constructor(messageList: Array<TestRxjsChatMessage>) {
+        this.messageList = messageList;
+    }
+
+    createCompletionByStream(options?:{
+        model?:string
+    }): Observable<{ content: string, cumulativeContent: string, done: boolean }> {
+        const token = localStorage.getItem("token");
+        const bodyJson = {
+            "token": `Bearer ${token}`,
+            "messages": this.messageList,
+            "model": options?.model || "fmode-3.6-16k",
+            "temperature": 0.5,
+            "presence_penalty": 0,
+            "frequency_penalty": 0,
+            "top_p": 1,
+            "stream": true
+        };
+
+        return from(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"
+        })).pipe(
+            switchMap(response => {
+                const reader = response.body?.getReader();
+                if (!reader) {
+                    throw new Error("Failed to get the response reader.");
+                }
+                const decoder = new TextDecoder();
+                let buffer = "";
+                let messageAiReply = "";
+                let messageIndex = this.messageList.length;
+
+                return new Observable<{ content: string, cumulativeContent: string, done: boolean }>(observer => {
+                    const read = () => {
+                        reader.read().then(({ done, value }) => {
+                            if (done) {
+                                observer.complete();
+                                return;
+                            }
+
+                            buffer += decoder.decode(value);
+                            let messages = buffer.split("\n");
+
+                            for (let i = 0; i < messages.length - 1; i++) {
+                                let message = messages[i];
+                                let dataText = message.replace("data: ", "");
+
+                                if (dataText.startsWith("{")) {
+                                    try {
+                                        let dataJson = JSON.parse(dataText);
+                                        let content = dataJson?.choices?.[0]?.delta?.content || "";
+                                        messageAiReply += content;
+                                        this.messageList[messageIndex] = {
+                                            role: "assistant",
+                                            content: messageAiReply
+                                        };
+                                        observer.next({ content, cumulativeContent: messageAiReply, done: false });
+                                    } catch (err) { }
+                                }
+
+                                if (dataText.startsWith("[")) {
+                                    this.messageList[messageIndex] = {
+                                        role: "assistant",
+                                        content: messageAiReply
+                                    };
+                                    observer.next({ content: "", cumulativeContent: messageAiReply, done: true });
+                                    messageAiReply = "";
+                                }
+
+                                buffer = buffer.slice(message.length + 1);
+                            }
+
+                            read();
+                        }).catch(err => observer.error(err));
+                    };
+
+                    read();
+                });
+            }),
+            catchError(err => {
+                console.error(err);
+                return of({ content: "", cumulativeContent: "", done: true });
+            }),
+            finalize(() => {
+                console.log("Stream completed");
+            })
+        );
+    }
+}

+ 3 - 1
src/modules/test/job-recommend/job-recommend.page.html

@@ -29,7 +29,9 @@
     <ion-content>
       <div class="container">
         <div class="ball" *ngFor="let ball of balls" [style.background-color]="ball.color" [style.left.px]="ball.x" [style.top.px]="ball.y">
-          <ion-button fill="clear"color="light">Clear</ion-button>
+          <div class="ion-buttons">
+            <ion-button fill="clear"color="light" shape="round" (click)="saveTextToLocalStorage(ball.text)" routerLink="/ai/agent/{{ball.text}}">{{ball.text}}</ion-button>
+          </div>
         </div>
       </div>
     </ion-content>

+ 3 - 0
src/modules/test/job-recommend/job-recommend.page.scss

@@ -9,4 +9,7 @@
     width: 100px;
     height: 100px;
     border-radius: 50%;
+  }
+  .ion-buttons{
+    padding-top:20%
   }

+ 14 - 8
src/modules/test/job-recommend/job-recommend.page.ts

@@ -20,16 +20,18 @@ export class JobRecommendPage implements OnInit {
   result:string | undefined
   suitablejobs:any
   balls = [
-    { color: 'red', x: 50, y: 50, vx: 2, vy: 1 },
-    { color: 'blue', x: 100, y: 100, vx: -1, vy: 2 },
-    { color: 'green', x: 150, y: 150, vx: 1, vy: -2 }
+    { text:'',color: 'red', x: 50, y: 50, vx: 2, vy: 1 },
+    { text:'',color: 'blue', x: 100, y: 100, vx: -1, vy: 2 },
+    { text:'',color: 'green', x: 150, y: 150, vx: 1, vy: -2 }
   ];
-  maxX = 900
-  maxY = 400;
+  maxX = window.innerWidth-100;
+  maxY = window.innerHeight-300;
 
   constructor() {
   }
-
+  saveTextToLocalStorage(text: string) {
+    localStorage.setItem('clickedText', text);
+  }
   moveBalls() {
     this.balls.forEach(ball => {
       ball.x += ball.vx;
@@ -46,12 +48,13 @@ export class JobRecommendPage implements OnInit {
   }
   ngOnInit() {
     setInterval(() => {
+      this.maxX = window.innerWidth-100;
+      this.maxY = window.innerHeight-320;
       this.moveBalls();
     }, 10);
     let user = Parse.User.current();
     if(user?.id){
       var testresult=user.get("mbti")
-      console.log(testresult)
     }
     this.testresult=testresult
     let BoleMbti = Parse.Object.extend("BoleMbti");
@@ -62,7 +65,10 @@ export class JobRecommendPage implements OnInit {
           this.result=result.get("result")
           const suitableJobs = result.get("suitableJobs");
           this.suitablejobs=suitableJobs
-          console.log(testresult+"适合的工作:", suitableJobs);
+          console.log(suitableJobs[0])
+          for(var i=0;i<3;i++){
+            this.balls[i].text=suitableJobs[i]
+          }
       } else {
           console.log("未找到符合条件的数据");
       }

+ 18 - 6
src/modules/test/skill-tree/skill-tree.page.html

@@ -1,13 +1,25 @@
 <ion-header [translucent]="true">
   <ion-toolbar>
-    <ion-title>skill-tree</ion-title>
+    <ion-buttons slot="start">
+      <ion-back-button defaultHref="/tabs/tab1"></ion-back-button>
+    </ion-buttons>
+    <ion-title>职业技能树</ion-title>
   </ion-toolbar>
 </ion-header>
 
 <ion-content [fullscreen]="true">
-  <ion-header collapse="condense">
-    <ion-toolbar>
-      <ion-title size="large">skill-tree</ion-title>
-    </ion-toolbar>
-  </ion-header>
+  <ion-card>
+    <ion-card-header>
+      <ion-card-title>{{clickedText}}</ion-card-title>
+    </ion-card-header>
+
+    <ion-card-content>
+      <p>想成为{{clickedText}},您需要以下技能</p>
+
+
+      <iframe border="0" *ngIf="jobSkillHtml" [srcdoc]="jobSkillHtml">
+
+      </iframe>
+    </ion-card-content>
+  </ion-card>
 </ion-content>

+ 4 - 0
src/modules/test/skill-tree/skill-tree.page.scss

@@ -0,0 +1,4 @@
+iframe{
+    border: none;
+    height: 40vh;
+}

+ 55 - 2
src/modules/test/skill-tree/skill-tree.page.ts

@@ -1,4 +1,7 @@
 import { Component, OnInit } from '@angular/core';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
+import { Transformer, builtInPlugins } from 'markmap-lib';
+import { fillTemplate } from 'markmap-render';
 
 @Component({
   selector: 'app-skill-tree',
@@ -6,10 +9,60 @@ import { Component, OnInit } from '@angular/core';
   styleUrls: ['./skill-tree.page.scss'],
 })
 export class SkillTreePage implements OnInit {
-
-  constructor() { }
+  clickedText:any
+  constructor(
+    private domSan:DomSanitizer
+  ) { 
+    this.clickedText = localStorage.getItem('clickedText')
+    console.log(this.clickedText)
+   }
 
   ngOnInit() {
+    this.jobSkillHtml = this.domSan.bypassSecurityTrustHtml(this.renderMarkMind(this.jobSkillMarkdown))
+  }
+
+  renderMarkMind(markdown:string){
+    let transformer:Transformer = new Transformer([...builtInPlugins]);
+    // 1. transform Markdown
+    const { root, features } = transformer.transform(markdown);
+
+    // 2. get assets
+    // get all possible assets that could be used later
+    const assets = transformer.getAssets();
+    let html = fillTemplate(root, assets);
+    console.log(html,markdown)
+    return html
   }
 
+  jobSkillHtml:SafeHtml|undefined
+  jobSkillMarkdown = `下面是每个能力需要的专业知识的具体细分:
+1. 沟通能力:
+   - 口才训练:学习如何清晰、流畅地表达自己的思想和情感,包括掌握语言表达技巧、声音控制等。
+   - 非语言沟通:了解身体语言、面部表情、姿势等非语言沟通的重要性,学习如何运用非语言沟通增强沟通效果。
+   - 情绪管理:学习如何管理自己的情绪,以及如何理解和应对他人的情绪,确保沟通效果更加顺畅。
+2. 主持能力:
+   - 节目设计:了解节目设计的基本原则和流程,包括节目结构、节目内容安排等。
+   - 现场控制:学习如何掌控现场气氛,处理突发情况,保持节目的顺利进行。
+   - 互动技巧:掌握与来宾和观众进行有效互动的技巧,包括提问技巧、引导对话等。
+3. 自信和魅力:
+   - 自我形象管理:学习如何塑造自己的形象,包括服装搭配、仪态举止等。
+   - 自信训练:进行自信心理训练,提升自我认知和自信水平。
+   - 魅力表现:学习如何展现个人魅力,吸引观众的注意和喜爱。
+4. 知识和素养:
+   - 广泛阅读:保持对各种话题的广泛了解,不断扩展自己的知识面。
+   - 社交礼仪:学习社交礼仪和文化知识,确保在不同场合表现得体。
+   - 文化素养:培养对艺术、历史、文学等方面的兴趣和了解,提升自己的文化素养。
+5. 适应能力:
+   - 灵活性训练:学习如何灵活适应不同情况和环境,调整自己的表现和态度。
+   - 压力管理:掌握有效的压力管理技巧,确保在压力下依然能够表现出色。
+6. 团队合作能力:
+   - 团队协作:学习如何与团队成员有效沟通、协作,共同完成节目制作和表演任务。
+   - 领导能力:了解如何在团队中发挥领导作用,引导团队成员共同实现共同目标。
+7. 幽默感:
+   - 幽默技巧:学习如何运用幽默元素,制造笑点,增加节目趣味性。
+   - 观众互动:掌握与观众进行幽默互动的技巧,拉近与观众的距离。
+8. 专业知识和技能:
+   - 主持培训:参加专业的主持培训课程,学习主持技巧和经验。
+   - 节目制作:了解节目制作的流程和技术,包括摄影、灯光、音响等方面的知识。
+以上是每个能力所需要的专业知识的一些细分,希望对你有所帮助。`
 }

+ 1 - 0
src/modules/test/test-routing.module.ts

@@ -5,6 +5,7 @@ const routes: Routes = [
   {path: 'mbti-test', loadChildren: () => import('./mbti-test/mbti-test.module').then(mod => mod.MBTITestPageModule)},
   {path: 'job-recommend', loadChildren: () => import('./job-recommend/job-recommend.module').then(mod => mod.JobRecommendPageModule)},
   {path: 'skill-tree', loadChildren: () => import('./skill-tree/skill-tree.module').then(mod => mod.SkillTreePageModule)},
+  {path: 'skill-tree/:id', loadChildren: () => import('./skill-tree/skill-tree.module').then(mod => mod.SkillTreePageModule)},
 ];
 
 @NgModule({

+ 1 - 0
tsconfig.json

@@ -2,6 +2,7 @@
 {
   "compileOnSave": false,
   "compilerOptions": {
+    "allowSyntheticDefaultImports":true,
     "baseUrl": "./",
     "outDir": "./dist/out-tsc",
     "forceConsistentCasingInFileNames": true,

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä