{% extends "base.html" %}
{% block title %}Trainline — psyc{% endblock %}
{% block content %}
<section class="panel">
  <div class="panel-head">
    <h1>Trainline — Datasets</h1>
    <span class="count">{{ datasets|length }} dataset{{ '' if datasets|length == 1 else 's' }}</span>
  </div>
  <p class="page-intro">Trainline turns reviewed cases into LoRA training data and tracks the fine-tuned adapters built from it — the JSONL datasets below, and the trained adapters with their loss curves further down. The adapter behind the Classifier bot is trained here.</p>
  <details class="page-help">
    <summary>how to use this view</summary>
    <div class="help-body">
      <p><b>How to use.</b> <code>psyc train-build-all</code> builds the datasets below; the <code>Dockerfile.train</code> workflow fine-tunes an adapter; both then appear here.</p>
      <p><b>What you're seeing.</b> JSONL datasets with example counts, and trained QLoRA adapters with their base model, hyperparameters, and per-step loss curve.</p>
      <p><b>Why it matters.</b> The adapter behind the Classifier bot is built here — this page is the provenance of the model that's actually in operation.</p>
    </div>
  </details>
  {% if not datasets %}
    <p class="empty">No datasets yet. Run <code>psyc train-build-all</code>.</p>
  {% else %}
  <table class="cases">
    <thead>
      <tr><th>Dataset</th><th>Examples</th><th>Size</th><th>Built</th></tr>
    </thead>
    <tbody>
    {% for d in datasets %}
      <tr>
        <td><code>{{ d.name }}</code></td>
        <td>{{ d.examples }}</td>
        <td class="muted">{{ d.size_bytes }} B</td>
        <td class="muted">{{ d.modified[:16] }}</td>
      </tr>
    {% endfor %}
    </tbody>
  </table>
  {% endif %}
</section>

<section class="panel" style="margin-top: 20px;">
  <div class="panel-head">
    <h1>Trainline — Adapters</h1>
    <span class="count">{{ adapters|length }} adapter{{ '' if adapters|length == 1 else 's' }}</span>
  </div>
  {% if not adapters %}
    <p class="empty">No adapters yet. Build <code>Dockerfile.train</code> and run a QLoRA fine-tune.</p>
  {% else %}
  <div class="grid">
    {% for a in adapters %}
    <div class="card wide">
      <h2>{{ a.name }}
        {% if a.status == 'trained' %}<span class="outcome-badge outcome-actioned">trained</span>
        {% elif a.status == 'in_progress' %}<span class="outcome-badge outcome-submitted">training…</span>
        {% else %}<span class="outcome-badge outcome-rejected">not started</span>{% endif %}
      </h2>
      <dl>
        <dt>Base model</dt><dd><code>{{ a.base_model }}</code></dd>
        <dt>Examples</dt><dd>{{ a.examples }}</dd>
        <dt>Epochs</dt><dd>{{ a.epochs }}</dd>
        <dt>LoRA r</dt><dd>{{ a.lora_r }}</dd>
        <dt>Learning rate</dt><dd>{{ a.lr }}</dd>
        <dt>Final train loss</dt><dd>{% if a.train_loss is not none %}<strong>{{ '%.4f'|format(a.train_loss) }}</strong>{% else %}<span class="muted">— (trained before loss capture)</span>{% endif %}</dd>
        <dt>Datasets</dt><dd>{% for ds in a.datasets %}<code>{{ ds }}</code> {% endfor %}{% if not a.datasets %}—{% endif %}</dd>
      </dl>
      {% if a.loss_history %}
      <h3>Training loss by step</h3>
      {% set max_loss = a.loss_history | map(attribute='loss') | max %}
      <div class="loss-chart">
        {% for h in a.loss_history %}
        <div class="loss-row">
          <span class="loss-step">step {{ h.step }} · ep {{ h.epoch | round(0, 'floor') | int }}</span>
          <span class="loss-bar-track"><span class="loss-bar" style="width: {{ (h.loss / max_loss * 100) | round(1) }}%"></span></span>
          <span class="loss-val">{{ '%.4f'|format(h.loss) }}</span>
        </div>
        {% endfor %}
      </div>
      {% else %}
      <p class="muted">No per-step loss recorded for this run.</p>
      {% endif %}
    </div>
    {% endfor %}
  </div>
  {% endif %}
</section>
{% endblock %}
