chore: initialize WiseGrade project

This commit is contained in:
2026-09-25 11:10:34 +08:00
parent f7a9091c86
commit 146d5566cf
16 changed files with 6603 additions and 1 deletions
+13
View File
@@ -0,0 +1,13 @@
WISEGRADE_DATA_DIR=./data/inbox
DATABASE_URL=postgresql+psycopg://wisegrade:wisegrade@db:5432/wisegrade
REDIS_URL=redis://redis:6379/0
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-flash
DEEPSEEK_API_KEY=
WISEGRADE_SECRET_KEY=replace-with-a-random-32-character-secret
EMBEDDING_MODEL_NAME=BAAI/bge-m3
EMBEDDING_MODEL_PATH=/models/bge-m3
EMBEDDING_MODEL_VERSION=local
MODEL_TIMEOUT_SECONDS=120
MODEL_CONCURRENCY=2
MODEL_RETRIES=2
+4
View File
@@ -16,7 +16,11 @@ coverage/
data/processed/ data/processed/
data/exports/ data/exports/
data/runtime/ data/runtime/
data/inbox/
data/test-fixtures/
models/ models/
*.tar.zst
*.tar
*.log *.log
*.sqlite3 *.sqlite3
*.db *.db
+9 -1
View File
@@ -2,7 +2,7 @@
WiseGrade 是面向《自动化专业综合实践》课程的教师端自动评分系统。 WiseGrade 是面向《自动化专业综合实践》课程的教师端自动评分系统。
当前项目处于技术方案固化和系统开发准备阶段。完整技术规格见: 教师端系统包含课程版本、挂载目录导入、文档解析、知识库检索、独立评分批次、教师复核及导出。完整技术规格见:
- [技术方案与开发规格](docs/WISEGRADE_TECHNICAL_SPEC.md) - [技术方案与开发规格](docs/WISEGRADE_TECHNICAL_SPEC.md)
- [Codex Goal 模式开发提示词](docs/CODEX_GOAL_PROMPT.md) - [Codex Goal 模式开发提示词](docs/CODEX_GOAL_PROMPT.md)
@@ -20,3 +20,11 @@ WiseGrade 是面向《自动化专业综合实践》课程的教师端自动评
## 资料 ## 资料
课程原始资料位于 `docs/` 目录。 课程原始资料位于 `docs/` 目录。
## 快速启动
1. 复制 `.env.example` 为 `.env`,设置 `WISEGRADE_DATA_DIR`、`DEEPSEEK_API_KEY` 和 `WISEGRADE_SECRET_KEY`。
2. 将离线嵌入模型放在 `models/bge-m3/`(或修改 `EMBEDDING_MODEL_PATH`)。
3. 运行 `docker compose up --build -d`,访问 <http://127.0.0.1:8080>。
学生材料只从只读挂载的 `/data/inbox` 读取。没有本地嵌入模型或 API 密钥时,系统仍可启动和完成导入;评分会显示明确错误。详细部署和使用步骤见 [部署与使用指南](docs/DEPLOYMENT.md)。
+8
View File
@@ -0,0 +1,8 @@
.venv/
.pytest_cache/
__pycache__/
*.pyc
tests/
*.db
*.sqlite3
.env
+9
View File
@@ -0,0 +1,9 @@
FROM python:3.11-slim
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1
RUN apt-get update && apt-get install -y --no-install-recommends libreoffice poppler-utils fonts-noto-cjk libpango-1.0-0 libpangoft2-1.0-0 libgl1 libglib2.0-0 && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=ghcr.io/astral-sh/uv:0.11.0 /uv /uvx /bin/
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --extra ocr
COPY . .
ENV PATH=/app/.venv/bin:$PATH PYTHONPATH=/app
+27
View File
@@ -0,0 +1,27 @@
[project]
name = "wisegrade-backend"
version = "0.1.0"
description = "WiseGrade teacher-only scoring backend"
requires-python = ">=3.10,<3.13"
dependencies = [
"fastapi>=0.115,<0.125", "starlette>=0.40,<0.50", "uvicorn[standard]>=0.34,<1", "sqlalchemy>=2,<3",
"alembic>=1.14,<2", "psycopg[binary]>=3.2,<4", "pgvector>=0.4,<1",
"pydantic-settings>=2,<3", "redis>=5,<7", "rq>=2,<3",
"pymupdf>=1.25,<2", "python-docx>=1.1,<2", "python-pptx>=1,<2",
"pillow>=11,<13", "sentence-transformers>=4,<6", "torch>=2.3,<3", "httpx>=0.28,<1",
"cryptography>=44,<48", "openpyxl>=3.1,<4", "weasyprint>=64,<70",
]
[dependency-groups]
dev = ["pytest>=8,<10"]
[project.optional-dependencies]
ocr = ["paddleocr>=2.9,<4", "paddlepaddle>=2.6,<4"]
[tool.uv.sources]
torch = { index = "pytorch-cpu" }
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["."]
markers = ["integration: tests using bundled course examples"]
+3501
View File
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
services:
db:
image: pgvector/pgvector:pg16
environment:
POSTGRES_DB: wisegrade
POSTGRES_USER: wisegrade
POSTGRES_PASSWORD: wisegrade
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: [CMD-SHELL, "pg_isready -U wisegrade"]
interval: 5s
retries: 12
redis:
image: redis:7-alpine
api:
build: ./backend
env_file: .env
volumes: &api-volumes
- ${WISEGRADE_DATA_DIR}:/data/inbox:ro
- ./data/processed:/data/processed
- ./data/exports:/data/exports
- ./models:/models:ro
- ./docs:/app/course-docs:ro
depends_on:
db: {condition: service_healthy}
redis: {condition: service_started}
command: ["sh", "-c", "alembic upgrade head && uvicorn wisegrade.main:app --host 0.0.0.0 --port 8000"]
healthcheck:
test: [CMD, python, -c, "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/api/health')"]
interval: 10s
retries: 12
worker:
build: ./backend
env_file: .env
volumes: *api-volumes
depends_on:
db: {condition: service_healthy}
redis: {condition: service_started}
command: ["sh", "-c", "rq worker wisegrade --url \"$$REDIS_URL\""]
web:
build: ./frontend
ports:
- "127.0.0.1:8080:80"
depends_on: [api]
healthcheck:
test: [CMD, wget, -q, -O, /dev/null, "http://127.0.0.1/health"]
interval: 10s
retries: 6
volumes:
pgdata:
+3
View File
@@ -0,0 +1,3 @@
node_modules/
dist/
.env
+9
View File
@@ -0,0 +1,9 @@
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="zh-CN"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>WiseGrade 智评</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>
+6
View File
@@ -0,0 +1,6 @@
server {
listen 80;
location = /health { add_header Content-Type text/plain; return 200 'ok'; }
location /api/ { proxy_pass http://api:8000; proxy_set_header Host $host; client_max_body_size 1m; }
location / { try_files $uri /index.html; }
}
+2946
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -0,0 +1,9 @@
{
"name": "wisegrade-frontend",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {"dev": "vite --host 0.0.0.0", "build": "tsc -b && vite build"},
"dependencies": {"antd": "^5.27.0", "@ant-design/icons": "^6.0.0", "react": "^19.1.0", "react-dom": "^19.1.0"},
"devDependencies": {"@types/react": "^19.1.0", "@types/react-dom": "^19.1.0", "@vitejs/plugin-react": "^5.0.0", "typescript": "^5.9.0", "vite": "^7.1.0"}
}
+4
View File
@@ -0,0 +1,4 @@
{
"compilerOptions": {"target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, "moduleResolution": "Bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "strict": false},
"include": ["src"]
}
+3
View File
@@ -0,0 +1,3 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({ plugins: [react()], server: { proxy: { '/api': 'http://localhost:8000' } } });