Commit 971def9c authored by Kantz's avatar Kantz
Browse files

Merge branch 'dev_nginx' into 'main'

Dev nginx

See merge request kantz/tutor_react!18
parents bca28457 2958718e
...@@ -8,6 +8,8 @@ Vergleiche das Ergebnis mit der korrekten Lösung. ...@@ -8,6 +8,8 @@ Vergleiche das Ergebnis mit der korrekten Lösung.
Stelle Nachfragen wenn der Lösungsweg nicht vollständig ist. Stelle Nachfragen wenn der Lösungsweg nicht vollständig ist.
Die Reihnfolge in mathematischen Ausdrücken ist irrellevant wenn sie äquivalent sind also a+b = b+a und a^bc = a^cb.
Zitiere 1 zu 1 aus der AKTUELLE Eingabe des Nutzers wenn du auf Fehler aufmerksam machst. Zitiere 1 zu 1 aus der AKTUELLE Eingabe des Nutzers wenn du auf Fehler aufmerksam machst.
verwende die $ für mathematische Formeln, z.B. $a^2 + b^2 = c^2$ verwende die $ für mathematische Formeln, z.B. $a^2 + b^2 = c^2$
......
...@@ -9,6 +9,7 @@ Du bist ein didaktischer Mathe-Tutor. Du beantwortest die mathematischen Fragen ...@@ -9,6 +9,7 @@ Du bist ein didaktischer Mathe-Tutor. Du beantwortest die mathematischen Fragen
3) Wenn der Nutzer etwas Falsches sagt weiße ihn darauf hin. 3) Wenn der Nutzer etwas Falsches sagt weiße ihn darauf hin.
4) Die Übergebene Lösung ist IMMER korrekt. 4) Die Übergebene Lösung ist IMMER korrekt.
5) Der Nutzer kenn die korrekte Lösung und den exemplarischer Lösungsweg nicht. 5) Der Nutzer kenn die korrekte Lösung und den exemplarischer Lösungsweg nicht.
6) Die Reihnfolge in mathematischen Ausdrücken ist irrellevant wenn sie äquivalent sind also a+b = b+a und a^bc = a^cb.
verwende die $ für mathematische Formeln, z.B. $a^2 + b^2 = c^2$ verwende die $ für mathematische Formeln, z.B. $a^2 + b^2 = c^2$
......
...@@ -4,7 +4,7 @@ services: ...@@ -4,7 +4,7 @@ services:
context: ../backend context: ../backend
dockerfile: Dockerfile dockerfile: Dockerfile
env_file: env_file:
- ../backend/.env - ../backend/.env_openai
expose: expose:
- "8000" - "8000"
healthcheck: healthcheck:
...@@ -22,7 +22,8 @@ services: ...@@ -22,7 +22,8 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./logs:/app/logs - ./logs:/app/logs
networks:
- web
frontend: frontend:
build: build:
...@@ -30,8 +31,10 @@ services: ...@@ -30,8 +31,10 @@ services:
dockerfile: Dockerfile dockerfile: Dockerfile
depends_on: depends_on:
- backend - backend
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
restart: unless-stopped restart: unless-stopped
networks:
- web
networks:
web:
external: true
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
FROM node:22-alpine AS build FROM node:22-alpine AS build
WORKDIR /app WORKDIR /app
RUN corepack enable RUN corepack enable
COPY package.json pnpm-lock.yaml ./ COPY package.json pnpm-lock.yaml ./
...@@ -11,9 +10,5 @@ COPY . . ...@@ -11,9 +10,5 @@ COPY . .
RUN pnpm run build RUN pnpm run build
FROM nginx:1.27-alpine FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
server {
listen 3000;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
...@@ -924,7 +924,7 @@ export default function ChatPage() { ...@@ -924,7 +924,7 @@ export default function ChatPage() {
<div className="brand"> <div className="brand">
<img className="brand-logo" src={sumintLogo} alt="SuMINT Logo" /> <img className="brand-logo" src={sumintLogo} alt="SuMINT Logo" />
<div className="brand-text"> <div className="brand-text">
<div className="brand-title">Math Tutor</div> <div className="brand-title">Mathe Tutor</div>
<div className="brand-subtitle">{t("prototypeWorkspace")}</div> <div className="brand-subtitle">{t("prototypeWorkspace")}</div>
</div> </div>
</div> </div>
......
...@@ -102,7 +102,7 @@ export default function TaskSelectionPage() { ...@@ -102,7 +102,7 @@ export default function TaskSelectionPage() {
<div className="brand"> <div className="brand">
<img className="brand-logo" src={sumintLogo} alt="SuMINT Logo" /> <img className="brand-logo" src={sumintLogo} alt="SuMINT Logo" />
<div className="brand-text"> <div className="brand-text">
<div className="brand-title">Math Tutor</div> <div className="brand-title">Mathe Tutor</div>
<div className="brand-subtitle">{t("taskSelectionSubtitle")}</div> <div className="brand-subtitle">{t("taskSelectionSubtitle")}</div>
</div> </div>
</div> </div>
......
const MATH_SEGMENT_PATTERN = const MATH_SEGMENT_PATTERN =
/(\$\$[\s\S]*?\$\$|\\\[[\s\S]*?\\\]|\\\([\s\S]*?\\\)|\$(?:\\.|[^$\\\n])+\$)/g; /(\$\$[\s\S]*?\$\$|\\\[[\s\S]*?\\\]|\\\([\s\S]*?\\\)|\$(?:\\.|[^$\\\n])+\$)/g;
// wandlet * in \* um sodass * in der MArkdown darstellung nich zum zeichen
// für kursiv oder fett gedruckt wird.
const escapeAsterisks = (value: string) => value.replace(/\*/g, "\\*"); const escapeAsterisks = (value: string) => value.replace(/\*/g, "\\*");
// Wandelt einfache Bruchschreibweisen in LaTeX-Brüche um.
// Beispiele:
// - (x+1)/(x-1) -> \frac{x+1}{x-1}
// - a/b -> \frac{a}{b}
//
// Diese Ersetzung läuft nur innerhalb erkannter Math-Segmente, damit
// normale Markdown-Links, URLs oder Fließtext unangetastet bleiben.
const convertSimpleFractions = (value: string) => {
let output = value;
// Vorrang für explizit geklammerte Ausdrücke:
// (x+1)/(x-1) => \frac{x+1}{x-1}
output = output.replace(
/\(([^()]+)\)\s*\/\s*\(([^()]+)\)/g,
(_match, numerator: string, denominator: string) =>
`\\frac{${numerator}}{${denominator}}`
);
// Einseitig geklammerte Ausdrücke:
// (a+b)/c => \frac{a+b}{c}
// a/(b+c) => \frac{a}{b+c}
// Diese Regel kommt vor der ganz einfachen a/b-Regel, damit die Klammern
// erhalten bleiben und nicht versehentlich nur Teilstücke ersetzt werden.
output = output.replace(
/\(([^()]+)\)\s*\/\s*([A-Za-z0-9]+)(?![\w{])/g,
(_match, numerator: string, denominator: string) =>
`\\frac{${numerator}}{${denominator}}`
);
output = output.replace(
/([A-Za-z0-9]+)\s*\/\s*\(([^()]+)\)(?![\w{])/g,
(_match, numerator: string, denominator: string) =>
`\\frac{${numerator}}{${denominator}}`
);
// Danach sehr einfache Kurzschreibweise:
// a/b => \frac{a}{b}
// Hinweis: Das ist bewusst konservativ gehalten, damit keine komplexen
// Ausdrücke oder schon vorhandene LaTeX-Befehle umgeschrieben werden.
output = output.replace(
/(^|[^\\\w}])([A-Za-z0-9]+)\s*\/\s*([A-Za-z0-9]+)(?![\w{])/g,
(_match, prefix: string, numerator: string, denominator: string) =>
`${prefix}\\frac{${numerator}}{${denominator}}`
);
return output;
};
// Formatiert Potenzen so, dass zusammengesetzte Exponenten in Klammern
// vollständig in LaTeX-Klammern gesetzt werden.
// Beispiel:
// - x^(a+b) -> x^{a+b}
const normalizePowers = (value: string) =>
value.replace(
/([A-Za-z0-9\\]+)\s*\^\s*\(([^()]+)\)/g,
(_match, base: string, exponent: string) => `${base}^{${exponent}}`
);
// Wandelt sqrt(...) in LaTeX-Wurzelnotation um.
// Beispiel:
// - sqrt(x) -> \sqrt{x}
const normalizeSquareRoots = (value: string) =>
value.replace(/\bsqrt\s*\(([^()]+)\)/g, (_match, inner: string) => `\\sqrt{${inner}}`);
// Wandelt exp(x) in e^x um.
// Beispiel:
// - exp(x) -> e^x
const normalizeExp = (value: string) =>
value.replace(/\bexp\s*\(([^()]+)\)/g, (_match, inner: string) => `e^${inner}`);
// Wandelt log(x) in eine lesbare Logarithmus-Notation um.
// Beispiel:
// - log(x) -> \log x
const normalizeLog = (value: string) =>
value.replace(/\blog\s*\(([^()]+)\)/g, (_match, inner: string) => `\\log ${inner}`);
// Wandelt pi in das griechische LaTeX-Symbol um.
// Beispiel:
// - pi -> \pi
const normalizePi = (value: string) =>
value.replace(/\bpi\b/g, "\\pi");
// Wandelt sin/cos/tan-Aufrufe in LaTeX-Makros um.
// Beispiele:
// - sin(a) -> \sin(a)
// - cos(a) -> \cos(a)
// - tan(a) -> \tan(a)
const normalizeTrigFunctions = (value: string) =>
value.replace(/\b(sin|cos|tan)\s*\(([^()]+)\)/g, (_match, fn: string, inner: string) => `\\${fn}(${inner})`);
// Wandelt inf/minf in Infinities um.
// Beispiele:
// - inf -> \infty
// - minf -> - \infty
const normalizeInfinityTokens = (value: string) =>
value
.replace(/\bminf\b/g, "- \\infty")
.replace(/\binf\b/g, "\\infty");
// Macht bereits geschriebene Mengenklammern in Math-Segmenten sichtbar.
// Beispiele:
// - \{1, 2, 3\} -> \\{1, 2, 3\\}
// - \{x \in \mathbb{R} \mid x > 0\} -> \\{x \in \mathbb{R} \mid x > 0\\}
//
// Wichtig:
// - Rohe {a,b,c} werden absichtlich NICHT umgeschrieben, damit z. B. x_{a,b}
// nicht fälschlich als Menge interpretiert wird.
// - Nur bereits escapte Klammern werden angehoben, damit MathJax sie sichtbar
// rendert statt sie als Gruppierungszeichen zu schlucken.
const normalizeSetBraces = (value: string) =>
value
.replace(/\\\{/g, "\\\\{")
.replace(/\\\}/g, "\\\\}");
export const escapeAsterisksInsideMath = (input: string): string => { export const escapeAsterisksInsideMath = (input: string): string => {
return input.replace(MATH_SEGMENT_PATTERN, (segment) => { return input.replace(MATH_SEGMENT_PATTERN, (segment) => {
if (segment.startsWith("$$") && segment.endsWith("$$")) { if (segment.startsWith("$$") && segment.endsWith("$$")) {
const inner = segment.slice(2, -2); const inner = segment.slice(2, -2);
return `$$${escapeAsterisks(inner)}$$`; return `$$${normalizeSetBraces(normalizeInfinityTokens(normalizeTrigFunctions(normalizePi(normalizeLog(normalizeExp(normalizeSquareRoots(normalizePowers(convertSimpleFractions(escapeAsterisks(inner))))))))))}$$`;
} }
if (segment.startsWith("\\[") && segment.endsWith("\\]")) { if (segment.startsWith("\\[") && segment.endsWith("\\]")) {
const inner = segment.slice(2, -2); const inner = segment.slice(2, -2);
return `\\[${escapeAsterisks(inner)}\\]`; return `\\[${normalizeSetBraces(normalizeInfinityTokens(normalizeTrigFunctions(normalizePi(normalizeLog(normalizeExp(normalizeSquareRoots(normalizePowers(convertSimpleFractions(escapeAsterisks(inner))))))))))}\\]`;
} }
if (segment.startsWith("\\(") && segment.endsWith("\\)")) { if (segment.startsWith("\\(") && segment.endsWith("\\)")) {
const inner = segment.slice(2, -2); const inner = segment.slice(2, -2);
return `\\(${escapeAsterisks(inner)}\\)`; return `\\(${normalizeSetBraces(normalizeInfinityTokens(normalizeTrigFunctions(normalizePi(normalizeLog(normalizeExp(normalizeSquareRoots(normalizePowers(convertSimpleFractions(escapeAsterisks(inner))))))))))}\\)`;
} }
if (segment.startsWith("$") && segment.endsWith("$")) { if (segment.startsWith("$") && segment.endsWith("$")) {
const inner = segment.slice(1, -1); const inner = segment.slice(1, -1);
return `$${escapeAsterisks(inner)}$`; return `$${normalizeSetBraces(normalizeInfinityTokens(normalizeTrigFunctions(normalizePi(normalizeLog(normalizeExp(normalizeSquareRoots(normalizePowers(convertSimpleFractions(escapeAsterisks(inner))))))))))}$`;
} }
return segment; return segment;
}); });
}; };
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment