Prechádzať zdrojové kódy

fix: 知识点公式解析 bug 跟踪。

yemeishu 2 týždňov pred
rodič
commit
d196398298
1 zmenil súbory, kde vykonal 68 pridanie a 0 odobranie
  1. 68 0
      app/Services/KatexRenderer.php

+ 68 - 0
app/Services/KatexRenderer.php

@@ -53,6 +53,9 @@ class KatexRenderer
             return $html;
         }
 
+        // 在渲染前修复公式中的实体与 cases 换行问题
+        $html = $this->sanitizeLatexInHtml($html);
+
         // 尝试从缓存获取
         $cacheKey = $this->getCacheKey($html);
         if ($this->cacheEnabled && $cached = cache()->get($cacheKey)) {
@@ -63,6 +66,12 @@ class KatexRenderer
         // 调用 Node.js 脚本渲染
         $rendered = $this->callNodeScript($html);
 
+        if (strpos($rendered, 'katex-error') !== false) {
+            Log::warning('KatexRenderer: 发现未解析公式(katex-error)', [
+                'sample' => $this->extractKatexErrorSnippet($rendered),
+            ]);
+        }
+
         // 缓存结果
         if ($this->cacheEnabled && $rendered !== $html) {
             cache()->put($cacheKey, $rendered, self::CACHE_TTL);
@@ -166,4 +175,63 @@ class KatexRenderer
         // 注意:这个方法需要 Redis 或支持通配符删除的缓存驱动
         Log::info('KatexRenderer: 缓存清除请求(需要手动清理或使用 Redis)');
     }
+
+    private function sanitizeLatexInHtml(string $html): string
+    {
+        $sanitize = function (string $tex): string {
+            $decoded = html_entity_decode($tex, ENT_QUOTES, 'UTF-8');
+            while ($decoded !== $tex) {
+                $tex = $decoded;
+                $decoded = html_entity_decode($tex, ENT_QUOTES, 'UTF-8');
+            }
+
+            return $this->fixCasesLineBreaks($tex);
+        };
+
+        // $$...$$
+        $html = preg_replace_callback('/\$\$([\s\S]*?)\$\$/', function ($m) use ($sanitize) {
+            return '$$' . $sanitize($m[1]) . '$$';
+        }, $html);
+
+        // $...$ (avoid $$)
+        $html = preg_replace_callback('/(?<!\$)\$([^$\n]+?)\$(?!\$)/', function ($m) use ($sanitize) {
+            return '$' . $sanitize($m[1]) . '$';
+        }, $html);
+
+        // \(...\)
+        $html = preg_replace_callback('/\\\\\(([\s\S]*?)\\\\\)/', function ($m) use ($sanitize) {
+            return '\\(' . $sanitize($m[1]) . '\\)';
+        }, $html);
+
+        // \[...\]
+        $html = preg_replace_callback('/\\\\\[([\s\S]*?)\\\\\]/', function ($m) use ($sanitize) {
+            return '\\[' . $sanitize($m[1]) . '\\]';
+        }, $html);
+
+        return $html;
+    }
+
+    private function fixCasesLineBreaks(string $tex): string
+    {
+        return preg_replace_callback('/\\\\begin\{cases\}([\s\S]*?)\\\\end\{cases\}/', function ($m) {
+            $content = $m[1];
+            // 将 cases 中被转成单反斜杠的换行恢复为双反斜杠(仅处理紧跟 +/- 的情况)
+            $content = preg_replace('/(?<!\\\\)\\\\(?=[-+])/', '\\\\\\\\', $content);
+            return '\\begin{cases}' . $content . '\\end{cases}';
+        }, $tex);
+    }
+
+    private function extractKatexErrorSnippet(string $html): array
+    {
+        if (!preg_match('/<span class="katex-error"[^>]*>(.*?)<\/span>/is', $html, $match)) {
+            return [];
+        }
+
+        $text = trim(strip_tags($match[1]));
+        $text = preg_replace('/\s+/', ' ', $text);
+
+        return [
+            'text' => mb_substr($text, 0, 200),
+        ];
+    }
 }