戒酒的李白

Delete the BCAT frontend page.

import os
import subprocess
import threading
from flask import Flask, render_template, request, redirect, url_for, flash
from werkzeug.utils import secure_filename
import json
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'data/' # 上传文件的保存目录
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 文件大小限制为16MB
app.secret_key = 'secret_key' # 用于Flash消息的密钥
ALLOWED_EXTENSIONS = {'csv'} # 允许的文件扩展名
processing_status = {} # 全局字典用于存储处理状态和统计信息
def allowed_file(filename):
"""检查文件是否是允许的类型"""
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/')
def upload_form():
"""显示文件上传表单"""
return render_template('main.html')
@app.route('/upload', methods=['POST'])
def upload_file():
"""处理文件上传和启动异步处理"""
if 'file' not in request.files:
flash('没有文件部分', 'error')
return redirect(url_for('upload_form'))
file = request.files['file']
if file.filename == '':
flash('未选择文件', 'error')
return redirect(url_for('upload_form'))
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
filepath = os.path.abspath(filepath) # 转换为绝对路径
try:
file.save(filepath)
print(f'文件已保存到 {filepath}')
# 初始化处理状态
processing_status[filename] = {'status': 'processing', 'stats': None}
# 启动后台线程处理文件
thread = threading.Thread(target=handle_file_processing, args=(filepath, filename))
thread.start()
# 重定向到等待页面,并传递文件名以跟踪状态
return redirect(url_for('waiting_page', filename=filename))
except Exception as e:
flash(f'文件上传失败: {str(e)}', 'error')
return redirect(url_for('upload_failure'))
else:
flash('文件类型不允许', 'error')
return redirect(url_for('upload_form'))
@app.route('/waiting/<filename>')
def waiting_page(filename):
"""显示等待页面,并传递文件名"""
return render_template('waiting.html', filename=filename)
@app.route('/status/<filename>')
def check_status(filename):
"""检查文件处理状态,并返回状态和统计信息"""
status_info = processing_status.get(filename, {'status': 'processing', 'stats': None})
return json.dumps(status_info)
@app.route('/upload-success')
def upload_success():
"""文件处理成功页面"""
filename = request.args.get('filename')
stats = processing_status.get(filename, {}).get('stats', {})
return render_template('success.html', stats=stats)
@app.route('/upload-failure')
def upload_failure():
"""文件处理失败页面"""
filename = request.args.get('filename')
stats = processing_status.get(filename, {}).get('stats', {})
return render_template('failure.html', stats=stats)
def handle_file_processing(filepath, filename):
"""异步处理文件并根据统计结果设置处理状态"""
try:
script_path = r'E:\ICTfront\BCAT\using_example.py' # 请根据实际路径更新
stats_output_path = os.path.join(app.config['UPLOAD_FOLDER'], f'stats_{filename}.json')
# 执行外部脚本,传递文件路径和统计信息文件路径作为参数
result = subprocess.run(
['python', script_path, filepath, stats_output_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='utf-8'
)
print(f"脚本标准输出: {result.stdout}")
print(f"脚本标准错误: {result.stderr}")
if result.returncode == 0:
# 读取统计信息
with open(stats_output_path, 'r', encoding='utf-8') as f:
stats = json.load(f)
# 获取“不良”标签的占比
bad_percentage = float(stats.get("不良", {}).get("percentage", "0%").strip('%'))
if bad_percentage > 5.0:
# 失败占比超过5%,标记为失败
processing_status[filename] = {
'status': 'failure',
'stats': stats
}
else:
# 成功
processing_status[filename] = {
'status': 'success',
'stats': stats
}
else:
# 脚本执行失败
processing_status[filename] = {
'status': 'failure',
'stats': None
}
except Exception as e:
print(f"运行脚本时出错: {str(e)}")
processing_status[filename] = {
'status': 'failure',
'stats': None
}
if __name__ == '__main__':
# 如果上传文件夹不存在,则创建
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.makedirs(app.config['UPLOAD_FOLDER'])
app.run(debug=True)
import torch
import pandas as pd
import numpy as np
from torch.utils.data import DataLoader, TensorDataset
from tqdm import tqdm
import os
import sys
import json
import chardet
# 导入改进版模型的组件
from model_pro.MHA import MultiHeadAttentionLayer
from model_pro.classifier import FinalClassifier
from model_pro.BERT_CTM import BERT_CTM_Model
class ModelManager:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super(ModelManager, cls).__new__(cls)
return cls._instance
def __init__(self):
if not self._initialized:
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.classifier_model = None
self.attention_model = None
self.bert_ctm_model = None
self._initialized = True
def load_models(self, model_save_path, bert_model_path, ctm_tokenizer_path):
"""加载所有需要的模型"""
try:
if self.classifier_model is None:
self.classifier_model = torch.load(model_save_path, map_location=self.device)
self.classifier_model.eval()
if self.attention_model is None:
self.attention_model = MultiHeadAttentionLayer(embed_size=768, num_heads=8)
self.attention_model.to(self.device)
self.attention_model.eval()
if self.bert_ctm_model is None:
self.bert_ctm_model = BERT_CTM_Model(
bert_model_path=bert_model_path,
ctm_tokenizer_path=ctm_tokenizer_path
)
return True
except Exception as e:
print(f"模型加载失败: {e}")
return False
def predict_batch(self, texts, batch_size=32):
"""批量预测文本情感"""
try:
all_predictions = []
all_probabilities = []
# 分批处理文本
for i in range(0, len(texts), batch_size):
batch_texts = texts[i:i + batch_size]
# 获取文本嵌入
embeddings = self.bert_ctm_model.get_bert_embeddings(batch_texts)
# 转换为tensor
batch_x = torch.tensor(embeddings, dtype=torch.float32).to(self.device)
batch_x = torch.mean(batch_x, dim=1)
with torch.no_grad():
# 使用注意力机制
attention_output = self.attention_model(batch_x, batch_x, batch_x)
# 获取分类结果
outputs = self.classifier_model(attention_output)
outputs = torch.mean(outputs, dim=1)
# 获取预测概率
probabilities = torch.softmax(outputs, dim=1)
# 获取预测标签
_, predicted = torch.max(outputs, 1)
all_predictions.extend(predicted.cpu().numpy())
all_probabilities.extend(probabilities.cpu().numpy())
return all_predictions, all_probabilities
except Exception as e:
print(f"预测过程中出现错误: {e}")
return None, None
# 创建全局的模型管理器实例
model_manager = ModelManager()
def detect_file_encoding(file_path, num_bytes=10000):
"""
使用 chardet 检测文件的编码。
:param file_path: 文件路径
:param num_bytes: 用于检测的字节数
:return: 检测到的编码
"""
with open(file_path, 'rb') as f:
rawdata = f.read(num_bytes)
result = chardet.detect(rawdata)
encoding = result['encoding']
confidence = result['confidence']
print(f"检测到的编码: {encoding}, 置信度: {confidence}")
return encoding
def get_bert_ctm_embeddings(texts, bert_model_path, ctm_tokenizer_path, n_components=12, num_epochs=20):
# 创建BERT_CTM_Model实例
bert_ctm_model = BERT_CTM_Model(
bert_model_path=bert_model_path,
ctm_tokenizer_path=ctm_tokenizer_path,
n_components=n_components,
num_epochs=num_epochs
)
# 获取嵌入
embeddings = bert_ctm_model.get_bert_embeddings(texts)
return embeddings
def prepare_dataloader(features, batch_size):
tensor_x = torch.tensor(features, dtype=torch.float32)
dataset = TensorDataset(tensor_x)
return DataLoader(dataset, batch_size=batch_size, shuffle=False)
def predict(model_save_path, input_data_path, output_path, bert_model_path, ctm_tokenizer_path, stats_output_path,
batch_size=128,
num_classes=2):
try:
# 加载模型
print("加载模型...")
if not model_manager.load_models(model_save_path, bert_model_path, ctm_tokenizer_path):
return False
# 检测文件编码
encoding = detect_file_encoding(input_data_path)
# 读取输入数据
print("读取输入数据...")
data = pd.read_csv(input_data_path, encoding=encoding)
texts = data['TEXT'].tolist()
# 生成嵌入
print("生成文本嵌入...")
embeddings = get_bert_ctm_embeddings(texts, bert_model_path, ctm_tokenizer_path)
# 准备DataLoader
data_loader = prepare_dataloader(embeddings, batch_size)
# 存储预测结果
all_predictions = []
all_probabilities = []
print("开始预测...")
with torch.no_grad():
for batch in tqdm(data_loader, desc="预测进度"):
batch_x = batch[0].to(model_manager.device)
batch_x = torch.mean(batch_x, dim=1)
# 使用注意力机制
attention_output = model_manager.attention_model(batch_x, batch_x, batch_x)
# 获取分类结果
outputs = model_manager.classifier_model(attention_output)
outputs = torch.mean(outputs, dim=1)
# 获取预测概率
probabilities = torch.softmax(outputs, dim=1)
# 获取预测标签
_, predicted = torch.max(outputs, 1)
all_predictions.extend(predicted.cpu().numpy())
all_probabilities.extend(probabilities.cpu().numpy())
# 添加预测结果和概率到数据框
data['Predicted_Label'] = all_predictions
data['Confidence'] = [prob[pred] for prob, pred in zip(all_probabilities, all_predictions)]
# 保存预测结果
data.to_csv(output_path, index=False, encoding='utf-8')
print(f"预测结果已保存到 {output_path}")
# 统计标签的个数和占比
label_counts = data['Predicted_Label'].value_counts()
total_count = len(data)
stats = {
'统计信息': {
'总样本数': total_count,
'各类别统计': {}
}
}
for label, count in label_counts.items():
label_name = "良好" if label == 0 else "不良"
percentage = (count / total_count) * 100
confidence_mean = data[data['Predicted_Label'] == label]['Confidence'].mean()
stats['统计信息']['各类别统计'][label_name] = {
'数量': int(count),
'占比': f"{percentage:.2f}%",
'平均置信度': f"{confidence_mean:.2f}"
}
print(f"标签: {label_name}, 数量: {count}, 占比: {percentage:.2f}%, 平均置信度: {confidence_mean:.2f}")
# 将统计信息保存到 JSON 文件
with open(stats_output_path, 'w', encoding='utf-8') as f:
json.dump(stats, f, ensure_ascii=False, indent=4)
return True
except Exception as e:
print(f"预测过程中出现错误: {e}")
return False
if __name__ == "__main__":
if len(sys.argv) != 3:
print("使用方法: python predict.py <input_data_path> <stats_output_path>")
sys.exit(1)
input_data_path = sys.argv[1]
stats_output_path = sys.argv[2]
# 定义路径
model_save_path = 'model_pro/final_model.pt'
output_path = 'model_pro/predictions.csv'
bert_model_path = 'model_pro/bert_model'
ctm_tokenizer_path = 'model_pro/sentence_bert_model'
# 执行预测
success = predict(model_save_path, input_data_path, output_path, bert_model_path, ctm_tokenizer_path,
stats_output_path)
if success:
sys.exit(0)
else:
sys.exit(1)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>检测到不良言论!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
width: 600px;
background-color: #fff;
padding: 50px;
border-radius: 15px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 28px; /* 与 main 的标题一致 */
margin-bottom: 20px;
}
.status-box {
margin-top: 20px;
padding: 20px;
font-size: 18px; /* 与 main 的字体大小一致 */
background-color: #ffebee;
color: #c62828;
border-radius: 10px;
border: 1px solid #c62828;
}
.stats-table {
margin-top: 30px;
width: 100%;
border-collapse: collapse;
}
.stats-table th, .stats-table td {
border: 1px solid #ddd;
padding: 12px;
}
.stats-table th {
background-color: #f2f2f2;
}
a {
display: inline-block;
margin-top: 30px;
padding: 15px 40px;
font-size: 18px;
background-color: #000;
color: white;
text-decoration: none;
border-radius: 30px;
font-weight: bold;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #333;
}
</style>
</head>
<body>
<div class="container">
<h1>数据分析完毕!</h1>
<div class="status-box">
检测到不良言论!
</div>
{% if stats %}
<h3>统计信息:</h3>
<table class="stats-table">
<thead>
<tr>
<th>标签</th>
<th>个数</th>
<th>占比</th>
</tr>
</thead>
<tbody>
{% for label, info in stats.items() %}
<tr>
<td>{{ label }}</td>
<td>{{ info.count }}</td>
<td>{{ info.percentage }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>没有统计信息可显示。</p>
{% endif %}
<a href="/">返回首页</a>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
position: relative;
overflow: hidden;
}
/* 全局遮罩层 */
#global-blur {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.2); /* 半透明遮罩 */
z-index: 2; /* 在 container 上面 */
display: none; /* 默认隐藏,拖拽时显示 */
pointer-events: none; /* 允许事件穿透模糊层 */
}
/* main 容器 */
.container {
z-index: 1; /* 在模糊层之下 */
text-align: center;
width: 600px;
background-color: #fff;
padding: 50px;
border-radius: 15px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
transition: filter 0.3s ease; /* 添加过渡效果 */
}
/* 当模糊时,应用到 container */
.container.blurred {
filter: blur(10px); /* 对 main 容器应用模糊效果 */
}
.upload-box {
border: 2px dashed #4caf50;
padding: 40px;
cursor: pointer;
border-radius: 15px;
margin-top: 20px;
position: relative;
}
.upload-box input[type="file"] {
display: none;
}
.upload-box label {
color: #4caf50;
font-size: 20px;
cursor: pointer;
}
.file-display {
display: none;
margin-top: 20px;
padding: 20px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 15px;
text-align: left;
position: relative; /* 修正删除按钮错位问题 */
}
.file-display img {
width: 40px;
height: 40px;
vertical-align: middle;
margin-right: 10px;
}
.file-display span {
font-size: 18px;
font-weight: bold;
}
.file-display .file-size {
font-size: 16px;
color: #888;
}
.file-display .remove-btn {
position: absolute;
right: 10px; /* 调整删除按钮的位置 */
top: 50%;
transform: translateY(-50%); /* 垂直居中 */
background-color: red;
color: white;
border: none;
border-radius: 50%;
width: 25px;
height: 25px;
cursor: pointer;
font-size: 16px;
line-height: 22px;
text-align: center;
}
.submit-button {
display: inline-block;
background-color: #000;
color: white;
padding: 15px 40px;
border-radius: 30px;
font-size: 18px;
font-weight: bold;
border: none;
cursor: pointer;
margin-top: 20px;
}
.submit-button:hover {
background-color: #333;
}
.submit-button::after {
content: '→';
font-size: 18px;
margin-left: 8px;
}
/* 弹窗样式 */
.popup {
position: fixed;
top: 35%;
left: 30%;
width: 40%;
height: 30%;
background-color: rgba(0, 0, 0, 0.8); /* 半透明黑色背景 */
border-radius: 15px;
display: none;
justify-content: center;
align-items: center;
text-align: center;
z-index: 9999; /* 确保弹窗在最上层 */
color: white;
font-size: 24px;
font-weight: bold;
padding: 20px;
flex-direction: column; /* 让文字上下排列 */
backdrop-filter: blur(5px); /* 添加背景模糊效果 */
}
.popup h2 {
margin-bottom: 10px;
font-size: 32px;
}
.popup p {
font-size: 20px;
}
/* 美化弹窗内容 */
.popup .upload-icon {
font-size: 60px;
margin-bottom: 20px;
color: #4caf50;
}
</style>
</head>
<body>
<!-- 全局模糊层 -->
<div id="global-blur"></div>
<div class="container" id="container">
<h1 style="font-size: 28px;">文件上传</h1>
<p style="font-size: 18px;">请选择一个 CSV 文件上传,我们将为您分析数据</p>
<!-- 文件上传区域 -->
<form id="upload-form" action="/upload" method="post" enctype="multipart/form-data">
<div class="upload-box" id="upload-box">
<label>点击这里或拖拽文件上传</label>
<input id="file-upload" type="file" name="file" accept=".csv" required>
</div>
<!-- 文件展示区域 -->
<div id="file-display" class="file-display">
<img src="https://img.icons8.com/color/48/000000/csv.png" alt="CSV">
<span id="file-name">文件名</span>
<span class="file-size" id="file-size">大小</span>
<button type="button" class="remove-btn" id="remove-btn">×</button>
</div>
<button type="submit" class="submit-button">Start now</button>
</form>
</div>
<!-- 弹窗 -->
<div class="popup" id="popup">
<h2>文件拖拽到此处即可上传</h2>
<p>支持的文件格式:CSV</p>
</div>
<script>
const fileInput = document.getElementById('file-upload');
const fileDisplay = document.getElementById('file-display');
const fileNameDisplay = document.getElementById('file-name');
const fileSizeDisplay = document.getElementById('file-size');
const removeBtn = document.getElementById('remove-btn');
const uploadBox = document.getElementById('upload-box');
const popup = document.getElementById('popup');
const globalBlur = document.getElementById('global-blur');
const container = document.getElementById('container');
// 点击上传区域时,触发文件选择框
uploadBox.addEventListener('click', function() {
fileInput.click();
});
// 监听文件选择事件
fileInput.addEventListener('change', function () {
const file = fileInput.files[0];
if (file) {
if (file.name.endsWith('.csv')) {
fileNameDisplay.textContent = file.name;
fileSizeDisplay.textContent = `, ${Math.round(file.size / 1024)} KB`;
fileDisplay.style.display = 'block';
} else {
alert('只允许上传 CSV 文件');
fileInput.value = ''; // 清除文件
}
// 隐藏模糊层和弹窗
globalBlur.style.display = 'none';
popup.style.display = 'none';
container.classList.remove('blurred'); // 移除模糊效果
}
});
// 删除按钮逻辑
removeBtn.addEventListener('click', function () {
fileDisplay.style.display = 'none';
fileInput.value = '';
// 隐藏模糊层和弹窗
globalBlur.style.display = 'none';
popup.style.display = 'none';
container.classList.remove('blurred'); // 移除模糊效果
});
// 监听整个页面的拖拽进入事件,显示弹窗和模糊层
document.addEventListener('dragenter', function (e) {
e.preventDefault();
globalBlur.style.display = 'block'; // 显示全局模糊层
popup.style.display = 'flex'; // 显示弹出框
container.classList.add('blurred'); // 对 container 添加模糊效果
});
// 监听拖拽离开弹窗区域,隐藏弹窗和模糊层
document.addEventListener('dragleave', function (e) {
e.preventDefault();
// 如果鼠标离开整个窗口,则隐藏模糊层和弹窗
if (e.clientX <= 0 || e.clientY <= 0 || e.clientX >= window.innerWidth || e.clientY >= window.innerHeight) {
globalBlur.style.display = 'none';
popup.style.display = 'none';
container.classList.remove('blurred');
}
});
// 在弹窗上允许拖拽
popup.addEventListener('dragover', function (e) {
e.preventDefault();
});
// 在弹窗上接收文件
popup.addEventListener('drop', function (e) {
e.preventDefault();
globalBlur.style.display = 'none';
popup.style.display = 'none';
container.classList.remove('blurred');
const file = e.dataTransfer.files[0];
if (file && file.name.endsWith('.csv')) {
fileInput.files = e.dataTransfer.files;
const event = new Event('change');
fileInput.dispatchEvent(event);
} else {
alert('只允许上传 CSV 文件');
}
});
// 在页面其他地方的 drop 事件,隐藏模糊层和弹窗
document.addEventListener('drop', function (e) {
e.preventDefault();
globalBlur.style.display = 'none';
popup.style.display = 'none';
container.classList.remove('blurred');
// 不处理文件上传
});
// 防止在页面其他位置的拖拽行为
document.addEventListener('dragover', function (e) {
e.preventDefault();
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>一切正常!</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
width: 600px;
background-color: #fff;
padding: 50px;
border-radius: 15px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
}
h1 {
font-size: 28px; /* 和 main 的标题一致 */
margin-bottom: 20px;
}
.status-box {
margin-top: 20px;
padding: 20px;
font-size: 18px; /* 和 main 的字体大小一致 */
background-color: #e0f7e9;
color: #2e7d32;
border-radius: 10px;
border: 1px solid #2e7d32;
}
.stats-table {
margin-top: 30px;
width: 100%;
border-collapse: collapse;
}
.stats-table th, .stats-table td {
border: 1px solid #ddd;
padding: 12px;
}
.stats-table th {
background-color: #f2f2f2;
}
a {
display: inline-block;
margin-top: 30px;
padding: 15px 40px;
font-size: 18px;
background-color: #000;
color: white;
text-decoration: none;
border-radius: 30px;
font-weight: bold;
transition: background-color 0.3s ease;
}
a:hover {
background-color: #333;
}
</style>
</head>
<body>
<div class="container">
<h1>数据分析完毕!</h1>
<div class="status-box">
一切正常!
</div>
{% if stats %}
<h3>统计信息:</h3>
<table class="stats-table">
<thead>
<tr>
<th>标签</th>
<th>个数</th>
<th>占比</th>
</tr>
</thead>
<tbody>
{% for label, info in stats.items() %}
<tr>
<td>{{ label }}</td>
<td>{{ info.count }}</td>
<td>{{ info.percentage }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>没有统计信息可显示。</p>
{% endif %}
<a href="/">返回首页</a>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>处理中</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.container {
text-align: center;
width: 600px; /* 调整容器宽度与 main.html 一致 */
background-color: #fff;
padding: 50px;
border-radius: 15px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1); /* 与 main.html 相同的阴影效果 */
display: flex;
flex-direction: column;
align-items: center; /* 水平居中 */
}
h1 {
font-size: 28px; /* 与 main.html 标题保持一致 */
margin-bottom: 20px;
}
p {
font-size: 18px; /* 与 main.html 副标题大小一致 */
color: #888;
margin-top: 20px;
}
.loading-icon {
margin-top: 20px;
width: 50px; /* 调整图标大小 */
height: 50px;
border: 5px solid #f3f3f3;
border-radius: 50%;
border-top: 5px solid #4caf50;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="container">
<h1>处理中,请稍候...</h1>
<div class="loading-icon"></div>
<p>您的文件正在分析中,请稍等片刻。</p>
</div>
<script>
function checkStatus() {
fetch('{{ url_for('check_status', filename=filename) }}')
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// 成功,跳转到成功页面,并传递文件名以获取统计信息
window.location.href = "{{ url_for('upload_success') }}?filename=" + encodeURIComponent('{{ filename }}');
} else if (data.status === 'failure') {
// 失败,跳转到失败页面,并传递文件名以获取统计信息
window.location.href = "{{ url_for('upload_failure') }}?filename=" + encodeURIComponent('{{ filename }}');
} else {
// 继续等待
setTimeout(checkStatus, 2000);
}
})
.catch(error => {
console.error('Error:', error);
setTimeout(checkStatus, 2000);
});
}
document.addEventListener('DOMContentLoaded', function() {
checkStatus();
});
</script>
</body>
</html>