@jungjaehoon/mama-os 0.26.0 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -1
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +92 -9
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/attachment-text-extractor.d.ts +2 -0
  7. package/dist/agent/attachment-text-extractor.d.ts.map +1 -0
  8. package/dist/agent/attachment-text-extractor.js +128 -0
  9. package/dist/agent/attachment-text-extractor.js.map +1 -0
  10. package/dist/agent/code-act/constants.d.ts.map +1 -1
  11. package/dist/agent/code-act/constants.js +17 -2
  12. package/dist/agent/code-act/constants.js.map +1 -1
  13. package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
  14. package/dist/agent/code-act/host-bridge.js +78 -5
  15. package/dist/agent/code-act/host-bridge.js.map +1 -1
  16. package/dist/agent/code-act/index.d.ts +2 -2
  17. package/dist/agent/code-act/index.d.ts.map +1 -1
  18. package/dist/agent/code-act/index.js +3 -1
  19. package/dist/agent/code-act/index.js.map +1 -1
  20. package/dist/agent/code-act/sandbox.d.ts +6 -2
  21. package/dist/agent/code-act/sandbox.d.ts.map +1 -1
  22. package/dist/agent/code-act/sandbox.js +275 -34
  23. package/dist/agent/code-act/sandbox.js.map +1 -1
  24. package/dist/agent/code-act/tool-policy.d.ts +7 -1
  25. package/dist/agent/code-act/tool-policy.d.ts.map +1 -1
  26. package/dist/agent/code-act/tool-policy.js +28 -1
  27. package/dist/agent/code-act/tool-policy.js.map +1 -1
  28. package/dist/agent/code-act/types.d.ts +20 -0
  29. package/dist/agent/code-act/types.d.ts.map +1 -1
  30. package/dist/agent/code-act/types.js +5 -1
  31. package/dist/agent/code-act/types.js.map +1 -1
  32. package/dist/agent/codex-app-server-process.d.ts +4 -1
  33. package/dist/agent/codex-app-server-process.d.ts.map +1 -1
  34. package/dist/agent/codex-app-server-process.js +45 -7
  35. package/dist/agent/codex-app-server-process.js.map +1 -1
  36. package/dist/agent/drive-tools.d.ts +6 -2
  37. package/dist/agent/drive-tools.d.ts.map +1 -1
  38. package/dist/agent/drive-tools.js +17 -6
  39. package/dist/agent/drive-tools.js.map +1 -1
  40. package/dist/agent/gateway-tool-executor.d.ts +10 -3
  41. package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
  42. package/dist/agent/gateway-tool-executor.js +232 -32
  43. package/dist/agent/gateway-tool-executor.js.map +1 -1
  44. package/dist/agent/gateway-tools.md +5 -1
  45. package/dist/agent/image-translation-tools.d.ts +48 -0
  46. package/dist/agent/image-translation-tools.d.ts.map +1 -0
  47. package/dist/agent/image-translation-tools.js +274 -0
  48. package/dist/agent/image-translation-tools.js.map +1 -0
  49. package/dist/agent/model-runner.d.ts +13 -0
  50. package/dist/agent/model-runner.d.ts.map +1 -1
  51. package/dist/agent/model-runner.js +17 -1
  52. package/dist/agent/model-runner.js.map +1 -1
  53. package/dist/agent/role-manager.d.ts.map +1 -1
  54. package/dist/agent/role-manager.js +9 -1
  55. package/dist/agent/role-manager.js.map +1 -1
  56. package/dist/agent/tool-registry.d.ts.map +1 -1
  57. package/dist/agent/tool-registry.js +25 -1
  58. package/dist/agent/tool-registry.js.map +1 -1
  59. package/dist/agent/types.d.ts +5 -34
  60. package/dist/agent/types.d.ts.map +1 -1
  61. package/dist/agent/types.js.map +1 -1
  62. package/dist/api/graph-api-types.d.ts +3 -0
  63. package/dist/api/graph-api-types.d.ts.map +1 -1
  64. package/dist/cli/commands/start.d.ts +11 -1
  65. package/dist/cli/commands/start.d.ts.map +1 -1
  66. package/dist/cli/commands/start.js +34 -17
  67. package/dist/cli/commands/start.js.map +1 -1
  68. package/dist/cli/config/types.d.ts.map +1 -1
  69. package/dist/cli/config/types.js +5 -1
  70. package/dist/cli/config/types.js.map +1 -1
  71. package/dist/cli/runtime/envelope-bootstrap.js +2 -2
  72. package/dist/cli/runtime/envelope-bootstrap.js.map +1 -1
  73. package/dist/gateways/message-router.d.ts +3 -0
  74. package/dist/gateways/message-router.d.ts.map +1 -1
  75. package/dist/gateways/message-router.js +428 -336
  76. package/dist/gateways/message-router.js.map +1 -1
  77. package/dist/gateways/session-store.d.ts +2 -0
  78. package/dist/gateways/session-store.d.ts.map +1 -1
  79. package/dist/gateways/session-store.js +41 -1
  80. package/dist/gateways/session-store.js.map +1 -1
  81. package/dist/gateways/telegram-media.d.ts +13 -0
  82. package/dist/gateways/telegram-media.d.ts.map +1 -1
  83. package/dist/gateways/telegram-media.js +77 -0
  84. package/dist/gateways/telegram-media.js.map +1 -1
  85. package/dist/gateways/telegram-message-ledger.d.ts +49 -0
  86. package/dist/gateways/telegram-message-ledger.d.ts.map +1 -0
  87. package/dist/gateways/telegram-message-ledger.js +266 -0
  88. package/dist/gateways/telegram-message-ledger.js.map +1 -0
  89. package/dist/gateways/telegram-response-presenter.d.ts +10 -0
  90. package/dist/gateways/telegram-response-presenter.d.ts.map +1 -1
  91. package/dist/gateways/telegram-response-presenter.js +129 -32
  92. package/dist/gateways/telegram-response-presenter.js.map +1 -1
  93. package/dist/gateways/telegram.d.ts +20 -4
  94. package/dist/gateways/telegram.d.ts.map +1 -1
  95. package/dist/gateways/telegram.js +300 -64
  96. package/dist/gateways/telegram.js.map +1 -1
  97. package/dist/mcp/code-act-api-client.d.ts +19 -0
  98. package/dist/mcp/code-act-api-client.d.ts.map +1 -0
  99. package/dist/mcp/code-act-api-client.js +80 -0
  100. package/dist/mcp/code-act-api-client.js.map +1 -0
  101. package/dist/mcp/code-act-server.js +18 -47
  102. package/dist/mcp/code-act-server.js.map +1 -1
  103. package/dist/mcp/code-act-terminal-transport.d.ts +35 -0
  104. package/dist/mcp/code-act-terminal-transport.d.ts.map +1 -0
  105. package/dist/mcp/code-act-terminal-transport.js +101 -0
  106. package/dist/mcp/code-act-terminal-transport.js.map +1 -0
  107. package/dist/multi-agent/runtime-process.d.ts +2 -1
  108. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  109. package/dist/multi-agent/runtime-process.js +11 -0
  110. package/dist/multi-agent/runtime-process.js.map +1 -1
  111. package/dist/operator/operator-interfaces.d.ts +1 -1
  112. package/dist/operator/operator-interfaces.d.ts.map +1 -1
  113. package/dist/operator/operator-trigger-loop.d.ts +12 -0
  114. package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
  115. package/dist/operator/operator-trigger-loop.js +184 -38
  116. package/dist/operator/operator-trigger-loop.js.map +1 -1
  117. package/dist/operator/pending-report-store.d.ts +35 -0
  118. package/dist/operator/pending-report-store.d.ts.map +1 -0
  119. package/dist/operator/pending-report-store.js +155 -0
  120. package/dist/operator/pending-report-store.js.map +1 -0
  121. package/dist/operator/runtime-config.d.ts +10 -0
  122. package/dist/operator/runtime-config.d.ts.map +1 -0
  123. package/dist/operator/runtime-config.js +21 -0
  124. package/dist/operator/runtime-config.js.map +1 -0
  125. package/dist/operator/situation-report.d.ts +37 -0
  126. package/dist/operator/situation-report.d.ts.map +1 -1
  127. package/dist/operator/situation-report.js +122 -9
  128. package/dist/operator/situation-report.js.map +1 -1
  129. package/dist/operator/task-ledger.d.ts +2 -1
  130. package/dist/operator/task-ledger.d.ts.map +1 -1
  131. package/dist/operator/task-ledger.js +11 -2
  132. package/dist/operator/task-ledger.js.map +1 -1
  133. package/dist/operator/workorder-consumer.d.ts +2 -1
  134. package/dist/operator/workorder-consumer.d.ts.map +1 -1
  135. package/dist/operator/workorder-consumer.js +43 -16
  136. package/dist/operator/workorder-consumer.js.map +1 -1
  137. package/dist/tools/browser-tool.d.ts +4 -2
  138. package/dist/tools/browser-tool.d.ts.map +1 -1
  139. package/dist/tools/browser-tool.js +56 -18
  140. package/dist/tools/browser-tool.js.map +1 -1
  141. package/package.json +3 -1
  142. package/scripts/attachment/extract-office-text.js +179 -0
  143. package/scripts/attachment/extract-pdf-text.swift +36 -0
  144. package/scripts/image/fb-overlay.py +128 -0
  145. package/scripts/image/ocr-image.py +38 -0
  146. package/scripts/setup-ocr.js +120 -0
  147. package/templates/skills/image-translate.md +17 -22
@@ -8,6 +8,9 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.BrowserTool = void 0;
10
10
  exports.getBrowserTool = getBrowserTool;
11
+ const node_fs_1 = require("node:fs");
12
+ const node_path_1 = require("node:path");
13
+ const node_crypto_1 = require("node:crypto");
11
14
  const DEFAULT_CONFIG = {
12
15
  headless: true,
13
16
  viewportWidth: 1280,
@@ -69,6 +72,29 @@ class BrowserTool {
69
72
  }
70
73
  return this.page;
71
74
  }
75
+ screenshotPaths(filename, prefix) {
76
+ const configuredRoot = (0, node_path_1.resolve)(this.config.screenshotDir);
77
+ (0, node_fs_1.mkdirSync)(configuredRoot, { recursive: true });
78
+ const root = (0, node_fs_1.realpathSync)(configuredRoot);
79
+ const name = filename?.trim() || `${prefix}-${Date.now()}-${(0, node_crypto_1.randomUUID)()}.png`;
80
+ if (name !== (0, node_path_1.basename)(name)) {
81
+ throw new Error('Screenshot filename must not contain directory components');
82
+ }
83
+ const outputPath = (0, node_path_1.resolve)(root, name);
84
+ const relativePath = (0, node_path_1.relative)(root, outputPath);
85
+ if (!relativePath || relativePath.startsWith('..') || (0, node_path_1.isAbsolute)(relativePath)) {
86
+ throw new Error('Screenshot filename must resolve inside the configured screenshot directory');
87
+ }
88
+ return {
89
+ outputPath,
90
+ temporaryPath: (0, node_path_1.resolve)(root, `.mama-screenshot-${(0, node_crypto_1.randomUUID)()}.tmp.png`),
91
+ };
92
+ }
93
+ removeOwnedArtifact(path) {
94
+ if ((0, node_fs_1.existsSync)(path)) {
95
+ (0, node_fs_1.unlinkSync)(path);
96
+ }
97
+ }
72
98
  /**
73
99
  * Navigate to URL
74
100
  */
@@ -86,32 +112,44 @@ class BrowserTool {
86
112
  /**
87
113
  * Take screenshot
88
114
  */
89
- async screenshot(filename) {
115
+ async screenshot(filename, signal) {
116
+ signal?.throwIfAborted();
90
117
  const page = await this.ensureBrowser();
91
- const { mkdirSync, existsSync } = await import('fs');
92
- if (!existsSync(this.config.screenshotDir)) {
93
- mkdirSync(this.config.screenshotDir, { recursive: true });
118
+ signal?.throwIfAborted();
119
+ const { outputPath, temporaryPath } = this.screenshotPaths(filename, 'screenshot');
120
+ try {
121
+ await page.screenshot({ path: temporaryPath, fullPage: false });
122
+ signal?.throwIfAborted();
123
+ (0, node_fs_1.copyFileSync)(temporaryPath, outputPath, node_fs_1.constants.COPYFILE_EXCL);
124
+ this.removeOwnedArtifact(temporaryPath);
94
125
  }
95
- const name = filename || `screenshot-${Date.now()}.png`;
96
- const path = `${this.config.screenshotDir}/${name}`;
97
- await page.screenshot({ path, fullPage: false });
98
- console.log(`[Browser] Screenshot saved: ${path}`);
99
- return { success: true, path };
126
+ catch (error) {
127
+ this.removeOwnedArtifact(temporaryPath);
128
+ throw error;
129
+ }
130
+ console.log(`[Browser] Screenshot saved: ${outputPath}`);
131
+ return { success: true, path: outputPath };
100
132
  }
101
133
  /**
102
134
  * Take full page screenshot
103
135
  */
104
- async screenshotFullPage(filename) {
136
+ async screenshotFullPage(filename, signal) {
137
+ signal?.throwIfAborted();
105
138
  const page = await this.ensureBrowser();
106
- const { mkdirSync, existsSync } = await import('fs');
107
- if (!existsSync(this.config.screenshotDir)) {
108
- mkdirSync(this.config.screenshotDir, { recursive: true });
139
+ signal?.throwIfAborted();
140
+ const { outputPath, temporaryPath } = this.screenshotPaths(filename, 'fullpage');
141
+ try {
142
+ await page.screenshot({ path: temporaryPath, fullPage: true });
143
+ signal?.throwIfAborted();
144
+ (0, node_fs_1.copyFileSync)(temporaryPath, outputPath, node_fs_1.constants.COPYFILE_EXCL);
145
+ this.removeOwnedArtifact(temporaryPath);
109
146
  }
110
- const name = filename || `fullpage-${Date.now()}.png`;
111
- const path = `${this.config.screenshotDir}/${name}`;
112
- await page.screenshot({ path, fullPage: true });
113
- console.log(`[Browser] Full page screenshot saved: ${path}`);
114
- return { success: true, path };
147
+ catch (error) {
148
+ this.removeOwnedArtifact(temporaryPath);
149
+ throw error;
150
+ }
151
+ console.log(`[Browser] Full page screenshot saved: ${outputPath}`);
152
+ return { success: true, path: outputPath };
115
153
  }
116
154
  /**
117
155
  * Click element by selector
@@ -1 +1 @@
1
- {"version":3,"file":"browser-tool.js","sourceRoot":"","sources":["../../src/tools/browser-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser-tool.js","sourceRoot":"","sources":["../../src/tools/browser-tool.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA+XH,wCAKC;AAjYD,qCAAmG;AACnG,yCAAoE;AACpE,6CAAyC;AAezC,MAAM,cAAc,GAAgC;IAClD,QAAQ,EAAE,IAAI;IACd,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,GAAG;IACnB,aAAa,EAAE,uBAAuB;IACtC,WAAW,EAAE,UAAU;CACxB,CAAC;AAEF,MAAa,WAAW;IACd,MAAM,CAA8B;IACpC,OAAO,GAAmB,IAAI,CAAC;IAC/B,OAAO,GAA0B,IAAI,CAAC;IACtC,IAAI,GAAgB,IAAI,CAAC;IAEjC,YAAY,SAA4B,EAAE;QACxC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,CAAC;QAEjE,0CAA0C;QAC1C,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;QAE9C,sBAAsB;QACtB,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAExD,IAAI,CAAC,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC;YACtC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;SAC/B,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YAC3C,QAAQ,EAAE;gBACR,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa;gBAChC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc;aACnC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAEzC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,aAAa;QACzB,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACtB,CAAC;QACD,OAAO,IAAI,CAAC,IAAK,CAAC;IACpB,CAAC;IAEO,eAAe,CACrB,QAA4B,EAC5B,MAAc;QAKd,MAAM,cAAc,GAAG,IAAA,mBAAO,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC1D,IAAA,mBAAS,EAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAA,sBAAY,EAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAA,wBAAU,GAAE,MAAM,CAAC;QAC/E,IAAI,IAAI,KAAK,IAAA,oBAAQ,EAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,UAAU,GAAG,IAAA,mBAAO,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,MAAM,YAAY,GAAG,IAAA,oBAAQ,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAChD,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAA,sBAAU,EAAC,YAAY,CAAC,EAAE,CAAC;YAC/E,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QACD,OAAO;YACL,UAAU;YACV,aAAa,EAAE,IAAA,mBAAO,EAAC,IAAI,EAAE,oBAAoB,IAAA,wBAAU,GAAE,UAAU,CAAC;SACzE,CAAC;IACJ,CAAC;IAEO,mBAAmB,CAAC,IAAY;QACtC,IAAI,IAAA,oBAAU,EAAC,IAAI,CAAC,EAAE,CAAC;YACrB,IAAA,oBAAU,EAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,GAAW;QACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;QAE/C,8DAA8D;QAC9D,8EAA8E;QAC9E,uDAAuD;QACvD,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAE5D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE9B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CACd,QAAiB,EACjB,MAAoB;QAEpB,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,EAAE,cAAc,EAAE,CAAC;QAEzB,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAEnF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YAChE,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,IAAA,sBAAY,EAAC,aAAa,EAAE,UAAU,EAAE,mBAAS,CAAC,aAAa,CAAC,CAAC;YACjE,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;YACxC,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;QAEzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,QAAiB,EACjB,MAAoB;QAEpB,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,EAAE,cAAc,EAAE,CAAC;QAEzB,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAEjF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/D,MAAM,EAAE,cAAc,EAAE,CAAC;YACzB,IAAA,sBAAY,EAAC,aAAa,EAAE,UAAU,EAAE,mBAAS,CAAC,aAAa,CAAC,CAAC;YACjE,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;YACxC,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,yCAAyC,UAAU,EAAE,CAAC,CAAC;QAEnE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,QAAgB;QAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,uBAAuB,QAAQ,EAAE,CAAC,CAAC;QAE/C,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,IAAY;QACvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QAElD,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,OAAO,GAAG,KAAK;QAC7C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QAElD,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,MAAc;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAE9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,QAAgB;QACnC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC9C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC9E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAa,EAAE,CAAC;IAC7F,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CACV,SAA2C,EAC3C,MAAM,GAAG,GAAG;QAEZ,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAExC,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,IAAI;gBACP,MAAM,IAAI,CAAC,QAAQ,CAAC,uBAAuB,MAAM,GAAG,CAAC,CAAC;gBACtD,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,IAAI,CAAC,QAAQ,CAAC,sBAAsB,MAAM,GAAG,CAAC,CAAC;gBACrD,MAAM;YACR,KAAK,KAAK;gBACR,MAAM,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC;gBAC7C,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,IAAI,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAC;gBACtE,MAAM;QACV,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,GAAW;QACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACxC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,QAAiB;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAExC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;YAC3C,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,IAAI,QAAQ,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC;QAClD,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,IAAI,EAAE,CAAC;QAEpD,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;QAE5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,CAAC;CACF;AA9VD,kCA8VC;AAED,qBAAqB;AACrB,IAAI,QAAQ,GAAuB,IAAI,CAAC;AAExC,SAAgB,cAAc,CAAC,MAA0B;IACvD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jungjaehoon/mama-os",
3
- "version": "0.26.0",
3
+ "version": "0.27.1",
4
4
  "description": "MAMA OS - Local AI Runtime. Your scattered knowledge, organized by AI agents that never sleep.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -11,6 +11,8 @@
11
11
  },
12
12
  "scripts": {
13
13
  "postinstall": "node scripts/postinstall.js",
14
+ "setup:ocr": "node scripts/setup-ocr.js",
15
+ "check:ocr": "node scripts/setup-ocr.js --check",
14
16
  "build": "tsc && pnpm exec tsx scripts/generate-gateway-tools.ts && rm -rf public/viewer/js && tsc -p public/viewer/tsconfig.viewer.json && pnpm run build:ui",
15
17
  "build:ui": "pnpm --dir ui run bundle",
16
18
  "dev:ui": "pnpm --dir ui run dev",
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { readFileSync, statSync } = require('node:fs');
4
+ const { inflateRawSync } = require('node:zlib');
5
+
6
+ const MAX_ARCHIVE_BYTES = 64 * 1024 * 1024;
7
+ const MAX_ARCHIVE_ENTRIES = 2_000;
8
+
9
+ const [, , filePath, extension, maxOutputRaw] = process.argv;
10
+ const maxOutputBytes = Number(maxOutputRaw);
11
+ if (!filePath || !['.docx', '.xlsx'].includes(extension) || !Number.isSafeInteger(maxOutputBytes)) {
12
+ throw new Error('usage: extract-office-text.js <path> <.docx|.xlsx> <max-output-bytes>');
13
+ }
14
+
15
+ const prefixes =
16
+ extension === '.docx' ? ['word/document.xml'] : ['xl/sharedStrings.xml', 'xl/worksheets/'];
17
+ const entries = readOfficeEntries(filePath, prefixes);
18
+ const text = extension === '.docx' ? extractDocxText(entries) : extractXlsxText(entries);
19
+ process.stdout.write(truncateUtf8(text, maxOutputBytes));
20
+
21
+ function readOfficeEntries(path, wantedPrefixes) {
22
+ if (statSync(path).size > MAX_ARCHIVE_BYTES) {
23
+ throw new Error('Office attachment is too large');
24
+ }
25
+ const archive = readFileSync(path);
26
+ const endOffset = findEndOfCentralDirectory(archive);
27
+ const entryCount = archive.readUInt16LE(endOffset + 10);
28
+ const centralOffset = archive.readUInt32LE(endOffset + 16);
29
+ if (entryCount > MAX_ARCHIVE_ENTRIES) {
30
+ throw new Error('Office attachment has too many entries');
31
+ }
32
+ const result = new Map();
33
+ let cursor = centralOffset;
34
+ let extractedBytes = 0;
35
+ for (let index = 0; index < entryCount; index += 1) {
36
+ requireSignature(archive, cursor, 0x02014b50, 'central directory');
37
+ const flags = archive.readUInt16LE(cursor + 8);
38
+ const method = archive.readUInt16LE(cursor + 10);
39
+ const compressedSize = archive.readUInt32LE(cursor + 20);
40
+ const uncompressedSize = archive.readUInt32LE(cursor + 24);
41
+ const nameLength = archive.readUInt16LE(cursor + 28);
42
+ const extraLength = archive.readUInt16LE(cursor + 30);
43
+ const commentLength = archive.readUInt16LE(cursor + 32);
44
+ const localOffset = archive.readUInt32LE(cursor + 42);
45
+ const nameStart = cursor + 46;
46
+ const name = archive.subarray(nameStart, nameStart + nameLength).toString('utf8');
47
+ cursor = nameStart + nameLength + extraLength + commentLength;
48
+ if (!wantedPrefixes.some((prefix) => name === prefix || name.startsWith(prefix))) {
49
+ continue;
50
+ }
51
+ if ((flags & 0x1) !== 0) {
52
+ throw new Error('Encrypted Office attachments are not supported');
53
+ }
54
+ extractedBytes += uncompressedSize;
55
+ if (extractedBytes > MAX_ARCHIVE_BYTES) {
56
+ throw new Error('Office attachment expands too far');
57
+ }
58
+ requireSignature(archive, localOffset, 0x04034b50, 'local file header');
59
+ const nameSize = archive.readUInt16LE(localOffset + 26);
60
+ const extraSize = archive.readUInt16LE(localOffset + 28);
61
+ const dataStart = localOffset + 30 + nameSize + extraSize;
62
+ const compressed = archive.subarray(dataStart, dataStart + compressedSize);
63
+ const data =
64
+ method === 0
65
+ ? compressed
66
+ : method === 8
67
+ ? inflateRawSync(compressed, { maxOutputLength: MAX_ARCHIVE_BYTES })
68
+ : unsupportedCompression(method);
69
+ if (data.length !== uncompressedSize) {
70
+ throw new Error('Corrupt Office entry');
71
+ }
72
+ result.set(name, data.toString('utf8'));
73
+ }
74
+ return result;
75
+ }
76
+
77
+ function findEndOfCentralDirectory(archive) {
78
+ const minimumOffset = Math.max(0, archive.length - 65_557);
79
+ for (let cursor = archive.length - 22; cursor >= minimumOffset; cursor -= 1) {
80
+ if (archive.readUInt32LE(cursor) === 0x06054b50) {
81
+ return cursor;
82
+ }
83
+ }
84
+ throw new Error('Invalid Office attachment: ZIP directory not found');
85
+ }
86
+
87
+ function requireSignature(archive, offset, expected, label) {
88
+ if (offset < 0 || offset + 4 > archive.length || archive.readUInt32LE(offset) !== expected) {
89
+ throw new Error(`Invalid Office attachment ${label}`);
90
+ }
91
+ }
92
+
93
+ function unsupportedCompression(method) {
94
+ throw new Error(`Unsupported Office compression method: ${method}`);
95
+ }
96
+
97
+ function extractDocxText(entries) {
98
+ const xml = entries.get('word/document.xml');
99
+ if (!xml) {
100
+ throw new Error('Invalid DOCX attachment: word/document.xml is missing');
101
+ }
102
+ return [...xml.matchAll(/<w:p\b[^>]*>([\s\S]*?)<\/w:p>/g)]
103
+ .map((match) => extractXmlText(match[1], 'w:t'))
104
+ .filter(Boolean)
105
+ .join('\n');
106
+ }
107
+
108
+ function extractXlsxText(entries) {
109
+ const sharedXml = entries.get('xl/sharedStrings.xml') || '';
110
+ const shared = [...sharedXml.matchAll(/<si\b[^>]*>([\s\S]*?)<\/si>/g)].map((match) =>
111
+ extractXmlText(match[1], 't')
112
+ );
113
+ const sheets = [...entries.entries()]
114
+ .filter(([name]) => /^xl\/worksheets\/sheet[^/]*\.xml$/.test(name))
115
+ .sort(([left], [right]) => left.localeCompare(right));
116
+ if (sheets.length === 0) {
117
+ throw new Error('Invalid XLSX attachment: no worksheets found');
118
+ }
119
+ const lines = [];
120
+ for (const [name, xml] of sheets) {
121
+ lines.push(`[${name.slice(name.lastIndexOf('/') + 1, -4)}]`);
122
+ for (const cell of xml.matchAll(/<c\b([^>]*)>([\s\S]*?)<\/c>/g)) {
123
+ const reference = readXmlAttribute(cell[1], 'r') || '?';
124
+ const type = readXmlAttribute(cell[1], 't');
125
+ const raw = firstXmlTagText(cell[2], 'v');
126
+ const value =
127
+ type === 's'
128
+ ? shared[Number(raw)] || ''
129
+ : type === 'inlineStr'
130
+ ? extractXmlText(cell[2], 't')
131
+ : decodeXmlEntities(raw);
132
+ if (value) {
133
+ lines.push(`${reference}=${value}`);
134
+ }
135
+ }
136
+ }
137
+ return lines.join('\n');
138
+ }
139
+
140
+ function extractXmlText(xml, tagName) {
141
+ const tag = tagName.replace(':', '\\:');
142
+ return [...xml.matchAll(new RegExp(`<${tag}\\b[^>]*>([\\s\\S]*?)<\\/${tag}>`, 'g'))]
143
+ .map((match) => decodeXmlEntities(match[1]))
144
+ .join('');
145
+ }
146
+
147
+ function firstXmlTagText(xml, tagName) {
148
+ const match = new RegExp(`<${tagName}\\b[^>]*>([\\s\\S]*?)<\\/${tagName}>`).exec(xml);
149
+ return match ? decodeXmlEntities(match[1]) : '';
150
+ }
151
+
152
+ function readXmlAttribute(attributes, name) {
153
+ const match = new RegExp(`(?:^|\\s)${name}=(?:"([^"]*)"|'([^']*)')`).exec(attributes);
154
+ return match ? match[1] || match[2] : undefined;
155
+ }
156
+
157
+ function decodeXmlEntities(value) {
158
+ return value
159
+ .replace(/<[^>]+>/g, '')
160
+ .replace(/&lt;/g, '<')
161
+ .replace(/&gt;/g, '>')
162
+ .replace(/&quot;/g, '"')
163
+ .replace(/&apos;/g, "'")
164
+ .replace(/&amp;/g, '&')
165
+ .replace(/&#(\d+);/g, (_match, code) => String.fromCodePoint(Number(code)))
166
+ .replace(/&#x([0-9a-f]+);/gi, (_match, code) => String.fromCodePoint(parseInt(code, 16)));
167
+ }
168
+
169
+ function truncateUtf8(content, maxBytes) {
170
+ const bytes = Buffer.from(content);
171
+ if (bytes.length <= maxBytes) {
172
+ return content;
173
+ }
174
+ let end = maxBytes;
175
+ while (end > 0 && (bytes[end] & 0xc0) === 0x80) {
176
+ end -= 1;
177
+ }
178
+ return `${bytes.subarray(0, end).toString('utf8')}\n\n[Truncated at ${maxBytes} bytes]`;
179
+ }
@@ -0,0 +1,36 @@
1
+ import Foundation
2
+ import PDFKit
3
+
4
+ guard CommandLine.arguments.count == 3, let maxBytes = Int(CommandLine.arguments[2]), maxBytes > 0 else {
5
+ fputs("usage: extract-pdf-text.swift <pdf-path> <max-output-bytes>\n", stderr)
6
+ exit(2)
7
+ }
8
+
9
+ let url = URL(fileURLWithPath: CommandLine.arguments[1])
10
+ guard let document = PDFDocument(url: url) else {
11
+ fputs("unable to open PDF\n", stderr)
12
+ exit(1)
13
+ }
14
+
15
+ var written = 0
16
+ for index in 0..<document.pageCount {
17
+ if let text = document.page(at: index)?.string, !text.isEmpty {
18
+ let separator = written == 0 ? "" : "\n\n"
19
+ let data = (separator + text).data(using: .utf8) ?? Data()
20
+ let remaining = maxBytes - written
21
+ if remaining <= 0 { break }
22
+ var bounded = Data()
23
+ var prefixLength = min(remaining, data.count)
24
+ while prefixLength > 0 {
25
+ let candidate = Data(data.prefix(prefixLength))
26
+ if String(data: candidate, encoding: .utf8) != nil {
27
+ bounded = candidate
28
+ break
29
+ }
30
+ prefixLength -= 1
31
+ }
32
+ FileHandle.standardOutput.write(bounded)
33
+ written += bounded.count
34
+ if bounded.count < data.count { break }
35
+ }
36
+ }
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env python3
2
+ """Render translated text over OCR regions and return the output path as JSON."""
3
+
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+
10
+ PADDING = 10
11
+ MIN_FONT_SIZE = 18
12
+
13
+
14
+ def font_candidates():
15
+ configured = os.environ.get("MAMA_KOREAN_FONT")
16
+ return [
17
+ configured,
18
+ "/System/Library/Fonts/AppleSDGothicNeo.ttc",
19
+ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
20
+ "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
21
+ ]
22
+
23
+
24
+ def load_font(image_draw, text, max_width, start_size):
25
+ from PIL import ImageFont
26
+
27
+ for candidate in font_candidates():
28
+ if not candidate or not Path(candidate).exists():
29
+ continue
30
+ size = max(start_size, MIN_FONT_SIZE)
31
+ while size >= MIN_FONT_SIZE:
32
+ font = ImageFont.truetype(candidate, size)
33
+ bounds = image_draw.textbbox((0, 0), text, font=font)
34
+ if bounds[2] - bounds[0] <= max_width or size == MIN_FONT_SIZE:
35
+ return font
36
+ size -= 1
37
+ raise RuntimeError("Korean font not found; set MAMA_KOREAN_FONT")
38
+
39
+
40
+ def sample_text_color(array, points):
41
+ import numpy
42
+
43
+ x1 = max(min(point[0] for point in points), 0)
44
+ y1 = max(min(point[1] for point in points), 0)
45
+ x2 = min(max(point[0] for point in points), array.shape[1])
46
+ y2 = min(max(point[1] for point in points), array.shape[0])
47
+ region = array[y1:y2, x1:x2]
48
+ if region.size == 0:
49
+ return (20, 20, 20)
50
+ dark_pixels = region.reshape(-1, 3)[region.mean(axis=2).flatten() < 80]
51
+ if len(dark_pixels) < 3:
52
+ return (20, 20, 20)
53
+ return tuple(int(channel) for channel in dark_pixels.mean(axis=0))
54
+
55
+
56
+ def main():
57
+ if len(sys.argv) < 3:
58
+ raise ValueError("Usage: fb-overlay.py <image> <annotations.json> [output.png]")
59
+
60
+ from PIL import Image, ImageDraw
61
+ import numpy
62
+
63
+ image_path = sys.argv[1]
64
+ annotations_path = sys.argv[2]
65
+ output_path = (
66
+ sys.argv[3]
67
+ if len(sys.argv) > 3
68
+ else str(Path(image_path).with_name(f"{Path(image_path).stem}_KR.png"))
69
+ )
70
+ with open(annotations_path, encoding="utf-8") as handle:
71
+ annotations = json.load(handle)
72
+
73
+ original = Image.open(image_path).convert("RGB")
74
+ image = original.copy()
75
+ pixels = numpy.array(original)
76
+ draw = ImageDraw.Draw(image)
77
+ render_items = []
78
+
79
+ for annotation in annotations:
80
+ points = annotation["bbox"]
81
+ translated = annotation.get("translated", "")
82
+ if not translated:
83
+ continue
84
+ x1 = min(point[0] for point in points)
85
+ y1 = min(point[1] for point in points)
86
+ x2 = max(point[0] for point in points)
87
+ y2 = max(point[1] for point in points)
88
+ font = load_font(draw, translated, x2 - x1, int((y2 - y1) * 0.92))
89
+ bounds = draw.textbbox((0, 0), translated, font=font)
90
+ width = bounds[2] - bounds[0]
91
+ height = bounds[3] - bounds[1]
92
+ render_items.append(
93
+ {
94
+ "box": (
95
+ x1 - PADDING,
96
+ y1 - PADDING,
97
+ max(x2, x1 + width) + PADDING,
98
+ max(y2, y1 + height + 4) + PADDING,
99
+ ),
100
+ "text": translated,
101
+ "font": font,
102
+ "color": sample_text_color(pixels, points),
103
+ "height": height,
104
+ }
105
+ )
106
+
107
+ for item in render_items:
108
+ draw.rectangle(list(item["box"]), fill=(255, 255, 255))
109
+ for item in render_items:
110
+ x1, y1, _x2, y2 = item["box"]
111
+ text_y = y1 + ((y2 - y1) - item["height"]) // 2
112
+ draw.text(
113
+ (x1 + PADDING, text_y),
114
+ item["text"],
115
+ font=item["font"],
116
+ fill=item["color"],
117
+ )
118
+
119
+ image.save(output_path, quality=95)
120
+ print(json.dumps({"outputPath": output_path}, ensure_ascii=False))
121
+
122
+
123
+ if __name__ == "__main__":
124
+ try:
125
+ main()
126
+ except Exception as error:
127
+ print(json.dumps({"error": str(error)}, ensure_ascii=False), file=sys.stderr)
128
+ sys.exit(1)
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python3
2
+ """Extract OCR regions as JSON for MAMA image translation tools."""
3
+
4
+ import json
5
+ import sys
6
+
7
+
8
+ def main():
9
+ if len(sys.argv) < 2:
10
+ raise ValueError("Usage: ocr-image.py <image_path> [--lang ja,en]")
11
+
12
+ image_path = sys.argv[1]
13
+ languages = ["ja", "en"]
14
+ for index, argument in enumerate(sys.argv[2:], 2):
15
+ if argument == "--lang" and index + 1 < len(sys.argv):
16
+ languages = sys.argv[index + 1].split(",")
17
+
18
+ import easyocr
19
+
20
+ reader = easyocr.Reader(languages, gpu=False, verbose=False)
21
+ output = []
22
+ for bbox, text, confidence in reader.readtext(image_path, detail=1):
23
+ output.append(
24
+ {
25
+ "bbox": [[int(point[0]), int(point[1])] for point in bbox],
26
+ "text": text,
27
+ "conf": round(confidence, 2),
28
+ }
29
+ )
30
+ print(json.dumps(output, ensure_ascii=False))
31
+
32
+
33
+ if __name__ == "__main__":
34
+ try:
35
+ main()
36
+ except Exception as error:
37
+ print(json.dumps({"error": str(error)}, ensure_ascii=False), file=sys.stderr)
38
+ sys.exit(1)
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { existsSync, mkdirSync } = require('node:fs');
4
+ const { homedir } = require('node:os');
5
+ const { dirname, join, resolve } = require('node:path');
6
+ const { spawnSync } = require('node:child_process');
7
+
8
+ const REQUIREMENTS = ['easyocr==1.7.2', 'Pillow>=10,<13', 'numpy>=1.26,<3'];
9
+ const FONT_GUIDANCE =
10
+ 'Install a Korean/CJK font (Ubuntu/Debian: apt install fonts-noto-cjk) or set ' +
11
+ 'MAMA_KOREAN_FONT to a readable .ttf/.ttc font file.';
12
+ const RUNTIME_CHECK = String.raw`
13
+ import os
14
+ from pathlib import Path
15
+ import easyocr, PIL, numpy
16
+ from PIL import ImageFont
17
+
18
+ candidates = [
19
+ os.environ.get("MAMA_KOREAN_FONT"),
20
+ "/System/Library/Fonts/AppleSDGothicNeo.ttc",
21
+ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
22
+ "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
23
+ ]
24
+ for candidate in candidates:
25
+ if not candidate or not Path(candidate).is_file():
26
+ continue
27
+ try:
28
+ font = ImageFont.truetype(candidate, 18)
29
+ if font.getbbox("한글"):
30
+ print(easyocr.__version__)
31
+ raise SystemExit(0)
32
+ except OSError:
33
+ pass
34
+ raise SystemExit("Korean/CJK font is unavailable")
35
+ `;
36
+
37
+ function runtimeRoot() {
38
+ return resolve(process.env.MAMA_OCR_ENV || join(homedir(), '.mama', 'ocr-env'));
39
+ }
40
+
41
+ function runtimePython(root) {
42
+ return process.platform === 'win32'
43
+ ? join(root, 'Scripts', 'python.exe')
44
+ : join(root, 'bin', 'python3');
45
+ }
46
+
47
+ function run(command, args, options = {}) {
48
+ const result = spawnSync(command, args, {
49
+ stdio: options.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
50
+ encoding: 'utf8',
51
+ env: process.env,
52
+ });
53
+ if (result.error || result.status !== 0) {
54
+ const detail = result.error?.message || result.stderr?.trim() || `exit ${result.status}`;
55
+ throw new Error(`${command} ${args.join(' ')} failed: ${detail}`);
56
+ }
57
+ return result.stdout || '';
58
+ }
59
+
60
+ function check() {
61
+ const python = runtimePython(runtimeRoot());
62
+ if (!existsSync(python)) {
63
+ return false;
64
+ }
65
+ try {
66
+ run(python, ['-c', RUNTIME_CHECK], { capture: true });
67
+ return true;
68
+ } catch {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ function setup() {
74
+ const root = runtimeRoot();
75
+ const bootstrapPython = process.env.MAMA_OCR_BOOTSTRAP_PYTHON || 'python3';
76
+ mkdirSync(dirname(root), { recursive: true, mode: 0o700 });
77
+ if (!existsSync(runtimePython(root))) {
78
+ run(bootstrapPython, ['-m', 'venv', root]);
79
+ }
80
+ const python = runtimePython(root);
81
+ run(python, ['-m', 'pip', 'install', '--upgrade', 'pip']);
82
+ run(python, ['-m', 'pip', 'install', ...REQUIREMENTS]);
83
+ if (!check()) {
84
+ throw new Error(`MAMA OCR runtime failed its dependency/font check. ${FONT_GUIDANCE}`);
85
+ }
86
+ process.stdout.write(`MAMA OCR runtime ready: ${python}\n`);
87
+ }
88
+
89
+ function main() {
90
+ const command = process.argv[2];
91
+ if (command === '--print-requirements') {
92
+ process.stdout.write(`${REQUIREMENTS.join('\n')}\n`);
93
+ return;
94
+ }
95
+ if (command === '--print-font-guidance') {
96
+ process.stdout.write(`${FONT_GUIDANCE}\n`);
97
+ return;
98
+ }
99
+ if (command === '--check') {
100
+ if (check()) {
101
+ process.stdout.write(`MAMA OCR runtime ready: ${runtimePython(runtimeRoot())}\n`);
102
+ return;
103
+ }
104
+ process.stderr.write(
105
+ `MAMA OCR runtime is not ready at ${runtimeRoot()}. Run: pnpm setup:ocr\n${FONT_GUIDANCE}\n`
106
+ );
107
+ process.exitCode = 1;
108
+ return;
109
+ }
110
+ setup();
111
+ }
112
+
113
+ try {
114
+ main();
115
+ } catch (error) {
116
+ process.stderr.write(
117
+ `MAMA OCR setup failed: ${error instanceof Error ? error.message : error}\n`
118
+ );
119
+ process.exitCode = 1;
120
+ }