diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..96112c3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +重要声明 +由于本项目是对 QwenLM 的逆向工程实现,仅供学习和研究使用。任何商业用途或滥用行为均与作者无关。请遵守相关法律法规和平台的使用条款。 + +开源协议 (LICENSE) +本项目采用 MIT 许可证,明确限制仅用于学习和研究目的。以下是 LICENSE 文件内容: + +``` +MIT License + +Copyright (c) 2025 [cunninger] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +1. The Software is provided for educational and research purposes only. + Commercial use is strictly prohibited. + +2. The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/README.md b/README.md new file mode 100644 index 0000000..c225e79 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# 🖼️ QwenLM OCR 逆向工程项目 + +本项目是对 [QwenLM](https://chat.qwenlm.ai/) 的 OCR 功能进行逆向工程的实现。通过调用 QwenLM 的 API,你可以从图片中提取文字内容,并且该项目支持一键部署到 **Cloudflare Workers** (CF) 上。 + +## 项目展示 + + +## 🚀 功能特性 + +- **图片 OCR**:使用 QwenLM 强大的 OCR 功能从图片中提取文字。 +- **拖拽上传**:直接将图片拖拽到页面即可识别。 +- **复制粘贴**:支持从剪贴板直接粘贴图片进行识别。 +- **Token 管理**:支持多 Token 轮询使用,提升稳定性。 +- **历史记录**:保存每次识别的结果和图片,方便查看。 +- **一键复制**:轻松复制识别结果到剪贴板。 +- **数学公式识别**:特别优化了对数学公式的提取,支持 LaTeX 格式输出。 +- **API 支持**:提供 `curl` 接口调用,支持 base64 和图片 URL 两种方式。 +- **验证码识别**:新增验证码识别功能,支持常见类型的验证码(如数字、字母、混合字符等),提升自动化处理能力。 +## 🛠️ 部署指南 + +### 1. 部署到 Cloudflare Workers + +1. **配置 Cloudflare Workers**: + - 登录 [Cloudflare Dashboard](https://dash.cloudflare.com/)。 + - 创建一个新的 Worker。 + - 将 `worker.js` 中的代码复制到 Worker 编辑器中。 + +2. **部署**: + - 保存并部署 Worker。 + - 获取 Worker 的访问地址,即可使用。 + +## 🧩 使用说明 + +1. **设置 Token**: + - 前往 [QwenLM](https://chat.qwenlm.ai/) 获取 Token。 + - 点击右上角的 **⚙️ Token设置** 按钮。 + - 输入你的 QwenLM API Token(多个 Token 用英文逗号分隔)。 + - 点击 **保存**。 + +2. **上传图片**: + - 拖拽图片到页面,或点击上传区域选择图片。 + - 支持直接粘贴图片。 + +3. **查看结果**: + - 识别结果会显示在页面下方。 + - 点击 **复制结果** 按钮,将识别内容复制到剪贴板。 + +4. **查看历史记录**: + - 点击左侧的 **📋 识别历史** 按钮,查看历史识别记录。 + - 点击历史记录中的图片,可以查看大图。 + +5. **API 调用**: + - **支持 base64**: + ```bash + curl --location 'https://ocr.doublefenzhuan.me/api/recognize/base64' \ + --header 'Content-Type: application/json' \ + --data '{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM", + "base64Image": "xxx" + }' + ``` + - **支持图片 URL**: + ```bash + curl --location 'https://ocr.doublefenzhuan.me/api/recognize/url' \ + --header 'Content-Type: application/json' \ + --data '{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM", + "imageUrl": "xxxx" + }' + ``` +6. **验证码识别** + + + +## 📜 许可证 + +本项目基于 MIT 许可证开源。详情请查看 [LICENSE](LICENSE) 文件。 + +## 🙏 致谢 + +- 感谢 [QwenLM](https://chat.qwenlm.ai/) 提供的 OCR 功能。 +- 感谢 Cloudflare 提供的 Workers 服务。 + +--- + +🌟 如果觉得这个项目对你有帮助,欢迎点个 Star 支持一下!🌟 + +**体验地址**:[智能图片识别 (doublefenzhuan.me)](https://ocr.doublefenzhuan.me/) + +**GitHub 仓库**:[Cunninger/ocr-based-qwen](https://github.com/Cunninger/ocr-based-qwen) + +--- + +#### 后续计划 +- 优化数学公式识别精度; +- 增加更多 API 功能支持; +- 提升识别速度和稳定性。 + +快来体验吧!如果有任何问题或建议,欢迎在 GitHub 上提 Issue 或直接联系我! + +## 更新 +### 2025/01/13 应佬友需求,优化了对数学公式的识别,效果如下图 +- 原图: + + + +- 识别效果图: + + + +### 2025/01/13 18点34分 支持`curl`接口调用 +- **支持base64**: +``` +curl --location 'https://ocr.doublefenzhuan.me/api/recognize/base64' \ +--header 'Content-Type: application/json' \ +--data '{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM", + "base64Image": "xxx" +}' +``` +- 效果图: + + +- **支持图片URL**: +```bash +curl --location 'https://ocr.doublefenzhuan.me/api/recognize/url' \ +--header 'Content-Type: application/json' \ +--data '{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM", + + "imageUrl": "xxxx" +}' +``` +- 效果图: + + +## 趋势 +[](https://star-history.com/#Cunninger/ocr-based-qwen&Date) diff --git a/worker.js b/worker.js index 2f233b6..38fc9ca 100644 --- a/worker.js +++ b/worker.js @@ -55,8 +55,8 @@ async function handleImageUrlRecognition(request) { const { token, imageUrl } = await request.json(); if (!token || !imageUrl) { - return new Response(JSON.stringify({ - error: 'Missing token or imageUrl' + return new Response(JSON.stringify({ + error: 'Missing token or imageUrl' }), { status: 400, headers: { 'Content-Type': 'application/json' }, @@ -86,8 +86,8 @@ async function handleImageUrlRecognition(request) { // 调用识别API return await recognizeImage(token, uploadData.id); } catch (error) { - return new Response(JSON.stringify({ - error: error.message || 'Internal Server Error' + return new Response(JSON.stringify({ + error: error.message || 'Internal Server Error' }), { status: 500, headers: { 'Content-Type': 'application/json' }, @@ -101,8 +101,8 @@ async function handleBase64Recognition(request) { const { token, base64Image } = await request.json(); if (!token || !base64Image) { - return new Response(JSON.stringify({ - error: 'Missing token or base64Image' + return new Response(JSON.stringify({ + error: 'Missing token or base64Image' }), { status: 400, headers: { 'Content-Type': 'application/json' }, @@ -110,10 +110,10 @@ async function handleBase64Recognition(request) { } // 转换Base64为Blob - const imageData = base64Image.startsWith('data:') ? - base64Image : + const imageData = base64Image.startsWith('data:') ? + base64Image : 'data:image/png;base64,' + base64Image; - + const response = await fetch(imageData); const blob = await response.blob(); @@ -136,8 +136,8 @@ async function handleBase64Recognition(request) { // 调用识别API return await recognizeImage(token, uploadData.id); } catch (error) { - return new Response(JSON.stringify({ - error: error.message || 'Internal Server Error' + return new Response(JSON.stringify({ + error: error.message || 'Internal Server Error' }), { status: 500, headers: { 'Content-Type': 'application/json' }, @@ -151,8 +151,8 @@ async function handleFileRecognition(request) { const { token, imageId } = await request.json(); if (!token || !imageId) { - return new Response(JSON.stringify({ - error: 'Missing token or imageId' + return new Response(JSON.stringify({ + error: 'Missing token or imageId' }), { status: 400, headers: { 'Content-Type': 'application/json' }, @@ -161,8 +161,8 @@ async function handleFileRecognition(request) { return await recognizeImage(token, imageId); } catch (error) { - return new Response(JSON.stringify({ - error: error.message || 'Internal Server Error' + return new Response(JSON.stringify({ + error: error.message || 'Internal Server Error' }), { status: 500, headers: { 'Content-Type': 'application/json' }, @@ -186,8 +186,8 @@ async function recognizeImage(token, imageId) { { role: 'user', content: [ - { - type: 'text', + { + type: 'text', text: '请识别图片中的内容,注意以下要求:\n' + '对于数学公式和普通文本:\n' + '1. 所有数学公式和数学符号都必须使用标准的LaTeX格式\n' + @@ -216,10 +216,10 @@ async function recognizeImage(token, imageId) { const data = await response.json(); let result = data.choices[0]?.message?.content || '识别失败'; - + // 如果结果长度小于10且只包含字母数字,很可能是验证码 if (result.length <= 10 && /^[A-Za-z0-9]+$/.test(result)) { - return new Response(JSON.stringify({ + return new Response(JSON.stringify({ success: true, result: result.toUpperCase(), // 验证码统一转大写 type: 'captcha' @@ -242,7 +242,7 @@ async function recognizeImage(token, imageId) { .replace(/\$\$/g, '$$') .trim(); - return new Response(JSON.stringify({ + return new Response(JSON.stringify({ success: true, result: result, type: 'text' @@ -262,7 +262,7 @@ function getHTML() { '', '', '