patient-mini/api/drugOcr.js
@zuopngfei 746614c2cc dsdd
2025-08-04 18:11:46 +08:00

136 lines
5.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export const getOcr = (url) => {
return new Promise((resolve, reject) => {
wx.request({
url: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
method: 'POST',
dataType: 'json', // 微信官方文档中介绍会对数据进行一次JSON.parse
header: {
'Authorization': 'Bearer sk-52414b887aee47e4883caf16cbf801bd',
'Content-Type': 'application/json'
},
data: {
"model": "qwen-vl-ocr-latest",
"messages": [{
"role": "user",
"content": [{
"type": "image_url",
"image_url": {
"url": url
},
"min_pixels": 3136,
"max_pixels": 6422528
},
{
"type": "text",
// "text": "要求准确无误的提取图片中的药品名称、每次用量、每日服用次数等信息,模糊或者强光遮挡的单个文字可以用英文问号?代替药品名称的key为'name'每次用量key为'jiliang'每日服用次数的key为'cishu'返回数据格式以JSON数组格式输出不要将多个药品信息放到一个药品名称字段内跟药品无关的信息不要"
"text": "请只返回提取好的药品名称、每日服用次数、单次用药剂量、饭前服用或饭后服用,格式为 JSON 数组,每个元素包含 'name''jiliang''cishu1', 'time' 四个字段。例如:[{\"name\": \"阿莫西林\", \"jiliang\": \"2片\", \"cishu\": \"3\", \"time\": \"饭后\"}]。不要返回包含 rotate_rect、text 等字段的原始 OCR 结构化表格数据。"
}
]
}]
},
success(res) {
let data = parseJsonBlock(res.data.choices[0].message.content)
if(data.length == 0){
wx.showToast({
title: '识别失败,请重新选择照片!',
icon: 'none',
duration: 5000
});
reject('识别失败,请重新选择照片!')
return
}
if(data.some((item)=>{
return !item.name && item.text;
})){
let sss = extractDrugsFromOcr(data)
if(sss.length == 0){
wx.showToast({
title: '识别失败,请重新选择照片!',
icon: 'none',
duration: 5000
});
reject('识别失败!')
return
}
resolve(sss);
} else {
resolve(data);
}
},
fail(err) {
wx.showToast({
title: '识别失败,请重新选择照片!',
icon: 'none',
duration: 2000
})
console.log(err)
// 断网、服务器挂了都会fail回调直接reject即可
reject(err);
},
});
})
}
/**
* 解析类似 ```json ... ``` 格式的字符串,提取检测项目数组
* @param {string} str
* @returns {Array<Object>}
*/
function parseJsonBlock(str) {
// 匹配 ```json ... ``` 或 ``` ... ```
const match = str.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
let jsonStr = match ? match[1] : str;
jsonStr = jsonStr.trim();
// 尝试直接解析
try {
return JSON.parse(jsonStr);
} catch (e) {
// 替换单引号包裹的 key 和 value 为双引号
let fixedStr = jsonStr
// 替换 key 的单引号(允许有空格、括号等)
.replace(/'([\w\u4e00-\u9fa5\(\)\s]+)'(?=\s*:)/g, '"$1"')
// 替换 value 的单引号(允许有空格、括号等,非贪婪匹配)
.replace(/:\s*'([^']*?)'/g, ': "$1"');
try {
return JSON.parse(fixedStr);
} catch (e2) {
console.error('JSON parse error:', e2, fixedStr);
return [];
}
}
}
function extractDrugsFromOcr(ocrArray) {
// 1. 合并所有 text 字段
const lines = ocrArray.map(item => item.text.trim()).filter(Boolean);
// 2. 分组药品以“1、”“2、”等开头
const drugGroups = [];
let currentDrug = null;
lines.forEach(line => {
// 判断是否为新药品的开始
if (/^\d+、/.test(line)) {
if (currentDrug) drugGroups.push(currentDrug);
currentDrug = { name: line.replace(/^\d+、/, '').trim(), jiliang: '', cishu: '' };
} else if (currentDrug) {
// 判断是否为用量
if (/每次|mg|片|粒|ml|g|单位/.test(line) && !currentDrug.jiliang) {
currentDrug.jiliang = line;
}
// 判断是否为次数
else if (/每日|每天|次|早|晚|中/.test(line) && !currentDrug.cishu) {
currentDrug.cishu = line;
}
// 其他信息可根据需要扩展
}
});
if (currentDrug) drugGroups.push(currentDrug);
// 过滤掉无效项
return drugGroups.filter(d => d.name);
}