@lyra_wang/dsh-image-ocr 0.2.0 → 0.3.0

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.
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
  1. 截图到剪贴板(⌃⌘⇧4 选区域,或 ⌃⌘⇧3 全屏);
18
18
  2. 输入框左侧点「+ 识图」打开面板;
19
19
  3. 在面板里按 **⌘V 粘贴截图**(也可以把图片文件拖进来);
20
- 4. 面板里显示识别出的文字,可编辑;点「插入输入框」进草稿,或「复制」带走;
20
+ 4. 面板里显示识别出的文字,**可编辑、可选中**;选中一段后点「插入输入框」/「复制」只处理选中的部分(不选则处理全部);
21
21
  5. 底部还有「直接读剪贴板」按钮,跳过粘贴直接识别剪贴板里的图。
22
22
 
23
23
  第一次识别可能需要等 30–60 秒(在编译 OCR 引擎),之后再点就很快(实测 0.66s)。
package/client.js CHANGED
@@ -35,10 +35,11 @@ window.__ModuleLoader__.load({
35
35
  color:var(--dsw-alias-label-secondary,#9a9aa2);text-align:center;outline:none}
36
36
  .${ROOT}-drop[data-over="true"]{border-color:#4c8dff;background:rgba(76,141,255,.08)}
37
37
  .${ROOT}-drop img{max-width:100%;max-height:120px;border-radius:6px}
38
- .${ROOT}-textarea{all:unset;box-sizing:border-box;width:100%;min-height:120px;max-height:260px;overflow:auto;
38
+ .${ROOT}-textarea{all:unset;box-sizing:border-box;display:block;width:100%;min-height:120px;max-height:260px;overflow:auto;
39
39
  padding:8px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-1,#1f1f23);
40
40
  border:1px solid var(--dsw-alias-border-l1,#3a3a40);color:var(--dsw-alias-label-primary,#e6e6e9);
41
- font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap;user-select:text}
41
+ font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;white-space:pre-wrap;user-select:text;
42
+ resize:vertical}
42
43
  .${ROOT}-row{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
43
44
  .${ROOT}-action{all:unset;cursor:pointer;padding:5px 10px;border-radius:7px;
44
45
  background:var(--dsw-alias-bg-layer-2,#3a3a41);color:var(--dsw-alias-label-primary,#e6e6e9);font-size:12px}
@@ -82,6 +83,7 @@ window.__ModuleLoader__.load({
82
83
  const btnRef = useRef(null);
83
84
  const panelRef = useRef(null);
84
85
  const dropRef = useRef(null);
86
+ const textRef = useRef(null);
85
87
 
86
88
  const openPanel = () => {
87
89
  const rect = btnRef.current ? btnRef.current.getBoundingClientRect() : null;
@@ -169,21 +171,31 @@ window.__ModuleLoader__.load({
169
171
  return () => document.removeEventListener('keydown', onKey, true);
170
172
  }, [open]);
171
173
 
174
+ const selectedText = () => {
175
+ const el = textRef.current;
176
+ if (!el) return '';
177
+ const start = el.selectionStart ?? 0;
178
+ const end = el.selectionEnd ?? 0;
179
+ return start !== end ? text.slice(start, end) : '';
180
+ };
181
+
172
182
  const insert = () => {
173
- if (text.trim() === '') return;
183
+ const payload = selectedText() || text;
184
+ if (payload.trim() === '') return;
174
185
  if (inputActions && typeof inputActions.captureInsertion === 'function' && typeof inputActions.insertText === 'function') {
175
186
  const span = inputActions.captureInsertion();
176
- inputActions.insertText(text, span);
187
+ inputActions.insertText(payload, span);
177
188
  close();
178
189
  } else if (navigator.clipboard) {
179
- navigator.clipboard.writeText(text);
190
+ navigator.clipboard.writeText(payload);
180
191
  close();
181
192
  }
182
193
  };
183
194
 
184
195
  const copy = () => {
185
- if (text === '') return;
186
- if (navigator.clipboard) navigator.clipboard.writeText(text);
196
+ const payload = selectedText() || text;
197
+ if (payload === '') return;
198
+ if (navigator.clipboard) navigator.clipboard.writeText(payload);
187
199
  };
188
200
 
189
201
  const button = h('button', {
@@ -243,7 +255,17 @@ window.__ModuleLoader__.load({
243
255
  busy ? h('div', { key: 'busy', className: ROOT + '-hint' }, '识别中…(第一次可能需要 30–60 秒编译引擎)') : null,
244
256
  error !== '' ? h('div', { key: 'err', className: ROOT + '-error' }, error) : null,
245
257
  text !== '' || busy
246
- ? h('div', { key: 'out', className: ROOT + '-textarea' }, text)
258
+ ? h('textarea', {
259
+ key: 'out',
260
+ ref: textRef,
261
+ className: ROOT + '-textarea',
262
+ value: text,
263
+ spellCheck: false,
264
+ onChange: (event) => setText(event.target.value),
265
+ })
266
+ : null,
267
+ text !== ''
268
+ ? h('div', { key: 'select-hint', className: ROOT + '-hint' }, '可在结果里选中一段,再点「插入输入框」或「复制」只处理选中的部分')
247
269
  : null,
248
270
  h('div', { key: 'row', className: ROOT + '-row' }, [
249
271
  h('button', {
package/index.js CHANGED
@@ -135,7 +135,7 @@ export function apply(ctx) {
135
135
  const buffer = Buffer.from(base64, 'base64');
136
136
  if (buffer.length === 0) throw new Error('图片数据为空');
137
137
  if (buffer.length > 12 * 1024 * 1024) throw new Error('图片太大(上限 12MB)');
138
- tempPath = join(os.tmpdir(), 'dsh-image-ocr-' + Date.now() + '-' + Math.random().toString(16).slice(2, 8) + '.png');
138
+ tempPath = join(tmpdir(), 'dsh-image-ocr-' + Date.now() + '-' + Math.random().toString(16).slice(2, 8) + '.png');
139
139
  writeFileSync(tempPath, buffer);
140
140
  }
141
141
  const text = await runOcr(binary, tempPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyra_wang/dsh-image-ocr",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Composer + button: OCR the clipboard image locally (macOS Vision) and insert the text into the DSH input box.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/LyraWang6688/ai-capability-store.git",
19
- "directory": "external-capabilities/plugin/image-ocr"
19
+ "directory": "external-capabilities/plugin/dsh/image-ocr"
20
20
  },
21
21
  "exports": {
22
22
  ".": "./index.js",