ai-techno-dj / app_feedback_callbacks.py
Rik Hoffbauer
Implement musical candidate ranking and feedback-driven learning
f02c67e
from __future__ import annotations
from app_state import app_state
def train_cue_model_from_feedback():
"""Train lightweight cue and transition-candidate scorers from feedback."""
from cue_learning import (
load_training_examples, examples_from_rating_rows, fit_logistic_model, save_model,
examples_from_candidate_rating_rows, fit_candidate_ranker, save_candidate_model,
)
from listening_benchmarks import load_ratings
manual = load_training_examples("data/manual-cue-edits.jsonl")
rows = load_ratings()
rating_examples = examples_from_rating_rows(rows)
candidate_examples = examples_from_candidate_rating_rows(rows)
examples = manual + rating_examples
if not examples and not candidate_examples:
return "⚠️ No manual cue edits or decisive listening ratings available for training yet."
path = None
candidate_path = None
if examples:
model = fit_logistic_model(examples)
path = save_model(model)
if candidate_examples:
candidate_model = fit_candidate_ranker(candidate_examples)
candidate_path = save_candidate_model(candidate_model)
return (
"✅ Feedback models trained\n\n"
f"- Cue examples: {len(examples)}\n"
f"- Manual cue edits: {len(manual)}\n"
f"- Rating-derived examples: {len(rating_examples)}\n"
f"- Candidate examples: {len(candidate_examples)}\n"
f"- Cue model output: `{path or 'not enough examples'}`\n"
f"- Candidate ranker output: `{candidate_path or 'not enough examples'}`\n\n"
"New analyses blend cue probability into cue confidence and candidate acceptance probability into transition ranking."
)
def save_transition_rating(transition_idx, candidate_rank, rating, accepted, notes):
"""Persist a human listening rating for a transition candidate."""
if not app_state.transitions:
return "⚠️ Generate a set plan first"
idx = int(transition_idx) - 1
if idx < 0 or idx >= len(app_state.transitions):
return f"⚠️ Invalid transition index. Choose 1-{len(app_state.transitions)}"
trans = app_state.transitions[idx]
track_a = app_state.analyses[trans.track_a_idx]
track_b = app_state.analyses[trans.track_b_idx]
from listening_benchmarks import record_transition_rating, summarize_ratings, format_rating_summary
record_transition_rating(
transition=trans,
track_a=track_a,
track_b=track_b,
rating=float(rating),
notes=str(notes or ""),
candidate_rank=int(candidate_rank or 0),
accepted=bool(accepted),
)
return "✅ Rating saved.\n\n" + format_rating_summary(summarize_ratings())
def show_listening_benchmarks():
from listening_benchmarks import summarize_ratings, format_rating_summary
return format_rating_summary(summarize_ratings())