scriptPath = base_path('scripts/katex-render.mjs'); } /** * 渲染 HTML 中的所有 LaTeX 公式 * * @param string $html 包含 LaTeX 公式的 HTML * @return string 渲染后的 HTML */ public function renderHtml(string $html): string { // 检查是否包含需要渲染的公式 if (!$this->containsLatex($html)) { Log::debug('KatexRenderer: HTML 不包含 LaTeX 公式,跳过渲染'); return $html; } // 尝试从缓存获取 $cacheKey = $this->getCacheKey($html); if ($this->cacheEnabled && $cached = cache()->get($cacheKey)) { Log::debug('KatexRenderer: 从缓存获取渲染结果'); return $cached; } // 调用 Node.js 脚本渲染 $rendered = $this->callNodeScript($html); // 缓存结果 if ($this->cacheEnabled && $rendered !== $html) { cache()->put($cacheKey, $rendered, self::CACHE_TTL); } return $rendered; } /** * 检查 HTML 是否包含 LaTeX 公式 */ private function containsLatex(string $html): bool { // 检查常见的 LaTeX 定界符 return preg_match('/\$[^$]+\$|\$\$[\s\S]+?\$\$|\\\\\([\s\S]+?\\\\\)|\\\\\[[\s\S]+?\\\\\]/', $html) === 1; } /** * 调用 Node.js KaTeX 渲染脚本 */ private function callNodeScript(string $html): string { // 检查脚本是否存在 if (!file_exists($this->scriptPath)) { Log::warning('KatexRenderer: 渲染脚本不存在', ['path' => $this->scriptPath]); return $html; } try { // 创建进程 $process = new Process(['node', $this->scriptPath]); $process->setInput($html); $process->setTimeout(30); // 30秒超时 // 执行 $process->run(); // 检查是否成功 if (!$process->isSuccessful()) { Log::warning('KatexRenderer: Node.js 脚本执行失败', [ 'exit_code' => $process->getExitCode(), 'error' => $process->getErrorOutput(), ]); return $html; } $output = $process->getOutput(); // 验证输出 if (empty($output)) { Log::warning('KatexRenderer: Node.js 脚本输出为空'); return $html; } Log::info('KatexRenderer: LaTeX 公式渲染成功', [ 'input_length' => strlen($html), 'output_length' => strlen($output), ]); return $output; } catch (\Exception $e) { Log::error('KatexRenderer: 渲染异常', [ 'error' => $e->getMessage(), ]); return $html; } } /** * 生成缓存键 */ private function getCacheKey(string $html): string { return self::CACHE_PREFIX . md5($html); } /** * 禁用缓存(用于调试) */ public function disableCache(): self { $this->cacheEnabled = false; return $this; } /** * 启用缓存 */ public function enableCache(): self { $this->cacheEnabled = true; return $this; } /** * 清除所有 KaTeX 渲染缓存 */ public function clearCache(): void { // 注意:这个方法需要 Redis 或支持通配符删除的缓存驱动 Log::info('KatexRenderer: 缓存清除请求(需要手动清理或使用 Redis)'); } }