Update worker.js

This commit is contained in:
programmerWsy 2025-01-13 18:50:30 +08:00 committed by GitHub
parent 3da4260d99
commit a6a5241c26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

377
worker.js
View File

@ -16,216 +16,86 @@ async function handleRequest(request) {
});
}
// API路由处理
switch (url.pathname) {
// 1. 通过图片URL识别
case '/api/recognize/url':
if (request.method === 'POST') {
return handleImageUrlRecognition(request);
// 处理 POST 请求
if (request.method === 'POST' && url.pathname === '/recognize') {
try {
const { token, imageId } = await request.json();
if (!token || !imageId) {
return new Response(JSON.stringify({ error: 'Missing token or imageId' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
break;
// 2. 通过Base64识别
case '/api/recognize/base64':
if (request.method === 'POST') {
return handleBase64Recognition(request);
}
break;
// 3. 通过图片文件识别 (原有的/recognize端点)
case '/recognize':
if (request.method === 'POST') {
return handleFileRecognition(request);
}
break;
// 返回前端界面
case '/':
return new Response(getHTML(), {
headers: { 'Content-Type': 'text/html' },
});
}
return new Response('Not Found', { status: 404 });
}
// 处理图片URL识别
async function handleImageUrlRecognition(request) {
try {
const { token, imageUrl } = await request.json();
if (!token || !imageUrl) {
return new Response(JSON.stringify({
error: 'Missing token or imageUrl'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// 下载图片
const imageResponse = await fetch(imageUrl);
const imageBlob = await imageResponse.blob();
// 上传到QwenLM
const formData = new FormData();
formData.append('file', imageBlob);
const uploadResponse = await fetch('https://chat.qwenlm.ai/api/v1/files/', {
method: 'POST',
headers: {
'accept': 'application/json',
'authorization': `Bearer ${token}`,
},
body: formData,
});
const uploadData = await uploadResponse.json();
if (!uploadData.id) throw new Error('File upload failed');
// 调用识别API
return await recognizeImage(token, uploadData.id);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// 处理Base64识别
async function handleBase64Recognition(request) {
try {
const { token, base64Image } = await request.json();
if (!token || !base64Image) {
return new Response(JSON.stringify({
error: 'Missing token or base64Image'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// 转换Base64为Blob
const imageData = base64Image.startsWith('data:') ?
base64Image :
'data:image/png;base64,' + base64Image;
const response = await fetch(imageData);
const blob = await response.blob();
// 上传到QwenLM
const formData = new FormData();
formData.append('file', blob);
const uploadResponse = await fetch('https://chat.qwenlm.ai/api/v1/files/', {
method: 'POST',
headers: {
'accept': 'application/json',
'authorization': `Bearer ${token}`,
},
body: formData,
});
const uploadData = await uploadResponse.json();
if (!uploadData.id) throw new Error('File upload failed');
// 调用识别API
return await recognizeImage(token, uploadData.id);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// 处理文件识别 (原有功能)
async function handleFileRecognition(request) {
try {
const { token, imageId } = await request.json();
if (!token || !imageId) {
return new Response(JSON.stringify({
error: 'Missing token or imageId'
}), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
return await recognizeImage(token, imageId);
} catch (error) {
return new Response(JSON.stringify({
error: error.message || 'Internal Server Error'
}), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// 通用的识别函数
async function recognizeImage(token, imageId) {
const response = await fetch('https://chat.qwenlm.ai/api/chat/completions', {
method: 'POST',
headers: {
'accept': '*/*',
'authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
stream: false,
model: 'qwen-vl-max-latest',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: '请识别图片中的内容。对于数学公式和数学符号请使用标准的LaTeX格式输出。' +
'要求:\n' +
'1. 所有数学公式和单个数学符号都要用LaTeX格式\n' +
'2. 普通文本保持原样\n' +
'3. 对于行内公式使用$单个符号$\n' +
'4. 对于独立公式块使用$$公式$$\n' +
'5. 严格保持原文的段落格式和换行\n' +
'6. 当文本明显换行时,使用\\n进行换行处理'
},
{ type: 'image', image: imageId },
],
// 调用 QwenLM API
const response = await fetch('https://chat.qwenlm.ai/api/chat/completions', {
method: 'POST',
headers: {
'accept': '*/*',
'authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
],
session_id: '1',
chat_id: '2',
id: '3',
}),
});
body: JSON.stringify({
stream: false,
model: 'qwen-vl-max-latest',
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: '请识别图片中的内容。对于数学公式和数学符号请使用标准的LaTeX格式输出。' +
'要求:\n' +
'1. 所有数学公式和单个数学符号都要用LaTeX格式\n' +
'2. 普通文本保持原样\n' +
'3. 对于行内公式使用$单个符号$\n' +
'4. 对于独立公式块使用$$公式$$\n' +
'5. 严格保持原文的段落格式和换行\n' +
'6. 当文本明显换行时,使用\\n进行换行处理\n' +
'请尽可能精确地转换每个数学符号并保持原始排版格式。'
},
{ type: 'image', image: imageId }, // 使用上传后的图片 ID
],
},
],
session_id: '1',
chat_id: '2',
id: '3',
}),
});
const data = await response.json();
const data = await response.json();
// 处理识别结果
let result = data.choices[0]?.message?.content || '识别失败';
result = result
.replace(/\\/g, '\\(')
.replace(/\\/g, '\\)')
.replace(/\n{3,}/g, '\n\n')
.replace(/([^\n])\n([^\n])/g, '$1\n$2')
.trim();
// 对识别结果进行后处理确保LaTeX格式正确并保持换行
let result = data.choices[0]?.message?.content || '识别失败';
result = result
// 修复可能的LaTeX格式问题
.replace(/\\/g, '\\(')
.replace(/\\/g, '\\)')
// 确保连续的换行符被保留2个以上的换行符表示段落分隔
.replace(/\n{3,}/g, '\n\n')
// 保留单个换行符,不合并
.replace(/([^\n])\n([^\n])/g, '$1\n$2')
.trim();
return new Response(JSON.stringify({
success: true,
result: result
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
return new Response(JSON.stringify({ ...data, choices: [{ message: { content: result } }] }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
} catch (error) {
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
// 返回前端界面
return new Response(getHTML(), {
headers: { 'Content-Type': 'text/html' },
});
}
@ -686,30 +556,6 @@ function getHTML() {
' .copy-btn.copied {',
' background: #27ae60;',
' }',
' /* Base64输入相关样式 */',
' #base64Input {',
' width: 100%;',
' height: 100px;',
' padding: 10px;',
' margin-top: 10px;',
' border: 1px solid #dcdde1;',
' border-radius: 8px;',
' resize: vertical;',
' }',
' .toggle-btn {',
' background: #3498db;',
' color: white;',
' border: none;',
' padding: 8px 15px;',
' border-radius: 5px;',
' cursor: pointer;',
' margin-top: 10px;',
' transition: background 0.3s ease;',
' }',
' .toggle-btn:hover {',
' background: #2980b9;',
' }',
'</style>',
'</head>',
'<body>',
@ -732,11 +578,9 @@ function getHTML() {
'<div class="upload-area" id="uploadArea">',
'<i>📸</i>',
'<div class="upload-text">',
'拖拽图片到这里,点击上传或粘贴Base64图片内容<br>',
'拖拽图片到这里,点击上传<br>',
'支持复制粘贴图片',
'</div>',
'<textarea id="base64Input" placeholder="在此输入Base64格式的图片内容..." style="display: none; width: 100%; height: 100px; margin-top: 10px;"></textarea>',
'<button id="toggleBase64" class="toggle-btn" style="margin-top: 10px;">切换Base64输入</button>',
'<img id="previewImage" class="preview-image">',
'</div>',
'<div class="loading" id="loading"></div>',
@ -976,15 +820,7 @@ function getHTML() {
' });',
' // 点击上传',
' uploadArea.addEventListener(\'click\', (e) => {',
' // 如果点击的是 base64Input 或 toggleBase64 按钮,不触发文件上传',
' if (e.target.id === \'base64Input\' || ',
' e.target.id === \'toggleBase64\' || ',
' e.target.closest(\'#base64Input\') || ',
' e.target.closest(\'#toggleBase64\')) {',
' return;',
' }',
' uploadArea.addEventListener(\'click\', () => {',
' const input = document.createElement(\'input\');',
' input.type = \'file\';',
' input.accept = \'image/*\';',
@ -1039,7 +875,6 @@ function getHTML() {
' // 复制结果功能',
' copyBtn.addEventListener(\'click\', async () => {',
' const result = resultDiv.textContent;',
' toggleBase64.textContent = \'隐藏Base64输入\';',
' try {',
' await navigator.clipboard.writeText(result);',
' copyBtn.textContent = \'已复制\';',
@ -1056,66 +891,6 @@ function getHTML() {
' document.getElementById("closeSidebar").addEventListener("click", () => {',
' sidebar.classList.remove("open");',
' });',
' // Base64 输入相关功能',
' const base64Input = document.getElementById(\'base64Input\');',
' const toggleBase64 = document.getElementById(\'toggleBase64\');',
' // 切换 Base64 输入框显示',
' toggleBase64.addEventListener(\'click\', (e) => {',
' e.stopPropagation(); // 阻止事件冒泡到 uploadArea',
' if (base64Input.style.display === \'none\') {',
' base64Input.style.display = \'block\';',
' toggleBase64.textContent = \'隐藏Base64输入\';',
' } else {',
' base64Input.style.display = \'none\';',
' toggleBase64.textContent = \'切换Base64输入\';',
' }',
' });',
' // 为 base64Input 添加阻止事件冒泡',
' document.getElementById(\'base64Input\').addEventListener(\'click\', (e) => {',
' e.stopPropagation(); // 阻止事件冒泡到 uploadArea',
' });',
' // base64Input 的 input 事件处理也需要阻止冒泡',
' base64Input.addEventListener(\'input\', async (e) => {',
' e.stopPropagation();',
' const base64Content = base64Input.value.trim();',
' if (base64Content) {',
' try {',
' // 尝试转换Base64为Blob',
' let imageData;',
' if (base64Content.startsWith(\'data:image\')) {',
' imageData = base64Content;',
' } else {',
' imageData = \'data:image/png;base64,\' + base64Content;',
' }',
' // 验证Base64是否为有效图片',
' const img = new Image();',
' img.src = imageData;',
' await new Promise((resolve, reject) => {',
' img.onload = resolve;',
' img.onerror = reject;',
' });',
' // 转换Base64为Blob',
' const response = await fetch(imageData);',
' const blob = await response.blob();',
' const file = new File([blob], "image.png", { type: "image/png" });',
' // 显示预览',
' previewImage.src = imageData;',
' previewImage.style.display = \'block\';',
' // 处理图片',
' processImage(file);',
' } catch (error) {',
' alert(\'无效的Base64图片内容\');',
' console.error(\'Base64处理错误:\', error);',
' }',
' }',
' });',
'</script>',
'</body>',
'</html>'