Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
OPENAI_API_KEY=sk-your-api-key-here

# API Server Port (optional, default: 8000)
API_PORT=8000
API_PORT=8000
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ htmlcov/

# Legacy
move_to_cache.py
config.json
38 changes: 36 additions & 2 deletions api_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
from typing import Optional as Opt
import uvicorn

from run import run_instructional_design, run_optimization
from run import (
run_instructional_design,
run_optimization,
run_evaluation,
run_refinement,
)
from src import __version__
from src.pdf_processor import PDFSlideProcessor
from src.ADDIE_optimize import ADDIEOptimizer
Expand Down Expand Up @@ -60,6 +65,12 @@ class CourseRequest(BaseModel):
catalog: Optional[str] = Field(default=None, description="Catalog name to use")
catalog_data: Optional[Dict[str, Any]] = Field(default=None, description="Catalog data as JSON object")
generate_pptx: Optional[bool] = Field(default=False, description="Also generate PPTX slides")
run_evaluation: Optional[bool] = Field(default=False, description="Run evaluation after generation")
run_refinement: Optional[bool] = Field(default=False, description="Run refinement after evaluation")
refinement_threshold: Optional[float] = Field(default=3.0, description="Score threshold for selecting files to refine")
refinement_retries: Optional[int] = Field(default=3, description="Maximum refinement retries per selected file")
refinement_route: Optional[str] = Field(default="all", description="Refinement route to run")


class OptimizeRequest(BaseModel):
storage_id: str = Field(..., description="ID of the stored PDF files")
Expand Down Expand Up @@ -817,6 +828,29 @@ async def run_generation_task(task_id: str, request: CourseRequest, api_key: str
print(f"✅ Generated {len(pptx_results)} PPTX files")
except Exception as pptx_err:
print(f"⚠️ PPTX generation failed: {pptx_err}")

if request.run_evaluation or request.run_refinement:
print("\n🔍 Running evaluation...")
tasks[task_id]["current_stage"] = "Running evaluation"
tasks[task_id]["progress"] = 80

run_evaluation(
model_name=request.model_name,
exp_name=request.exp_name,
)

if request.run_refinement:
print("\n🛠️ Running refinement...")
tasks[task_id]["current_stage"] = "Running refinement"
tasks[task_id]["progress"] = 90

run_refinement(
model_name=request.model_name,
exp_name=request.exp_name,
threshold=request.refinement_threshold,
retries=request.refinement_retries,
route=request.refinement_route,
)

# Mark as completed
print("\n" + "=" * 60)
Expand All @@ -833,7 +867,7 @@ async def run_generation_task(task_id: str, request: CourseRequest, api_key: str
os.environ["OPENAI_API_KEY"] = original_key
elif "OPENAI_API_KEY" in os.environ:
del os.environ["OPENAI_API_KEY"]

except Exception as e:
# Mark as failed
error_msg = str(e)
Expand Down
59 changes: 57 additions & 2 deletions frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ const translations = {
modeGenerate: '生成新课程',
modeOptimize: '优化已有材料',
pptxLabel: '同时生成 PPTX 幻灯片',
postProcessTitle: '评估与优化',
evaluationLabel: '生成后运行评估',
refinementLabel: '评估后优化低分文件',
refinementThresholdLabel: '优化阈值',
refinementThresholdTip: '平均分低于该值的文件会被优化',
refinementRetriesLabel: '最大重试次数',
refinementRetriesTip: '每个文件最多运行的优化重试次数',
refinementRouteLabel: '优化文件类型',
refinementRouteAll: '全部',
refinementRouteAssessment: 'Assessment',
refinementRouteSlides: 'Slides',
refinementRouteScript: 'Scripts',
refinementRouteSyllabus: 'Syllabus',
refinementRouteObjectives: 'Learning Objectives',
optimizeSectionTitle: '优化配置',
optimizeSubmitButton: '<span>🔧</span><span>开始优化</span>',
optimizeProgressTitle: '优化进度',
Expand Down Expand Up @@ -237,6 +251,20 @@ const translations = {
modeGenerate: 'Generate Course',
modeOptimize: 'Optimize Materials',
pptxLabel: 'Also generate PPTX slides',
postProcessTitle: 'Evaluation & Refinement',
evaluationLabel: 'Run evaluation after generation',
refinementLabel: 'Refine low-scoring files after evaluation',
refinementThresholdLabel: 'Refinement Threshold',
refinementThresholdTip: 'Files below this average score are selected for refinement',
refinementRetriesLabel: 'Max Retries',
refinementRetriesTip: 'Maximum refinement retries per selected file',
refinementRouteLabel: 'File Types to Refine',
refinementRouteAll: 'All',
refinementRouteAssessment: 'Assessment',
refinementRouteSlides: 'Slides',
refinementRouteScript: 'Scripts',
refinementRouteSyllabus: 'Syllabus',
refinementRouteObjectives: 'Learning Objectives',
optimizeSectionTitle: 'Optimization Settings',
optimizeSubmitButton: '<span>🔧</span><span>Start Optimization</span>',
optimizeProgressTitle: 'Optimization Progress',
Expand Down Expand Up @@ -503,6 +531,12 @@ function setupEventListeners() {
const catalogMode = document.getElementById('catalog-mode');
catalogMode.addEventListener('change', handleCatalogModeChange);

const refinementMode = document.getElementById('refinement-mode');
if (refinementMode) {
refinementMode.addEventListener('change', handleRefinementModeChange);
handleRefinementModeChange();
}

// API Key management
document.getElementById('save-api-key').addEventListener('click', saveApiKey);
document.getElementById('toggle-api-key').addEventListener('click', toggleApiKeyVisibility);
Expand Down Expand Up @@ -648,6 +682,23 @@ function handleCatalogModeChange(e) {
}
}

function handleRefinementModeChange() {
const refinementMode = document.getElementById('refinement-mode');
const evaluationMode = document.getElementById('evaluation-mode');
const settings = document.getElementById('refinement-settings');

if (!refinementMode || !settings) {
return;
}

const enabled = refinementMode.checked;
settings.style.display = enabled ? 'block' : 'none';

if (enabled && evaluationMode) {
evaluationMode.checked = true;
}
}

async function handleFormSubmit(e) {
e.preventDefault();

Expand All @@ -672,7 +723,12 @@ async function handleFormSubmit(e) {
model_name: document.getElementById('model-name').value,
exp_name: document.getElementById('exp-name').value || 'default',
copilot: document.getElementById('copilot-mode').checked,
generate_pptx: document.getElementById('pptx-mode').checked
generate_pptx: document.getElementById('pptx-mode').checked,
run_evaluation: document.getElementById('evaluation-mode').checked,
run_refinement: document.getElementById('refinement-mode').checked,
refinement_threshold: parseFloat(document.getElementById('refinement-threshold').value || '3.0'),
refinement_retries: parseInt(document.getElementById('refinement-retries').value || '3', 10),
refinement_route: document.getElementById('refinement-route').value
};

// Handle catalog
Expand Down Expand Up @@ -1606,4 +1662,3 @@ function escapeHtml(text) {
div.textContent = text;
return div.innerHTML;
}

49 changes: 48 additions & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,54 @@ <h2 data-i18n="configSectionTitle">课程配置</h2>
</label>
</div>

<div class="refinement-options">
<h3 data-i18n="postProcessTitle">评估与优化</h3>

<div class="form-group checkbox-group">
<label>
<input type="checkbox" id="evaluation-mode" name="run_evaluation">
<span data-i18n="evaluationLabel">生成后运行评估</span>
</label>
</div>

<div class="form-group checkbox-group">
<label>
<input type="checkbox" id="refinement-mode" name="run_refinement">
<span data-i18n="refinementLabel">评估后优化低分文件</span>
</label>
</div>

<div id="refinement-settings" class="refinement-settings" style="display: none;">
<div class="form-row">
<div class="form-group">
<label for="refinement-threshold" data-i18n="refinementThresholdLabel">优化阈值</label>
<input type="number" id="refinement-threshold" name="refinement_threshold"
min="0" max="5" step="0.1" value="3.0">
<small data-i18n="refinementThresholdTip">平均分低于该值的文件会被优化</small>
</div>

<div class="form-group">
<label for="refinement-retries" data-i18n="refinementRetriesLabel">最大重试次数</label>
<input type="number" id="refinement-retries" name="refinement_retries"
min="0" max="5" step="1" value="3">
<small data-i18n="refinementRetriesTip">每个文件最多运行的优化重试次数</small>
</div>
</div>

<div class="form-group">
<label for="refinement-route" data-i18n="refinementRouteLabel">优化文件类型</label>
<select id="refinement-route" name="refinement_route">
<option value="all" data-i18n="refinementRouteAll">全部</option>
<option value="assessment" data-i18n="refinementRouteAssessment">Assessment</option>
<option value="slides" data-i18n="refinementRouteSlides">Slides</option>
<option value="script" data-i18n="refinementRouteScript">Scripts</option>
<option value="syllabus" data-i18n="refinementRouteSyllabus">Syllabus</option>
<option value="objectives" data-i18n="refinementRouteObjectives">Learning Objectives</option>
</select>
</div>
</div>
</div>

<div class="form-group">
<label for="catalog-mode" data-i18n="catalogModeLabel">Catalog 模式</label>
<select id="catalog-mode" name="catalog_mode">
Expand Down Expand Up @@ -256,4 +304,3 @@ <h2 data-i18n="resultsSectionTitle">生成结果</h2>
<script src="app.js?v=2"></script>
</body>
</html>

32 changes: 32 additions & 0 deletions frontend/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ body::before {

.form-group input[type="text"],
.form-group input[type="password"],
.form-group input[type="number"],
.form-group input[type="file"],
.form-group select,
.form-group textarea {
Expand Down Expand Up @@ -329,6 +330,32 @@ body::before {
accent-color: var(--ink);
}

.refinement-options {
margin: 10px 0 24px;
padding: 18px;
border: 1.5px solid var(--border);
border-radius: 8px;
background: var(--bg-card);
}

.refinement-options h3 {
margin: 0 0 14px;
font-size: 1rem;
color: var(--text);
}

.refinement-settings {
margin-top: 8px;
padding-top: 16px;
border-top: 1px solid var(--border);
}

.form-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}

/* ================= BUTTONS ================= */
.btn {
padding: 13px 28px;
Expand Down Expand Up @@ -745,6 +772,11 @@ footer {
padding: 0 16px;
}

.form-row {
grid-template-columns: 1fr;
gap: 0;
}

.file-item {
flex-direction: column;
align-items: flex-start;
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ classifiers = [
dependencies = [
"openai>=1.0.0",
"pandas>=2.0.0",
"fastapi>=0.104.1",
"fastapi[standard]>=0.104.1",
"uvicorn[standard]>=0.24.0",
"python-multipart>=0.0.6",
"pydantic>=2.0.0",
Expand Down
Loading