后端迁移会话运行时模块
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { runtimeConfig } from '../../config/runtime.js'
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 60_000
|
||||
|
||||
type OcrAction = 'recognize' | 'batch'
|
||||
|
||||
type OcrRequestPayload = Record<string, unknown>
|
||||
|
||||
type OcrHttpResult = Record<string, any> & {
|
||||
code: number
|
||||
msg?: string
|
||||
}
|
||||
|
||||
export async function recognizeTencentCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
|
||||
return callOcrViaHttp('recognize', payload)
|
||||
}
|
||||
|
||||
export async function recognizeImageCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
|
||||
return callOcrViaHttp('recognize', payload)
|
||||
}
|
||||
|
||||
export async function batchRecognizeTencentCaptcha(payload: OcrRequestPayload): Promise<OcrHttpResult> {
|
||||
return callOcrViaHttp('batch', payload, { timeoutMs: 180_000 })
|
||||
}
|
||||
|
||||
export async function warmupLocalOcrWorker(): Promise<void> {
|
||||
await warmupOcrViaHttp()
|
||||
}
|
||||
|
||||
export async function closeLocalOcrWorker(): Promise<void> {
|
||||
// HTTP 模式无持久连接,无需关闭。
|
||||
}
|
||||
|
||||
// ── HTTP Call ───────────────────────────────────────────────────────────────
|
||||
|
||||
async function callOcrViaHttp(
|
||||
action: OcrAction,
|
||||
payload: OcrRequestPayload,
|
||||
{ timeoutMs = DEFAULT_TIMEOUT_MS }: { timeoutMs?: number } = {},
|
||||
): Promise<OcrHttpResult> {
|
||||
const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '')
|
||||
|
||||
if (!baseUrl) {
|
||||
throw new Error('OCR_BASE_URL 未配置,无法调用 OCR 服务')
|
||||
}
|
||||
|
||||
const url = `${baseUrl}/ocr/${action}`
|
||||
|
||||
let response
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(timeoutMs),
|
||||
})
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'TimeoutError') {
|
||||
throw new Error(`OCR 请求超时(${timeoutMs}ms),请检查 OCR 服务状态`)
|
||||
}
|
||||
throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`)
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`OCR 服务返回错误:HTTP ${response.status}`)
|
||||
}
|
||||
|
||||
const result = await response.json()
|
||||
if (!result || typeof result !== 'object' || Array.isArray(result)) {
|
||||
throw new Error('OCR 服务返回了无效响应')
|
||||
}
|
||||
const ocrResult = result as OcrHttpResult
|
||||
if (ocrResult.code !== 0) {
|
||||
throw new Error(`OCR 服务返回错误:${ocrResult.msg || '未知错误'}`)
|
||||
}
|
||||
|
||||
return ocrResult
|
||||
}
|
||||
|
||||
async function warmupOcrViaHttp(): Promise<void> {
|
||||
const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '')
|
||||
|
||||
if (!baseUrl) {
|
||||
throw new Error('OCR_BASE_URL 未配置,无法启动 OCR 健康检查')
|
||||
}
|
||||
|
||||
let response
|
||||
try {
|
||||
response = await fetch(`${baseUrl}/health`, {
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.name === 'TimeoutError') {
|
||||
throw new Error(`OCR 服务健康检查超时,请检查 ${baseUrl} 是否可访问`)
|
||||
}
|
||||
throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`)
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new Error(`OCR 服务健康检查失败:HTTP ${response.status}`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user