diff --git a/api/BOcr.js b/api/BOcr.js new file mode 100644 index 0000000..712f4d8 --- /dev/null +++ b/api/BOcr.js @@ -0,0 +1,141 @@ +export const getBOcr = (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": "要求准确无误的提取上述关键信息、不要遗漏和捏造虚假信息,模糊或者强光遮挡的单个文字可以用英文问号?代替。返回数据格式以MD方式输出" + } + ] + }] + }, + success(res) { + console.log(res.data) + return + let data = parseJsonBlock(res.data.choices[0].message.content) + if(data.length == 0){ + wx.showToast({ + title: '识别失败,请重新选择照片!', + icon: 'none', + duration: 2000 + }); + reject('识别失败!') + return + } + // 判断是否为 rotate_rect 格式 + if (Array.isArray(data) && data.length && data[0].rotate_rect) { + let items = extractCheckItemsFromOcrTable(data); + if(items.length==0){ + wx.showToast({ + title: '识别失败,请重新选择照片!', + icon: 'none', + duration: 2000 + }); + reject('识别失败!') + return + } + resolve(items); + return; + } + resolve(data); + + }, + fail(err) { + wx.showToast({ + title: '识别失败,请重新选择照片!', + icon: 'none', + duration: 2000 + }) + console.log(err) + // 断网、服务器挂了都会fail回调,直接reject即可 + reject(err); + }, + }); + }) +} + + + +/** + * 解析类似 ```json ... ``` 格式的字符串,提取检测项目数组 + * @param {string} str + * @returns {Array} + */ +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 extractCheckItemsFromOcrTable(ocrArray) { + // 1. 找到表头的 x 坐标 + const nameHeader = ocrArray.find(item => item.text.includes('检验项目')); + const valueHeader = ocrArray.find(item => item.text.includes('结果')); + if (!nameHeader || !valueHeader) return []; + + const nameX = nameHeader.rotate_rect[0]; + const valueX = valueHeader.rotate_rect[0]; + + // 2. 过滤掉表头,按 y 坐标分组(每一行) + const rows = {}; + ocrArray.forEach(item => { + if (item.text && !['检验项目', '结果', '单位', '提示', '参考区间'].includes(item.text)) { + // 以 y 坐标为 key,允许有一定误差(如±5) + const y = Math.round(item.rotate_rect[1] / 5) * 5; + if (!rows[y]) rows[y] = []; + rows[y].push(item); + } + }); + + // 3. 每一行找 name/value + const result = []; + Object.values(rows).forEach(items => { + let name = null, value = null; + items.forEach(item => { + if (Math.abs(item.rotate_rect[0] - nameX) < 50) name = item.text.trim(); + if (Math.abs(item.rotate_rect[0] - valueX) < 50) value = item.text.trim(); + }); + if (name && value) result.push({ name, value }); + }); + return result; +} \ No newline at end of file diff --git a/api/ocr.js b/api/ocr.js index 25bd394..56b9bd8 100644 --- a/api/ocr.js +++ b/api/ocr.js @@ -31,9 +31,9 @@ export const getOcr = (url) => { let data = parseJsonBlock(res.data.choices[0].message.content) if(data.length == 0){ wx.showToast({ - title: '识别失败,请重新选择照片!', + title: '识别失败,请选择带有符合表单字段的照片!', icon: 'none', - duration: 2000 + duration: 5000 }); reject('识别失败!') return @@ -43,9 +43,9 @@ export const getOcr = (url) => { let items = extractCheckItemsFromOcrTable(data); if(items.length==0){ wx.showToast({ - title: '识别失败,请重新选择照片!', + title: '识别失败,请选择带有符合表单字段的照片!', icon: 'none', - duration: 2000 + duration: 5000 }); reject('识别失败!') return @@ -58,9 +58,9 @@ export const getOcr = (url) => { }, fail(err) { wx.showToast({ - title: '识别失败,请重新选择照片!', + title: '识别失败,请选择带有符合表单字段的照片!', icon: 'none', - duration: 2000 + duration: 5000 }) console.log(err) // 断网、服务器挂了都会fail回调,直接reject即可 diff --git a/pages/followUp/index.js b/pages/followUp/index.js index 1bd133f..ee4d6c3 100644 --- a/pages/followUp/index.js +++ b/pages/followUp/index.js @@ -1,6 +1,7 @@ import request from '~/api/request'; import { getOcr } from '~/api/ocr'; +import { getBOcr } from '~/api/BOcr'; Page({ /** diff --git a/pages/followUp/index.wxml b/pages/followUp/index.wxml index 32824cf..f2bd5b7 100644 --- a/pages/followUp/index.wxml +++ b/pages/followUp/index.wxml @@ -536,7 +536,7 @@ 弹性成像最小值(kPa) - + diff --git a/pages/home/index.js b/pages/home/index.js index bbfe5ff..b45107f 100644 --- a/pages/home/index.js +++ b/pages/home/index.js @@ -166,6 +166,14 @@ Page({ }, async getPersonalInfo() { + // const token = await wx.getStorageSync('access_token'); + // if(!token){ + // wx.navigateTo({ + // url: '/pages/login/login' + // }) + // return + // } + const user_info = await wx.getStorageSync('user_info') console.log(user_info) if (user_info) { @@ -178,9 +186,12 @@ Page({ } this.getChartData() } else { - wx.navigateTo({ - url: '/pages/login/login' - }) + const res = await request('patient/basic/0') + await wx.setStorageSync('user_info', res) + this.getChartData() + // wx.navigateTo({ + // url: '/pages/login/login' + // }) } }, diff --git a/pages/my/index.less b/pages/my/index.less index 98a70b1..c20afbd 100644 --- a/pages/my/index.less +++ b/pages/my/index.less @@ -276,6 +276,7 @@ // width: 188rpx; // margin: 8rpx 0 8rpx 0; margin-top: 4rpx; + white-space: nowrap; } .thumbnail_1 { color: rgba(212,48,48,1); diff --git a/pages/my/index.wxml b/pages/my/index.wxml index b042503..aaf7a4d 100644 --- a/pages/my/index.wxml +++ b/pages/my/index.wxml @@ -41,7 +41,9 @@ 高危 - +