| """ |
| Resolve a natural language prompt to a skill and trajectory via Modal inference. |
| |
| Flow: |
| prompt -> infer_modal (Modal GPU) -> skill -> skill_router -> trajectory path |
| |
| Run: |
| python -m modal_apps.run_modal "play my workout playlist" |
| """ |
|
|
| from __future__ import annotations |
|
|
| import argparse |
| import json |
| import sys |
| from pathlib import Path |
|
|
| _ROOT = Path(__file__).resolve().parent.parent |
| if str(_ROOT) not in sys.path: |
| sys.path.insert(0, str(_ROOT)) |
|
|
| from modal_apps.infer_modal import app, infer |
| from src.skill_router import ROOT_DIR, route_skill |
|
|
|
|
| def resolve_prompt(prompt: str) -> dict[str, str]: |
| """Classify prompt on Modal and resolve its trajectory file.""" |
| with app.run(): |
| skill_payload = json.loads(infer.remote(prompt)) |
| skill = skill_payload["skill"] |
|
|
| trajectory_path = route_skill(skill) |
| try: |
| trajectory = str(trajectory_path.relative_to(ROOT_DIR)) |
| except ValueError: |
| trajectory = str(trajectory_path) |
|
|
| return { |
| "prompt": prompt, |
| "skill": skill, |
| "trajectory": trajectory, |
| } |
|
|
|
|
| def main() -> None: |
| parser = argparse.ArgumentParser( |
| description="Resolve a prompt to a skill and trajectory (no replay)." |
| ) |
| parser.add_argument("prompt", help="Natural language prompt") |
| args = parser.parse_args() |
|
|
| result = resolve_prompt(args.prompt) |
|
|
| print(f"Prompt: {result['prompt']}") |
| print(f"Predicted Skill: {result['skill']}") |
| print(f"Trajectory: {result['trajectory']}") |
| print(json.dumps(result, indent=2)) |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|