cloudenv / inference.py
Vishvam10
debug: (inference) stuff
a121494
Raw History Blame Contribute Delete
6.83 kB
import asyncio
import json
import os
import sys
import re
from pathlib import Path
from typing import List, Optional
import httpx
from dotenv import load_dotenv
from openai import OpenAI
ROOT = Path(__file__).resolve().parent
REPO_ROOT = ROOT.parent
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))
load_dotenv()
TASK_DIR = ROOT / "tasks"
SYSTEM_PROMPT = (ROOT / "system_prompt.txt").read_text().strip()
HF_TOKEN = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o")
BASE_URL = "https://vishvam10-cloudenv.hf.space"
TASK_ORDER = ["easy-task", "medium-task", "hard-task"]
MAX_PARSE_RETRIES = 3
MAX_STEPS = 5
client = OpenAI(base_url="https://api.openai.com/v1", api_key=HF_TOKEN)
def log_start(task: str, env: str, model: str) -> None:
print(f"[START] task={task} env={env} model={model}", flush=True)
def log_step(
step: int, action: str, reward: float, done: bool, error: Optional[str]
) -> None:
error_val = error if error else "null"
done_val = str(done).lower()
action_safe = action.replace("\n", " ").replace("\r", "")[:120]
print(
f"[STEP] step={step} action={action_safe} reward={reward:.2f} "
f"done={done_val} error={error_val}",
flush=True,
)
def log_end(
success: bool, steps: int, score: float, rewards: List[float]
) -> None:
rewards_str = ",".join(f"{r:.2f}" for r in rewards)
print(
f"[END] success={str(success).lower()} steps={steps} "
f"score={score:.3f} rewards={rewards_str}",
flush=True,
)
def load_task(name: str):
return json.loads((TASK_DIR / f"{name}.json").read_text())
async def register_pipeline(task: dict):
async with httpx.AsyncClient(timeout=30) as http:
r = await http.post(
f"{BASE_URL}/api/pipelines",
json={
"pipeline_id": task["pipeline_id"],
"broken_pipeline": task["broken_pipeline"],
"ideal_pipeline": task["ideal_pipeline"],
},
)
if r.status_code not in (200, 201, 400):
print(
f"[PIPELINE REGISTER ERROR] {r.status_code} {r.text}",
flush=True,
)
async def env_reset(task_id: str, episode_id: str):
async with httpx.AsyncClient(timeout=30) as http:
r = await http.post(
f"{BASE_URL}/reset",
json={"task_id": task_id, "episode_id": episode_id},
)
r.raise_for_status()
return r.json()
async def env_step(action: dict):
async with httpx.AsyncClient(timeout=30) as http:
r = await http.post(
f"{BASE_URL}/step",
json={"action": action},
)
r.raise_for_status()
return r.json()
def clean_json(raw: str) -> str:
raw = raw.strip()
raw = re.sub(r"^```(?:json)?\s*", "", raw)
raw = re.sub(r"\s*```$", "", raw)
match = re.search(r"\{.*\}", raw, re.DOTALL)
if match:
return match.group(0)
return raw
def build_action(raw: str, task_id: str, episode_id: str):
try:
raw = clean_json(raw)
data = json.loads(raw)
if isinstance(data, dict) and "action" in data:
data = data["action"]
if not isinstance(data, dict):
return None
service = data.get("service")
operation = data.get("operation")
if not service or not operation:
return None
instance_id = data.get("instance_id")
if isinstance(service, str) and ":" in service:
service, parsed_instance = service.split(":", 1)
instance_id = instance_id or parsed_instance
return {
"task_id": task_id,
"episode_id": episode_id,
"service": service.lower(),
"instance_id": instance_id,
"operation": operation.strip(),
"payload": data.get("payload", {})
if isinstance(data.get("payload"), dict)
else {},
"principal_arn": data.get("principal_arn"),
"intent": data.get("intent"),
}
except Exception:
return None
def call_model(step, state, broken, ideal, history):
prompt = f"""
Return ONLY valid JSON.
STEP {step}
STATE {json.dumps(state)[:1000]}
BROKEN {json.dumps(broken)[:1000]}
IDEAL {json.dumps(ideal)[:1000]}
HISTORY {history[-5:]}
"""
res = client.chat.completions.create(
model=MODEL_NAME,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": prompt},
],
temperature=0.3,
max_tokens=500,
)
return (res.choices[0].message.content or "").strip()
async def run_episode(task):
task_id = task["pipeline_id"]
episode_id = f"{task_id}-episode-1"
log_start(task=task_id, env="http", model=MODEL_NAME)
result = await env_reset(task_id, episode_id)
await env_step(
{
"task_id": task_id,
"episode_id": episode_id,
"service": "internal",
"instance_id": None,
"operation": "InitializeEnvironment",
"payload": {},
}
)
await register_pipeline(task)
obs = {}
history = []
rewards = []
step_count = 0
for step in range(MAX_STEPS):
if obs.get("done"):
break
error = None
try:
raw = call_model(
step,
obs,
task["broken_pipeline"],
task["ideal_pipeline"],
history,
)
action = build_action(raw, task_id, episode_id)
if action is None:
error = "invalid_action"
log_step(step, "INVALID_ACTION", 0.0, False, error)
continue
result = await env_step(action)
obs = result["observation"]
reward = float(obs.get("reward", 0.0))
done = bool(obs.get("done", False))
rewards.append(reward)
history.append(raw)
step_count += 1
log_step(
step=step_count,
action=str(action),
reward=reward,
done=done,
error=None,
)
except Exception as e:
error = str(e)
log_step(step, "ERROR", 0.0, False, error)
break
if obs.get("done"):
break
success = obs.get("done", False)
score = sum(rewards) / (len(rewards) or 1)
log_end(success=success, steps=step_count, score=score, rewards=rewards)
async def main():
for name in TASK_ORDER:
task = load_task(name)
await run_episode(task)
if __name__ == "__main__":
asyncio.run(main())