Files
dsProject/dsLightRag/Routes/TeacherHelperRoute.py
2025-09-05 07:52:23 +08:00

248 lines
9.9 KiB
Python
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.

import json
import logging
import os
import json
import subprocess
import tempfile
from datetime import datetime
from fastapi.responses import FileResponse
from fastapi import APIRouter, Request, HTTPException, Depends
from fastapi.responses import StreamingResponse
from TeacherHelper.Kit.TeacherHelper import (
generate_lesson_plan,
generate_courseware,
generate_homework
)
# 创建路由器
router = APIRouter(prefix="/api", tags=["教师辅助工具"])
# 配置日志
logger = logging.getLogger(__name__)
@router.api_route("/teacher/daoXueAn", methods=["GET", "POST"]) # 修改这里
async def generate_dao_xue_an(request: Request):
"""生成导学案接口"""
try:
# 获取请求参数兼容GET和POST
if request.method == "GET":
params = dict(request.query_params)
else:
body = await request.body()
params = json.loads(body) if body else {}
# 获取提示词参数
system_prompt = params.get("system_prompt")
user_prompt = params.get("user_prompt")
# 生成导学案
content_generator = await generate_lesson_plan(system_prompt, user_prompt)
# 定义SSE响应生成器
async def generate_sse_response():
try:
buffer = [] # 用于收集完整内容
yield "data: 开始生成导学案...\n\n"
async for chunk in content_generator:
buffer.append(chunk) # 仅收集内容,不实时发送
# 保存为Markdown并转换为Word
if buffer:
# 创建保存目录 - 修改保存路径到static下
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
save_dir = os.path.join(project_root, "static", "teacherHelpergenerated_files")
os.makedirs(save_dir, exist_ok=True)
# 获取难度参数(默认为"默认难度"
difficulty = params.get("difficulty", "默认难度")
# 生成唯一文件名
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
# 创建临时Markdown文件
with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.md', delete=False) as temp_md:
temp_md.write(''.join(buffer))
temp_md_path = temp_md.name
# 使用Pandoc转换为Word
docx_filename = f"导学案_{difficulty}_{timestamp}.docx"
docx_path = os.path.join(save_dir, docx_filename)
try:
yield "data: 正在转换为Word文档...\n\n"
# 恢复Pandoc转换执行代码
result = subprocess.run(
["pandoc", temp_md_path, "-o", docx_path],
capture_output=True,
text=True,
check=True
)
# 清理临时文件
os.unlink(temp_md_path)
# 添加转换完成状态提示
yield "data: Word文档转换完成准备下载...\n\n"
# 修改下载链接为静态文件路径
yield f"data: [下载链接] /static/teacherHelpergenerated_files/{docx_filename}\n\n"
except subprocess.CalledProcessError as e:
yield f"data: [转换失败] Pandoc错误: {e.stderr}\n\n"
except Exception as e:
yield f"data: [转换失败] {str(e)}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logger.error(f"生成导学案时发生异常: {str(e)}")
yield f"data: 生成导学案时发生异常: {str(e)}\n\n"
# 返回SSE响应
return StreamingResponse(
generate_sse_response(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
)
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="无效的JSON格式")
except Exception as e:
logger.error(f"导学案接口异常: {str(e)}")
raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")
@router.post("/teacher/jiaoAn")
async def generate_jiao_an(request: Request):
"""生成教案接口"""
try:
# 解析请求体
body = await request.body()
data = json.loads(body) if body else {}
# 获取提示词参数,如果没有提供则使用默认值
system_prompt = data.get("system_prompt")
user_prompt = data.get("user_prompt")
# 生成教案
content_generator = await generate_lesson_plan(system_prompt, user_prompt)
# 定义SSE响应生成器
async def generate_sse_response():
try:
yield "data: 开始生成教案...\n\n"
async for chunk in content_generator:
yield f"data: {chunk}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logger.error(f"生成教案时发生异常: {str(e)}")
yield f"data: 生成教案时发生异常: {str(e)}\n\n"
# 返回SSE响应
return StreamingResponse(
generate_sse_response(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
)
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="无效的JSON格式")
except Exception as e:
logger.error(f"教案接口异常: {str(e)}")
raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")
@router.post("/teacher/keJian")
async def generate_ke_jian(request: Request):
"""生成课件接口"""
try:
# 解析请求体
body = await request.body()
data = json.loads(body) if body else {}
# 获取提示词参数,如果没有提供则使用默认值
system_prompt = data.get("system_prompt")
user_prompt = data.get("user_prompt")
# 生成课件
content_generator = await generate_courseware(system_prompt, user_prompt)
# 定义SSE响应生成器
async def generate_sse_response():
try:
yield "data: 开始生成课件...\n\n"
async for chunk in content_generator:
yield f"data: {chunk}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logger.error(f"生成课件时发生异常: {str(e)}")
yield f"data: 生成课件时发生异常: {str(e)}\n\n"
# 返回SSE响应
return StreamingResponse(
generate_sse_response(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
)
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="无效的JSON格式")
except Exception as e:
logger.error(f"课件接口异常: {str(e)}")
raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")
@router.post("/teacher/zuoYe")
async def generate_zuo_ye(request: Request):
"""生成作业接口"""
try:
# 解析请求体
body = await request.body()
data = json.loads(body) if body else {}
# 获取提示词参数,如果没有提供则使用默认值
system_prompt = data.get("system_prompt")
user_prompt = data.get("user_prompt")
material_path = data.get("material_path")
# 生成作业
content_generator = await generate_homework(system_prompt, user_prompt, material_path)
# 定义SSE响应生成器
async def generate_sse_response():
try:
yield "data: 开始生成作业...\n\n"
async for chunk in content_generator:
yield f"data: {chunk}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logger.error(f"生成作业时发生异常: {str(e)}")
yield f"data: 生成作业时发生异常: {str(e)}\n\n"
# 返回SSE响应
return StreamingResponse(
generate_sse_response(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"}
)
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="无效的JSON格式")
except Exception as e:
logger.error(f"作业接口异常: {str(e)}")
raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")
@router.get("/teacher/download/{filename}")
async def download_word_file(filename: str):
"""下载生成的Word文件"""
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
save_dir = os.path.join(project_root, "static", "teacherHelpergenerated_files")
file_path = os.path.join(save_dir, filename)
if not os.path.exists(file_path):
raise HTTPException(status_code=404, detail="文件不存在")
return FileResponse(
path=file_path,
filename=filename,
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)