mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-12 14:45:42 +08:00
fix(web): prevent LaTeX from being cut at \right] or \big) in agent o… (#13155)
### What problem does this PR solve?
- Use negative lookbehind (?<![a-zA-Z]) so \] and \) inside commands
(e.g. \right], \big)) are not treated as block/inline delimiters
- Use greedy matching to capture up to the last valid delimiter, fixing
truncated formulas (e.g. C_{seq}(y|x) = \frac{1}{|y|} ...)
- Add unit tests for preprocessLaTeX
Closes #13134
### Type of change
- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
34
web/src/utils/__tests__/chat.test.ts
Normal file
34
web/src/utils/__tests__/chat.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { preprocessLaTeX } from '../chat';
|
||||
|
||||
describe('preprocessLaTeX', () => {
|
||||
it('converts block \\[ \\] to $$ $$', () => {
|
||||
expect(preprocessLaTeX('\\[ x + y \\]')).toBe('$$x + y$$');
|
||||
});
|
||||
|
||||
it('converts inline \\( \\) to $ $', () => {
|
||||
expect(preprocessLaTeX('\\( a \\)')).toBe('$a$');
|
||||
});
|
||||
|
||||
it('does not cut block math at \\right] (Closes #13134)', () => {
|
||||
const content = '\\[ C_{seq}(y|x) = \\frac{1}{|y|} \\sum_{t=1}^{|y|} \\right] \\]';
|
||||
const result = preprocessLaTeX(content);
|
||||
expect(result).toContain('\\right]');
|
||||
expect(result).toContain('\\frac{1}{|y|}');
|
||||
expect(result).toBe(
|
||||
'$$ C_{seq}(y|x) = \\frac{1}{|y|} \\sum_{t=1}^{|y|} \\right] $$',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not cut inline math at \\big) or nested parens', () => {
|
||||
const content = '\\( f(x) + \\big) \\)';
|
||||
const result = preprocessLaTeX(content);
|
||||
expect(result).toContain('\\big)');
|
||||
expect(result).toBe('$ f(x) + \\big) $');
|
||||
});
|
||||
|
||||
it('handles multiple block equations', () => {
|
||||
const content = 'First \\[ a \\] then \\[ b \\right] c \\]';
|
||||
const result = preprocessLaTeX(content);
|
||||
expect(result).toBe('First $$a$$ then $$ b \\right] c $$');
|
||||
});
|
||||
});
|
||||
@@ -39,14 +39,24 @@ export const buildMessageUuidWithRole = (
|
||||
|
||||
// Preprocess LaTeX equations to be rendered by KaTeX
|
||||
// ref: https://github.com/remarkjs/react-markdown/issues/785
|
||||
//
|
||||
// Delimiter matching: we only treat \] and \) as block/inline endings when they
|
||||
// are not part of a LaTeX command (e.g. \right], \big), \left)). Use a negative
|
||||
// lookbehind (?<![a-zA-Z]) so that \] or \) preceded by a letter (command name)
|
||||
// is not considered the closing delimiter. Use greedy matching so we match up to
|
||||
// the last valid delimiter and avoid cutting at the first \] or \) inside the
|
||||
// equation (e.g. \frac{1}{|y|} or \right]).
|
||||
|
||||
const BLOCK_MATH_RE = /\\\[([\s\S]*)(?<![a-zA-Z])\\\]/g;
|
||||
const INLINE_MATH_RE = /\\\(([\s\S]*)(?<![a-zA-Z])\\\)/g;
|
||||
|
||||
export const preprocessLaTeX = (content: string) => {
|
||||
const blockProcessedContent = content.replace(
|
||||
/\\\[([\s\S]*?)\\\]/g,
|
||||
BLOCK_MATH_RE,
|
||||
(_, equation) => `$$${equation}$$`,
|
||||
);
|
||||
const inlineProcessedContent = blockProcessedContent.replace(
|
||||
/\\\(([\s\S]*?)\\\)/g,
|
||||
INLINE_MATH_RE,
|
||||
(_, equation) => `$${equation}$`,
|
||||
);
|
||||
return inlineProcessedContent;
|
||||
|
||||
Reference in New Issue
Block a user