diff --git a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
index 12ddadb5c28685d76562b98182867fcaed028841..72c1bb989922404415c8e5d66158337929770773 100644
--- a/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
+++ b/src/app/components/shared/_dialogs/create-comment/create-comment.component.ts
@@ -1,16 +1,16 @@
 import { Component, Inject, Input, OnInit, ViewChild } from '@angular/core';
-import { Comment, Language as CommentLanguage } from '../../../../models/comment';
+import { Comment } from '../../../../models/comment';
 import { NotificationService } from '../../../../services/util/notification.service';
 import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
 import { TranslateService } from '@ngx-translate/core';
 import { User } from '../../../../models/user';
 import { EventService } from '../../../../services/util/event.service';
 import { SpacyDialogComponent } from '../spacy-dialog/spacy-dialog.component';
-import { LanguagetoolService, Language, LanguagetoolResult } from '../../../../services/http/languagetool.service';
-import { CreateCommentKeywords } from '../../../../utils/create-comment-keywords';
+import { LanguagetoolService } from '../../../../services/http/languagetool.service';
+import { CreateCommentKeywords, KeywordsResultType } from '../../../../utils/create-comment-keywords';
 import { WriteCommentComponent } from '../../write-comment/write-comment.component';
-import { DeepLDialogComponent } from '../deep-ldialog/deep-ldialog.component';
-import { DeepLService, SourceLang, TargetLang } from '../../../../services/http/deep-l.service';
+import { DeepLService } from '../../../../services/http/deep-l.service';
+import { SpacyService } from '../../../../services/http/spacy.service';
 
 @Component({
   selector: 'app-submit-comment',
@@ -33,6 +33,7 @@ export class CreateCommentComponent implements OnInit {
     public dialog: MatDialog,
     public languagetoolService: LanguagetoolService,
     private deeplService: DeepLService,
+    private spacyService: SpacyService,
     public eventService: EventService,
     @Inject(MAT_DIALOG_DATA) public data: any) {
   }
@@ -67,63 +68,30 @@ export class CreateCommentComponent implements OnInit {
   }
 
   openSpacyDialog(comment: Comment, rawText: string, forward: boolean): void {
-    CreateCommentKeywords.isSpellingAcceptable(this.languagetoolService, rawText, this.commentComponent.selectedLang)
-      .subscribe((result) => {
-        if (result.isAcceptable) {
-          if (forward) {
-            this.callDeepL(comment, result.text, result.result);
-          } else {
-            this.callSpacy(comment, result.text, result.result);
-          }
-        } else {
-          comment.language = CommentLanguage.auto;
+    CreateCommentKeywords.generateKeywords(this.languagetoolService, this.deeplService,
+      this.spacyService, comment.body, forward, this.commentComponent.selectedLang)
+      .subscribe(result => {
+        this.isSendingToSpacy = false;
+        comment.language = result.language;
+        comment.keywordsFromSpacy = result.keywords;
+        comment.keywordsFromQuestioner = [];
+        if (forward ||
+          ((result.resultType === KeywordsResultType.failure) && !result.wasSpacyError) ||
+          result.resultType === KeywordsResultType.badSpelled) {
           this.dialogRef.close(comment);
-          this.isSendingToSpacy = false;
+        } else {
+          const dialogRef = this.dialog.open(SpacyDialogComponent, {
+            data: {
+              result: result.resultType,
+              comment
+            }
+          });
+          dialogRef.afterClosed().subscribe(dialogResult => {
+            if (dialogResult) {
+              this.dialogRef.close(dialogResult);
+            }
+          });
         }
-      }, () => {
-        comment.language = CommentLanguage.auto;
-        this.dialogRef.close(comment);
-        this.isSendingToSpacy = false;
       });
   }
-
-  private callDeepL(comment: Comment, text: string, result: LanguagetoolResult) {
-    let target = TargetLang.EN_US;
-    const code = result.language.detectedLanguage.code.toUpperCase().split('-')[0];
-    if (code.startsWith(SourceLang.EN)) {
-      target = TargetLang.DE;
-    }
-    DeepLDialogComponent.generateDeeplDelta(this.deeplService, comment.body, target)
-      .subscribe(([_, improvedText]) => {
-        this.callSpacy(comment, CreateCommentKeywords.escapeForSpacy(improvedText), result, true);
-      }, () => {
-        this.callSpacy(comment, text, result, true);
-      });
-  }
-
-  private callSpacy(comment: Comment, text: string, result: LanguagetoolResult, forward = false) {
-    const commentLang = this.languagetoolService.mapLanguageToSpacyModel(result.language.code as Language);
-    const selectedLangExtend = this.commentComponent.selectedLang[2] === '-' ?
-      this.commentComponent.selectedLang.substr(0, 2) : this.commentComponent.selectedLang;
-    // Store language if it was auto-detected
-    if (this.commentComponent.selectedLang === 'auto') {
-      comment.language = Comment.mapModelToLanguage(commentLang);
-    } else if (CommentLanguage[selectedLangExtend]) {
-      comment.language = CommentLanguage[selectedLangExtend];
-    }
-    this.isSendingToSpacy = false;
-    const dialogRef = this.dialog.open(SpacyDialogComponent, {
-      data: {
-        comment,
-        commentLang,
-        commentBodyChecked: text,
-        forward
-      }
-    });
-    dialogRef.afterClosed().subscribe(dialogResult => {
-      if (dialogResult) {
-        this.dialogRef.close(dialogResult);
-      }
-    });
-  }
 }
diff --git a/src/app/components/shared/_dialogs/deep-ldialog/deep-ldialog.component.ts b/src/app/components/shared/_dialogs/deep-ldialog/deep-ldialog.component.ts
index 5844ca5d937fb344a7157ba2bbcd9112332d5b4c..9b43649b0438721375efb8dbf11e5cbe5a9512c9 100644
--- a/src/app/components/shared/_dialogs/deep-ldialog/deep-ldialog.component.ts
+++ b/src/app/components/shared/_dialogs/deep-ldialog/deep-ldialog.component.ts
@@ -5,9 +5,7 @@ import { NotificationService } from '../../../../services/util/notification.serv
 import { LanguageService } from '../../../../services/util/language.service';
 import { TranslateService } from '@ngx-translate/core';
 import { ExplanationDialogComponent } from '../explanation-dialog/explanation-dialog.component';
-import { DeepLService, FormalityType, TargetLang } from '../../../../services/http/deep-l.service';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { DeepLService, FormalityType } from '../../../../services/http/deep-l.service';
 import { CreateCommentKeywords } from '../../../../utils/create-comment-keywords';
 
 export interface ResultValue {
@@ -44,45 +42,6 @@ export class DeepLDialogComponent implements OnInit, AfterViewInit {
     this.supportsFormality = DeepLService.supportsFormality(this.data.target);
   }
 
-  public static generateDeeplDelta(deepl: DeepLService, body: string, targetLang: TargetLang,
-                                   formality = FormalityType.less): Observable<[string, string]> {
-    const delta = ViewCommentDataComponent.getDeltaFromData(body);
-    const xml = delta.ops.reduce((acc, e, i) => {
-      if (typeof e['insert'] === 'string' && e['insert'].trim().length) {
-        acc += '<x i="' + i + '">' + this.encodeHTML(CreateCommentKeywords.removeMarkdown(e['insert'])) + '</x>';
-        e['insert'] = '';
-      }
-      return acc;
-    }, '');
-    return deepl.improveTextStyle(xml, targetLang, formality).pipe(
-      map(str => {
-        const regex = /<x i="(\d+)">([^<]+)<\/x>/gm;
-        let m;
-        while ((m = regex.exec(str)) !== null) {
-          delta.ops[+m[1]]['insert'] += this.decodeHTML(m[2]);
-        }
-        const text = delta.ops.reduce((acc, el) => acc + (typeof el['insert'] === 'string' ? el['insert'] : ''), '');
-        return [ViewCommentDataComponent.getDataFromDelta(delta), text];
-      })
-    );
-  }
-
-  private static encodeHTML(str: string): string {
-    return str.replace(/&/g, '&amp;')
-      .replace(/</g, '&lt;')
-      .replace(/>/g, '&gt;')
-      .replace(/"/g, '&quot;')
-      .replace(/'/g, '&apos;');
-  }
-
-  private static decodeHTML(str: string): string {
-    return str.replace(/&apos;/g, '\'')
-      .replace(/&quot;/g, '"')
-      .replace(/&gt;/g, '>')
-      .replace(/&lt;/g, '<')
-      .replace(/&amp;/g, '&');
-  }
-
   ngOnInit(): void {
     this.translateService.use(localStorage.getItem('currentLang'));
     this.normalValue = {
@@ -138,7 +97,7 @@ export class DeepLDialogComponent implements OnInit, AfterViewInit {
   }
 
   onFormalityChange(formality: string) {
-    DeepLDialogComponent.generateDeeplDelta(this.deeplService, this.data.body, this.data.usedTarget, formality as FormalityType)
+    CreateCommentKeywords.generateDeeplDelta(this.deeplService, this.data.body, this.data.usedTarget, formality as FormalityType)
       .subscribe(([improvedBody, improvedText]) => {
         this.improvedValue.body = improvedBody;
         this.improvedValue.text = improvedText;
diff --git a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html
index ed46fd8e49743888ad00a1952d5792ec99713899..a3d1da967a308ba10454e0168f315067ee3885cb 100644
--- a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html
+++ b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.html
@@ -23,9 +23,6 @@
       </ars-row>
     </span>
     <ars-row class="list-container">
-      <div fxLayout="row" fxLayoutAlign="center center" fxFill>
-        <app-mat-spinner-overlay *ngIf="isLoading"></app-mat-spinner-overlay>
-      </div>
       <mat-list dense class="keywords-list">
         <mat-list-item *ngFor="let keyword of keywords; let odd = odd; let even = even; let i = index"
                        [class.keywords-alternate]="odd"
@@ -59,7 +56,7 @@
       </mat-list>
     </ars-row>
     <ars-row>
-      <span *ngIf="!isLoading && (!langSupported || !hasKeywordsFromSpacy)">
+      <span *ngIf="!langSupported || !hasKeywordsFromSpacy">
         <p class="manual-input-title">{{ 'spacy-dialog.add-manually' | translate }}</p>
         <textarea class="manual-input" [(ngModel)]="manualKeywords" (input)="manualKeywordsToKeywords()"></textarea>
       </span>
@@ -68,7 +65,7 @@
 </ars-row>
 
 <ars-row ars-flex-box class="action-button-container">
-  <ars-col *ngIf="!isLoading && langSupported && hasKeywordsFromSpacy">
+  <ars-col *ngIf="langSupported && hasKeywordsFromSpacy">
     <button
       mat-flat-button
       class="help-button"
@@ -77,7 +74,7 @@
       {{ 'explanation.label' | translate}}
     </button>
   </ars-col>
-  <ars-fill *ngIf="isLoading || !langSupported || !hasKeywordsFromSpacy">
+  <ars-fill *ngIf="!langSupported || !hasKeywordsFromSpacy">
   </ars-fill>
   <ars-col>
     <app-dialog-action-buttons
@@ -87,7 +84,7 @@
       [showDivider]="false"
       [spacing]="false"
       [cancelButtonClickAction]="buildCloseDialogActionCallback()"
-      [confirmButtonClickAction]="!isLoading ? buildCreateCommentActionCallback() : undefined">
+      [confirmButtonClickAction]="buildCreateCommentActionCallback()">
     </app-dialog-action-buttons>
   </ars-col>
 </ars-row>
diff --git a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts
index d31762cc223b63b29718e60b93256b1615de0635..0b478d36cacf7074b641a9482d0153811b487f04 100644
--- a/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts
+++ b/src/app/components/shared/_dialogs/spacy-dialog/spacy-dialog.component.ts
@@ -1,11 +1,10 @@
-import { AfterContentInit, Component, Inject, OnInit, ViewChild } from '@angular/core';
+import { Component, Inject, OnInit, ViewChild } from '@angular/core';
 import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
-import { SpacyService, SpacyKeyword } from '../../../../services/http/spacy.service';
-import { LanguagetoolService } from '../../../../services/http/languagetool.service';
+import { SpacyKeyword } from '../../../../services/http/spacy.service';
 import { Comment } from '../../../../models/comment';
 import { DialogActionButtonsComponent } from '../../dialog/dialog-action-buttons/dialog-action-buttons.component';
-import { Model } from '../../../../services/http/spacy.interface';
 import { ExplanationDialogComponent } from '../explanation-dialog/explanation-dialog.component';
+import { KeywordsResultType } from '../../../../utils/create-comment-keywords';
 
 export interface Keyword {
   word: string;
@@ -20,24 +19,19 @@ export interface Keyword {
   templateUrl: './spacy-dialog.component.html',
   styleUrls: ['./spacy-dialog.component.scss']
 })
-export class SpacyDialogComponent implements OnInit, AfterContentInit {
+export class SpacyDialogComponent implements OnInit {
 
   @ViewChild('appDialogActionButtons') appDialogActionButtons: DialogActionButtonsComponent;
 
   comment: Comment;
-  commentLang: Model;
-  commentBodyChecked: string;
   keywords: Keyword[] = [];
   keywordsOriginal: SpacyKeyword[] = [];
   hasKeywordsFromSpacy = false;
-  isLoading = false;
   langSupported: boolean;
   manualKeywords = '';
   _concurrentEdits = 0;
 
   constructor(
-    protected langService: LanguagetoolService,
-    private spacyService: SpacyService,
     public dialogRef: MatDialogRef<SpacyDialogComponent>,
     private dialog: MatDialog,
     @Inject(MAT_DIALOG_DATA) public data) {
@@ -45,24 +39,19 @@ export class SpacyDialogComponent implements OnInit, AfterContentInit {
 
   ngOnInit(): void {
     this.comment = this.data.comment;
-    this.commentLang = this.data.commentLang;
-    this.commentBodyChecked = this.data.commentBodyChecked;
-    this.langSupported = this.langService.isSupportedLanguage(this.data.commentLang);
+    this.langSupported = this.data.result !== KeywordsResultType.languageNotSupported;
+    this.hasKeywordsFromSpacy = this.data.result === KeywordsResultType.successful &&
+      this.comment.keywordsFromSpacy.length > 0;
+    this.keywords = this.comment.keywordsFromSpacy.map(keyword => ({
+      word: keyword.text,
+      dep: [...keyword.dep],
+      completed: false,
+      editing: false,
+      selected: false
+    } as Keyword));
+    this.keywords.sort((a, b) => a.word.localeCompare(b.word));
   }
 
-  ngAfterContentInit(): void {
-    if (this.langSupported) {
-      this.evalInput(this.commentLang);
-    } else if (this.data.forward) {
-      this.keywords = [];
-      this.keywordsOriginal = [];
-      setTimeout(() => this.buildCreateCommentActionCallback()());
-    }
-  }
-
-  /**
-   * Returns a lambda which closes the dialog on call.
-   */
   buildCloseDialogActionCallback(): () => void {
     return () => this.dialogRef.close();
   }
@@ -78,39 +67,6 @@ export class SpacyDialogComponent implements OnInit, AfterContentInit {
     };
   }
 
-  evalInput(model: Model) {
-    this.isLoading = true;
-    const afterFinish = () => {
-      if (this.data.forward) {
-        this.buildCreateCommentActionCallback()();
-      }
-    };
-
-    // N at first pos = all Nouns(NN de/en) including singular(NN, NNP en), plural (NNPS, NNS en), proper Noun(NNE, NE de)
-    this.spacyService.getKeywords(this.commentBodyChecked, model)
-      .subscribe(words => {
-        this.keywordsOriginal = words;
-        this.keywords = words.map(keyword => ({
-          word: keyword.text,
-          dep: [...keyword.dep],
-          completed: false,
-          editing: false,
-          selected: false
-        } as Keyword));
-        this.keywords.sort((a, b) => a.word.localeCompare(b.word));
-        this.hasKeywordsFromSpacy = this.keywords.length > 0;
-      }, () => {
-        this.keywords = [];
-        this.keywordsOriginal = [];
-        this.hasKeywordsFromSpacy = false;
-        this.isLoading = false;
-        afterFinish();
-      }, () => {
-        this.isLoading = false;
-        afterFinish();
-      });
-  }
-
   onEdit(keyword) {
     keyword.editing = true;
     keyword.completed = false;
diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts
index 8298e161b3516dd5e71d37cf28a102b586f09b2e..35607461c19c1bbf527c5010d9d2965207b0d316 100644
--- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts
+++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog-task.ts
@@ -3,26 +3,20 @@ import { SpacyKeyword, SpacyService } from '../../../../services/http/spacy.serv
 import { CommentService } from '../../../../services/http/comment.service';
 import { Comment, Language } from '../../../../models/comment';
 import { Language as Lang, LanguagetoolService } from '../../../../services/http/languagetool.service';
-import { CreateCommentKeywords } from '../../../../utils/create-comment-keywords';
+import { CreateCommentKeywords, KeywordsResult, KeywordsResultType } from '../../../../utils/create-comment-keywords';
 import { TSMap } from 'typescript-map';
 import { HttpErrorResponse } from '@angular/common/http';
-import { CURRENT_SUPPORTED_LANGUAGES, Model } from '../../../../services/http/spacy.interface';
-import { ViewCommentDataComponent } from '../../view-comment-data/view-comment-data.component';
+import { DeepLService } from '../../../../services/http/deep-l.service';
 
 const concurrentCallsPerTask = 4;
 
-enum FinishType {
-  completed,
-  badSpelled,
-  failed
-}
-
 export class WorkerDialogTask {
 
   error: string = null;
   readonly statistics = {
     succeeded: 0,
     badSpelled: 0,
+    notSupported: 0,
     failed: 0,
     length: 0
   };
@@ -32,6 +26,7 @@ export class WorkerDialogTask {
   constructor(public readonly room: Room,
               private comments: Comment[],
               private spacyService: SpacyService,
+              private deeplService: DeepLService,
               private commentService: CommentService,
               private languagetoolService: LanguagetoolService,
               private finished: () => void) {
@@ -60,48 +55,43 @@ export class WorkerDialogTask {
       return;
     }
     const currentComment = this._comments[currentIndex];
-    const text = ViewCommentDataComponent.getTextFromData(currentComment.body);
-    CreateCommentKeywords.isSpellingAcceptable(this.languagetoolService, text)
-      .subscribe(result => {
-        if (!result.isAcceptable) {
-          this.finishSpacyCall(FinishType.badSpelled, currentIndex);
-          return;
-        }
-        const commentModel = currentComment.language.toLowerCase();
-        const model = commentModel !== 'auto' ? commentModel.toLowerCase() as Model :
-          this.languagetoolService.mapLanguageToSpacyModel(result.result.language.detectedLanguage.code as Lang);
-        if (model === 'auto' || !CURRENT_SUPPORTED_LANGUAGES.includes(model)) {
-          this.finishSpacyCall(FinishType.badSpelled, currentIndex);
-          return;
-        }
-        this.spacyService.getKeywords(result.text, model)
-          .subscribe(newKeywords =>
-              this.finishSpacyCall(FinishType.completed, currentIndex, newKeywords, model.toUpperCase() as Language),
-            __ => this.finishSpacyCall(FinishType.failed, currentIndex));
-      }, _ => this.finishSpacyCall(FinishType.failed, currentIndex));
+    CreateCommentKeywords.generateKeywords(this.languagetoolService, this.deeplService, this.spacyService,
+      currentComment.body,
+      !currentComment.keywordsFromQuestioner || currentComment.keywordsFromQuestioner.length === 0,
+      currentComment.language.toLowerCase() as Lang)
+      .subscribe((result) => this.finishSpacyCall(currentIndex, result, currentComment.language));
   }
 
-  private finishSpacyCall(finishType: FinishType, index: number, tags?: SpacyKeyword[], lang?: Language): void {
-    if (finishType === FinishType.completed) {
-      this.patchToServer(tags, index, lang);
-    } else if (finishType === FinishType.badSpelled) {
+  private finishSpacyCall(index: number, result: KeywordsResult, previous: Language): void {
+    let undo: () => any = () => '';
+    if (result.resultType === KeywordsResultType.badSpelled) {
       this.statistics.badSpelled++;
-      this.patchToServer([], index, Language.auto);
-    } else {
+      undo = () => this.statistics.badSpelled--;
+    } else if (result.resultType === KeywordsResultType.languageNotSupported) {
+      this.statistics.notSupported++;
+      undo = () => this.statistics.notSupported--;
+    } else if (result.resultType === KeywordsResultType.failure) {
       this.statistics.failed++;
-      this.patchToServer([], index, Language.auto);
+      undo = () => this.statistics.failed--;
+    }
+    if (result.language === Language.auto) {
+      result.language = null;
     }
+    this.patchToServer(result.keywords, index, result.language, undo);
   }
 
-  private patchToServer(tags: SpacyKeyword[], index: number, language: Language) {
+  private patchToServer(tags: SpacyKeyword[], index: number, language: Language, undo: () => any) {
     const changes = new TSMap<string, string>();
     changes.set('keywordsFromSpacy', JSON.stringify(tags));
-    changes.set('language', language);
+    if (language !== null) {
+      changes.set('language', language);
+    }
     this.commentService.patchComment(this._comments[index], changes).subscribe(_ => {
         this.statistics.succeeded++;
         this.callSpacy(index + concurrentCallsPerTask);
       },
       patchError => {
+        undo();
         this.statistics.failed++;
         if (patchError instanceof HttpErrorResponse && patchError.status === 403) {
           this.error = 'forbidden';
diff --git a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
index 13dfc7c5063776a8323006f55193fb1fbbc8f05f..2054bfece2147aad01ba4f1804bbc54f0bc257df 100644
--- a/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
+++ b/src/app/components/shared/_dialogs/worker-dialog/worker-dialog.component.ts
@@ -10,6 +10,7 @@ import { TranslateService } from '@ngx-translate/core';
 import { LanguageService } from '../../../../services/util/language.service';
 import { Comment, Language } from '../../../../models/comment';
 import { RoomDataService } from '../../../../services/util/room-data.service';
+import { DeepLService } from '../../../../services/http/deep-l.service';
 
 @Component({
   selector: 'app-worker-dialog',
@@ -27,6 +28,7 @@ export class WorkerDialogComponent implements OnInit {
               private languagetoolService: LanguagetoolService,
               private spacyService: SpacyService,
               protected langService: LanguageService,
+              private deepLService: DeepLService,
               private translateService: TranslateService,
               private roomDataService: RoomDataService) {
     langService.langEmitter.subscribe(lang => translateService.use(lang));
@@ -112,14 +114,15 @@ export class WorkerDialogComponent implements OnInit {
 
   appendRoom(room: Room, comments: Comment[]) {
     WorkerDialogComponent.queuedRooms.set(room.id,
-      new WorkerDialogTask(room, comments, this.spacyService, this.commentService, this.languagetoolService, () => {
-        setTimeout(() => {
-          WorkerDialogComponent.queuedRooms.delete(room.id);
-          if (WorkerDialogComponent.queuedRooms.length === 0) {
-            this.close();
-          }
-        }, 10_000);
-      })
+      new WorkerDialogTask(room, comments, this.spacyService, this.deepLService, this.commentService,
+        this.languagetoolService, () => {
+          setTimeout(() => {
+            WorkerDialogComponent.queuedRooms.delete(room.id);
+            if (WorkerDialogComponent.queuedRooms.length === 0) {
+              this.close();
+            }
+          }, 10_000);
+        })
     );
   }
 
diff --git a/src/app/components/shared/header/header.component.ts b/src/app/components/shared/header/header.component.ts
index a8d0271cdca2525269378cc2e0eb4b6fc8db7050..2e64ca1d4f4d8723cc9111939fc94da4b59a51bb 100644
--- a/src/app/components/shared/header/header.component.ts
+++ b/src/app/components/shared/header/header.component.ts
@@ -145,6 +145,7 @@ export class HeaderComponent implements OnInit,AfterViewInit {
             localStorage.setItem('shortId', this.shortId);
             this.roomService.getRoomByShortId(this.shortId).subscribe(room => {
               this.room = room;
+              this.moderationEnabled = !room.directSend;
               this._subscriptionRoomService = this.wsRoomService.getRoomStream(this.room.id).subscribe(msg => {
                 const message = JSON.parse(msg.body);
                 if (message.type === 'RoomPatched') {
diff --git a/src/app/components/shared/write-comment/write-comment.component.ts b/src/app/components/shared/write-comment/write-comment.component.ts
index 5e0e5152cfa92f6caefa8d8513734ee26bee29a8..4008918a5ab59512872d50224ca7e515a9e9ad9c 100644
--- a/src/app/components/shared/write-comment/write-comment.component.ts
+++ b/src/app/components/shared/write-comment/write-comment.component.ts
@@ -9,6 +9,7 @@ import { DeepLService, SourceLang, TargetLang } from '../../../services/http/dee
 import { DeepLDialogComponent, ResultValue } from '../_dialogs/deep-ldialog/deep-ldialog.component';
 import { MatDialog } from '@angular/material/dialog';
 import { FormControl, Validators } from '@angular/forms';
+import { CreateCommentKeywords } from '../../../utils/create-comment-keywords';
 
 type SubmitFunction = (commentData: string, commentText: string, selectedTag: string, name?: string,
                        verifiedWithoutDeepl?: boolean) => any;
@@ -159,7 +160,7 @@ export class WriteCommentComponent implements OnInit {
     if (code.startsWith(SourceLang.EN)) {
       target = TargetLang.DE;
     }
-    DeepLDialogComponent.generateDeeplDelta(this.deeplService, body, target)
+    CreateCommentKeywords.generateDeeplDelta(this.deeplService, body, target)
       .subscribe(([improvedBody, improvedText]) => {
         this.isSpellchecking = false;
         if (improvedText.replace(/\s+/g, '') === text.replace(/\s+/g, '')) {
diff --git a/src/app/services/http/base-http.service.ts b/src/app/services/http/base-http.service.ts
index 77b29ce5b2122f95bdb86e5220c6da08eee2788c..520bf005c8cdf626a178f063c8cc25aea692e27f 100644
--- a/src/app/services/http/base-http.service.ts
+++ b/src/app/services/http/base-http.service.ts
@@ -21,7 +21,7 @@ export class BaseHttpService {
           this.nextRequest = new Date().getTime() + 86_400_000;
         }
       }
-      console.error(error);
+      console.error(operation, error);
       return throwError(error);
     };
   }
diff --git a/src/app/utils/create-comment-keywords.ts b/src/app/utils/create-comment-keywords.ts
index e827d8c1c5b330c1b8495f0b9cc78a572cbe6378..9ba833a870ee2d266fa01a7abe411d47f1c6060c 100644
--- a/src/app/utils/create-comment-keywords.ts
+++ b/src/app/utils/create-comment-keywords.ts
@@ -1,5 +1,29 @@
-import { Language, LanguagetoolService } from '../services/http/languagetool.service';
-import { map } from 'rxjs/operators';
+import { Language, LanguagetoolResult, LanguagetoolService } from '../services/http/languagetool.service';
+import { catchError, map, switchMap } from 'rxjs/operators';
+import { Observable, of } from 'rxjs';
+import { SpacyKeyword, SpacyService } from '../services/http/spacy.service';
+import { DeepLService, FormalityType, SourceLang, TargetLang } from '../services/http/deep-l.service';
+import { Comment, Language as CommentLanguage } from '../models/comment';
+import { ViewCommentDataComponent } from '../components/shared/view-comment-data/view-comment-data.component';
+import { CURRENT_SUPPORTED_LANGUAGES, Model } from '../services/http/spacy.interface';
+
+export enum KeywordsResultType {
+  successful,
+  badSpelled,
+  languageNotSupported,
+  failure
+}
+
+export interface KeywordsResult {
+  keywords: SpacyKeyword[];
+  language: CommentLanguage;
+  resultType: KeywordsResultType;
+  error?: any;
+  wasSpacyError?: boolean;
+}
+
+const ERROR_QUOTIENT_WELL_SPELLED = 20;
+const ERROR_QUOTIENT_USE_DEEPL = 75;
 
 export class CreateCommentKeywords {
 
@@ -14,22 +38,126 @@ export class CreateCommentKeywords {
       .replace(/\[([^\n\[\]]*)\]\(([^()\n]*)\)/gm, '$1 $2');
   }
 
-  static isSpellingAcceptable(languagetoolService: LanguagetoolService, text: string, language: Language = 'auto') {
-    return languagetoolService.checkSpellings(text, language).pipe(
-      map(result => {
-        const wordCount = text.trim().split(' ').length;
-        const hasConfidence = language === 'auto' ? result.language.detectedLanguage.confidence >= 0.5 : true;
-        const hasLessMistakes = (result.matches.length * 100) / wordCount <= 50;
-        return {
-          isAcceptable: hasConfidence && hasLessMistakes,
-          text: this.escapeForSpacy(text),
-          result
-        };
+  public static generateDeeplDelta(deepl: DeepLService, body: string, targetLang: TargetLang,
+                                   formality = FormalityType.less): Observable<[string, string]> {
+    const delta = ViewCommentDataComponent.getDeltaFromData(body);
+    const xml = delta.ops.reduce((acc, e, i) => {
+      if (typeof e['insert'] === 'string' && e['insert'].trim().length) {
+        acc += '<x i="' + i + '">' + this.encodeHTML(CreateCommentKeywords.removeMarkdown(e['insert'])) + '</x>';
+        e['insert'] = '';
+      }
+      return acc;
+    }, '');
+    return deepl.improveTextStyle(xml, targetLang, formality).pipe(
+      map(str => {
+        const regex = /<x i="(\d+)">([^<]+)<\/x>/gm;
+        let m;
+        while ((m = regex.exec(str)) !== null) {
+          delta.ops[+m[1]]['insert'] += this.decodeHTML(m[2]);
+        }
+        const text = delta.ops.reduce((acc, el) => acc + (typeof el['insert'] === 'string' ? el['insert'] : ''), '');
+        return [ViewCommentDataComponent.getDataFromDelta(delta), text];
       })
     );
   }
 
-  static escapeForSpacy(text: string): string {
+  static generateKeywords(languagetoolService: LanguagetoolService,
+                          deeplService: DeepLService,
+                          spacyService: SpacyService,
+                          body: string,
+                          useDeepl: boolean = false,
+                          language: Language = 'auto'): Observable<KeywordsResult> {
+    const text = ViewCommentDataComponent.getTextFromData(body);
+    return languagetoolService.checkSpellings(text, language).pipe(
+      switchMap(result => this.spacyKeywordsFromLanguagetoolResult(languagetoolService, deeplService,
+        spacyService, text, body, language, result, useDeepl)),
+      catchError((err) => of({
+        keywords: [],
+        language: CommentLanguage.auto,
+        resultType: KeywordsResultType.failure,
+        error: err
+      } as KeywordsResult))
+    );
+  }
+
+  private static spacyKeywordsFromLanguagetoolResult(languagetoolService: LanguagetoolService,
+                                                     deeplService: DeepLService,
+                                                     spacyService: SpacyService,
+                                                     text: string,
+                                                     body: string,
+                                                     selectedLanguage: Language,
+                                                     result: LanguagetoolResult,
+                                                     useDeepl: boolean): Observable<KeywordsResult> {
+    const wordCount = text.trim().split(' ').length;
+    const hasConfidence = selectedLanguage === 'auto' ? result.language.detectedLanguage.confidence >= 0.5 : true;
+    const errorQuotient = (result.matches.length * 100) / wordCount;
+    console.log(errorQuotient);
+    if (!hasConfidence ||
+      errorQuotient > ERROR_QUOTIENT_USE_DEEPL ||
+      (!useDeepl && errorQuotient > ERROR_QUOTIENT_WELL_SPELLED)) {
+      return of({
+        keywords: [],
+        language: CommentLanguage.auto,
+        resultType: KeywordsResultType.badSpelled
+      } as KeywordsResult);
+    }
+    const escapedText = this.escapeForSpacy(text);
+    let textLangObservable = of(escapedText);
+    if (useDeepl && errorQuotient > ERROR_QUOTIENT_WELL_SPELLED) {
+      let target = TargetLang.EN_US;
+      const code = result.language.detectedLanguage.code.toUpperCase().split('-')[0];
+      if (code.startsWith(SourceLang.EN)) {
+        target = TargetLang.DE;
+      }
+      textLangObservable = this.generateDeeplDelta(deeplService, body, target)
+        .pipe(
+          map(([_, improvedText]) => this.escapeForSpacy(improvedText))
+        );
+    }
+    return textLangObservable.pipe(
+      switchMap((textForSpacy) => this.callSpacy(spacyService, textForSpacy,
+        languagetoolService.isSupportedLanguage(result.language.code as Language), selectedLanguage,
+        languagetoolService.mapLanguageToSpacyModel(result.language.code as Language)))
+    );
+  }
+
+  private static callSpacy(spacyService: SpacyService,
+                           text: string,
+                           isResultLangSupported: boolean,
+                           selectedLanguage: Language,
+                           commentModel: Model): Observable<KeywordsResult> {
+    const selectedLangExtend =
+      selectedLanguage[2] === '-' ? selectedLanguage.substr(0, 2) : selectedLanguage;
+    let finalLanguage: CommentLanguage;
+    if (selectedLanguage === 'auto') {
+      finalLanguage = Comment.mapModelToLanguage(commentModel);
+    } else if (CommentLanguage[selectedLangExtend]) {
+      finalLanguage = CommentLanguage[selectedLangExtend];
+    }
+    if (!isResultLangSupported || !CURRENT_SUPPORTED_LANGUAGES.includes(commentModel)) {
+      return of({
+        keywords: [],
+        language: finalLanguage,
+        resultType: KeywordsResultType.languageNotSupported
+      } as KeywordsResult);
+    }
+    return spacyService.getKeywords(text, commentModel).pipe(
+      map(keywords => ({
+        keywords,
+        language: finalLanguage,
+        resultType: KeywordsResultType.successful
+      } as KeywordsResult)),
+      catchError(err => of({
+        keywords: [],
+        language: finalLanguage,
+        resultType: KeywordsResultType.failure,
+        error: err,
+        wasSpacyError: true
+      } as KeywordsResult))
+    );
+  }
+
+  private static escapeForSpacy(text: string): string {
     text = this.makeCapslockLowercase(text);
     return text.replace(/\(([^-\s)]+-)\)([^\s]+)/gmi, '$1$2');
   }
@@ -55,4 +183,20 @@ export class CreateCommentKeywords {
     }
     return result;
   }
+
+  private static encodeHTML(str: string): string {
+    return str.replace(/&/g, '&amp;')
+      .replace(/</g, '&lt;')
+      .replace(/>/g, '&gt;')
+      .replace(/"/g, '&quot;')
+      .replace(/'/g, '&apos;');
+  }
+
+  private static decodeHTML(str: string): string {
+    return str.replace(/&apos;/g, '\'')
+      .replace(/&quot;/g, '"')
+      .replace(/&gt;/g, '>')
+      .replace(/&lt;/g, '<')
+      .replace(/&amp;/g, '&');
+  }
 }