fix: 修复登录跳转 + OCR识别问题(前端改用XMLHttpRequest)
This commit is contained in:
parent
c46aebb5cf
commit
8b60c31b2b
|
|
@ -61,30 +61,30 @@ async def recognize_image(
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 阿里云 DashScope API 格式 (qwen-vl-max 视觉模型)
|
# 阿里云 DashScope API 格式 (qwen-vl-plus 视觉模型)
|
||||||
payload = {
|
payload = {
|
||||||
"model": "qwen-vl-max",
|
"model": "qwen-vl-plus",
|
||||||
"messages": [{
|
"input": {
|
||||||
"role": "user",
|
"messages": [{
|
||||||
"content": [
|
"role": "user",
|
||||||
{
|
"content": [
|
||||||
"type": "image_url",
|
{
|
||||||
"image_url": {
|
"image": f"data:{image.content_type};base64,{image_base64}"
|
||||||
"url": f"data:image/jpeg;base64,{image_base64}"
|
},
|
||||||
|
{
|
||||||
|
"text": PROFESSIONAL_PROMPT
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
{
|
}]
|
||||||
"type": "text",
|
},
|
||||||
"text": PROFESSIONAL_PROMPT
|
"parameters": {
|
||||||
}
|
"max_tokens": 1000
|
||||||
]
|
}
|
||||||
}],
|
|
||||||
"max_tokens": 1000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||||
response = await client.post(
|
response = await client.post(
|
||||||
"https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
|
"https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation",
|
||||||
json=payload,
|
json=payload,
|
||||||
headers=headers
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|
@ -94,8 +94,13 @@ async def recognize_image(
|
||||||
|
|
||||||
ocr_result = response.json()
|
ocr_result = response.json()
|
||||||
text_content = ""
|
text_content = ""
|
||||||
if "choices" in ocr_result and len(ocr_result["choices"]) > 0:
|
# 新版API返回格式
|
||||||
text_content = ocr_result["choices"][0]["message"]["content"]
|
if "output" in ocr_result and "choices" in ocr_result["output"]:
|
||||||
|
choices = ocr_result["output"]["choices"]
|
||||||
|
if choices and len(choices) > 0:
|
||||||
|
content = choices[0].get("message", {}).get("content", [])
|
||||||
|
if content and len(content) > 0:
|
||||||
|
text_content = content[0].get("text", "")
|
||||||
|
|
||||||
fields = extract_fields(text_content)
|
fields = extract_fields(text_content)
|
||||||
|
|
||||||
|
|
@ -106,7 +111,9 @@ async def recognize_image(
|
||||||
return {"success": True, "text": text_content, "fields": fields}
|
return {"success": True, "text": text_content, "fields": fields}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"识别失败:{str(e)}")
|
import traceback
|
||||||
|
error_detail = f"识别失败:{str(e)}\n{traceback.format_exc()}"
|
||||||
|
raise HTTPException(status_code=500, detail=error_detail)
|
||||||
|
|
||||||
|
|
||||||
def extract_fields(text: str) -> dict:
|
def extract_fields(text: str) -> dict:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# Version Configuration for Zodiac Collection Management System
|
# Version Configuration for Zodiac Collection Management System
|
||||||
|
|
||||||
# 当前版本号 (语义化版本:主版本。次版本.修订版)
|
# 当前版本号 (语义化版本:主版本。次版本.修订版)
|
||||||
VERSION=1.0.3
|
VERSION=1.0.5
|
||||||
|
|
||||||
# 版本代号 (可选)
|
# 版本代号 (可选)
|
||||||
VERSION_CODENAME="新生"
|
VERSION_CODENAME="新生"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<title>甲辰收藏 v1.0.1</title>
|
<title>甲辰收藏 v1.0.3-1773807001352</title>
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/x-icon" href="/static/icons/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/static/icons/favicon.ico" />
|
||||||
|
|
|
||||||
|
|
@ -170,14 +170,38 @@ export default function Add() {
|
||||||
const token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('image', selectedImage)
|
formData.append('image', selectedImage)
|
||||||
|
|
||||||
|
// 使用 XMLHttpRequest 替代 fetch
|
||||||
|
const data = await new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest()
|
||||||
|
xhr.open('POST', '/api/ocr/recognize')
|
||||||
|
xhr.setRequestHeader('Authorization', 'Bearer ' + token)
|
||||||
|
|
||||||
|
xhr.onload = function() {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(xhr.responseText)
|
||||||
|
resolve(data)
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error('JSON解析失败: ' + xhr.responseText.substring(0, 100)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(xhr.responseText)
|
||||||
|
reject(new Error(data.error?.message || data.detail || '识别失败'))
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error('请求失败: ' + xhr.status))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.onerror = function() {
|
||||||
|
reject(new Error('网络错误'))
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send(formData)
|
||||||
|
})
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/ocr/recognize', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Authorization': 'Bearer ' + token },
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
const data = await res.json()
|
|
||||||
if (!res.ok) throw new Error(data.error?.message || '识别失败')
|
|
||||||
if (data.fields) {
|
if (data.fields) {
|
||||||
const recognizedForm = { ...getDefaultForm() }
|
const recognizedForm = { ...getDefaultForm() }
|
||||||
// 直接对应 AI 返回的字段,不需要二次解析
|
// 直接对应 AI 返回的字段,不需要二次解析
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ export default function BatchMode() {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('image', file)
|
formData.append('image', file)
|
||||||
|
|
||||||
const res = await fetch('/api/ocr', { method: 'POST', body: formData })
|
const res = await fetch('/api/ocr/recognize', { method: 'POST', body: formData })
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const text = data.result || ''
|
const text = data.result || ''
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,21 +229,38 @@ export default function OCR() {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('image', selectedImage)
|
formData.append('image', selectedImage)
|
||||||
|
|
||||||
try {
|
// 使用 XMLHttpRequest 替代 fetch,兼容性更好
|
||||||
const res = await fetch('/api/ocr/recognize', {
|
const data = await new Promise((resolve, reject) => {
|
||||||
method: 'POST',
|
const xhr = new XMLHttpRequest()
|
||||||
headers: {
|
xhr.open('POST', '/api/ocr/recognize')
|
||||||
'Authorization': 'Bearer ' + token
|
xhr.setRequestHeader('Authorization', 'Bearer ' + token)
|
||||||
},
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
|
|
||||||
const data = await res.json()
|
xhr.onload = function() {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
if (!res.ok) {
|
try {
|
||||||
throw new Error(data.error?.message || '识别失败')
|
const data = JSON.parse(xhr.responseText)
|
||||||
|
resolve(data)
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error('JSON解析失败: ' + xhr.responseText.substring(0, 100)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(xhr.responseText)
|
||||||
|
reject(new Error(data.error?.message || data.detail || '识别失败'))
|
||||||
|
} catch (e) {
|
||||||
|
reject(new Error('请求失败: ' + xhr.status))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xhr.onerror = function() {
|
||||||
|
reject(new Error('网络错误'))
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send(formData)
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
// 自动填充识别结果
|
// 自动填充识别结果
|
||||||
if (data.fields) {
|
if (data.fields) {
|
||||||
const recognizedForm = { ...getDefaultForm() }
|
const recognizedForm = { ...getDefaultForm() }
|
||||||
|
|
|
||||||
|
|
@ -203,9 +203,9 @@ export const api = {
|
||||||
ocr: {
|
ocr: {
|
||||||
recognize: (file) => {
|
recognize: (file) => {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('image', file)
|
||||||
|
|
||||||
return request('/api/ocr', {
|
return request('/api/ocr/recognize', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData
|
body: formData
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ function getVersion() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const APP_VERSION = getVersion()
|
const APP_VERSION = getVersion() + '-' + Date.now()
|
||||||
console.log(`📦 构建版本:v${APP_VERSION}`)
|
console.log(`📦 构建版本:v${APP_VERSION}`)
|
||||||
|
|
||||||
// 构建时自动更新 index.html 的 title
|
// 构建时自动更新 index.html 的 title
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue