feat(config): add OCR URL configuration and improve image node handling

- Add VITE_OCR_URL environment variable with fallback URL construction
- Define IMAGE_NODE_TYPES constant to support 'image', 'image-block', and 'imageBlock' node types
- Add helper functions for safer image attribute access (getImageSrc, isImageNodeWithSrc, getImageLabel)
- Improve OCR error handling with HTTP status checking and error details
- Wrap OCR context in HTML comments to prevent prompt injection issues
- Update MilkdownEditor to use centralized OCR_URL configuration
This commit is contained in:
“ydy0615”
2026-02-14 21:21:06 +08:00
parent 64cfa58376
commit 794fbf8493
4 changed files with 58 additions and 15 deletions

View File

@@ -102,7 +102,7 @@ import { Crepe } from '@milkdown/crepe'
import { editorViewCtx } from '@milkdown/kit/core'
import { copilotPlugin, copilotConfigCtx, copilotGhostMark, setCopilotEnabled, COPILOT_PLUGIN_KEY, SIZE_LIMIT, checkSizeLimit } from '../plugins/copilotPlugin'
import { fetchSuggestion } from '../utils/api.js'
import { DEBUG, API_URL } from '../utils/config.js'
import { DEBUG, OCR_URL } from '../utils/config.js'
import { setOcrCache, clearOcrCache, clearAllOcrCache } from '../utils/ocrCache.js'
const emit = defineEmits(['update:markdown'])
@@ -125,6 +125,7 @@ const aiButtonLabel = computed(() => {
let crepe = null
let markdownSyncTimer = null
const objectUrls = new Set()
const IMAGE_NODE_TYPES = new Set(['image', 'image-block', 'imageBlock'])
const revokeObjectUrl = (url) => {
if (!objectUrls.has(url)) return
@@ -136,12 +137,12 @@ const revokeObjectUrl = (url) => {
const collectImageObjectUrls = (doc) => {
const activeUrls = new Set()
doc.descendants((node) => {
const src = typeof node.attrs?.src === 'string' ? node.attrs.src : ''
if (
node.type?.name === 'image' &&
typeof node.attrs?.src === 'string' &&
node.attrs.src.startsWith('blob:')
IMAGE_NODE_TYPES.has(node.type?.name) &&
src.startsWith('blob:')
) {
activeUrls.add(node.attrs.src)
activeUrls.add(src)
}
})
return activeUrls
@@ -219,8 +220,7 @@ const performOCR = async (file, cacheKey) => {
const base64 = dataUrl.slice(splitIndex + 1)
try {
const ocrUrl = API_URL.replace('/v1/completions', '/v1/ocr')
const res = await fetch(ocrUrl, {
const res = await fetch(OCR_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -229,6 +229,10 @@ const performOCR = async (file, cacheKey) => {
language: 'auto'
})
})
if (!res.ok) {
const errorText = await res.text()
throw new Error(`HTTP ${res.status}: ${errorText}`)
}
const data = await res.json()
if (data.text) {
setOcrCache(cacheKey, data.text)
@@ -240,7 +244,7 @@ const performOCR = async (file, cacheKey) => {
}
}
} catch (e) {
if (DEBUG) console.error('[OCR] Error:', e)
console.error('[OCR] Error:', e)
}
}
reader.readAsDataURL(file)