Add handwriting OCR pipeline and update documentation

- Introduce full OCR workflow: HWR extraction → PNG rendering → GLM-OCR → Ollama refinement
- Add new modules for page rendering, GLM-OCR client, style refinement, and ZIP utilities
- Update settings with drawj2d path and batch size controls
- Document Phase 2 completion and known limitations in IMPLEMENTATION.md
- Validate dependencies and handle cross-platform temp directory cleanup
  ```
This commit is contained in:
2026-05-31 14:34:38 +02:00
parent e39fbca087
commit 0211cf33f3
12 changed files with 794 additions and 63 deletions
+64
View File
@@ -0,0 +1,64 @@
import { GlmOcrResponse } from "../types";
import RemarkablePlugin from "../main";
import { runCommand } from "../utils/process";
export class GlmOcrClient {
plugin: RemarkablePlugin;
constructor(plugin: RemarkablePlugin) {
this.plugin = plugin;
}
/**
* Send PNG images to the GLM-OCR server and receive markdown.
*/
async parseImages(pngPaths: string[]): Promise<GlmOcrResponse> {
const url = `${this.plugin.settings.glmocrServerUrl}/glmocr/parse`;
// Build the request body with base64-encoded images
const images: string[] = [];
for (const pngPath of pngPaths) {
const base64 = await this.fileToBase64(pngPath);
images.push(`data:image/png;base64,${base64}`);
}
const body = JSON.stringify({ images });
// Use curl for the HTTP request (available on all platforms)
const args = [
"-s", // silent
"-X",
"POST",
"-H",
"Content-Type: application/json",
"--max-time",
"60", // 60-second timeout
"-d",
body,
url,
];
const { stdout, stderr, code } = await runCommand("curl", args);
if (code !== 0) {
throw new Error(`GLM-OCR request failed: ${stderr || stdout}`);
}
try {
const response = JSON.parse(stdout) as GlmOcrResponse;
return response;
} catch (e) {
throw new Error(`Failed to parse GLM-OCR response: ${e}\nRaw: ${stdout}`);
}
}
/**
* Convert a file to base64 string.
*/
private async fileToBase64(path: string): Promise<string> {
const { stdout, code, stderr } = await runCommand("base64", ["-w", "0", path]);
if (code !== 0) {
throw new Error(`base64 encoding failed: ${stderr}`);
}
return stdout.trim();
}
}