File size: 2,641 Bytes
52a2a94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"""
Human feedback capture (the RLHF data loop).

Stores each generation + the engineer's edits and feedback as a JSONL record.
This is the seed of the proprietary dataset described in the business plan:
every reviewed generation becomes a training example (preference pair: original
AI output vs. engineer-corrected output, plus a usefulness rating and rationale).

MVP storage: local JSONL file. Production: swap for a database (SQL/cloud) by
replacing save_feedback(); the record schema stays the same.
"""

import json
import os
import time
import uuid
from typing import Optional

FEEDBACK_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                            "feedback_data")
FEEDBACK_FILE = os.path.join(FEEDBACK_DIR, "feedback_log.jsonl")


def save_feedback(record: dict) -> dict:
    """Append a feedback record. Returns {"ok": bool, "id": str, "error": str?}."""
    try:
        os.makedirs(FEEDBACK_DIR, exist_ok=True)
        record = dict(record)
        record.setdefault("id", str(uuid.uuid4()))
        record.setdefault("timestamp", time.time())
        record.setdefault("timestamp_iso",
                          time.strftime("%Y-%m-%dT%H:%M:%S",
                                        time.localtime(record["timestamp"])))
        with open(FEEDBACK_FILE, "a", encoding="utf-8") as f:
            f.write(json.dumps(record, ensure_ascii=False) + "\n")
        return {"ok": True, "id": record["id"], "error": None}
    except Exception as e:  # noqa: BLE001
        return {"ok": False, "id": None, "error": str(e)}


def load_feedback() -> list[dict]:
    """Load all feedback records (for a simple in-app review/metrics view)."""
    if not os.path.exists(FEEDBACK_FILE):
        return []
    out = []
    with open(FEEDBACK_FILE, "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if line:
                try:
                    out.append(json.loads(line))
                except json.JSONDecodeError:
                    continue
    return out


def feedback_stats() -> dict:
    """Quick aggregate metrics for the demo / grant package."""
    records = load_feedback()
    if not records:
        return {"count": 0, "avg_usefulness": None, "edited_fraction": None}
    ratings = [r.get("usefulness") for r in records
               if isinstance(r.get("usefulness"), (int, float))]
    edited = [r for r in records if r.get("was_edited")]
    return {
        "count": len(records),
        "avg_usefulness": round(sum(ratings) / len(ratings), 2) if ratings else None,
        "edited_fraction": round(len(edited) / len(records), 2),
    }