ashdev commited on
Commit
df660ab
·
1 Parent(s): 34067c4

fix(inference): resolve connection exception and align ports to 8002

Browse files

- fix: asyncio connection exception by adding wait_for_server retry logic
- feat: implement structured logging [START], [STEP], [END] for hackathon validation
- chore: unify app port to 8002 across Dockerfile, app.py, README.md, and openenv.yaml
- chore: use mandated environment variables (API_BASE_URL, MODEL_NAME, HF_TOKEN)
- docs: update project summary and reminders

Files changed (5) hide show
  1. Dockerfile +4 -4
  2. README.md +1 -1
  3. REMINDERS.md +16 -0
  4. inference.py +119 -25
  5. server/app.py +8 -3
Dockerfile CHANGED
@@ -20,15 +20,15 @@ COPY . .
20
 
21
  # Set environment variables
22
  ENV PYTHONPATH="/app"
23
- ENV PORT=7860
24
  ENV HOST=0.0.0.0
25
 
26
  # Expose the app port
27
- EXPOSE 7860
28
 
29
  # Health check
30
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
31
- CMD curl -f http://localhost:7860/health || exit 1
32
 
33
  # Start the server
34
- CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "7860"]
 
20
 
21
  # Set environment variables
22
  ENV PYTHONPATH="/app"
23
+ ENV PORT=8002
24
  ENV HOST=0.0.0.0
25
 
26
  # Expose the app port
27
+ EXPOSE 8002
28
 
29
  # Health check
30
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
31
+ CMD curl -f http://localhost:8002/health || exit 1
32
 
33
  # Start the server
34
+ CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "8002"]
README.md CHANGED
@@ -3,7 +3,7 @@ title: MedTriage OpenEnv
3
  emoji: 🏥
4
  sdk: docker
5
  pinned: false
6
- app_port: 7860
7
  tags:
8
  - openenv
9
  - healthcare
 
3
  emoji: 🏥
4
  sdk: docker
5
  pinned: false
6
+ app_port: 8002
7
  tags:
8
  - openenv
9
  - healthcare
REMINDERS.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🗓️ Hackathon Schedule & Reminders
2
+
3
+ ## 🚀 Key Dates
4
+ - **April 8, 2026**: Round 1 Submission Deadline (Completed ✓)
5
+ - **April 10, 2026**: Round 1 Results Announcement 🔔
6
+ - **April 25-26, 2026**: Grand Finale (If qualified)
7
+
8
+ ## 🔗 Links
9
+ - **Dashboard**: [Meta PyTorch Hackathon Dashboard](https://www.scaler.com/school-of-technology/meta-pytorch-hackathon/dashboard)
10
+ - **Hugging Face Space**: [ashdev/med-triage-openenv](https://huggingface.co/spaces/ashdev/med-triage-openenv)
11
+ - **GitHub Repo**: [ash399/med-triage-openenv](https://github.com/ash399/med-triage-openenv)
12
+
13
+ ## 📝 Post-Submission Notes
14
+ - All automated checks passed on March 30th.
15
+ - Environment is running on port 7860.
16
+ - `PROJECT_SUMMARY.md` contains the full technical breakdown.
inference.py CHANGED
@@ -3,44 +3,138 @@
3
 
4
  import os
5
  import time
6
- import subprocess
7
  import requests
 
 
8
  from client import MedTriageEnv
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  def run_baseline(base_url: str = "http://localhost:8002"):
11
  """Run baseline agent against all 3 tasks and return results."""
12
- print(f"🚀 Starting MedTriage Baseline Inference on {base_url}...")
13
-
 
 
 
 
 
 
14
  tasks = ["TASK_EASY", "TASK_MEDIUM", "TASK_HARD"]
15
- scores = {}
16
 
17
- # Simple heuristic-based baseline (no LLM required for this local test)
18
  try:
19
  from client import MedTriageEnv
20
  except ImportError:
21
  from .client import MedTriageEnv
22
 
23
- with MedTriageEnv(base_url=base_url).sync() as env:
24
- for task_id in tasks:
25
- print(f"📋 Running {task_id}...", end=" ", flush=True)
26
- obs = env.reset(task_id=task_id)
27
-
28
- # Simple heuristic logic
29
- bp_sys = int(obs.vitals.get("bp", "120/80").split("/")[0])
30
-
31
- if bp_sys > 150 or obs.age > 65:
32
- level = 3 # EMERGENCY
33
- elif "severe pain" in obs.symptoms_text.lower():
34
- level = 2 # URGENT_CARE
35
- else:
36
- level = 0 # SELF_CARE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- result = env.step({"tool_name": "triage_patient", "arguments": {"level": level, "reasoning": "Heuristic baseline."}})
39
- scores[task_id] = result.reward
40
- print(f"Score: {result.reward}")
 
 
 
 
 
 
41
 
42
- return scores
 
 
43
 
44
  if __name__ == "__main__":
45
- results = run_baseline()
46
- print("\n📊 FINAL BASELINE SCORES:", results)
 
 
 
 
 
 
 
3
 
4
  import os
5
  import time
6
+ import json
7
  import requests
8
+ import asyncio
9
+ from typing import List, Dict, Any
10
  from client import MedTriageEnv
11
 
12
+ # --- Mandatory Environment Configuration ---
13
+ API_BASE_URL = os.getenv("API_BASE_URL", "http://localhost:8002/v1")
14
+ MODEL_NAME = os.getenv("MODEL_NAME", "med-triage-baseline")
15
+ HF_TOKEN = os.getenv("HF_TOKEN", "dummy-token")
16
+
17
+ # --- Structured Logging Functions ---
18
+ def log_start(task: str, env: str, model: str):
19
+ """Emit structured [START] log."""
20
+ data = {
21
+ "timestamp": time.time(),
22
+ "task": task,
23
+ "env": env,
24
+ "model": model,
25
+ "config": {
26
+ "api_base": API_BASE_URL,
27
+ "max_steps": 10
28
+ }
29
+ }
30
+ print(f"[START] {json.dumps(data)}", flush=True)
31
+
32
+ def log_step(step: int, action: Any, reward: float, done: bool, error: str = None):
33
+ """Emit structured [STEP] log."""
34
+ data = {
35
+ "timestamp": time.time(),
36
+ "step": step,
37
+ "action": action,
38
+ "reward": reward,
39
+ "done": done,
40
+ "error": error
41
+ }
42
+ print(f"[STEP] {json.dumps(data)}", flush=True)
43
+
44
+ def log_end(success: bool, steps: int, score: float, rewards: List[float]):
45
+ """Emit structured [END] log."""
46
+ data = {
47
+ "timestamp": time.time(),
48
+ "success": success,
49
+ "steps_taken": steps,
50
+ "score": score,
51
+ "rewards": rewards
52
+ }
53
+ print(f"[END] {json.dumps(data)}", flush=True)
54
+
55
+ # --- Server Readiness Check ---
56
+ def wait_for_server(url: str, timeout: int = 30):
57
+ """Wait for the server to be ready before proceeding."""
58
+ start_time = time.time()
59
+ health_url = f"{url.rstrip('/')}/health"
60
+
61
+ while time.time() - start_time < timeout:
62
+ try:
63
+ response = requests.get(health_url, timeout=2)
64
+ if response.status_code == 200:
65
+ return True
66
+ except (requests.RequestException, ConnectionError):
67
+ pass
68
+ time.sleep(1)
69
+ return False
70
+
71
  def run_baseline(base_url: str = "http://localhost:8002"):
72
  """Run baseline agent against all 3 tasks and return results."""
73
+ # Ensure base_url uses the port from environment if available
74
+ env_port = os.environ.get("PORT", "8002")
75
+ if "localhost" in base_url and f":{env_port}" not in base_url:
76
+ base_url = f"http://localhost:{env_port}"
77
+
78
+ # Wait for server readiness
79
+ wait_for_server(base_url)
80
+
81
  tasks = ["TASK_EASY", "TASK_MEDIUM", "TASK_HARD"]
82
+ all_scores = {}
83
 
 
84
  try:
85
  from client import MedTriageEnv
86
  except ImportError:
87
  from .client import MedTriageEnv
88
 
89
+ for task_id in tasks:
90
+ log_start(task=task_id, env="med_triage_env", model=MODEL_NAME)
91
+
92
+ rewards = []
93
+ steps_taken = 0
94
+ success = False
95
+ final_score = 0.0
96
+
97
+ try:
98
+ with MedTriageEnv(base_url=base_url).sync() as env:
99
+ obs = env.reset(task_id=task_id)
100
+ steps_taken = 1
101
+
102
+ # Heuristic Logic (mimes model output)
103
+ bp_sys = int(obs.vitals.get("bp", "120/80").split("/")[0])
104
+ if bp_sys > 150 or obs.age > 65:
105
+ level = 3 # EMERGENCY
106
+ elif "severe pain" in obs.symptoms_text.lower():
107
+ level = 2 # URGENT_CARE
108
+ else:
109
+ level = 0 # SELF_CARE
110
+
111
+ action = {"tool_name": "triage_patient", "arguments": {"level": level, "reasoning": "Heuristic baseline."}}
112
+ result = env.step(action)
113
+
114
+ reward = result.reward or 0.0
115
+ done = result.done
116
+ rewards.append(reward)
117
 
118
+ log_step(step=1, action=action, reward=reward, done=done)
119
+
120
+ final_score = reward
121
+ success = reward >= 1.0
122
+ all_scores[task_id] = reward
123
+
124
+ except Exception as e:
125
+ log_step(step=steps_taken, action=None, reward=0.0, done=True, error=str(e))
126
+ all_scores[task_id] = 0.0
127
 
128
+ log_end(success=success, steps=steps_taken, score=final_score, rewards=rewards)
129
+
130
+ return all_scores
131
 
132
  if __name__ == "__main__":
133
+ try:
134
+ results = run_baseline()
135
+ # Final summary for human readability
136
+ print(f"\n📊 FINAL BASELINE SCORES: {results}")
137
+ except Exception as e:
138
+ print(f"FATAL: {e}")
139
+ import sys
140
+ sys.exit(1)
server/app.py CHANGED
@@ -70,9 +70,12 @@ async def trigger_baseline():
70
  if parent_dir not in sys.path:
71
  sys.path.append(parent_dir)
72
  from inference import run_baseline
73
-
 
 
 
74
  # Execute actual baseline
75
- scores = run_baseline(base_url="http://localhost:7860")
76
 
77
  return {
78
  "status": "baseline_completed",
@@ -81,7 +84,9 @@ async def trigger_baseline():
81
 
82
  def main():
83
  import uvicorn
84
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
 
85
 
86
  if __name__ == "__main__":
87
  main()
 
70
  if parent_dir not in sys.path:
71
  sys.path.append(parent_dir)
72
  from inference import run_baseline
73
+
74
+ # Get current port from environment or default to 8002
75
+ port = os.environ.get("PORT", "8002")
76
+
77
  # Execute actual baseline
78
+ scores = run_baseline(base_url=f"http://localhost:{port}")
79
 
80
  return {
81
  "status": "baseline_completed",
 
84
 
85
  def main():
86
  import uvicorn
87
+ import os
88
+ port = int(os.environ.get("PORT", 8002))
89
+ uvicorn.run(app, host="0.0.0.0", port=port)
90
 
91
  if __name__ == "__main__":
92
  main()