Utkarsh430 commited on
Commit
47e89f3
·
verified ·
1 Parent(s): 6f68578

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +18 -0
  2. app.py +127 -0
  3. inference.py +101 -0
  4. requirements.txt +5 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ # Copy the environment source
9
+ COPY . .
10
+
11
+ # Set environment variables for HF Spaces / Gradio
12
+ ENV PYTHONUNBUFFERED=1
13
+ ENV PYTHONPATH=/app
14
+
15
+ EXPOSE 7860
16
+
17
+ # Run the Gradio configuration app to interact with/view the environment
18
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import multiprocessing
2
+ import uvicorn
3
+ from fastapi import FastAPI, Request
4
+ from fastapi.responses import JSONResponse
5
+ import gradio as gr
6
+ import json
7
+ import logging
8
+ from core.environment import EmailOpsEnv
9
+ from core.models import Action
10
+
11
+ # Setup logging
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ app = FastAPI(title="OpenEnv - EmailOps API")
16
+ env = EmailOpsEnv()
17
+
18
+ # --- FastAPI Endpoints ---
19
+
20
+ @app.post("/reset")
21
+ async def reset(request: Request):
22
+ """Reset the environment with a specific task."""
23
+ try:
24
+ data = await request.json()
25
+ task_id = data.get("task_id", "easy")
26
+ obs = env.reset(task_id)
27
+ logger.info(f"Environment reset with task: {task_id}")
28
+ return obs.model_dump()
29
+ except Exception as e:
30
+ logger.error(f"Error resetting environment: {e}")
31
+ return JSONResponse(status_code=500, content={"detail": str(e)})
32
+
33
+ @app.post("/step")
34
+ async def step(request: Request):
35
+ """Take a step in the environment."""
36
+ try:
37
+ action_data = await request.json()
38
+ action = Action(**action_data)
39
+ obs, reward, done, metrics = env.step(action)
40
+ return {
41
+ "obs": obs.model_dump(),
42
+ "reward": reward,
43
+ "done": done,
44
+ "metrics": metrics
45
+ }
46
+ except Exception as e:
47
+ logger.error(f"Error stepping environment: {e}")
48
+ return JSONResponse(status_code=500, content={"detail": str(e)})
49
+
50
+ @app.get("/state")
51
+ async def state():
52
+ """Get the current state of the environment."""
53
+ return env.state().model_dump()
54
+
55
+ # --- Gradio UI Logic ---
56
+
57
+ def initialize_ui(task_name):
58
+ obs = env.reset(task_name)
59
+ return (
60
+ f"Task loaded: {task_name.upper()}\n{env.task.description}",
61
+ json.dumps(obs.model_dump(), indent=2),
62
+ "0.0",
63
+ str(env.metrics)
64
+ )
65
+
66
+ def step_env_ui(action_type, email_id, folder_name, reply_body):
67
+ action_dict = {
68
+ "action_type": action_type,
69
+ "email_id": email_id if email_id else None,
70
+ "folder_name": folder_name if folder_name else None,
71
+ "reply_body": reply_body if reply_body else None
72
+ }
73
+ action = Action(**action_dict)
74
+ obs, score, done, metrics = env.step(action)
75
+ return (
76
+ json.dumps(obs.model_dump(), indent=2),
77
+ f"{score}",
78
+ str(metrics),
79
+ "Completed" if done else "In Progress"
80
+ )
81
+
82
+ with gr.Blocks(title="OpenEnv - EmailOps Dashboard") as demo:
83
+ gr.Markdown("# Email Triage & Operations (OpenEnv)")
84
+ gr.Markdown("Interactive UI for monitoring and testing the EmailOps environment.")
85
+
86
+ with gr.Row():
87
+ with gr.Column():
88
+ task_dropdown = gr.Dropdown(choices=["easy", "medium", "hard"], value="easy", label="Select Task")
89
+ init_btn = gr.Button("Initialize / Reset Environment")
90
+ task_desc = gr.Textbox(label="Task Description", lines=2)
91
+
92
+ gr.Markdown("### Manual Action Overrides")
93
+ act_type = gr.Dropdown(
94
+ choices=["open_email", "close_email", "move_email", "reply", "delete_email", "flag_email", "submit"],
95
+ value="open_email", label="Action Type"
96
+ )
97
+ email_id = gr.Textbox(label="Email ID (optional)")
98
+ folder_name = gr.Textbox(label="Folder Name (optional, for move)")
99
+ reply_body = gr.Textbox(label="Reply Body (optional, for reply)")
100
+
101
+ step_btn = gr.Button("Step Environment")
102
+
103
+ with gr.Column():
104
+ gr.Markdown("### Observation & Reward")
105
+ observation_display = gr.Code(label="Current Observation", language="json")
106
+ with gr.Row():
107
+ score_display = gr.Textbox(label="Reward Score")
108
+ status_display = gr.Textbox(label="Status")
109
+ metrics_display = gr.Textbox(label="Metrics", lines=2)
110
+
111
+ init_btn.click(
112
+ fn=initialize_ui,
113
+ inputs=[task_dropdown],
114
+ outputs=[task_desc, observation_display, score_display, metrics_display]
115
+ )
116
+
117
+ step_btn.click(
118
+ fn=step_env_ui,
119
+ inputs=[act_type, email_id, folder_name, reply_body],
120
+ outputs=[observation_display, score_display, metrics_display, status_display]
121
+ )
122
+
123
+ # Mount Gradio into FastAPI
124
+ app = gr.mount_gradio_app(app, demo, path="/")
125
+
126
+ if __name__ == "__main__":
127
+ uvicorn.run(app, host="0.0.0.0", port=7860)
inference.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import argparse
4
+ from openai import OpenAI
5
+ from core.environment import EmailOpsEnv
6
+ from core.models import Action
7
+
8
+ # Mandatory environment variables with defaults per OpenEnv spec
9
+ API_BASE_URL = os.getenv("API_BASE_URL", "https://api.openai.com/v1")
10
+ MODEL_NAME = os.getenv("MODEL_NAME", "gpt-4o-mini")
11
+ HF_TOKEN = os.getenv("HF_TOKEN") # No default for token
12
+
13
+ def run_baseline(api_key: str, model_name: str, base_url: str):
14
+ client = OpenAI(api_key=api_key, base_url=base_url)
15
+ env = EmailOpsEnv()
16
+
17
+ tasks = ["easy", "medium", "hard"]
18
+
19
+ print(f"Running baseline on model: {model_name}")
20
+ print("=" * 40)
21
+
22
+ for task_name in tasks:
23
+ # START: Structured logging for OpenEnv automated grading
24
+ print(f"START: {task_name}")
25
+
26
+ obs = env.reset(task_name)
27
+
28
+ step_count = 0
29
+ max_steps = 15
30
+ is_done = False
31
+ total_reward = 0.0
32
+
33
+ while not is_done and step_count < max_steps:
34
+ system_prompt = (
35
+ "You are an intelligent email operations agent. "
36
+ f"Your current goal is: {env.task.description}\n"
37
+ "You must perform actions to achieve this goal. Once you are finished, output the 'submit' action.\n"
38
+ "Available action types:\n"
39
+ " - open_email (requires email_id)\n"
40
+ " - close_email\n"
41
+ " - move_email (requires email_id, folder_name)\n"
42
+ " - reply (requires email_id, reply_body)\n"
43
+ " - delete_email (requires email_id)\n"
44
+ " - flag_email (requires email_id)\n"
45
+ " - submit"
46
+ )
47
+
48
+ try:
49
+ response = client.beta.chat.completions.parse(
50
+ model=model_name,
51
+ messages=[
52
+ {"role": "system", "content": system_prompt},
53
+ {"role": "user", "content": f"Current Observation:\n{obs.model_dump_json(indent=2)}\nWhat is your next action?"}
54
+ ],
55
+ response_format=Action,
56
+ temperature=0.1
57
+ )
58
+
59
+ action = response.choices[0].message.parsed
60
+ if not action:
61
+ break
62
+
63
+ # STEP: Structured logging for OpenEnv automated grading
64
+ print(f"STEP: {action.model_dump_json()}")
65
+
66
+ obs, reward, is_done, metrics = env.step(action)
67
+ total_reward = reward
68
+
69
+ if action.action_type == "submit":
70
+ break
71
+
72
+ except Exception as e:
73
+ print(f"Error during inference: {e}")
74
+ break
75
+
76
+ step_count += 1
77
+
78
+ # END: Structured logging for OpenEnv automated grading
79
+ result = {
80
+ "task": task_name,
81
+ "steps": step_count,
82
+ "reward": total_reward,
83
+ "metrics": env.metrics
84
+ }
85
+ print(f"END: {json.dumps(result)}")
86
+ print("-" * 40)
87
+
88
+ if __name__ == "__main__":
89
+ parser = argparse.ArgumentParser()
90
+ # Prioritizing environment variables as per requirements
91
+ parser.add_argument("--api-key", type=str, default=HF_TOKEN)
92
+ parser.add_argument("--model", type=str, default=MODEL_NAME)
93
+ parser.add_argument("--base-url", type=str, default=API_BASE_URL)
94
+ args = parser.parse_args()
95
+
96
+ # HF_TOKEN is mandatory for automated submissions
97
+ if not args.api_key:
98
+ print("Please set HF_TOKEN environment variable.")
99
+ exit(1)
100
+
101
+ run_baseline(args.api_key, args.model, args.base_url)
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ pydantic>=2.0.0
2
+ openai>=1.0.0
3
+ gradio>=4.0.0
4
+ fastapi
5
+ uvicorn