anvisinghh commited on
Commit
98aeb91
·
verified ·
1 Parent(s): be63ecf

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +17 -0
  2. env.py +77 -0
  3. inference.py +73 -0
  4. models.py +15 -0
  5. openenv.yaml +19 -0
  6. requirements.txt +5 -0
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use a lightweight Python image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /app
6
+
7
+ # Copy all your files (env.py, models.py, etc.) into the container
8
+ COPY . .
9
+
10
+ # Install the required libraries
11
+ RUN pip install --no-cache-dir fastapi pydantic openenv-core uvicorn
12
+
13
+ # Expose the port your env.py is running on
14
+ EXPOSE 8000
15
+
16
+ # Command to run your environment server
17
+ CMD ["python", "env.py"]
env.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ from typing import Optional
3
+ from types import SimpleNamespace
4
+ from openenv.core.env_server import Environment
5
+ from models import MyEnvV4Observation, MyEnvV4Action
6
+
7
+ class MyEnvV4Env(Environment):
8
+ def __init__(self):
9
+ super().__init__()
10
+ # Realistic Dataset with Digital Seduction/Phishing markers
11
+ self.dataset = [
12
+ {
13
+ "sender": "dean.office@manipal.edu",
14
+ "subject": "B.Tech Lab Exam Schedule",
15
+ "body": "Please find the attached PDF for the upcoming CSE lab exams.",
16
+ "headers": ["SPF: Pass", "DKIM: Pass"],
17
+ "label": "INBOX"
18
+ },
19
+ {
20
+ "sender": "verify-account@security-amazon.net",
21
+ "subject": "Urgent: Your account is locked!",
22
+ "body": "Digital Seduction Alert: High urgency used. Click http://bit.ly/fake-link to unlock.",
23
+ "headers": ["SPF: Fail", "DMARC: Fail"],
24
+ "label": "QUARANTINE"
25
+ },
26
+ {
27
+ "sender": "prize@lottery-winner.co",
28
+ "subject": "Congratulations! You won $10,000",
29
+ "body": "Reply with your bank details to claim your cash prize immediately.",
30
+ "headers": ["SPF: Neutral"],
31
+ "label": "SPAM"
32
+ }
33
+ ]
34
+ self.current_step = 0
35
+
36
+ async def reset(self):
37
+ self.current_step = 0
38
+ return self._get_result()
39
+
40
+ def _get_result(self, reward=0.0, done=False):
41
+ if self.current_step >= len(self.dataset):
42
+ obs = MyEnvV4Observation(
43
+ sender="N/A", subject="N/A", body="N/A",
44
+ headers=[], echoed_message="End of Data"
45
+ )
46
+ return SimpleNamespace(observation=obs, reward=reward, done=True)
47
+
48
+ data = self.dataset[self.current_step]
49
+ obs = MyEnvV4Observation(
50
+ sender=data["sender"],
51
+ subject=data["subject"],
52
+ body=data["body"],
53
+ headers=data["headers"],
54
+ echoed_message=f"Step {self.current_step + 1}"
55
+ )
56
+ return SimpleNamespace(observation=obs, reward=reward, done=done)
57
+
58
+ async def step(self, action: MyEnvV4Action):
59
+ if self.current_step >= len(self.dataset):
60
+ return self._get_result(done=True)
61
+
62
+ correct_label = self.dataset[self.current_step]["label"]
63
+ # Exact match reward logic for 0.0 - 1.0 range
64
+ reward = 1.0 if action.message.strip().upper() == correct_label else 0.0
65
+
66
+ self.current_step += 1
67
+ done = self.current_step >= len(self.dataset)
68
+
69
+ return self._get_result(reward=reward, done=done)
70
+
71
+ async def close(self):
72
+ pass
73
+
74
+ @classmethod
75
+ async def from_docker_image(cls, image_name: str):
76
+ """Simulated helper for local/containerized runs."""
77
+ return cls()
inference.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import os
3
+ import textwrap
4
+ from typing import List, Optional
5
+ from openai import OpenAI
6
+ from my_env_v4 import MyEnvV4Action, MyEnvV4Env
7
+
8
+ # Environment Configuration
9
+ API_BASE_URL = os.getenv("API_BASE_URL") or "https://router.huggingface.co/v1"
10
+ API_KEY = os.getenv("HF_TOKEN") or os.getenv("API_KEY")
11
+ MODEL_NAME = os.getenv("MODEL_NAME") or "Qwen/Qwen2.5-72B-Instruct"
12
+ TASK_NAME = "email-triage"
13
+ BENCHMARK = "mit-manipal-v4"
14
+ MAX_STEPS = 3
15
+ SUCCESS_THRESHOLD = 0.5
16
+
17
+ SYSTEM_PROMPT = """
18
+ You are an Email Security Agent. Triage the following email based on sender, headers, and body content.
19
+ Digital Seduction Rules:
20
+ - 'INBOX': Official domains (.edu, .gov) and passed security headers.
21
+ - 'SPAM': Marketing, gambling, or generic lottery win claims.
22
+ - 'QUARANTINE': Phishing, high-urgency threats, suspicious links (.net, .co), or failed headers (SPF/DMARC Fail).
23
+
24
+ REPLY WITH EXACTLY ONE WORD: 'INBOX', 'SPAM', or 'QUARANTINE'.
25
+ """
26
+
27
+ def log_start():
28
+ print(f"[START] task={TASK_NAME} env={BENCHMARK} model={MODEL_NAME}", flush=True)
29
+
30
+ def log_step(step, action, reward, done):
31
+ print(f"[STEP] step={step} action={action} reward={reward:.2f} done={str(done).lower()} error=null", flush=True)
32
+
33
+ def log_end(success, steps, score, rewards):
34
+ r_str = ",".join(f"{r:.2f}" for r in rewards)
35
+ print(f"[END] success={str(success).lower()} steps={steps} score={score:.3f} rewards={r_str}", flush=True)
36
+
37
+ async def main():
38
+ client = OpenAI(base_url=API_BASE_URL, api_key=API_KEY)
39
+ env = MyEnvV4Env() # Local instance for testing, can use from_docker_image if needed
40
+
41
+ rewards = []
42
+ log_start()
43
+
44
+ try:
45
+ result = await env.reset()
46
+ for step in range(1, MAX_STEPS + 1):
47
+ if result.done: break
48
+
49
+ obs = result.observation
50
+ prompt = f"Sender: {obs.sender}\nSubject: {obs.subject}\nBody: {obs.body}\nHeaders: {obs.headers}"
51
+
52
+ # OpenAI Call
53
+ response = client.chat.completions.create(
54
+ model=MODEL_NAME,
55
+ messages=[{"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt}],
56
+ max_tokens=10,
57
+ temperature=0.0 # Deterministic for testing
58
+ )
59
+ action_text = response.choices[0].message.content.strip().upper()
60
+
61
+ result = await env.step(MyEnvV4Action(message=action_text))
62
+ rewards.append(result.reward)
63
+
64
+ log_step(step, action_text, result.reward, result.done)
65
+ if result.done: break
66
+
67
+ total_score = sum(rewards) / MAX_STEPS
68
+ log_end(total_score >= SUCCESS_THRESHOLD, len(rewards), total_score, rewards)
69
+ finally:
70
+ await env.close()
71
+
72
+ if __name__ == "__main__":
73
+ asyncio.run(main())
models.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import Field
2
+ from typing import Optional, List
3
+ from openenv.core.env_server import Action, Observation
4
+
5
+ class MyEnvV4Observation(Observation):
6
+ """What the Agent sees."""
7
+ sender: str
8
+ subject: str
9
+ body: str
10
+ headers: List[str]
11
+ echoed_message: str = "" # Required by sample inference script contract
12
+
13
+ class MyEnvV4Action(Action):
14
+ """What the Agent chooses."""
15
+ message: str = Field(..., description="Action string: 'INBOX', 'SPAM', or 'QUARANTINE'")
openenv.yaml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Metadata for OpenEnv Triage Agent
2
+ name: "mail-triage-v4"
3
+ version: "1.0.0"
4
+ description: "An automated triage agent for university mailboxes, specializing in Digital Seduction detection."
5
+
6
+ # Environment Specification
7
+ repo_url: "https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME"
8
+ task_type: "classification"
9
+
10
+ # Compliance Metrics
11
+ reward_range: [0.0, 1.0]
12
+ tags:
13
+ - security
14
+ - nlp
15
+ - mit-manipal-hackathon
16
+
17
+ # Typed Model References
18
+ observation_space: "models.MyEnvV4Observation"
19
+ action_space: "models.MyEnvV4Action"
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ fastapi==0.109.0
2
+ uvicorn==0.27.0
3
+ pydantic==2.6.1
4
+ openenv-core==0.1.5
5
+ openai==1.12.0