Issues with Katex/ngx-markdown Rendering in Angular 16

24 views Asked by At

I use in my Angular 16 application the ngx-markdown library along with some others, especially Katex.

My issue arises when my backend (an LLM) returns the response with all the necessary markdowns and upon rendering this text, there are conflicts with Katex delimiters.

I used Katex's default delimiters (https://katex.org/docs/autorender):

[
 {left: "$$", right: "$$", display: true},
 {left: '$', right: '$', display: false}, // I added
 {left: "\\(", right: "\\)", display: false},
 {left: "\(", right: "\)", display: false}, // I added
 {left: "\\begin{equation}", right: "\\end{equation}", display: true},
 {left: "\\begin{align}", right: "\\end{align}", display: true},
 {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
 {left: "\\begin{gather}", right: "\\end{gather}", display: true},
 {left: "\\begin{CD}", right: "\\end{CD}", display: true},
 {left: "\\[", right: "\\]", display: true},
 {left: "\[", right: "\]", display: true}, // I added
]

I added some delimiters in an attempt to render correctly. However, when the returned text contained ( ) or [ ], Katex, or Angular, or ngx-markdown, considered it as a delimiter and triggered Katex's delimiters. Consequently, it rendered incorrectly.

Below is an example of how the rendering is being displayed: enter image description here

Following is the Angular script with the main parts:

HTML -

  <markdown lineNumbers katex [katexOptions]="optionsKatex" clipboard [clipboardButtonTemplate]="buttonTemplate">
     {{ mensagem.content }}
  </markdown>

Angular TypeScript Component:

import { Component, OnInit, AfterViewInit } from '@angular/core';
import { KatexOptions } from 'ngx-markdown';

type questionAnswer={
  type: "Question" | "Answer",
  content: string,
  keyChat: number,
  likeSelected: boolean,
  dislikeSelected: boolean,
  isActive: boolean,
  isButtonsDisabled: boolean
}

export class TestComponent implements OnInit, AfterViewInit {

 public optionsKatex: KatexOptions = {
   delimiters: [
     {left: "$$", right: "$$", display: true},
     {left: '$', right: '$', display: false}, // I added
     {left: "\\(", right: "\\)", display: false},
     {left: "\(", right: "\)", display: false}, // I added
     {left: "\\begin{equation}", right: "\\end{equation}", display: true},
     {left: "\\begin{align}", right: "\\end{align}", display: true},
     {left: "\\begin{alignat}", right: "\\end{alignat}", display: true},
     {left: "\\begin{gather}", right: "\\end{gather}", display: true},
     {left: "\\begin{CD}", right: "\\end{CD}", display: true},
     {left: "\\[", right: "\\]", display: true},
     {left: "\[", right: "\]", display: true}, // I added
   ]
 };

 listMessagesQA: questionAnswer[] = [];

 ngOnInit(): void { }

 ngAfterViewInit(): void {
   this.listMessagesQA.push({ content: 'A Meta é uma empresa de tecnologia que teve sua fundação em 1990, em São Leopoldo, no Rio Grande do Sul, Brasil[3]. Atualmente, a empresa opera não só no Brasil, mas também no exterior, estando presente em mais de 100 cidades ao redor do mundo, com sedes em São Paulo, Miami e Waterloo, e é parceira da multinacional alemã SAP[3]. A Meta tem como foco realizar consultoria estratégica para implementar soluções de tecnologia e transformação digital, auxiliando seus clientes a atualizarem seus modelos de negócios[3].\n\nAlém disso, a Meta foi reconhecida como uma das melhores empresas de TI para se trabalhar em 2020 e 2021, pelo Great Place to Work[3]. A empresa busca acelerar resultados de grandes e médias companhias, tanto no Brasil quanto no exterior, implementando soluções inovadoras[3].\n\nA empresa também projeta aquisições em áreas como experiência do usuário (UX), inteligência artificial (IA) e segmento SAP, buscando promover um ecossistema de inovação que conecta startups, investidores, empresas, parceiros, universidades, laboratórios de pesquisa e sociedade, por meio de seu braço de Venture Capital e investimentos, a Meta Ventures[3].\n\nReferências:\n1. https://pt.wikipedia.org/wiki/Meta_(empresa_de_tecnologia)\n2. https://pt.wikipedia.org/w/index.php?title=Meta_(empresa_de_tecnologia)&oldid=67577792', type: 'Answer', keyChat:0, likeSelected: false, dislikeSelected: false, isActive: true, isButtonsDisabled: false });
   this.listMessagesQA.push({ content: "O cálculo do delta (\( \Delta \)) de uma equação de segundo grau na forma \( ax^2 + bx + c = 0 \) é feito pela fórmula: \[ \Delta = b^2 - 4ac \] onde: - \( a \), \( b \) e \( c \) são os coeficientes da equação de segundo grau; - \( \Delta \) é o discriminante, que é utilizado para determinar a natureza das raízes da equação. O valor do discriminante (\( \Delta \)) é fundamental para identificar se a equação possui duas raízes reais distintas (\( \Delta > 0 \)), uma raiz real (\( \Delta = 0 \)) ou raízes complexas conjugadas (\( \Delta < 0 \)).", type: 'Answer', keyChat:0, likeSelected: false, dislikeSelected: false, isActive: true, isButtonsDisabled: false });
   this.listMessagesQA.push({ content: `A fórmula de Bhaskara é utilizada para encontrar as raízes de uma equação de segundo grau na forma \\( ax^2 + bx + c = 0 \\). A fórmula é dada por:\n\n\\[x = \\frac{{-b \\pm \\sqrt{{b^2 - 4ac}}}}{{2a}}\\]\n\nonde:\n- \\( a \\), \\( b \\) e \\( c \\) são os coeficientes da equação de segundo grau;\n- O termo \\( b^2 - 4ac \\) é chamado de discriminante.\n\nEssa fórmula é fundamental para resolver equações quadráticas e encontrar os valores de \\( x \\) que satisfazem a equação dada.`, type: 'Answer', keyChat:0, likeSelected: false, dislikeSelected: false, isActive: true, isButtonsDisabled: false });
   this.listMessagesQA.push({ content: 'A fórmula do discriminante (delta) da equação quadrática $ ax^2 + bx + c = 0 $ é:\n\n$$ \\Delta = b^2 - 4ac $$', type: 'Answer', keyChat:0, likeSelected: false, dislikeSelected: false, isActive: true, isButtonsDisabled: false });
 }

}

AppModule -

import { MarkdownModule, MarkedOptions } from 'ngx-markdown';

@NgModule({
  declarations: [
    AppComponent,
    TestComponent
  ],
  imports: [
    BrowserModule,
    MarkdownModule.forRoot({
      markedOptions: {
        provide: MarkedOptions,
        useValue: {
          gfm: true,
          breaks: true
        }
      }
    })
  ]
})
export class AppModule { }

Angular json -

"styles": [
          "src/styles.scss",
          "node_modules/prismjs/themes/prism-okaidia.css",
          "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
          "node_modules/katex/dist/katex.min.css"
        ],
        "scripts": [
          "node_modules/marked/marked.min.js",
          "node_modules/prismjs/prism.js",
          "node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js",
          "node_modules/katex/dist/katex.min.js",
          "node_modules/katex/dist/contrib/auto-render.min.js",
          "node_modules/clipboard/dist/clipboard.min.js",
          "node_modules/prismjs/components/prism-python.min.js",
          "node_modules/prismjs/components/prism-css.min.js",
          "node_modules/prismjs/components/prism-cobol.min.js",
          "node_modules/prismjs/components/prism-java.min.js",
          "node_modules/prismjs/components/prism-fortran.min.js",
          "node_modules/prismjs/components/prism-csv.min.js",
          "node_modules/prismjs/components/prism-markup.min.js",
          "node_modules/prismjs/components/prism-javascript.min.js",
          "node_modules/prismjs/components/prism-abap.min.js",
          "node_modules/prismjs/components/prism-bash.min.js",
          "node_modules/prismjs/components/prism-basic.min.js",
          "node_modules/prismjs/components/prism-batch.min.js",
          "node_modules/prismjs/components/prism-csharp.min.js",
          "node_modules/prismjs/components/prism-docker.min.js",
          "node_modules/prismjs/components/prism-excel-formula.min.js",
          "node_modules/prismjs/components/prism-git.min.js",
          "node_modules/prismjs/components/prism-go.min.js",
          "node_modules/prismjs/components/prism-graphql.min.js",
          "node_modules/prismjs/components/prism-http.min.js",
          "node_modules/prismjs/components/prism-json.min.js",
          "node_modules/prismjs/components/prism-julia.min.js",
          "node_modules/prismjs/components/prism-kotlin.min.js",
          "node_modules/prismjs/components/prism-latex.min.js",
          "node_modules/prismjs/components/prism-markdown.min.js",
          "node_modules/prismjs/components/prism-matlab.min.js",
          "node_modules/prismjs/components/prism-mongodb.min.js",
          "node_modules/prismjs/components/prism-nginx.min.js",
          "node_modules/prismjs/components/prism-pascal.min.js",
          "node_modules/prismjs/components/prism-powershell.min.js",
          "node_modules/prismjs/components/prism-r.min.js",
          "node_modules/prismjs/components/prism-regex.min.js",
          "node_modules/prismjs/components/prism-rust.min.js",
          "node_modules/prismjs/components/prism-scss.min.js",
          "node_modules/prismjs/components/prism-scheme.min.js",
          "node_modules/prismjs/components/prism-sql.min.js",
          "node_modules/prismjs/components/prism-typescript.min.js",
          "node_modules/prismjs/components/prism-vim.min.js",
          "node_modules/prismjs/components/prism-visual-basic.min.js",
          "node_modules/prismjs/components/prism-yaml.min.js"
        ]

Angular versions dependencies -

"dependencies": {
 "@angular/animations": "^16.2.0",
 "@angular/common": "^16.2.0",
 "@angular/compiler": "^16.2.0",
 "@angular/core": "^16.2.0",
 "@angular/forms": "^16.2.0",
 "@angular/platform-browser": "^16.2.0",
 "@angular/platform-browser-dynamic": "^16.2.0",
 "@angular/router": "^16.2.0",
 "@reactivex/rxjs": "^6.6.7",
 "@rxjs/rx": "^4.1.0",
 "bootstrap": "^5.3.1",
 "bootstrap-icons": "^1.11.0",
 "clipboard": "^2.0.11",
 "comon": "^1.0.4",
 "jwt-decode": "^4.0.0",
 "katex": "^0.16.9",
 "marked": "^4.3.0",
 "ng2-cookies": "^1.0.12",
 "ng2-pdf-viewer": "^10.0.0",
 "ngx-markdown": "^16.0.0",
 "prismjs": "^1.28.0",
 "rxjs": "~7.8.0",
 "tslib": "^2.3.0",
 "zone.js": "~0.13.0"
}

References I used for the implementation of ngx-markdown:

  1. https://www.npmjs.com/package/ngx-markdown/v/16.0.0
  2. https://katex.org/docs/autorender
0

There are 0 answers