| """ |
| Generates synthetic fine-tuning examples in the <ui>β¦</ui> format. |
| |
| Each adapter needs examples where the assistant emits a valid ui_spec |
| wrapped in <ui>β¦</ui> tags followed by a prose explanation. |
| |
| Usage: |
| python training/generate_examples.py --mode support --n 50 -o data/support.jsonl |
| python training/generate_examples.py --mode analytics --n 50 -o data/analytics.jsonl |
| python training/generate_examples.py --mode form --n 50 -o data/form.jsonl |
| python training/generate_examples.py --all -o data/ |
| """ |
| import argparse |
| import json |
| import random |
| from pathlib import Path |
| from typing import Callable |
|
|
| |
|
|
| _SUPPORT_ISSUES = [ |
| ("login fails with 401", "Authentication error β token may be expired."), |
| ("page not loading", "Possible network timeout or server error."), |
| ("export button missing", "Feature may be behind a permission flag."), |
| ("data not syncing", "Background sync may be paused or failing silently."), |
| ("slow performance", "Cache may be stale β clearing it often helps."), |
| ] |
|
|
| def _support_example() -> dict: |
| issue, summary = random.choice(_SUPPORT_ISSUES) |
| steps = ["Check console for error codes", "Clear cache and retry", |
| "Verify account permissions", "Contact support with error ID"] |
| spec = { |
| "component": "card", |
| "props": { |
| "title": f"Troubleshooting: {issue}", |
| "body": summary, |
| "items": [{"label": f"Step {i+1}", "value": s} for i, s in enumerate(steps)], |
| }, |
| } |
| user = f"I have an issue: {issue}" |
| assist = f"<ui>{json.dumps(spec)}</ui>\n\n{summary} Here are the recommended steps." |
| return {"messages": [{"role": "user", "content": user}, |
| {"role": "assistant", "content": assist}]} |
|
|
|
|
| |
|
|
| _METRICS = ["revenue", "active users", "churn rate", "conversion", "page views"] |
| _PERIODS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"] |
|
|
| def _analytics_example() -> dict: |
| metric = random.choice(_METRICS) |
| values = [random.randint(100, 900) for _ in _PERIODS] |
| spec = { |
| "component": "chart", |
| "props": { |
| "title": f"{metric.title()} β Last 6 Months", |
| "type": "bar", |
| "data": { |
| "labels": _PERIODS, |
| "datasets": [{"label": metric.title(), "data": values}], |
| }, |
| }, |
| } |
| user = f"Show me {metric} trends over the last 6 months" |
| insight = f"Peak was {_PERIODS[values.index(max(values))]} at {max(values)}." |
| assist = f"<ui>{json.dumps(spec)}</ui>\n\n{insight}" |
| return {"messages": [{"role": "user", "content": user}, |
| {"role": "assistant", "content": assist}]} |
|
|
|
|
| |
|
|
| _FORMS = [ |
| { |
| "title": "Contact Support", |
| "submitLabel": "Send Request", |
| "fields": [ |
| {"name": "name", "label": "Full Name", "type": "text", "required": True}, |
| {"name": "email", "label": "Email", "type": "email", "required": True}, |
| {"name": "subject", "label": "Subject", "type": "text"}, |
| {"name": "message", "label": "Message", "type": "textarea", "required": True}, |
| ], |
| }, |
| { |
| "title": "Account Registration", |
| "submitLabel": "Create Account", |
| "fields": [ |
| {"name": "username", "label": "Username", "type": "text", "required": True}, |
| {"name": "email", "label": "Email", "type": "email", "required": True}, |
| {"name": "password", "label": "Password", "type": "password", "required": True}, |
| {"name": "plan", "label": "Plan", "type": "select", |
| "options": ["Free", "Pro", "Enterprise"]}, |
| ], |
| }, |
| { |
| "title": "Export Data", |
| "submitLabel": "Export", |
| "fields": [ |
| {"name": "format", "label": "Format", "type": "select", |
| "options": ["CSV", "JSON", "Excel"]}, |
| {"name": "date_from", "label": "From", "type": "date", "required": True}, |
| {"name": "date_to", "label": "To", "type": "date", "required": True}, |
| ], |
| }, |
| ] |
|
|
| def _form_example() -> dict: |
| form_def = random.choice(_FORMS) |
| spec = {"component": "form", "props": form_def} |
| user = f"I need to {form_def['submitLabel'].lower()}" |
| assist = (f"<ui>{json.dumps(spec)}</ui>\n\n" |
| f"Please fill in the {form_def['title']} form below.") |
| return {"messages": [{"role": "user", "content": user}, |
| {"role": "assistant", "content": assist}]} |
|
|
|
|
| |
|
|
| _GENERATORS: dict[str, Callable[[], dict]] = { |
| "support": _support_example, |
| "analytics": _analytics_example, |
| "form": _form_example, |
| } |
|
|
|
|
| def generate(mode: str, n: int) -> list[dict]: |
| fn = _GENERATORS[mode] |
| return [fn() for _ in range(n)] |
|
|
|
|
| def write_jsonl(examples: list[dict], path: Path) -> None: |
| path.parent.mkdir(parents=True, exist_ok=True) |
| with open(path, "w", encoding="utf-8") as f: |
| for ex in examples: |
| f.write(json.dumps(ex, ensure_ascii=False) + "\n") |
| print(f"Wrote {len(examples)} examples β {path}") |
|
|
|
|
| |
|
|
| def main() -> None: |
| p = argparse.ArgumentParser(description="Generate synthetic adapter training data") |
| p.add_argument("--mode", choices=list(_GENERATORS.keys()), |
| help="Adapter mode to generate for") |
| p.add_argument("--all", action="store_true", |
| help="Generate for all modes (saves to <output>/<mode>.jsonl)") |
| p.add_argument("--n", type=int, default=50, help="Examples per mode") |
| p.add_argument("-o", "--output", default="data", help="Output path or directory") |
| args = p.parse_args() |
|
|
| modes = list(_GENERATORS.keys()) if args.all else ([args.mode] if args.mode else []) |
| if not modes: |
| p.error("Specify --mode or --all") |
|
|
| out = Path(args.output) |
| for mode in modes: |
| dest = (out / f"{mode}.jsonl") if args.all or out.suffix != ".jsonl" else out |
| write_jsonl(generate(mode, args.n), dest) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|