First commit.

Signed-off-by: Chen Xiao <abigwc@gmail.com>
This commit is contained in:
Chen Xiao
2026-05-08 14:43:16 +08:00
commit 0b64e2de94
10989 changed files with 2253791 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
import db
import auth
router = APIRouter()
class UserAuth(BaseModel):
username: str
password: str
@router.post("/api/register")
def register(user: UserAuth):
if not user.username or not user.password:
raise HTTPException(status_code=400, detail="用户名和密码不能为空")
if len(user.username) < 3 or len(user.username) > 20:
raise HTTPException(status_code=400, detail="用户名长度需在3-20个字符之间")
if len(user.password) < 6:
raise HTTPException(status_code=400, detail="密码长度至少6个字符")
existing_user = db.get_user_by_username(user.username)
if existing_user:
raise HTTPException(status_code=400, detail="用户名已存在")
hashed_password = auth.get_password_hash(user.password)
new_user = db.create_user({"username": user.username, "password": hashed_password})
return {"message": "注册成功", "userId": new_user["id"]}
@router.post("/api/login")
def login(user: UserAuth):
if not user.username or not user.password:
raise HTTPException(status_code=400, detail="用户名和密码不能为空")
db_user = db.get_user_by_username(user.username)
if not db_user:
raise HTTPException(status_code=401, detail="用户名或密码错误")
if not auth.verify_password(user.password, db_user["password"]):
raise HTTPException(status_code=401, detail="用户名或密码错误")
token = auth.create_access_token({"id": db_user["id"], "username": db_user["username"]})
return {
"message": "登录成功",
"token": token,
"user": {"id": db_user["id"], "username": db_user["username"]}
}
@router.get("/api/me")
def get_me(current_user: dict = Depends(auth.get_current_user)):
return {"user": {"id": current_user["id"], "username": current_user["username"]}}
@router.post("/api/logout")
def logout():
return {"message": "已退出登录"}
+69
View File
@@ -0,0 +1,69 @@
import os
import tempfile
import pypandoc
from typing import Optional
from fastapi import APIRouter, HTTPException, Depends
from fastapi.responses import FileResponse
from pydantic import BaseModel
from starlette.background import BackgroundTask
import auth
import db
from formula_processor import preprocess_formulas
router = APIRouter()
class DocRequest(BaseModel):
markdown: str
def remove_file(path: str):
try:
os.remove(path)
except Exception:
pass
@router.post("/api/convert")
async def convert_md_to_docx(req: DocRequest, current_user: Optional[dict] = Depends(auth.get_optional_user)):
try:
# 如果带有合法登录 token,则记录历史
if current_user:
db.add_history_record(current_user["id"], req.markdown)
try:
pypandoc.get_pandoc_version()
except OSError:
pypandoc.download_pandoc()
# ====== 公式预处理:统一各种定界符格式 ======
# 将 GPT/AI 生成内容中 \(...\)、\[...\]、缺失反斜杠的 [...] 和 (...)
# 全部转换为 Pandoc 可识别的标准 $...$ 和 $$...$$ 格式
processed_markdown = preprocess_formulas(req.markdown)
fd, tmp_path = tempfile.mkstemp(suffix=".docx")
os.close(fd)
md_fd, md_tmp_path = tempfile.mkstemp(suffix=".md")
with os.fdopen(md_fd, 'w', encoding='utf-8') as f:
f.write(processed_markdown)
pypandoc.convert_file(
md_tmp_path,
'docx',
format='markdown+tex_math_dollars',
outputfile=tmp_path
)
os.remove(md_tmp_path)
return FileResponse(
tmp_path,
media_type='application/vnd.openxmlformats-officedocument.wordprocessingml.document',
filename='document.docx',
background=BackgroundTask(remove_file, tmp_path)
)
except Exception as e:
print(f"Error during conversion: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.get("/api/history")
async def get_history(current_user: dict = Depends(auth.get_current_user)):
history = db.get_history_records(current_user["id"])
return {"history": history}