feat(admin): lock AI variant generation to llama model
This commit is contained in:
@@ -35,12 +35,10 @@ from app.models import (
|
||||
Website,
|
||||
)
|
||||
from app.services.ai_generation import (
|
||||
SUPPORTED_MODELS,
|
||||
create_generation_run,
|
||||
generate_questions_batch,
|
||||
get_ai_stats,
|
||||
save_ai_question,
|
||||
validate_ai_model,
|
||||
)
|
||||
from app.services.irt_calibration import get_calibration_status
|
||||
from app.services.tryout_json_import import (
|
||||
@@ -687,7 +685,7 @@ def _basis_item_workspace_body(
|
||||
error: str | None = None,
|
||||
success: str | None = None,
|
||||
target_level: str = "mudah",
|
||||
ai_model: str = settings.OPENROUTER_MODEL_QWEN,
|
||||
ai_model: str = settings.OPENROUTER_MODEL_LLAMA,
|
||||
generation_count: str = "1",
|
||||
operator_notes: str = "",
|
||||
include_note_for_admin: bool = True,
|
||||
@@ -695,10 +693,6 @@ def _basis_item_workspace_body(
|
||||
) -> str:
|
||||
error_html = f'<div class="error">{escape(error)}</div>' if error else ""
|
||||
success_html = f'<div class="success">{escape(success)}</div>' if success else ""
|
||||
model_options = "".join(
|
||||
f'<option value="{escape(model)}" {"selected" if model == ai_model else ""}>{escape(label)}</option>'
|
||||
for model, label in SUPPORTED_MODELS.items()
|
||||
)
|
||||
status_filter = filters.get("status", "")
|
||||
level_filter = filters.get("level", "")
|
||||
min_frequency_filter = filters.get("min_frequency", "")
|
||||
@@ -805,7 +799,7 @@ def _basis_item_workspace_body(
|
||||
<option value="sulit" {"selected" if target_level == "sulit" else ""}>sulit</option>
|
||||
</select>
|
||||
<label for="ai_model">Model</label>
|
||||
<select id="ai_model" name="ai_model">{model_options}</select>
|
||||
<input id="ai_model" name="ai_model" type="text" value="{escape(settings.OPENROUTER_MODEL_LLAMA)}" readonly>
|
||||
<label for="generation_count">Generate Count</label>
|
||||
<input id="generation_count" name="generation_count" type="number" min="1" max="50" value="{escape(generation_count)}">
|
||||
<p class="muted">Recommended: 1-3 per run. Larger runs increase overlap and review burden.</p>
|
||||
@@ -1926,7 +1920,7 @@ async def basis_item_generate_submit(
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
target_level: str = Form(...),
|
||||
ai_model: str = Form(...),
|
||||
ai_model: str = Form(""),
|
||||
generation_count: int = Form(1),
|
||||
operator_notes: str = Form(""),
|
||||
include_note_for_admin: str | None = Form(None),
|
||||
@@ -1941,6 +1935,8 @@ async def basis_item_generate_submit(
|
||||
if basis_item is None or basis_item.generated_by == "ai" or basis_item.level != "sedang":
|
||||
return RedirectResponse(url="/admin/basis-items", status_code=HTTP_303_SEE_OTHER)
|
||||
|
||||
# Llama-only policy for production quality consistency.
|
||||
ai_model = settings.OPENROUTER_MODEL_LLAMA
|
||||
note_for_admin = include_note_for_admin == "on"
|
||||
note_in_prompt = include_note_in_prompt == "on"
|
||||
|
||||
@@ -1983,8 +1979,6 @@ async def basis_item_generate_submit(
|
||||
|
||||
if target_level not in {"mudah", "sulit"}:
|
||||
return RedirectResponse(url=f"/admin/basis-items/{basis_item.id}", status_code=HTTP_303_SEE_OTHER)
|
||||
if not validate_ai_model(ai_model):
|
||||
return RedirectResponse(url=f"/admin/basis-items/{basis_item.id}", status_code=HTTP_303_SEE_OTHER)
|
||||
if generation_count < 1 or generation_count > 50:
|
||||
return RedirectResponse(url=f"/admin/basis-items/{basis_item.id}", status_code=HTTP_303_SEE_OTHER)
|
||||
|
||||
@@ -2153,7 +2147,7 @@ def _ai_form_body(
|
||||
generated_variants: list[Item] | None = None,
|
||||
basis_item_id: str = "",
|
||||
target_level: str = "mudah",
|
||||
ai_model: str = settings.OPENROUTER_MODEL_QWEN,
|
||||
ai_model: str = settings.OPENROUTER_MODEL_LLAMA,
|
||||
generation_count: str = "1",
|
||||
operator_notes: str = "",
|
||||
include_note_for_admin: bool = True,
|
||||
@@ -2161,10 +2155,6 @@ def _ai_form_body(
|
||||
) -> str:
|
||||
error_html = f'<div class="error">{escape(error)}</div>' if error else ""
|
||||
success_html = f'<div class="success">{escape(success)}</div>' if success else ""
|
||||
options_html = "".join(
|
||||
f'<option value="{escape(model)}" {"selected" if model == ai_model else ""}>{escape(label)}</option>'
|
||||
for model, label in SUPPORTED_MODELS.items()
|
||||
)
|
||||
basis_items = basis_items or []
|
||||
generation_runs = generation_runs or []
|
||||
generated_variants = generated_variants or []
|
||||
@@ -2271,9 +2261,7 @@ def _ai_form_body(
|
||||
<option value="sulit" {"selected" if target_level == "sulit" else ""}>sulit</option>
|
||||
</select>
|
||||
<label for="ai_model">Model</label>
|
||||
<select id="ai_model" name="ai_model" style="width:100%;box-sizing:border-box;border:1px solid #cbd5e1;border-radius:10px;padding:12px 14px;font-size:15px;">
|
||||
{options_html}
|
||||
</select>
|
||||
<input id="ai_model" name="ai_model" type="text" value="{escape(settings.OPENROUTER_MODEL_LLAMA)}" readonly style="width:100%;box-sizing:border-box;border:1px solid #cbd5e1;border-radius:10px;padding:12px 14px;font-size:15px;background:#f8fafc;">
|
||||
<label for="generation_count">Generate Count</label>
|
||||
<input id="generation_count" name="generation_count" type="number" min="1" max="50" value="{escape(generation_count)}">
|
||||
<p class="muted">Recommended: 1-3 variants per run. Larger runs can increase overlap and review burden. Backend safety cap: 50.</p>
|
||||
@@ -2353,7 +2341,7 @@ async def ai_playground_submit(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
basis_item_id: int = Form(...),
|
||||
target_level: str = Form(...),
|
||||
ai_model: str = Form(...),
|
||||
ai_model: str = Form(""),
|
||||
generation_count: int = Form(1),
|
||||
operator_notes: str = Form(""),
|
||||
include_note_for_admin: str | None = Form(None),
|
||||
@@ -2368,6 +2356,8 @@ async def ai_playground_submit(
|
||||
generation_runs = await _recent_generation_runs(db)
|
||||
generated_variants = await _recent_generated_variants(db)
|
||||
|
||||
# Llama-only policy for production quality consistency.
|
||||
ai_model = settings.OPENROUTER_MODEL_LLAMA
|
||||
note_for_admin = include_note_for_admin == "on"
|
||||
note_in_prompt = include_note_in_prompt == "on"
|
||||
|
||||
@@ -2407,24 +2397,6 @@ async def ai_playground_submit(
|
||||
)
|
||||
return _render_admin_page(request, "AI Playground", "AI Playground", body)
|
||||
|
||||
if not validate_ai_model(ai_model):
|
||||
body = _ai_form_body(
|
||||
True,
|
||||
stats,
|
||||
error="Unsupported AI model.",
|
||||
basis_items=basis_items,
|
||||
generation_runs=generation_runs,
|
||||
generated_variants=generated_variants,
|
||||
basis_item_id=str(basis_item_id),
|
||||
target_level=target_level,
|
||||
ai_model=ai_model,
|
||||
generation_count=str(generation_count),
|
||||
operator_notes=operator_notes,
|
||||
include_note_for_admin=note_for_admin,
|
||||
include_note_in_prompt=note_in_prompt,
|
||||
)
|
||||
return _render_admin_page(request, "AI Playground", "AI Playground", body)
|
||||
|
||||
result = await db.execute(select(Item).where(Item.id == basis_item_id))
|
||||
basis_item = result.scalar_one_or_none()
|
||||
if not basis_item:
|
||||
|
||||
Reference in New Issue
Block a user