635 lines
22 KiB
HTML
635 lines
22 KiB
HTML
<!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;
|
||
}
|
||
|
||
.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;
|
||
cursor: pointer; /* 添加鼠标悬停小手效果 */
|
||
}
|
||
|
||
.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" onclick="switchTab('formula')">公式识别</button>
|
||
<button class="tab-button" onclick="switchTab('question')">试题识别</button>
|
||
<button class="tab-button" onclick="switchTab('handwriting')">手写识别</button>
|
||
</div>
|
||
|
||
<!-- 公式识别标签页 -->
|
||
<div id="formula-tab" class="tab-content active">
|
||
<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>
|
||
|
||
<!-- 试题识别标签页 -->
|
||
<div id="question-tab" class="tab-content">
|
||
<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/ShiTi.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="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>
|
||
|
||
<!-- 图片查看模态框 -->
|
||
<div id="imageModal" class="modal">
|
||
<span class="close-btn" onclick="closeModal()">×</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) {
|
||
// 移除所有标签的激活状态
|
||
document.querySelectorAll('.tab-button').forEach(button => button.classList.remove('active'));
|
||
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
|
||
|
||
// 激活当前标签
|
||
const targetButton = document.querySelector(`.tab-button[onclick="switchTab('${tabName}')"]`);
|
||
const targetContent = document.getElementById(`${tabName}-tab`);
|
||
|
||
if (targetButton && targetContent) {
|
||
targetButton.classList.add('active');
|
||
targetContent.classList.add('active');
|
||
} 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>`;
|
||
}
|
||
}
|
||
|
||
// 打开图片模态框
|
||
function openModal(imageSrc) {
|
||
const modal = document.getElementById('imageModal');
|
||
const modalImg = document.getElementById('modalImage');
|
||
modal.style.display = 'block';
|
||
modalImg.src = imageSrc;
|
||
}
|
||
|
||
// 关闭图片模态框
|
||
function closeModal() {
|
||
const modal = document.getElementById('imageModal');
|
||
modal.style.display = 'none';
|
||
}
|
||
|
||
// 点击模态框外部关闭
|
||
window.onclick = function (event) {
|
||
const modal = document.getElementById('imageModal');
|
||
if (event.target === modal) {
|
||
closeModal();
|
||
}
|
||
}
|
||
|
||
// HTML转义函数
|
||
function escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML;
|
||
}
|
||
|
||
// 识别手写(仅显示提示信息)
|
||
function recognizeHandwriting() {
|
||
alert("功能尚未实现,敬请期待!");
|
||
}
|
||
</script>
|
||
|
||
<!-- 手写识别标签页 -->
|
||
<div id="handwriting-tab" class="tab-content">
|
||
<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/ShouXie1.jpg"
|
||
alt="手写示例1"
|
||
onclick="openModal(this.src)">
|
||
<div class="description">手写示例1</div>
|
||
</div>
|
||
<div class="example-image-card">
|
||
<img src="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/ShouXie2.jpg"
|
||
alt="手写示例2"
|
||
onclick="openModal(this.src)">
|
||
<div class="description">手写示例2</div>
|
||
</div>
|
||
<div class="example-image-card">
|
||
<img src="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/ShouXie3.jpg"
|
||
alt="手写示例3"
|
||
onclick="openModal(this.src)">
|
||
<div class="description">手写示例3</div>
|
||
</div>
|
||
<div class="example-image-card">
|
||
<img src="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/ShouXie4.jpg"
|
||
alt="手写示例4"
|
||
onclick="openModal(this.src)">
|
||
<div class="description">手写示例4</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="recognize-section">
|
||
<h2>手写识别</h2>
|
||
<div class="input-area">
|
||
<div class="input-group">
|
||
<input type="text" id="handwritingImageUrl" placeholder="请输入图片URL或使用示例图片"
|
||
value="https://dsideal.obs.cn-north-1.myhuaweicloud.com/HuangHai/Backup/ShouXie1.jpg">
|
||
|
||
<button onclick="recognizeHandwriting()">识别手写</button>
|
||
</div>
|
||
<div id="handwritingResult" class="result-area">
|
||
<div style="color:#666; text-align:center; padding:20px;">识别结果将在此处显示</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</body>
|
||
</html> |