fix(cloud): replace DEFAULT_DB with get_db_path() across all Streamlit pages
Pages were hardcoding DEFAULT_DB at import time, meaning cloud-mode
per-user DB routing was silently ignored. Pages affected:
1_Job_Review, 5_Interviews, 6_Interview_Prep, 7_Survey.
Adds resolve_session("peregrine") + get_db_path() pattern to each,
matching the pattern already used in 4_Apply.py.
Fixes #24.
This commit is contained in:
parent
15dc4b2646
commit
9702646738
4 changed files with 76 additions and 64 deletions
|
|
@ -12,12 +12,15 @@ from scripts.db import (
|
||||||
DEFAULT_DB, init_db, get_jobs_by_status, update_job_status,
|
DEFAULT_DB, init_db, get_jobs_by_status, update_job_status,
|
||||||
update_cover_letter, mark_applied, get_email_leads,
|
update_cover_letter, mark_applied, get_email_leads,
|
||||||
)
|
)
|
||||||
|
from app.cloud_session import resolve_session, get_db_path
|
||||||
|
|
||||||
|
resolve_session("peregrine")
|
||||||
|
|
||||||
st.title("📋 Job Review")
|
st.title("📋 Job Review")
|
||||||
|
|
||||||
init_db(DEFAULT_DB)
|
init_db(get_db_path())
|
||||||
|
|
||||||
_email_leads = get_email_leads(DEFAULT_DB)
|
_email_leads = get_email_leads(get_db_path())
|
||||||
|
|
||||||
# ── Sidebar filters ────────────────────────────────────────────────────────────
|
# ── Sidebar filters ────────────────────────────────────────────────────────────
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
|
|
@ -37,7 +40,7 @@ with st.sidebar:
|
||||||
index=0,
|
index=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
jobs = get_jobs_by_status(DEFAULT_DB, show_status)
|
jobs = get_jobs_by_status(get_db_path(), show_status)
|
||||||
|
|
||||||
if remote_only:
|
if remote_only:
|
||||||
jobs = [j for j in jobs if j.get("is_remote")]
|
jobs = [j for j in jobs if j.get("is_remote")]
|
||||||
|
|
@ -86,11 +89,11 @@ if show_status == "pending" and _email_leads:
|
||||||
with right_l:
|
with right_l:
|
||||||
if st.button("✅ Approve", key=f"el_approve_{lead_id}",
|
if st.button("✅ Approve", key=f"el_approve_{lead_id}",
|
||||||
type="primary", use_container_width=True):
|
type="primary", use_container_width=True):
|
||||||
update_job_status(DEFAULT_DB, [lead_id], "approved")
|
update_job_status(get_db_path(), [lead_id], "approved")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
if st.button("❌ Reject", key=f"el_reject_{lead_id}",
|
if st.button("❌ Reject", key=f"el_reject_{lead_id}",
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
update_job_status(DEFAULT_DB, [lead_id], "rejected")
|
update_job_status(get_db_path(), [lead_id], "rejected")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
st.divider()
|
st.divider()
|
||||||
|
|
||||||
|
|
@ -162,7 +165,7 @@ for job in jobs:
|
||||||
)
|
)
|
||||||
save_col, _ = st.columns([2, 5])
|
save_col, _ = st.columns([2, 5])
|
||||||
if save_col.button("💾 Save draft", key=f"save_cl_{job_id}"):
|
if save_col.button("💾 Save draft", key=f"save_cl_{job_id}"):
|
||||||
update_cover_letter(DEFAULT_DB, job_id, st.session_state[_cl_key])
|
update_cover_letter(get_db_path(), job_id, st.session_state[_cl_key])
|
||||||
st.success("Saved!")
|
st.success("Saved!")
|
||||||
|
|
||||||
# Applied date + cover letter preview (applied/synced)
|
# Applied date + cover letter preview (applied/synced)
|
||||||
|
|
@ -182,11 +185,11 @@ for job in jobs:
|
||||||
if show_status == "pending":
|
if show_status == "pending":
|
||||||
if st.button("✅ Approve", key=f"approve_{job_id}",
|
if st.button("✅ Approve", key=f"approve_{job_id}",
|
||||||
type="primary", use_container_width=True):
|
type="primary", use_container_width=True):
|
||||||
update_job_status(DEFAULT_DB, [job_id], "approved")
|
update_job_status(get_db_path(), [job_id], "approved")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
if st.button("❌ Reject", key=f"reject_{job_id}",
|
if st.button("❌ Reject", key=f"reject_{job_id}",
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
update_job_status(DEFAULT_DB, [job_id], "rejected")
|
update_job_status(get_db_path(), [job_id], "rejected")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
elif show_status == "approved":
|
elif show_status == "approved":
|
||||||
|
|
@ -198,6 +201,6 @@ for job in jobs:
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
cl_text = st.session_state.get(f"cl_{job_id}", "")
|
cl_text = st.session_state.get(f"cl_{job_id}", "")
|
||||||
if cl_text:
|
if cl_text:
|
||||||
update_cover_letter(DEFAULT_DB, job_id, cl_text)
|
update_cover_letter(get_db_path(), job_id, cl_text)
|
||||||
mark_applied(DEFAULT_DB, [job_id])
|
mark_applied(get_db_path(), [job_id])
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ from scripts.db import (
|
||||||
get_unread_stage_signals, dismiss_stage_signal,
|
get_unread_stage_signals, dismiss_stage_signal,
|
||||||
)
|
)
|
||||||
from scripts.task_runner import submit_task
|
from scripts.task_runner import submit_task
|
||||||
|
from app.cloud_session import resolve_session, get_db_path
|
||||||
|
|
||||||
|
resolve_session("peregrine")
|
||||||
|
|
||||||
_CONFIG_DIR = Path(__file__).parent.parent.parent / "config"
|
_CONFIG_DIR = Path(__file__).parent.parent.parent / "config"
|
||||||
_CALENDAR_INTEGRATIONS = ("apple_calendar", "google_calendar")
|
_CALENDAR_INTEGRATIONS = ("apple_calendar", "google_calendar")
|
||||||
|
|
@ -46,23 +49,23 @@ _calendar_connected = any(
|
||||||
|
|
||||||
st.title("🎯 Interviews")
|
st.title("🎯 Interviews")
|
||||||
|
|
||||||
init_db(DEFAULT_DB)
|
init_db(get_db_path())
|
||||||
|
|
||||||
# ── Sidebar: Email sync ────────────────────────────────────────────────────────
|
# ── Sidebar: Email sync ────────────────────────────────────────────────────────
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
st.markdown("### 📧 Email Sync")
|
st.markdown("### 📧 Email Sync")
|
||||||
_email_task = get_task_for_job(DEFAULT_DB, "email_sync", 0)
|
_email_task = get_task_for_job(get_db_path(), "email_sync", 0)
|
||||||
_email_running = _email_task and _email_task["status"] in ("queued", "running")
|
_email_running = _email_task and _email_task["status"] in ("queued", "running")
|
||||||
|
|
||||||
if st.button("🔄 Sync Emails", use_container_width=True, type="primary",
|
if st.button("🔄 Sync Emails", use_container_width=True, type="primary",
|
||||||
disabled=bool(_email_running)):
|
disabled=bool(_email_running)):
|
||||||
submit_task(DEFAULT_DB, "email_sync", 0)
|
submit_task(get_db_path(), "email_sync", 0)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
if _email_running:
|
if _email_running:
|
||||||
@st.fragment(run_every=4)
|
@st.fragment(run_every=4)
|
||||||
def _email_sidebar_status():
|
def _email_sidebar_status():
|
||||||
t = get_task_for_job(DEFAULT_DB, "email_sync", 0)
|
t = get_task_for_job(get_db_path(), "email_sync", 0)
|
||||||
if t and t["status"] in ("queued", "running"):
|
if t and t["status"] in ("queued", "running"):
|
||||||
st.info("⏳ Syncing…")
|
st.info("⏳ Syncing…")
|
||||||
else:
|
else:
|
||||||
|
|
@ -99,7 +102,7 @@ STAGE_NEXT_LABEL = {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Data ──────────────────────────────────────────────────────────────────────
|
# ── Data ──────────────────────────────────────────────────────────────────────
|
||||||
jobs_by_stage = get_interview_jobs(DEFAULT_DB)
|
jobs_by_stage = get_interview_jobs(get_db_path())
|
||||||
|
|
||||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||||
def _days_ago(date_str: str | None) -> str:
|
def _days_ago(date_str: str | None) -> str:
|
||||||
|
|
@ -120,8 +123,8 @@ def _days_ago(date_str: str | None) -> str:
|
||||||
def _research_modal(job: dict) -> None:
|
def _research_modal(job: dict) -> None:
|
||||||
job_id = job["id"]
|
job_id = job["id"]
|
||||||
st.caption(f"**{job.get('company')}** — {job.get('title')}")
|
st.caption(f"**{job.get('company')}** — {job.get('title')}")
|
||||||
research = get_research(DEFAULT_DB, job_id=job_id)
|
research = get_research(get_db_path(), job_id=job_id)
|
||||||
task = get_task_for_job(DEFAULT_DB, "company_research", job_id)
|
task = get_task_for_job(get_db_path(), "company_research", job_id)
|
||||||
running = task and task["status"] in ("queued", "running")
|
running = task and task["status"] in ("queued", "running")
|
||||||
|
|
||||||
if running:
|
if running:
|
||||||
|
|
@ -144,7 +147,7 @@ def _research_modal(job: dict) -> None:
|
||||||
"inaccuracies. SearXNG is now available — re-run to get verified facts."
|
"inaccuracies. SearXNG is now available — re-run to get verified facts."
|
||||||
)
|
)
|
||||||
if st.button("🔄 Re-run with live data", key=f"modal_rescrape_{job_id}", type="primary"):
|
if st.button("🔄 Re-run with live data", key=f"modal_rescrape_{job_id}", type="primary"):
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
st.divider()
|
st.divider()
|
||||||
else:
|
else:
|
||||||
|
|
@ -160,14 +163,14 @@ def _research_modal(job: dict) -> None:
|
||||||
)
|
)
|
||||||
st.markdown(research["raw_output"])
|
st.markdown(research["raw_output"])
|
||||||
if st.button("🔄 Refresh", key=f"modal_regen_{job_id}", disabled=bool(running)):
|
if st.button("🔄 Refresh", key=f"modal_regen_{job_id}", disabled=bool(running)):
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
else:
|
else:
|
||||||
st.info("No research brief yet.")
|
st.info("No research brief yet.")
|
||||||
if task and task["status"] == "failed":
|
if task and task["status"] == "failed":
|
||||||
st.error(f"Last attempt failed: {task.get('error', '')}")
|
st.error(f"Last attempt failed: {task.get('error', '')}")
|
||||||
if st.button("🔬 Generate now", key=f"modal_gen_{job_id}"):
|
if st.button("🔬 Generate now", key=f"modal_gen_{job_id}"):
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -175,7 +178,7 @@ def _research_modal(job: dict) -> None:
|
||||||
def _email_modal(job: dict) -> None:
|
def _email_modal(job: dict) -> None:
|
||||||
job_id = job["id"]
|
job_id = job["id"]
|
||||||
st.caption(f"**{job.get('company')}** — {job.get('title')}")
|
st.caption(f"**{job.get('company')}** — {job.get('title')}")
|
||||||
contacts = get_contacts(DEFAULT_DB, job_id=job_id)
|
contacts = get_contacts(get_db_path(), job_id=job_id)
|
||||||
|
|
||||||
if not contacts:
|
if not contacts:
|
||||||
st.info("No emails logged yet. Use the form below to add one.")
|
st.info("No emails logged yet. Use the form below to add one.")
|
||||||
|
|
@ -246,7 +249,7 @@ def _email_modal(job: dict) -> None:
|
||||||
body_text = st.text_area("Body / notes", height=80, key=f"body_modal_{job_id}")
|
body_text = st.text_area("Body / notes", height=80, key=f"body_modal_{job_id}")
|
||||||
if st.form_submit_button("📧 Save contact"):
|
if st.form_submit_button("📧 Save contact"):
|
||||||
add_contact(
|
add_contact(
|
||||||
DEFAULT_DB, job_id=job_id,
|
get_db_path(), job_id=job_id,
|
||||||
direction=direction, subject=subject,
|
direction=direction, subject=subject,
|
||||||
from_addr=from_addr, body=body_text, received_at=recv_at,
|
from_addr=from_addr, body=body_text, received_at=recv_at,
|
||||||
)
|
)
|
||||||
|
|
@ -255,7 +258,7 @@ def _email_modal(job: dict) -> None:
|
||||||
def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
"""Render a single job card appropriate for the given stage."""
|
"""Render a single job card appropriate for the given stage."""
|
||||||
job_id = job["id"]
|
job_id = job["id"]
|
||||||
contacts = get_contacts(DEFAULT_DB, job_id=job_id)
|
contacts = get_contacts(get_db_path(), job_id=job_id)
|
||||||
last_contact = contacts[-1] if contacts else None
|
last_contact = contacts[-1] if contacts else None
|
||||||
|
|
||||||
with st.container(border=True):
|
with st.container(border=True):
|
||||||
|
|
@ -278,7 +281,7 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
format="YYYY-MM-DD",
|
format="YYYY-MM-DD",
|
||||||
)
|
)
|
||||||
if st.form_submit_button("📅 Save date"):
|
if st.form_submit_button("📅 Save date"):
|
||||||
set_interview_date(DEFAULT_DB, job_id=job_id, date_str=str(new_date))
|
set_interview_date(get_db_path(), job_id=job_id, date_str=str(new_date))
|
||||||
st.success("Saved!")
|
st.success("Saved!")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
|
@ -288,7 +291,7 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
_cal_label = "🔄 Update Calendar" if _has_event else "📅 Add to Calendar"
|
_cal_label = "🔄 Update Calendar" if _has_event else "📅 Add to Calendar"
|
||||||
if st.button(_cal_label, key=f"cal_push_{job_id}", use_container_width=True):
|
if st.button(_cal_label, key=f"cal_push_{job_id}", use_container_width=True):
|
||||||
from scripts.calendar_push import push_interview_event
|
from scripts.calendar_push import push_interview_event
|
||||||
result = push_interview_event(DEFAULT_DB, job_id=job_id, config_dir=_CONFIG_DIR)
|
result = push_interview_event(get_db_path(), job_id=job_id, config_dir=_CONFIG_DIR)
|
||||||
if result["ok"]:
|
if result["ok"]:
|
||||||
st.success(f"Event {'updated' if _has_event else 'added'} ({result['provider'].replace('_', ' ').title()})")
|
st.success(f"Event {'updated' if _has_event else 'added'} ({result['provider'].replace('_', ' ').title()})")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
@ -297,7 +300,7 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
|
|
||||||
if not compact:
|
if not compact:
|
||||||
if stage in ("applied", "phone_screen", "interviewing"):
|
if stage in ("applied", "phone_screen", "interviewing"):
|
||||||
signals = get_unread_stage_signals(DEFAULT_DB, job_id=job_id)
|
signals = get_unread_stage_signals(get_db_path(), job_id=job_id)
|
||||||
if signals:
|
if signals:
|
||||||
sig = signals[-1]
|
sig = signals[-1]
|
||||||
_SIGNAL_TO_STAGE = {
|
_SIGNAL_TO_STAGE = {
|
||||||
|
|
@ -318,23 +321,23 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
if sig["stage_signal"] == "rejected":
|
if sig["stage_signal"] == "rejected":
|
||||||
if b1.button("✗ Reject", key=f"sig_rej_{sig['id']}",
|
if b1.button("✗ Reject", key=f"sig_rej_{sig['id']}",
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
reject_at_stage(DEFAULT_DB, job_id=job_id, rejection_stage=stage)
|
reject_at_stage(get_db_path(), job_id=job_id, rejection_stage=stage)
|
||||||
dismiss_stage_signal(DEFAULT_DB, sig["id"])
|
dismiss_stage_signal(get_db_path(), sig["id"])
|
||||||
st.rerun(scope="app")
|
st.rerun(scope="app")
|
||||||
elif target_stage and b1.button(
|
elif target_stage and b1.button(
|
||||||
f"→ {target_label}", key=f"sig_adv_{sig['id']}",
|
f"→ {target_label}", key=f"sig_adv_{sig['id']}",
|
||||||
use_container_width=True, type="primary",
|
use_container_width=True, type="primary",
|
||||||
):
|
):
|
||||||
if target_stage == "phone_screen" and stage == "applied":
|
if target_stage == "phone_screen" and stage == "applied":
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage="phone_screen")
|
advance_to_stage(get_db_path(), job_id=job_id, stage="phone_screen")
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
elif target_stage:
|
elif target_stage:
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage=target_stage)
|
advance_to_stage(get_db_path(), job_id=job_id, stage=target_stage)
|
||||||
dismiss_stage_signal(DEFAULT_DB, sig["id"])
|
dismiss_stage_signal(get_db_path(), sig["id"])
|
||||||
st.rerun(scope="app")
|
st.rerun(scope="app")
|
||||||
if b2.button("Dismiss", key=f"sig_dis_{sig['id']}",
|
if b2.button("Dismiss", key=f"sig_dis_{sig['id']}",
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
dismiss_stage_signal(DEFAULT_DB, sig["id"])
|
dismiss_stage_signal(get_db_path(), sig["id"])
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
# Advance / Reject buttons
|
# Advance / Reject buttons
|
||||||
|
|
@ -346,16 +349,16 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
f"→ {next_label}", key=f"adv_{job_id}",
|
f"→ {next_label}", key=f"adv_{job_id}",
|
||||||
use_container_width=True, type="primary",
|
use_container_width=True, type="primary",
|
||||||
):
|
):
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage=next_stage)
|
advance_to_stage(get_db_path(), job_id=job_id, stage=next_stage)
|
||||||
if next_stage == "phone_screen":
|
if next_stage == "phone_screen":
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
st.rerun(scope="app") # full rerun — card must appear in new column
|
st.rerun(scope="app") # full rerun — card must appear in new column
|
||||||
|
|
||||||
if c2.button(
|
if c2.button(
|
||||||
"✗ Reject", key=f"rej_{job_id}",
|
"✗ Reject", key=f"rej_{job_id}",
|
||||||
use_container_width=True,
|
use_container_width=True,
|
||||||
):
|
):
|
||||||
reject_at_stage(DEFAULT_DB, job_id=job_id, rejection_stage=stage)
|
reject_at_stage(get_db_path(), job_id=job_id, rejection_stage=stage)
|
||||||
st.rerun() # fragment-scope rerun — card disappears without scroll-to-top
|
st.rerun() # fragment-scope rerun — card disappears without scroll-to-top
|
||||||
|
|
||||||
if job.get("url"):
|
if job.get("url"):
|
||||||
|
|
@ -385,7 +388,7 @@ def _render_card(job: dict, stage: str, compact: bool = False) -> None:
|
||||||
@st.fragment
|
@st.fragment
|
||||||
def _card_fragment(job_id: int, stage: str) -> None:
|
def _card_fragment(job_id: int, stage: str) -> None:
|
||||||
"""Re-fetches the job on each fragment rerun; renders nothing if moved/rejected."""
|
"""Re-fetches the job on each fragment rerun; renders nothing if moved/rejected."""
|
||||||
job = get_job_by_id(DEFAULT_DB, job_id)
|
job = get_job_by_id(get_db_path(), job_id)
|
||||||
if job is None or job.get("status") != stage:
|
if job is None or job.get("status") != stage:
|
||||||
return
|
return
|
||||||
_render_card(job, stage)
|
_render_card(job, stage)
|
||||||
|
|
@ -394,11 +397,11 @@ def _card_fragment(job_id: int, stage: str) -> None:
|
||||||
@st.fragment
|
@st.fragment
|
||||||
def _pre_kanban_row_fragment(job_id: int) -> None:
|
def _pre_kanban_row_fragment(job_id: int) -> None:
|
||||||
"""Pre-kanban compact row for applied and survey-stage jobs."""
|
"""Pre-kanban compact row for applied and survey-stage jobs."""
|
||||||
job = get_job_by_id(DEFAULT_DB, job_id)
|
job = get_job_by_id(get_db_path(), job_id)
|
||||||
if job is None or job.get("status") not in ("applied", "survey"):
|
if job is None or job.get("status") not in ("applied", "survey"):
|
||||||
return
|
return
|
||||||
stage = job["status"]
|
stage = job["status"]
|
||||||
contacts = get_contacts(DEFAULT_DB, job_id=job_id)
|
contacts = get_contacts(get_db_path(), job_id=job_id)
|
||||||
last_contact = contacts[-1] if contacts else None
|
last_contact = contacts[-1] if contacts else None
|
||||||
|
|
||||||
with st.container(border=True):
|
with st.container(border=True):
|
||||||
|
|
@ -414,7 +417,7 @@ def _pre_kanban_row_fragment(job_id: int) -> None:
|
||||||
_email_modal(job)
|
_email_modal(job)
|
||||||
|
|
||||||
# Stage signal hint (email-detected next steps)
|
# Stage signal hint (email-detected next steps)
|
||||||
signals = get_unread_stage_signals(DEFAULT_DB, job_id=job_id)
|
signals = get_unread_stage_signals(get_db_path(), job_id=job_id)
|
||||||
if signals:
|
if signals:
|
||||||
sig = signals[-1]
|
sig = signals[-1]
|
||||||
_SIGNAL_TO_STAGE = {
|
_SIGNAL_TO_STAGE = {
|
||||||
|
|
@ -437,15 +440,15 @@ def _pre_kanban_row_fragment(job_id: int) -> None:
|
||||||
use_container_width=True, type="primary",
|
use_container_width=True, type="primary",
|
||||||
):
|
):
|
||||||
if target_stage == "phone_screen":
|
if target_stage == "phone_screen":
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage="phone_screen")
|
advance_to_stage(get_db_path(), job_id=job_id, stage="phone_screen")
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
else:
|
else:
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage=target_stage)
|
advance_to_stage(get_db_path(), job_id=job_id, stage=target_stage)
|
||||||
dismiss_stage_signal(DEFAULT_DB, sig["id"])
|
dismiss_stage_signal(get_db_path(), sig["id"])
|
||||||
st.rerun(scope="app")
|
st.rerun(scope="app")
|
||||||
if s2.button("Dismiss", key=f"sig_dis_pre_{sig['id']}",
|
if s2.button("Dismiss", key=f"sig_dis_pre_{sig['id']}",
|
||||||
use_container_width=True):
|
use_container_width=True):
|
||||||
dismiss_stage_signal(DEFAULT_DB, sig["id"])
|
dismiss_stage_signal(get_db_path(), sig["id"])
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
with right:
|
with right:
|
||||||
|
|
@ -453,24 +456,24 @@ def _pre_kanban_row_fragment(job_id: int) -> None:
|
||||||
"→ 📞 Phone Screen", key=f"adv_pre_{job_id}",
|
"→ 📞 Phone Screen", key=f"adv_pre_{job_id}",
|
||||||
use_container_width=True, type="primary",
|
use_container_width=True, type="primary",
|
||||||
):
|
):
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage="phone_screen")
|
advance_to_stage(get_db_path(), job_id=job_id, stage="phone_screen")
|
||||||
submit_task(DEFAULT_DB, "company_research", job_id)
|
submit_task(get_db_path(), "company_research", job_id)
|
||||||
st.rerun(scope="app")
|
st.rerun(scope="app")
|
||||||
col_a, col_b = st.columns(2)
|
col_a, col_b = st.columns(2)
|
||||||
if stage == "applied" and col_a.button(
|
if stage == "applied" and col_a.button(
|
||||||
"📋 Survey", key=f"to_survey_{job_id}", use_container_width=True,
|
"📋 Survey", key=f"to_survey_{job_id}", use_container_width=True,
|
||||||
):
|
):
|
||||||
advance_to_stage(DEFAULT_DB, job_id=job_id, stage="survey")
|
advance_to_stage(get_db_path(), job_id=job_id, stage="survey")
|
||||||
st.rerun(scope="app")
|
st.rerun(scope="app")
|
||||||
if col_b.button("✗ Reject", key=f"rej_pre_{job_id}", use_container_width=True):
|
if col_b.button("✗ Reject", key=f"rej_pre_{job_id}", use_container_width=True):
|
||||||
reject_at_stage(DEFAULT_DB, job_id=job_id, rejection_stage=stage)
|
reject_at_stage(get_db_path(), job_id=job_id, rejection_stage=stage)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
|
|
||||||
@st.fragment
|
@st.fragment
|
||||||
def _hired_card_fragment(job_id: int) -> None:
|
def _hired_card_fragment(job_id: int) -> None:
|
||||||
"""Compact hired job card — shown in the Offer/Hired column."""
|
"""Compact hired job card — shown in the Offer/Hired column."""
|
||||||
job = get_job_by_id(DEFAULT_DB, job_id)
|
job = get_job_by_id(get_db_path(), job_id)
|
||||||
if job is None or job.get("status") != "hired":
|
if job is None or job.get("status") != "hired":
|
||||||
return
|
return
|
||||||
with st.container(border=True):
|
with st.container(border=True):
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@ from scripts.db import (
|
||||||
get_task_for_job,
|
get_task_for_job,
|
||||||
)
|
)
|
||||||
from scripts.task_runner import submit_task
|
from scripts.task_runner import submit_task
|
||||||
|
from app.cloud_session import resolve_session, get_db_path
|
||||||
|
|
||||||
init_db(DEFAULT_DB)
|
resolve_session("peregrine")
|
||||||
|
|
||||||
|
init_db(get_db_path())
|
||||||
|
|
||||||
# ── Job selection ─────────────────────────────────────────────────────────────
|
# ── Job selection ─────────────────────────────────────────────────────────────
|
||||||
jobs_by_stage = get_interview_jobs(DEFAULT_DB)
|
jobs_by_stage = get_interview_jobs(get_db_path())
|
||||||
active_stages = ["phone_screen", "interviewing", "offer"]
|
active_stages = ["phone_screen", "interviewing", "offer"]
|
||||||
active_jobs = [
|
active_jobs = [
|
||||||
j for stage in active_stages
|
j for stage in active_stages
|
||||||
|
|
@ -100,10 +103,10 @@ col_prep, col_context = st.columns([2, 3])
|
||||||
# ════════════════════════════════════════════════
|
# ════════════════════════════════════════════════
|
||||||
with col_prep:
|
with col_prep:
|
||||||
|
|
||||||
research = get_research(DEFAULT_DB, job_id=selected_id)
|
research = get_research(get_db_path(), job_id=selected_id)
|
||||||
|
|
||||||
# Refresh / generate research
|
# Refresh / generate research
|
||||||
_res_task = get_task_for_job(DEFAULT_DB, "company_research", selected_id)
|
_res_task = get_task_for_job(get_db_path(), "company_research", selected_id)
|
||||||
_res_running = _res_task and _res_task["status"] in ("queued", "running")
|
_res_running = _res_task and _res_task["status"] in ("queued", "running")
|
||||||
|
|
||||||
if not research:
|
if not research:
|
||||||
|
|
@ -112,13 +115,13 @@ with col_prep:
|
||||||
if _res_task and _res_task["status"] == "failed":
|
if _res_task and _res_task["status"] == "failed":
|
||||||
st.error(f"Last attempt failed: {_res_task.get('error', '')}")
|
st.error(f"Last attempt failed: {_res_task.get('error', '')}")
|
||||||
if st.button("🔬 Generate research brief", type="primary", use_container_width=True):
|
if st.button("🔬 Generate research brief", type="primary", use_container_width=True):
|
||||||
submit_task(DEFAULT_DB, "company_research", selected_id)
|
submit_task(get_db_path(), "company_research", selected_id)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
if _res_running:
|
if _res_running:
|
||||||
@st.fragment(run_every=3)
|
@st.fragment(run_every=3)
|
||||||
def _res_status_initial():
|
def _res_status_initial():
|
||||||
t = get_task_for_job(DEFAULT_DB, "company_research", selected_id)
|
t = get_task_for_job(get_db_path(), "company_research", selected_id)
|
||||||
if t and t["status"] in ("queued", "running"):
|
if t and t["status"] in ("queued", "running"):
|
||||||
stage = t.get("stage") or ""
|
stage = t.get("stage") or ""
|
||||||
lbl = "Queued…" if t["status"] == "queued" else (stage or "Generating… this may take 30–60 seconds")
|
lbl = "Queued…" if t["status"] == "queued" else (stage or "Generating… this may take 30–60 seconds")
|
||||||
|
|
@ -133,13 +136,13 @@ with col_prep:
|
||||||
col_ts, col_btn = st.columns([3, 1])
|
col_ts, col_btn = st.columns([3, 1])
|
||||||
col_ts.caption(f"Research generated: {generated_at}")
|
col_ts.caption(f"Research generated: {generated_at}")
|
||||||
if col_btn.button("🔄 Refresh", use_container_width=True, disabled=bool(_res_running)):
|
if col_btn.button("🔄 Refresh", use_container_width=True, disabled=bool(_res_running)):
|
||||||
submit_task(DEFAULT_DB, "company_research", selected_id)
|
submit_task(get_db_path(), "company_research", selected_id)
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
if _res_running:
|
if _res_running:
|
||||||
@st.fragment(run_every=3)
|
@st.fragment(run_every=3)
|
||||||
def _res_status_refresh():
|
def _res_status_refresh():
|
||||||
t = get_task_for_job(DEFAULT_DB, "company_research", selected_id)
|
t = get_task_for_job(get_db_path(), "company_research", selected_id)
|
||||||
if t and t["status"] in ("queued", "running"):
|
if t and t["status"] in ("queued", "running"):
|
||||||
stage = t.get("stage") or ""
|
stage = t.get("stage") or ""
|
||||||
lbl = "Queued…" if t["status"] == "queued" else (stage or "Refreshing research…")
|
lbl = "Queued…" if t["status"] == "queued" else (stage or "Refreshing research…")
|
||||||
|
|
@ -311,7 +314,7 @@ with col_context:
|
||||||
st.markdown(job.get("description") or "_No description saved for this listing._")
|
st.markdown(job.get("description") or "_No description saved for this listing._")
|
||||||
|
|
||||||
with tab_emails:
|
with tab_emails:
|
||||||
contacts = get_contacts(DEFAULT_DB, job_id=selected_id)
|
contacts = get_contacts(get_db_path(), job_id=selected_id)
|
||||||
if not contacts:
|
if not contacts:
|
||||||
st.info("No contacts logged yet. Use the Interviews page to log emails.")
|
st.info("No contacts logged yet. Use the Interviews page to log emails.")
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,13 @@ from scripts.db import (
|
||||||
insert_survey_response, get_survey_responses,
|
insert_survey_response, get_survey_responses,
|
||||||
)
|
)
|
||||||
from scripts.llm_router import LLMRouter
|
from scripts.llm_router import LLMRouter
|
||||||
|
from app.cloud_session import resolve_session, get_db_path
|
||||||
|
|
||||||
|
resolve_session("peregrine")
|
||||||
|
|
||||||
st.title("📋 Survey Assistant")
|
st.title("📋 Survey Assistant")
|
||||||
|
|
||||||
init_db(DEFAULT_DB)
|
init_db(get_db_path())
|
||||||
|
|
||||||
|
|
||||||
# ── Vision service health check ────────────────────────────────────────────────
|
# ── Vision service health check ────────────────────────────────────────────────
|
||||||
|
|
@ -40,7 +43,7 @@ def _vision_available() -> bool:
|
||||||
vision_up = _vision_available()
|
vision_up = _vision_available()
|
||||||
|
|
||||||
# ── Job selector ───────────────────────────────────────────────────────────────
|
# ── Job selector ───────────────────────────────────────────────────────────────
|
||||||
jobs_by_stage = get_interview_jobs(DEFAULT_DB)
|
jobs_by_stage = get_interview_jobs(get_db_path())
|
||||||
survey_jobs = jobs_by_stage.get("survey", [])
|
survey_jobs = jobs_by_stage.get("survey", [])
|
||||||
other_jobs = (
|
other_jobs = (
|
||||||
jobs_by_stage.get("applied", []) +
|
jobs_by_stage.get("applied", []) +
|
||||||
|
|
@ -61,7 +64,7 @@ selected_job_id = st.selectbox(
|
||||||
format_func=lambda jid: job_labels[jid],
|
format_func=lambda jid: job_labels[jid],
|
||||||
index=0,
|
index=0,
|
||||||
)
|
)
|
||||||
selected_job = get_job_by_id(DEFAULT_DB, selected_job_id)
|
selected_job = get_job_by_id(get_db_path(), selected_job_id)
|
||||||
|
|
||||||
# ── LLM prompt builders ────────────────────────────────────────────────────────
|
# ── LLM prompt builders ────────────────────────────────────────────────────────
|
||||||
_SURVEY_SYSTEM = (
|
_SURVEY_SYSTEM = (
|
||||||
|
|
@ -236,7 +239,7 @@ with right_col:
|
||||||
image_path = str(img_file)
|
image_path = str(img_file)
|
||||||
|
|
||||||
insert_survey_response(
|
insert_survey_response(
|
||||||
DEFAULT_DB,
|
get_db_path(),
|
||||||
job_id=selected_job_id,
|
job_id=selected_job_id,
|
||||||
survey_name=survey_name,
|
survey_name=survey_name,
|
||||||
source=source,
|
source=source,
|
||||||
|
|
@ -256,7 +259,7 @@ with right_col:
|
||||||
# ── History ────────────────────────────────────────────────────────────────────
|
# ── History ────────────────────────────────────────────────────────────────────
|
||||||
st.divider()
|
st.divider()
|
||||||
st.subheader("📂 Response History")
|
st.subheader("📂 Response History")
|
||||||
history = get_survey_responses(DEFAULT_DB, job_id=selected_job_id)
|
history = get_survey_responses(get_db_path(), job_id=selected_job_id)
|
||||||
|
|
||||||
if not history:
|
if not history:
|
||||||
st.caption("No saved responses for this job yet.")
|
st.caption("No saved responses for this job yet.")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue