Files
dsProject/dsLightRag/static/RecognizeEduQuestionOcr.html
2025-09-01 11:16:24 +08:00

624 lines
21 KiB
HTML
Raw 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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>教育场景识别</title>
<link rel="icon" href="data:">
<!-- 新增引入MathJax库 -->
<script src="https://gcore.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<!-- 新增MathJax配置 -->
<script>
MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
displayMath: [['$$', '$$'], ['\\[', '\\]']],
processEscapes: true
}
};
</script>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
margin: 0;
padding: 0;
background-color: #f5f5f5;
}
.tab-container {
display: flex;
border-bottom: 1px solid #ccc;
margin-bottom: 20px;
}
.tab-button {
padding: 10px 20px;
border: none;
background: #f1f1f1;
cursor: pointer;
transition: all 0.3s ease;
}
.tab-button.active {
background: #4CAF50;
color: white;
}
.tab-button:hover:not(.active) {
background: #ddd;
}
.tab-content {
display: none;
padding: 10px;
}
.tab-content.active {
display: block;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
color: #333;
text-align: center;
}
.tab-container {
display: flex;
margin-bottom: 20px;
}
.tab-button {
flex: 1;
padding: 12px;
background-color: #e0e0e0;
border: none;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
.tab-button.active {
background-color: #4CAF50;
color: white;
}
.tab-button:first-child {
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
}
.tab-button:last-child {
border-top-right-radius: 8px;
border-bottom-right-radius: 8px;
}
.tab-content {
display: none;
background-color: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.tab-content.active {
display: block;
}
.example-section {
margin-bottom: 30px;
}
.example-section h2 {
color: #333;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
}
.example-images {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin-top: 15px;
}
.example-image-card {
width: 200px;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.2s;
}
.example-image-card:hover {
transform: translateY(-5px);
}
.example-image-card img {
width: 100%;
height: 150px;
object-fit: contain;
background-color: #f9f9f9;
}
.example-image-card .description {
padding: 10px;
text-align: center;
font-size: 14px;
color: #666;
}
.recognize-section {
margin-top: 30px;
}
.recognize-section h2 {
color: #333;
border-bottom: 2px solid #4CAF50;
padding-bottom: 10px;
}
.input-area {
margin-top: 15px;
}
.input-group {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.input-group input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
.input-group button {
padding: 10px 15px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.input-group button:hover {
background-color: #45a049;
}
.option-item {
display: block !important; /* 强制块级显示 */
margin: 0.5em 0; /* 上下间距 */
padding: 0.3em; /* 内边距 */
width: 100%; /* 占满容器宽度 */
box-sizing: border-box; /* 确保padding不会溢出 */
padding-right: 15px; /* 序号与内容间距 */
font-weight: bold; /* 突出显示选项序号 */
}
.result-area {
margin-top: 20px;
min-height: 200px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
line-height: 1.8; /* 优化行高 */
}
.option-item {
margin: 8px 0; /* 为选项添加上下间距 */
background-color: #f9f9f9;
}
.loading-animation {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1000;
display: flex !important;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
min-height: 200px;
color: #666;
background-color: rgba(249, 249, 249, 0.7); /* 将不透明度从0.95调整为0.7 */
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite !important;
margin-bottom: 10px;
}
.result-area {
margin-top: 20px;
min-height: 200px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
line-height: 1.8;
position: relative; /* 关键:作为动画容器的定位基准 */
overflow: hidden; /* 防止动画溢出 */
}
.option-item {
margin: 8px 0; /* 为选项添加上下间距 */
background-color: #f9f9f9;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 图片模态框样式 */
.modal {
display: none; /* 默认隐藏 */
position: fixed;
z-index: 1001; /* 确保在加载动画之上 */
padding-top: 50px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.9);
}
.modal-content {
margin: auto;
display: block;
max-width: 80%;
max-height: 80%;
}
.close-btn {
position: absolute;
top: 20px;
right: 35px;
color: white;
font-size: 40px;
font-weight: bold;
cursor: pointer;
transition: 0.3s;
}
.close-btn:hover {
color: #bbb;
}
</style>
</head>
<body>
<div class="container">
<h1>教育场景识别</h1>
<div class="tab-container">
<button class="tab-button active" data-tab="formula" onclick="switchTab('formula')">公式识别</button>
<button class="tab-button" data-tab="question" onclick="switchTab('question')">试题识别</button>
<button class="tab-button" data-tab="handwriting" onclick="switchTab('handwriting')">手写识别</button>
</div>
<!-- 标签内容区域 -->
<div id="formula-content" class="tab-content active">公式识别内容...</div>
<div id="question-content" class="tab-content">试题识别内容...</div>
<div id="handwriting-content" class="tab-content">手写识别内容...</div>
<div class="example-section">
<h2>示例公式图片</h2>
<div class="example-images">
<div class="example-image-card">
<img src="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/GongShi.jpg" alt="公式示例1"
onclick="openModal(this.src)">
<div class="description">数学公式示例</div>
</div>
</div>
</div>
<div class="recognize-section">
<h2>公式识别</h2>
<div class="input-area">
<div class="input-group">
<input type="text" id="formulaImageUrl" placeholder="请输入图片URL或使用示例图片"
value="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/GongShi.jpg">
<button onclick="recognizeFormula()">识别公式</button>
</div>
<div id="formulaResult" class="result-area">
<div style="color:#666; text-align:center; padding:20px;">识别结果将在此处显示</div>
</div>
</div>
</div>
<div class="recognize-section">
<h2>试题识别</h2>
<div class="input-area">
<div class="input-group">
<input type="text" id="questionImageUrl" placeholder="请输入图片URL或使用示例图片"
value="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/ShiTi.jpg">
<button onclick="recognizeQuestion()">识别试题</button>
</div>
<div id="questionResult" class="result-area">
<div style="color:#666; text-align:center; padding:20px;">识别结果将在此处显示</div>
</div>
</div>
</div>
<!-- 图片查看模态框 -->
<div id="imageModal" class="modal">
<span class="close-btn" onclick="closeModal()">&times;</span>
<img class="modal-content" id="modalImage">
</div>
</body>
</html>
<script>
// MathJax 配置
window.MathJax = {
tex: {
inlineMath: [['$', '$'], ['\(', '\)']],
displayMath: [['$$', '$$'], ['\[', '\]']],
processEscapes: true,
packages: {'[+]': ['ams']}
},
svg: {fontCache: 'global'},
startup: {pageReady: pageReady}
};
// MathJax 加载完成后执行
function pageReady() {
return MathJax.startup.defaultPageReady().then(function () {
console.log('MathJax 3 加载完成');
});
}
</script>
<script src="https://gcore.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" id="MathJax-script"></script>
<script>
// 切换标签页
function switchTab(tabName) {
console.log('切换到标签页:', tabName);
// 移除所有标签按钮的active类
document.querySelectorAll('.tab-button').forEach(button => {
button.classList.remove('active');
console.log('移除按钮active类:', button.textContent);
});
// 移除所有标签内容的active类
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
console.log('移除内容active类:', content.id);
});
// 添加active类到当前标签按钮
const targetButton = document.querySelector(`.tab-button[data-tab="${tabName}"]`);
if (targetButton) {
targetButton.classList.add('active');
console.log('添加按钮active类成功:', tabName);
} else {
console.error('未找到标签按钮:', tabName);
}
// 添加active类到当前标签内容
const targetContent = document.getElementById(`${tabName}-content`);
if (targetContent) {
targetContent.classList.add('active');
console.log('添加内容active类成功:', tabName);
} else {
console.error('未找到标签内容:', tabName);
}
}
// 识别公式
function recognizeFormula() {
const imageUrl = document.getElementById('formulaImageUrl').value.trim();
const resultArea = document.getElementById('formulaResult');
if (!imageUrl) {
alert('请输入图片URL');
return;
}
resultArea.innerHTML = '<div class="loading-animation"><div class="spinner"></div><div>正在识别公式...</div></div>';
// 添加延迟模拟API调用
setTimeout(() => {
// 读取本地JSON文件
fetch('Formula.json')
.then(response => {
console.log('JSON请求响应:', response);
if (!response.ok) throw new Error('无法加载本地JSON文件');
return response.json();
})
.then(data => {
if (data.error) {
resultArea.innerHTML = `<div style="color:red">识别失败: ${data.error}</div>`;
return;
}
const content = data.Data?.content || '';
if (!content) {
resultArea.innerHTML = '<div>未识别到公式内容</div>';
return;
}
try {
resultArea.innerHTML = `<div class="tex2jax_process">$$${content}$$</div>`;
renderWithMathJax(resultArea);
} catch (error) {
console.error('公式处理错误:', error);
resultArea.innerHTML = `<div style="color:red">公式处理失败: ${error.message}</div>`;
}
})
.catch(error => {
console.error('请求错误:', error);
const errorMsg = '加载本地JSON失败: ' + error.message;
resultArea.innerHTML = `<div style="color:red">${errorMsg}</div>`;
});
}, 1000); // 1秒延迟
}
// 识别试题
function recognizeQuestion() {
const imageUrl = document.getElementById('questionImageUrl').value.trim();
const resultArea = document.getElementById('questionResult');
if (!imageUrl) {
alert('请输入图片URL');
return;
}
// 立即显示加载动画(关键修复)
console.log('显示加载动画');
resultArea.innerHTML = '<div class="loading-animation"><div class="spinner"></div><div>正在识别试题...</div></div>';
// 添加延迟模拟API调用
setTimeout(() => {
// 读取本地JSON文件
fetch('ShiTi.json')
.then(response => {
console.log('JSON请求响应:', response);
if (!response.ok) throw new Error('无法加载本地JSON文件');
return response.json();
})
.then(data => {
if (data.error) {
resultArea.innerHTML = `<div style="color:red">识别失败: ${data.error}</div>`;
return;
}
let content = data.Data?.content || '';
console.log("处理前:" + content);
try {
// 彻底修复选项标签闭合问题 - 采用分而治之策略
// 1. 首先拆分所有选项为独立数组
const options = content.split(/(?=[A-D]\s*\.)/);
// 2. 逐个处理每个选项确保标签完整
content = options.map(option => {
// 仅处理以选项标签开头的部分
if (/^[A-D]\s*\./.test(option)) {
return `<span class="option-item">$${option}$</span>`; // 添加$符号
}
return option;
}).join('');
// 3. 清理可能的空标签
content = content.replace(/<span class="option-item"><\/span>/g, '');
if (!content.includes('<span class="option-item">')) {
content = content.replace(/((?:[A-D]\s*\.\s*[^.]+)+)/g, '<span class="option-item">$1</span>');
}
// 添加选项间的分隔处理
content = content.replace(/<\/span>\s*<span class="option-item">/g, '</span>\n<span class="option-item">');
const latexContainer = document.createElement('div');
latexContainer.className = 'tex2jax_process';
latexContainer.innerHTML = content;
console.log('预处理后的内容:', latexContainer.innerHTML);
resultArea.innerHTML = '';
resultArea.appendChild(latexContainer);
renderWithMathJax(resultArea);
} catch (error) {
console.error('试题处理错误:', error);
resultArea.innerHTML = `<div style="color:red">试题处理失败: ${error.message}</div>`;
}
})
.catch(error => {
console.error('请求错误:', error);
const errorMsg = '加载本地JSON失败: ' + error.message;
resultArea.innerHTML = `<div style="color:red">${errorMsg}</div>`;
});
}, 1000); // 1秒延迟
}
// MathJax渲染函数
function renderWithMathJax(element) {
if (!window.MathJax) {
console.error('MathJax未加载5秒后重试');
setTimeout(() => renderWithMathJax(element), 5000);
return;
}
try {
MathJax.typesetPromise([element]).then(() => {
console.log('MathJax渲染完成');
}).catch((e) => {
console.error('MathJax渲染错误:', e);
fallbackRender(element);
});
} catch (e) {
console.error('MathJax调用错误:', e);
fallbackRender(element);
}
}
// 渲染失败时的回退方法
function fallbackRender(element) {
const originalContent = element.querySelector('.tex2jax_process')?.textContent || '';
if (originalContent) {
element.innerHTML = `<div style="font-family: monospace; white-space: pre-wrap;">${escapeHtml(originalContent)}</div><div style="color:orange">提示MathJax渲染失败显示原始公式代码</div>`;
}
}
// HTML转义函数
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 等待DOM加载完成
document.addEventListener('DOMContentLoaded', function () {
// 初始化第一个标签为活动状态
document.querySelector('.tab-button[data-tab="formula"]').classList.add('active');
document.getElementById('formula-content').classList.add('active');
// 为所有标签按钮添加点击事件
document.querySelectorAll('.tab-button').forEach(button => {
button.addEventListener('click', function () {
const tabName = this.getAttribute('data-tab');
// 移除所有活动状态
document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
// 设置当前标签为活动状态
this.classList.add('active');
document.getElementById(`${tabName}-content`).classList.add('active');
});
});
});
// 图片模态框控制函数
function openModal(imageSrc) {
const modal = document.getElementById('imageModal');
const modalImg = document.getElementById('modalImage');
modal.style.display = 'block';
modalImg.src = imageSrc;
}
function closeModal() {
document.getElementById('imageModal').style.display = 'none';
}
</script>