feat: add mastery feature to recitation wheel

This commit is contained in:
赵杰 Jie Zhao (雄狮汽车科技)
2025-11-02 23:46:11 +08:00
parent eddbe71849
commit cad03268f3
14 changed files with 439 additions and 617 deletions

View File

@@ -18,14 +18,25 @@ from modules.ai_analysis import AIAnalysisModule
from modules.recommendation_engine import RecommendationEngine
from modules.ocr_calorie_recognition import OCRCalorieRecognitionModule
# 配置日志
# 配置日志 - 确保UTF-8编码
import sys
# 设置标准输出编码为UTF-8
if sys.stdout.encoding != 'utf-8':
sys.stdout.reconfigure(encoding='utf-8')
if sys.stderr.encoding != 'utf-8':
sys.stderr.reconfigure(encoding='utf-8')
# 创建logs目录
Path('logs').mkdir(exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/web_app.log', encoding='utf-8'),
logging.StreamHandler()
]
logging.StreamHandler(sys.stdout)
],
force=True # 强制重新配置
)
logger = logging.getLogger(__name__)
@@ -35,6 +46,9 @@ app.config['SECRET_KEY'] = 'your-secret-key-here'
# 确保模板文件使用UTF-8编码读取
app.jinja_env.auto_reload = True
app.config['TEMPLATES_AUTO_RELOAD'] = True
# 设置Jinja2模板加载器使用UTF-8编码
from jinja2 import FileSystemLoader
app.jinja_loader = FileSystemLoader('templates', encoding='utf-8')
# 确保所有响应使用UTF-8编码
@app.after_request
@@ -156,31 +170,31 @@ sorter = RecitationSorter()
@app.route('/')
def index():
"""首页"""
return render_template('index.html', encoding='utf-8')
return render_template('index.html')
@app.route('/recitation')
def recitation():
"""背诵排序页面"""
return render_template('recitation.html', encoding='utf-8')
return render_template('recitation.html')
@app.route('/data-collection')
def data_collection():
"""数据采集页面"""
return render_template('data_collection.html', encoding='utf-8')
return render_template('data_collection.html')
@app.route('/recommendation')
def recommendation():
"""推荐页面"""
return render_template('recommendation.html', encoding='utf-8')
return render_template('recommendation.html')
@app.route('/analysis')
def analysis():
"""分析页面"""
return render_template('analysis.html', encoding='utf-8')
return render_template('analysis.html')
@app.route('/api/extract', methods=['POST'])
@@ -295,11 +309,36 @@ def export_sorted():
filename = f'背诵排序结果_{datetime.now().strftime("%Y%m%d_%H%M%S")}.txt'
mimetype = 'text/plain; charset=utf-8'
# 修复文件名编码问题HTTP头必须使用latin-1编码
# 使用RFC 5987标准编码中文文件名
from urllib.parse import quote
# ASCII fallback文件名确保兼容性
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
fallback_filename = f'recitation_sorted_{timestamp}.{export_format}'
# RFC 5987编码对UTF-8字节序列进行百分号编码
# 格式: filename="fallback"; filename*=UTF-8''encoded
# 将所有字节都进行百分号编码确保HTTP头的latin-1兼容性
try:
utf8_bytes = filename.encode('utf-8')
# 对所有字节进行百分号编码(大写十六进制)
encoded_filename = ''.join([f'%{b:02X}' for b in utf8_bytes])
except Exception as e:
logger.warning(f"文件名编码失败使用fallback: {e}")
encoded_filename = fallback_filename
# 构建Content-Disposition头同时提供fallback和UTF-8编码版本
content_disposition = (
f'attachment; filename="{fallback_filename}"; '
f"filename*=UTF-8''{encoded_filename}"
)
response = Response(
content.encode('utf-8'),
mimetype=mimetype,
headers={
'Content-Disposition': f'attachment; filename="{filename}"'
'Content-Disposition': content_disposition
}
)