Files
aiagent/backend/scripts/compare_homework_agents.py
renjianbo 41ffd31923 feat: P0 commercial readiness — password security, legal, account management
Backend changes for Phase A of v1.0 commercial launch:

P0-3: Password Security
- Remove hardcoded admin/123456 defaults from 34+ bootstrap scripts
- Add PLATFORM_USERNAME/PLATFORM_PASSWORD env vars to config
- Add PUT /api/v1/auth/change-password endpoint (requires old password)

P0-1: User Agreement & Privacy Policy
- Add agreed_terms/agreed_terms_version/agreed_terms_at to User model
- New GET /api/v1/legal/privacy and GET /api/v1/legal/terms endpoints
- New POST /api/v1/legal/agree endpoint to record consent
- Register endpoint now validates agreed_terms must be True

P0-6: Account Management
- Add phone/status/is_email_verified to User model
- Add DELETE /api/v1/auth/account for account deletion (with password confirmation)
- Add PUT /api/v1/auth/phone for phone binding
- Reject authentication for deleted accounts (status=deleted)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-01 22:01:54 +08:00

157 lines
4.7 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.
#!/usr/bin/env python3
"""
对比「学生作业管理助手」与「学生作业管理助手2号」在相同输入下的节点测试结果。
调用 POST /api/v1/nodes/test同步需后端运行且 DEEPSEEK_API_KEY 有效。
用法: cd backend && .\\venv\\Scripts\\python.exe scripts/compare_homework_agents.py
"""
from __future__ import annotations
import json
import os
import sys
import time
from typing import Any, Dict, List, Optional
import requests
BACKEND = os.getenv("PLATFORM_BASE_URL", "http://127.0.0.1:8037").rstrip("/")
USER = os.getenv("PLATFORM_USERNAME")
PWD = os.getenv("PLATFORM_PASSWORD")
NAMES = ["学生作业管理助手", "学生作业管理助手2号"]
TEST_QUERY = (
"帮我记一项作业语文摘抄名著段落3处并批注截止周五下午5点前。"
"请只回复一条简短清单科目、要点、截止时间不要超过120字。"
)
def _login() -> str:
r = requests.post(
f"{BACKEND}/api/v1/auth/login",
data={"username": USER, "password": PWD},
headers={"Content-Type": "application/x-www-form-urlencoded"},
timeout=15,
)
r.raise_for_status()
t = r.json().get("access_token")
if not t:
raise RuntimeError("无 access_token")
return t
def _find_llm_node(wf: Dict[str, Any]) -> Optional[Dict[str, Any]]:
for n in wf.get("nodes") or []:
if n.get("type") == "llm":
return n
return None
def _get_agents(h: Dict[str, str]) -> List[Dict[str, Any]]:
r = requests.get(
f"{BACKEND}/api/v1/agents",
params={"search": "学生作业管理", "limit": 50},
headers=h,
timeout=30,
)
r.raise_for_status()
return list(r.json() or [])
def _fetch_agent_detail(h: Dict[str, str], aid: str) -> Dict[str, Any]:
r = requests.get(f"{BACKEND}/api/v1/agents/{aid}", headers=h, timeout=30)
r.raise_for_status()
return r.json()
def _test_node(h: Dict[str, str], node: Dict[str, Any]):
body = {"node": node, "input_data": {"query": TEST_QUERY}}
t0 = time.perf_counter()
r = requests.post(
f"{BACKEND}/api/v1/nodes/test",
headers=h,
json=body,
timeout=240,
)
elapsed_ms = int((time.perf_counter() - t0) * 1000)
if r.status_code != 200:
return elapsed_ms, "", f"HTTP {r.status_code}: {r.text[:800]}", None
data = r.json()
out = data.get("output")
if isinstance(out, dict):
text = out.get("output") or out.get("text") or json.dumps(out, ensure_ascii=False)
else:
text = str(out)
err = data.get("error_message")
status = data.get("status")
return elapsed_ms, text[:4000], err, status
def main() -> int:
if hasattr(sys.stdout, "reconfigure"):
try:
sys.stdout.reconfigure(encoding="utf-8")
except Exception:
pass
try:
token = _login()
except Exception as e:
print("登录失败:", e, file=sys.stderr)
return 1
h = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
agents = _get_agents(h)
by_name = {a.get("name"): a for a in agents}
results = []
for name in NAMES:
a = by_name.get(name)
if not a:
results.append(
{"name": name, "error": f"未找到名为「{name}」的 Agent"}
)
continue
detail = _fetch_agent_detail(h, a["id"])
wf = detail.get("workflow_config") or {}
node = _find_llm_node(wf)
if not node:
results.append({"name": name, "id": a["id"], "error": "工作流中无 LLM 节点"})
continue
data = node.get("data") or {}
elapsed_ms, text, err, st = _test_node(h, node)
results.append(
{
"name": name,
"id": a["id"],
"provider": data.get("provider"),
"model": data.get("model"),
"elapsed_ms": elapsed_ms,
"status": st,
"api_error": err,
"output_excerpt": text[:2000],
}
)
print("=== 对比测试(同步节点测试 API===")
print("输入:", TEST_QUERY)
print()
for r in results:
print(f"{r['name']}")
if r.get("error"):
print(" ", r["error"])
print()
continue
print(f" id: {r['id']}")
print(f" provider/model: {r.get('provider')} / {r.get('model')}")
print(f" 耗时: {r['elapsed_ms']} ms status: {r.get('status')}")
if r.get("api_error"):
print(f" error_message: {r['api_error']}")
print(f" 输出节选:\n{r.get('output_excerpt', '')}\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())