fix(ci): restore green backend CI — ruff config + unused import cleanup #117
13 changed files with 97 additions and 22 deletions
|
|
@ -14,7 +14,6 @@ Enhanced features:
|
|||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ sys.path.insert(0, str(Path(__file__).parent.parent))
|
|||
|
||||
from scripts.classifier_adapters import (
|
||||
LABELS,
|
||||
LABEL_DESCRIPTIONS,
|
||||
ClassifierAdapter,
|
||||
GLiClassAdapter,
|
||||
RerankerAdapter,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ push updates the existing event rather than creating a duplicate.
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
import yaml
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
|
|
|||
|
|
@ -121,6 +121,17 @@ CREATE TABLE IF NOT EXISTS survey_responses (
|
|||
);
|
||||
"""
|
||||
|
||||
CREATE_RESUME_CORRECTIONS = """
|
||||
CREATE TABLE IF NOT EXISTS resume_optimizer_corrections (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
job_id INTEGER NOT NULL REFERENCES jobs(id),
|
||||
section TEXT NOT NULL,
|
||||
proposed_json TEXT NOT NULL,
|
||||
accepted_json TEXT NOT NULL,
|
||||
created_at TEXT DEFAULT (datetime('now'))
|
||||
);
|
||||
"""
|
||||
|
||||
CREATE_DIGEST_QUEUE = """
|
||||
CREATE TABLE IF NOT EXISTS digest_queue (
|
||||
id INTEGER PRIMARY KEY,
|
||||
|
|
@ -205,9 +216,10 @@ def _migrate_db(db_path: Path) -> None:
|
|||
conn.execute("ALTER TABLE background_tasks ADD COLUMN params TEXT")
|
||||
except sqlite3.OperationalError:
|
||||
pass # column already exists
|
||||
# Ensure references tables exist (CREATE IF NOT EXISTS is idempotent)
|
||||
# Ensure tables that can't be added via ALTER TABLE exist (all idempotent).
|
||||
conn.execute(CREATE_REFERENCES)
|
||||
conn.execute(CREATE_JOB_REFERENCES)
|
||||
conn.execute(CREATE_RESUME_CORRECTIONS)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
|
@ -223,6 +235,7 @@ def init_db(db_path: Path = DEFAULT_DB) -> None:
|
|||
conn.execute(CREATE_DIGEST_QUEUE)
|
||||
conn.execute(CREATE_REFERENCES)
|
||||
conn.execute(CREATE_JOB_REFERENCES)
|
||||
conn.execute(CREATE_RESUME_CORRECTIONS)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
_migrate_db(db_path)
|
||||
|
|
@ -1241,3 +1254,76 @@ def set_training_exclusion(db_path: Path, job_id: int, excluded: bool) -> None:
|
|||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
# ── Resume optimizer corrections ──────────────────────────────────────────────
|
||||
|
||||
def save_resume_correction(
|
||||
db_path: Path,
|
||||
job_id: int,
|
||||
section: str,
|
||||
proposed: object,
|
||||
accepted: object,
|
||||
) -> None:
|
||||
"""Persist a (proposed, accepted) correction pair from the resume review UI.
|
||||
|
||||
Called when a user edits an LLM-proposed value and accepts it. The pair
|
||||
becomes a supervised fine-tuning (SFT) candidate routed through Avocet.
|
||||
|
||||
Args:
|
||||
section: 'summary' or 'experience:<title>|<company>'
|
||||
proposed: Original LLM output (string for summary, list for bullets).
|
||||
accepted: User-edited value (same type as proposed).
|
||||
"""
|
||||
import json as _json
|
||||
conn = sqlite3.connect(db_path)
|
||||
try:
|
||||
conn.execute(
|
||||
"""INSERT INTO resume_optimizer_corrections
|
||||
(job_id, section, proposed_json, accepted_json)
|
||||
VALUES (?, ?, ?, ?)""",
|
||||
(job_id, section, _json.dumps(proposed), _json.dumps(accepted)),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_resume_corrections(
|
||||
db_path: Path,
|
||||
limit: int = 200,
|
||||
job_id: int | None = None,
|
||||
) -> list[dict]:
|
||||
"""Return pending resume corrections for Avocet export.
|
||||
|
||||
Args:
|
||||
limit: Maximum rows to return.
|
||||
job_id: If set, filter to corrections for a specific job.
|
||||
"""
|
||||
import json as _json
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
try:
|
||||
if job_id is not None:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM resume_optimizer_corrections WHERE job_id=? ORDER BY created_at DESC LIMIT ?",
|
||||
(job_id, limit),
|
||||
).fetchall()
|
||||
else:
|
||||
rows = conn.execute(
|
||||
"SELECT * FROM resume_optimizer_corrections ORDER BY created_at DESC LIMIT ?",
|
||||
(limit,),
|
||||
).fetchall()
|
||||
finally:
|
||||
conn.close()
|
||||
return [
|
||||
{
|
||||
"id": r["id"],
|
||||
"job_id": r["job_id"],
|
||||
"section": r["section"],
|
||||
"proposed": _json.loads(r["proposed_json"]),
|
||||
"accepted": _json.loads(r["accepted_json"]),
|
||||
"created_at": r["created_at"],
|
||||
}
|
||||
for r in rows
|
||||
]
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ def build_prompt(
|
|||
)
|
||||
parts.append(f"{recruiter_note}\n")
|
||||
|
||||
parts.append(f"Now write a new cover letter for:")
|
||||
parts.append("Now write a new cover letter for:")
|
||||
parts.append(f" Role: {title}")
|
||||
parts.append(f" Company: {company}")
|
||||
if description:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from __future__ import annotations
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime
|
||||
from scripts.integrations.base import IntegrationBase
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import argparse
|
|||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import yaml
|
||||
|
||||
|
|
|
|||
|
|
@ -348,14 +348,14 @@ def write_compose_override(ports: dict[str, dict]) -> None:
|
|||
for name, info in to_disable.items():
|
||||
lines += [
|
||||
f" {name}: # adopted — host service on :{info['resolved']}",
|
||||
f" entrypoint: [\"/bin/sh\", \"-c\", \"sleep infinity\"]",
|
||||
f" ports: []",
|
||||
f" healthcheck:",
|
||||
f" test: [\"CMD\", \"true\"]",
|
||||
f" interval: 1s",
|
||||
f" timeout: 1s",
|
||||
f" start_period: 0s",
|
||||
f" retries: 1",
|
||||
" entrypoint: [\"/bin/sh\", \"-c\", \"sleep infinity\"]",
|
||||
" ports: []",
|
||||
" healthcheck:",
|
||||
" test: [\"CMD\", \"true\"]",
|
||||
" interval: 1s",
|
||||
" timeout: 1s",
|
||||
" start_period: 0s",
|
||||
" retries: 1",
|
||||
]
|
||||
|
||||
OVERRIDE_YML.write_text("\n".join(lines) + "\n")
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ from __future__ import annotations
|
|||
import json
|
||||
import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@ Falls back to empty dict on unrecoverable errors — caller shows the form build
|
|||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
import pdfplumber
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ FastAPI application. Callable directly or via the survey_analyze background task
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
|
|
|||
|
|
@ -341,7 +341,6 @@ def _run_task(db_path: Path, task_id: int, task_type: str, job_id: int,
|
|||
prioritize_gaps,
|
||||
rewrite_for_ats,
|
||||
hallucination_check,
|
||||
render_resume_text,
|
||||
)
|
||||
from scripts.user_profile import load_user_profile
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,11 @@ Public API (unchanged — callers do not need to change):
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional
|
||||
|
||||
from circuitforge_core.tasks.scheduler import (
|
||||
TaskSpec, # re-export unchanged
|
||||
LocalScheduler as _CoreTaskScheduler,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue