13 Commits

Author SHA1 Message Date
9ce7d47b8a fix: encode custom prompt to handle non-ASCII characters in request headers 2025-02-15 10:51:22 +08:00
69629b1eb3 Update README.md 2025-02-15 10:39:50 +08:00
09526242ff Update README.md 2025-02-15 10:36:40 +08:00
d2b6d7bd3f Add custom prompt feature with advanced/raw mode support 2025-02-15 10:30:09 +08:00
2637226c23 Update README.md 2025-02-15 09:49:03 +08:00
f638c5d65e Update README.md 2025-02-13 13:48:59 +08:00
6bd52ea74a Update README.md 2025-02-13 13:47:19 +08:00
4e55b325e0 feat: add "Get Cookie" button next to GitHub icon
- Introduced a new green "Get Cookie" button to the UI.
- Positioned the button to the right of the history button for easy access.
- Implemented functionality to open the URL `https://chat.qwenlm.ai` in a new tab when the button is clicked.
- Enhanced user experience by providing a direct link for users to obtain their cookie.
2025-02-13 13:15:20 +08:00
2f8f57ade7 Update README.md 2025-02-13 09:20:15 +08:00
ad532bd994 docs: update API endpoint examples 2025-02-10 12:15:24 +08:00
9c6745fcf5 docs: update API endpoint examples and usage notes 2025-02-10 12:02:12 +08:00
d7e0bf4106 docs: update API endpoint examples and usage notes 2025-02-10 11:54:33 +08:00
bee8754e24 feat: enhance API implementation and add documentation
- Added detailed comments to API endpoint implementations for clarity.
- Ensured consistent error handling across all endpoints with standardized JSON responses.
- Implemented unit tests for API endpoints to verify functionality.
- Updated constants and added comments for better understanding of parameters.
- Ensured code logic aligns with the updated README documentation.
2025-02-10 11:48:05 +08:00
2 changed files with 290 additions and 109 deletions

View File

@ -1,6 +1,10 @@
# 🖼️ QwenLM OCR
<div align="center"> <img src="https://github.com/Cunninger/ocr-based-qwen/blob/main/ocr.png?raw=true" width="120"> </div>
本项目是对 [QwenLM](https://chat.qwenlm.ai/) 的 OCR 功能进行逆向工程的实现。通过调用 QwenLM 的 API你可以从图片中提取文字内容并且该项目支持一键部署到 **Cloudflare Workers** (CF) 上。
# QwenLM OCR
本项目基于 [QwenLM](https://chat.qwenlm.ai/) 。通过调用 QwenLM 的 API你可以从图片中提取文字内容并且该项目支持一键部署到 **Cloudflare Workers** (CF) 上。
## 项目展示
![image](https://github.com/user-attachments/assets/9e794686-f914-4fb7-9931-1ada7c22bb2d)
@ -17,8 +21,9 @@ cna=LI8HIAirQyACAWrg3cNOjH8F; _gcl_au=1.1.1200556497.1736728490; xlly_s=1; acw_t
- **历史记录**:保存每次识别的结果和图片,方便查看。
- **一键复制**:轻松复制识别结果到剪贴板。
- **数学公式识别**:特别优化了对数学公式的提取,支持 LaTeX 格式输出。
- **API 支持**:提供 `curl` 接口调用,支持 base64 和图片 URL 种方式。
- **API 支持**:提供 `curl` 接口调用,支持通过图片文件、base64 和图片 URL 3种方式。(Apifox调用文档示例(**仅作为代码示例,尝试本地调试**)https://we4q3dzb3r.apifox.cn/)
- **验证码识别**:新增验证码识别功能,支持常见类型的验证码(如数字、字母、混合字符等),提升自动化处理能力。
- **自定义prompt**: 在高级模式下(v1.1.0支持),用户可以自定义 prompt跳过格式化处理直接返回原始结果而在普通模式下使用默认的 prompt 并保持现有的格式化处理逻辑。
## 🛠️ 部署指南
### 1. 部署到 Cloudflare Workers
@ -57,20 +62,22 @@ cna=LI8HIAirQyACAWrg3cNOjH8F; _gcl_au=1.1.1200556497.1736728490; xlly_s=1; acw_t
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"
}'
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/api/recognize/base64' \
-H 'Content-Type: application/json' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-d '{
"base64Image": "YOUR_BASE64_IMAGE_STRING"
}'
```
- **支持图片 URL**:
```bash
curl --location 'https://ocr.doublefenzhuan.me/api/recognize/url' \
--header 'Content-Type: application/json' \
--data '{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM",
"imageUrl": "xxxx"
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/api/recognize/url' \
-H 'Content-Type: application/json' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-d '{
"imageUrl": "YOUR_IMAGE_URL"
}'
```
6. **验证码识别**
@ -115,29 +122,48 @@ cna=LI8HIAirQyACAWrg3cNOjH8F; _gcl_au=1.1.1200556497.1736728490; xlly_s=1; acw_t
### 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"
}'
```bash
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/api/recognize/base64' \
-H 'Content-Type: application/json' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-d '{
"base64Image": "YOUR_BASE64_IMAGE_STRING"
}'
```
- 效果图:
![image](https://github.com/user-attachments/assets/ef160aae-e741-49d3-96f0-a0969b883f1a)
![image](https://github.com/user-attachments/assets/363afb39-444b-4308-a2bd-55831df81b6f)
- **支持图片URL**:
```bash
curl --location 'https://ocr.doublefenzhuan.me/api/recognize/url' \
--header 'Content-Type: application/json' \
--data '{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjUzZTk0Nzg4LWMwM2QtNDY4Mi05OTNhLWE0ZDNjNGUyZDY0OSIsImV4cCI6MTczOTA3NTE0MX0.FtwG6xDLYd2rngWUhuldg56WXCiLSTL0RI6xJJQ4vHM",
"imageUrl": "xxxx"
}'
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/api/recognize/url' \
-H 'Content-Type: application/json' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-d '{
"imageUrl": "YOUR_IMAGE_URL"
}'
```
- 效果图:
![image](https://github.com/user-attachments/assets/db0c89f9-96f1-45b1-b1e9-88ac3d01e196)
![image](https://github.com/user-attachments/assets/a816085e-8a52-4425-b02c-94ea543bf95b)
- **通过图片文件识别需要先上传获取imageId**
```bash
# 1. 先上传文件
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/proxy/upload' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-F 'file=@/path/to/your/image.jpg'
# 2. 使用返回的imageId进行识别
curl -X POST \
'https://test-qwen-cor.aughumes8.workers.dev/recognize' \
-H 'Content-Type: application/json' \
-H 'x-custom-cookie: YOUR_COOKIE_STRING' \
-d '{
"imageId": "RETURNED_IMAGE_ID"
}'
```
## Cloudflare访问数据
![image](https://github.com/user-attachments/assets/bb456075-6107-47ee-a361-a0edba532c38)

313
worker.js
View File

@ -60,17 +60,30 @@ async function handleRequest(request) {
// 处理图片URL识别
async function handleImageUrlRecognition(request) {
try {
const { token, imageUrl } = await request.json();
const { imageUrl } = await request.json();
const cookie = request.headers.get('x-custom-cookie');
if (!token || !imageUrl) {
if (!cookie || !imageUrl) {
return new Response(JSON.stringify({
error: 'Missing token or imageUrl'
error: 'Missing cookie or imageUrl'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// 从cookie中提取token
const tokenMatch = cookie.match(/token=([^;]+)/);
if (!tokenMatch) {
return new Response(JSON.stringify({
error: 'Invalid cookie format: missing token'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
const token = tokenMatch[1];
// 下载图片
const imageResponse = await fetch(imageUrl);
const imageBlob = await imageResponse.blob();
@ -84,6 +97,7 @@ async function handleImageUrlRecognition(request) {
headers: {
'accept': 'application/json',
'authorization': `Bearer ${token}`,
'cookie': cookie
},
body: formData,
});
@ -91,8 +105,8 @@ async function handleImageUrlRecognition(request) {
const uploadData = await uploadResponse.json();
if (!uploadData.id) throw new Error('File upload failed');
// 调用识别API
return await recognizeImage(token, uploadData.id);
// 调用通用识别函数
return await recognizeImage(token, uploadData.id, request);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
@ -106,22 +120,32 @@ async function handleImageUrlRecognition(request) {
// 处理Base64识别
async function handleBase64Recognition(request) {
try {
const { token, base64Image } = await request.json();
const { base64Image } = await request.json();
const cookie = request.headers.get('x-custom-cookie');
if (!token || !base64Image) {
if (!cookie || !base64Image) {
return new Response(JSON.stringify({
error: 'Missing token or base64Image'
error: 'Missing cookie or base64Image'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// 转换Base64为Blob
const imageData = base64Image.startsWith('data:') ?
base64Image :
'data:image/png;base64,' + base64Image;
// 从cookie中提取token
const tokenMatch = cookie.match(/token=([^;]+)/);
if (!tokenMatch) {
return new Response(JSON.stringify({
error: 'Invalid cookie format: missing token'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
const token = tokenMatch[1];
// 转换Base64为Blob
const imageData = base64Image.startsWith('data:') ? base64Image : 'data:image/png;base64,' + base64Image;
const response = await fetch(imageData);
const blob = await response.blob();
@ -134,6 +158,7 @@ async function handleBase64Recognition(request) {
headers: {
'accept': 'application/json',
'authorization': `Bearer ${token}`,
'cookie': cookie
},
body: formData,
});
@ -141,8 +166,8 @@ async function handleBase64Recognition(request) {
const uploadData = await uploadResponse.json();
if (!uploadData.id) throw new Error('File upload failed');
// 调用识别API
return await recognizeImage(token, uploadData.id);
// 调用通用识别函数
return await recognizeImage(token, uploadData.id, request);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
@ -156,18 +181,23 @@ async function handleBase64Recognition(request) {
// 处理文件识别 (原有功能)
async function handleFileRecognition(request) {
try {
const { token, imageId } = await request.json();
const { imageId } = await request.json();
const cookie = request.headers.get('x-custom-cookie') || '';
if (!token || !imageId) {
if (!cookie || !imageId) {
return new Response(JSON.stringify({
error: 'Missing token or imageId'
error: 'Missing cookie or imageId'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
return await recognizeImage(token, imageId, request); // 传递 request 对象
// 从cookie中提取token
const tokenMatch = cookie.match(/token=([^;]+)/);
const token = tokenMatch ? tokenMatch[1] : '';
return await recognizeImage(token, imageId, request);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
@ -182,13 +212,18 @@ async function handleFileRecognition(request) {
async function handleProxyUpload(request) {
try {
const formData = await request.formData();
const token = request.headers.get('Authorization').replace('Bearer ', '');
const cookie = request.headers.get('x-custom-cookie') || '';
// 从cookie中提取token
const tokenMatch = cookie.match(/token=([^;]+)/);
const token = tokenMatch ? tokenMatch[1] : '';
const response = await fetch('https://chat.qwenlm.ai/api/v1/files/', {
method: 'POST',
headers: {
'accept': 'application/json',
'authorization': `Bearer ${token}`,
'cookie': cookie
},
body: formData,
});
@ -216,27 +251,23 @@ async function handleProxyUpload(request) {
// 通用的识别函数
async function recognizeImage(token, imageId, request) {
// 从请求头获取 cookie
const response = await fetch('https://chat.qwenlm.ai/api/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'PostmanRuntime/7.43.0',
'accept': '*/*',
'authorization': `Bearer ${token}`,
'cookie': request.headers.get('x-custom-cookie') || '', // 使用自定义请求头中的 cookie
},
body: JSON.stringify({
stream: false,
chat_type: "t2t",
model: 'qwen2.5-vl-72b-instruct',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: '请识别图片中的内容,注意以下要求:\n' +
const cookie = request.headers.get('x-custom-cookie') || '';
// 从请求头中获取高级模式状态和自定义prompt
const advancedMode = request.headers.get('x-advanced-mode') === 'true';
// 解码自定义prompt
let customPrompt = '';
try {
const encodedPrompt = request.headers.get('x-custom-prompt');
if (encodedPrompt) {
customPrompt = decodeURIComponent(atob(encodedPrompt));
}
} catch (error) {
console.error('Prompt解码错误:', error);
}
const defaultPrompt = '请识别图片中的内容,注意以下要求:\n' +
'对于数学公式和普通文本:\n' +
'1. 所有数学公式和数学符号都必须使用标准的LaTeX格式\n' +
'2. 行内公式使用单个$符号包裹,如:$x^2$\n' +
@ -250,7 +281,28 @@ async function recognizeImage(token, imageId, request) {
'2. 忽略干扰线和噪点\n' +
'3. 注意区分相似字符如0和O、1和l、2和Z等\n' +
'4. 验证码通常为4-6位字母数字组合\n\n' +
'不要输出任何额外的解释或说明',
'不要输出任何额外的解释或说明';
const response = await fetch('https://chat.qwenlm.ai/api/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': 'PostmanRuntime/7.43.0',
'accept': '*/*',
'authorization': `Bearer ${token}`,
'cookie': cookie,
},
body: JSON.stringify({
stream: false,
chat_type: "t2t",
model: 'qwen2.5-vl-72b-instruct',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: advancedMode ? customPrompt : defaultPrompt,
chat_type: "t2t"
},
{
@ -270,30 +322,33 @@ async function recognizeImage(token, imageId, request) {
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({
success: true,
result: result.toUpperCase(), // 验证码统一转大写
type: 'captcha'
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
// 只在非高级模式下进行格式化处理
if (!advancedMode) {
// 如果结果长度小于10且只包含字母数字很可能是验证码
if (result.length <= 10 && /^[A-Za-z0-9]+$/.test(result)) {
return new Response(JSON.stringify({
success: true,
result: result.toUpperCase(),
type: 'captcha'
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}
// 其他情况(数学公式和普通文本)的处理
result = result
.replace(/\\/g, '\\(')
.replace(/\\/g, '\\)')
.replace(/\n{3,}/g, '\n\n')
.replace(/([^\n])\n([^\n])/g, '$1\n$2')
.replace(/\$\s+/g, '$')
.replace(/\s+\$/g, '$')
.replace(/\$\$/g, '$$')
.trim();
// 其他情况(数学公式和普通文本)的处理
result = result
.replace(/\\/g, '\\(')
.replace(/\\/g, '\\)')
.replace(/\n{3,}/g, '\n\n')
.replace(/([^\n])\n([^\n])/g, '$1\n$2')
.replace(/\$\s+/g, '$')
.replace(/\s+\$/g, '$')
.replace(/\$\$/g, '$$')
.trim();
}
return new Response(JSON.stringify({
success: true,
@ -1015,7 +1070,6 @@ function getHTML() {
' background: rgba(255, 255, 255, 0.9);',
' backdrop-filter: blur(5px);',
' z-index: 900;',
' border-top: 1px solid rgba(0, 0, 0, 0.1);',
' display: flex;',
' justify-content: center;',
' align-items: center;',
@ -1080,13 +1134,13 @@ function getHTML() {
' .github-link {',
' position: fixed;',
' right: 150px;', // 放在 token 设置按钮左边',
' right: 150px;',
' top: 20px;',
' background: #333;', // GitHub 的深色背景',
' background: #333;',
' color: white;',
' border: none;',
' padding: 10px;',
' border-radius: 50%;', // 圆形按钮',
' border-radius: 50%;',
' cursor: pointer;',
' z-index: 1001;',
' width: 40px;',
@ -1098,7 +1152,7 @@ function getHTML() {
' }',
' .github-link:hover {',
' background: #24292e;', // GitHub hover 颜色',
' background: #24292e;',
' }',
' .github-icon {',
@ -1144,10 +1198,73 @@ function getHTML() {
' color: #3498db;',
' font-family: monospace;',
' word-break: break-all;',
' }',
// 添加获取cookie按钮样式
' .get-cookie-link {',
' position: fixed;',
' left: 150px;', // 放在github图标左边
' top: 22px;',
' background: #2ecc71;', // 使用不同的颜色区分
' color: white;',
' border: none;',
' padding: 8px 15px;',
' border-radius: 5px;',
' cursor: pointer;',
' z-index: 1001;',
' text-decoration: none;',
' font-size: 14px;',
' transition: background 0.3s ease;',
' }',
' .get-cookie-link:hover {',
' background: #27ae60;',
' }',
' .advanced-mode-toggle {',
' display: flex;',
' align-items: center;',
' margin-bottom: 15px;',
' padding: 10px;',
' background: #f8f9fa;',
' border-radius: 8px;',
' }',
' .advanced-mode-toggle input[type="checkbox"] {',
' margin-right: 10px;',
' }',
' .prompt-container {',
' display: none;', // 默认隐藏
' margin-bottom: 15px;',
' }',
' .prompt-container.show {',
' display: block;',
' }',
' #promptInput {',
' width: 100%;',
' padding: 12px;',
' border: 2px solid #e9ecef;',
' border-radius: 8px;',
' font-size: 0.95rem;',
' resize: vertical;',
' min-height: 120px;',
' font-family: monospace;',
' line-height: 1.4;',
' }',
' #promptInput:focus {',
' outline: none;',
' border-color: #3498db;',
' }',
'</style>',
'</head>',
'<body>',
'<a href="https://chat.qwenlm.ai/" target="_blank" rel="noopener noreferrer" class="get-cookie-link">',
' 获取Cookie',
'</a>',
'<a href="https://github.com/Cunninger/ocr-based-qwen" target="_blank" rel="noopener noreferrer" class="github-link" title="View on GitHub">',
' <svg class="github-icon" viewBox="0 0 16 16" fill="currentColor">',
' <path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>',
@ -1171,6 +1288,14 @@ function getHTML() {
'</div>',
// 添加 tokenList 容器
'<div class="token-list" id="tokenList"></div>', // 添加这一行
'<div class="advanced-mode-toggle">',
' <input type="checkbox" id="advancedMode">',
' <label for="advancedMode">高级模式 (自定义Prompt)</label>',
'</div>',
'<div class="prompt-container" id="promptContainer">',
' <label for="promptInput">自定义Prompt</label>',
' <textarea id="promptInput" placeholder="输入自定义prompt...">请识别图片中的内容,注意以下要求:\n对于数学公式和普通文本\n1. 所有数学公式和数学符号都必须使用标准的LaTeX格式\n2. 行内公式使用单个$符号包裹,如:$x^2$\n3. 独立公式块使用两个$$符号包裹,如:$$\\sum_{i=1}^n i^2$$\n4. 普通文本保持原样不要使用LaTeX格式\n5. 保持原文的段落格式和换行\n6. 明显的换行使用\\n表示\n7. 确保所有数学符号都被正确包裹在$或$$中\n\n对于验证码图片\n1. 只输出验证码字符,不要加任何额外解释\n2. 忽略干扰线和噪点\n3. 注意区分相似字符如0和O、1和l、2和Z等\n4. 验证码通常为4-6位字母数字组合\n\n不要输出任何额外的解释或说明</textarea>',
'</div>',
'</div>',
'<div class="container">',
@ -1421,6 +1546,12 @@ function getHTML() {
' }',
' const savedCookie = localStorage.getItem(\'imageRecognitionCookie\');',
' if (!savedCookie) {',
' alert(\'请先设置Cookie\');',
' sidebar.classList.add(\'open\');',
' return;',
' }',
' // 显示图片预览',
' const reader = new FileReader();',
' let imageData;',
@ -1443,8 +1574,7 @@ function getHTML() {
' const uploadResponse = await fetch(\'/proxy/upload\', {',
' method: \'POST\',',
' headers: {',
' \'Authorization\': \'Bearer \' + currentToken,',
' \'x-custom-cookie\': savedCookie || \'\', // 添加 cookie 到请求头',
' \'x-custom-cookie\': savedCookie,',
' },',
' body: formData,',
' });',
@ -1455,22 +1585,21 @@ function getHTML() {
' // 识别图片',
' const recognizeResponse = await fetch(\'/recognize\', {',
' method: \'POST\',',
' headers: { \'Content-Type\': \'application/json\' },',
' body: JSON.stringify({ ',
' token: currentToken, ',
' imageId: uploadData.id ',
' }),',
' headers: { ',
' \'Content-Type\': \'application/json\',',
' \'x-custom-cookie\': savedCookie,',
' \'x-advanced-mode\': advancedMode.checked, // 添加高级模式状态',
' \'x-custom-prompt\': btoa(encodeURIComponent(promptInput.value)), // Base64编码',
' },',
' body: JSON.stringify({ imageId: uploadData.id }),',
' });',
' const recognizeData = await recognizeResponse.json();',
' // 修改这里:使用新的响应格式',
' if (!recognizeData.success) {',
' throw new Error(recognizeData.error || \'识别失败\');',
' }',
' const result = recognizeData.result || \'识别失败\';',
' // 保存原始文本到属性中,确保 LaTeX 格式完整',
' resultDiv.setAttribute(\'data-original-text\', result);',
' resultDiv.innerHTML = result;',
' waitForMathJax(() => {',
@ -1865,6 +1994,32 @@ function getHTML() {
' // 初始化时调用loadSettings',
' loadSettings();',
' // 高级模式切换处理',
' const advancedMode = document.getElementById(\'advancedMode\');',
' const promptContainer = document.getElementById(\'promptContainer\');',
' const promptInput = document.getElementById(\'promptInput\');',
' advancedMode.addEventListener(\'change\', () => {',
' promptContainer.classList.toggle(\'show\', advancedMode.checked);',
' localStorage.setItem(\'advancedMode\', advancedMode.checked);',
' localStorage.setItem(\'customPrompt\', promptInput.value);',
' });',
' // 加载保存的高级模式设置',
' function loadAdvancedSettings() {',
' const savedMode = localStorage.getItem(\'advancedMode\');',
' const savedPrompt = localStorage.getItem(\'customPrompt\');',
' if (savedMode === \'true\') {',
' advancedMode.checked = true;',
' promptContainer.classList.add(\'show\');',
' }',
' if (savedPrompt) {',
' promptInput.value = savedPrompt;',
' }',
' }',
' loadAdvancedSettings();',
'</script>',
'</body>',
'</html>'