| """Synthos CLI. Usage: |
| |
| python -m synthos ask "your question" one-shot, with memory + refine |
| python -m synthos ask "..." --image pic.png multimodal: reason over an image + text |
| python -m synthos ask "..." --audio clip.wav multimodal: transcribe speech, then reason |
| python -m synthos see pic.png ["question"] describe/answer about an image (open VLM) |
| python -m synthos hear clip.wav ["question"] transcribe speech, then reason with memory |
| python -m synthos chat interactive session (persists memory) |
| python -m synthos remember "a durable fact" store a fact |
| python -m synthos recall "cue" show what memory surfaces for a cue |
| python -m synthos stats memory + model status |
| |
| Multimodal = routing to OPEN backends (LLaVA/Qwen-VL for vision, Whisper for audio) and |
| fusing their output with memory + reasoning. Not a from-scratch multimodal model. |
| |
| Flags: --profile {laptop,commander,phone} --think {refine,vote} --adaptive --route |
| --k N --rounds N --n N |
| --image PATH --audio PATH --vision-expert KEY --whisper-model SIZE |
| """ |
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import sys |
|
|
| from .engine import Synthos |
|
|
|
|
| def _bot(args) -> Synthos: |
| return Synthos(profile=args.profile, think=args.think, |
| adaptive=getattr(args, "adaptive", False), |
| route=getattr(args, "route", False), |
| vision_expert=getattr(args, "vision_expert", "vision"), |
| whisper_model=getattr(args, "whisper_model", "base.en")) |
|
|
|
|
| def main(argv=None) -> int: |
| ap = argparse.ArgumentParser(prog="synthos") |
| ap.add_argument("--profile", default="laptop", |
| choices=["laptop", "commander", "phone"]) |
| ap.add_argument("--think", default="refine", choices=["refine", "vote"]) |
| ap.add_argument("--adaptive", action="store_true", |
| help="spend test-time compute proportional to difficulty (recommended)") |
| ap.add_argument("--route", action="store_true", |
| help="route each task to its best-fit local expert (model-level MoE)") |
| ap.add_argument("--k", type=int, default=4, help="memories to recall") |
| ap.add_argument("--rounds", type=int, default=1, help="refine critique/revise rounds") |
| ap.add_argument("--n", type=int, default=1, help="vote samples (think=vote)") |
| ap.add_argument("--image", default=None, help="image path to reason over (multimodal)") |
| ap.add_argument("--audio", default=None, help="audio path to transcribe (multimodal)") |
| ap.add_argument("--vision-expert", dest="vision_expert", default="vision", |
| help="router expert key for the VLM (default: vision -> llava)") |
| ap.add_argument("--whisper-model", dest="whisper_model", default="base.en", |
| help="faster-whisper model size (default: base.en)") |
| sub = ap.add_subparsers(dest="cmd", required=True) |
| a = sub.add_parser("ask"); a.add_argument("query", nargs="*") |
| s = sub.add_parser("see"); s.add_argument("image"); s.add_argument("query", nargs="*") |
| h = sub.add_parser("hear"); h.add_argument("audio"); h.add_argument("query", nargs="*") |
| sub.add_parser("chat") |
| r = sub.add_parser("remember"); r.add_argument("fact", nargs="+") |
| rc = sub.add_parser("recall"); rc.add_argument("cue", nargs="+") |
| sub.add_parser("stats") |
| args = ap.parse_args(argv) |
|
|
| if args.cmd == "stats": |
| print(json.dumps(_bot(args).stats(), indent=2)); return 0 |
| if args.cmd == "remember": |
| bot = _bot(args) |
| print("stored:", bot.remember(" ".join(args.fact))); return 0 |
| if args.cmd == "recall": |
| for r_ in _bot(args).recall(" ".join(args.cue), k=args.k): |
| print(f" [{r_.score:+.3f}] ({r_.kind}) {r_.summary}") |
| return 0 |
| if args.cmd in ("ask", "see", "hear"): |
| n = args.n if args.think == "vote" else 1 |
| image = args.image |
| audio = args.audio |
| if args.cmd == "see": |
| image = args.image |
| if args.cmd == "hear": |
| audio = args.audio |
| text = " ".join(args.query) |
| out = _bot(args).ask(text, k=args.k, rounds=args.rounds, n=n, |
| image=image, audio=audio) |
| print(out["answer"]) |
| if out.get("modality"): |
| print("\n--", json.dumps(out["modality"]), file=sys.stderr) |
| print("\n--", json.dumps(out["usage"]), file=sys.stderr) |
| return 0 |
| if args.cmd == "chat": |
| bot = _bot(args) |
| print(f"Synthos [{bot.client.p.name}: {bot.client.p.model}] — Ctrl-C to exit.") |
| n = args.n if args.think == "vote" else 1 |
| try: |
| while True: |
| q = input("\nyou> ").strip() |
| if not q: |
| continue |
| out = bot.ask(q, k=args.k, rounds=args.rounds, n=n) |
| print(f"\nsynthos> {out['answer']}") |
| except (KeyboardInterrupt, EOFError): |
| print("\nbye."); return 0 |
| return 1 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|