Spaces:
Sleeping
Sleeping
Create agents.py
Browse files
agents.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# agents.py
|
| 2 |
+
import os, json, textwrap, pathlib
|
| 3 |
+
from typing import Dict, Any, Tuple
|
| 4 |
+
from openai import OpenAI
|
| 5 |
+
|
| 6 |
+
from files_process import load_input_text
|
| 7 |
+
|
| 8 |
+
# ---------- Instructions ----------
|
| 9 |
+
|
| 10 |
+
def build_case_study_instructions() -> str:
|
| 11 |
+
return textwrap.dedent("""\
|
| 12 |
+
You are a senior medical writer specializing in AI in healthcare.
|
| 13 |
+
Using ONLY the provided INPUT (no fabrication), produce a professional case study in **Markdown**.
|
| 14 |
+
|
| 15 |
+
STRICT REQUIREMENTS (cite inline in prose, not as links):
|
| 16 |
+
- Use established reporting guidance:
|
| 17 |
+
• CARE case reports for completeness/transparency (CARE, 2013/2017).
|
| 18 |
+
• CONSORT-AI (trial reports) and SPIRIT-AI (protocols) where applicable (2020).
|
| 19 |
+
• TRIPOD+AI (2024) for prediction model reporting (discrimination, calibration, validation).
|
| 20 |
+
• HIPAA de-identification Safe Harbor: state that 18 identifiers are removed or avoided; avoid re-identification risk.
|
| 21 |
+
• FDA AI/ML SaMD perspective: risk controls, monitoring, change management.
|
| 22 |
+
- If a section lacks data, write “Not specified.”
|
| 23 |
+
- Use a neutral, clinical tone (avoid marketing fluff).
|
| 24 |
+
- Prefer short paragraphs and tables where appropriate.
|
| 25 |
+
|
| 26 |
+
MANDATORY SECTIONS (use these exact headings):
|
| 27 |
+
# Title
|
| 28 |
+
## Executive Summary
|
| 29 |
+
- 3–6 bullets
|
| 30 |
+
|
| 31 |
+
## Clinical Context & Problem
|
| 32 |
+
## Patient/Population & Setting
|
| 33 |
+
## Data Sources & Governance
|
| 34 |
+
- Provenance; access; quality checks; de-identification approach (HIPAA Safe Harbor)
|
| 35 |
+
- Security/compliance: HIPAA (and GDPR if applicable)
|
| 36 |
+
|
| 37 |
+
## AI/ML Approach
|
| 38 |
+
- Task definition; target(s)
|
| 39 |
+
- Features/data preparation
|
| 40 |
+
- Model(s); training/validation split; external validation if any
|
| 41 |
+
- Fairness/bias checks
|
| 42 |
+
|
| 43 |
+
## Evaluation & Metrics if provided
|
| 44 |
+
- Classification/regression metrics
|
| 45 |
+
- Calibration; confidence estimation
|
| 46 |
+
- Clinical outcomes (if available)
|
| 47 |
+
- Reference TRIPOD+AI for what to report
|
| 48 |
+
|
| 49 |
+
## Workflow Integration & Safety
|
| 50 |
+
- Human oversight; failure modes; alerting
|
| 51 |
+
- Monitoring & model updates (FDA SaMD AI/ML perspective)
|
| 52 |
+
|
| 53 |
+
## Results & Impact
|
| 54 |
+
- Clinical impact; operational efficiency; ROI/costs where applicable
|
| 55 |
+
|
| 56 |
+
## Ethics & Bias Mitigation
|
| 57 |
+
## Regulatory, Privacy & Security
|
| 58 |
+
- HIPAA/GDPR; access controls; audit
|
| 59 |
+
## Limitations & Generalizability
|
| 60 |
+
## Conclusion
|
| 61 |
+
|
| 62 |
+
LENGTH: aim 4,000–5,800 words.
|
| 63 |
+
|
| 64 |
+
OUTPUT: Valid Markdown only.
|
| 65 |
+
DO NOT include code fences around the Markdown.
|
| 66 |
+
""")
|
| 67 |
+
|
| 68 |
+
def build_manager_instructions() -> str:
|
| 69 |
+
return textwrap.dedent("""\
|
| 70 |
+
You are the manager reviewing three case study drafts on AI in healthcare.
|
| 71 |
+
|
| 72 |
+
TASKS:
|
| 73 |
+
1) Rate each draft on a 1–10 scale for:
|
| 74 |
+
- Clinical completeness (CARE)
|
| 75 |
+
- AI reporting rigor (TRIPOD+AI)
|
| 76 |
+
- Trial/protocol framing where relevant (CONSORT-AI / SPIRIT-AI)
|
| 77 |
+
- Privacy & regulatory correctness (HIPAA Safe Harbor; FDA SaMD)
|
| 78 |
+
- Clarity & structure
|
| 79 |
+
2) Briefly justify each rating (1–3 sentences).
|
| 80 |
+
3) Pick a **single winner** among the three drafts (best overall).
|
| 81 |
+
|
| 82 |
+
OUTPUT JSON (strict):
|
| 83 |
+
{
|
| 84 |
+
"scores": [
|
| 85 |
+
{"agent": "agent1", "clinical_completeness": int, "ai_rigor": int, "trial_framing": int, "privacy_regulatory": int, "clarity_structure": int, "justification": "..."},
|
| 86 |
+
{"agent": "agent2", "clinical_completeness": int, "ai_rigor": int, "trial_framing": int, "privacy_regulatory": int, "clarity_structure": int, "justification": "..."},
|
| 87 |
+
{"agent": "agent3", "clinical_completeness": int, "ai_rigor": int, "trial_framing": int, "privacy_regulatory": int, "clarity_structure": int, "justification": "..."}
|
| 88 |
+
],
|
| 89 |
+
"winner": "agent1|agent2|agent3"
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
IMPORTANT:
|
| 93 |
+
- Return only JSON.
|
| 94 |
+
""")
|
| 95 |
+
|
| 96 |
+
# ---------- Agent calls (OpenAI SDK) ----------
|
| 97 |
+
|
| 98 |
+
def _openai_client() -> OpenAI:
|
| 99 |
+
return OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
| 100 |
+
|
| 101 |
+
def call_openai_case_study(input_text: str, model: str = "gpt-4o-mini") -> str:
|
| 102 |
+
client = _openai_client()
|
| 103 |
+
system = build_case_study_instructions()
|
| 104 |
+
prompt = f"INPUT:\n{input_text}\n\nFollow the instructions strictly."
|
| 105 |
+
resp = client.responses.create(
|
| 106 |
+
model=model,
|
| 107 |
+
instructions=system,
|
| 108 |
+
input=prompt,
|
| 109 |
+
temperature=0.3,
|
| 110 |
+
)
|
| 111 |
+
return resp.output_text.strip()
|
| 112 |
+
|
| 113 |
+
def call_gemini_case_study(input_text: str, model: str = "gpt-4.1-nano") -> str:
|
| 114 |
+
client = _openai_client()
|
| 115 |
+
system = build_case_study_instructions()
|
| 116 |
+
prompt = f"INPUT:\n{input_text}\n\nFollow the instructions strictly."
|
| 117 |
+
resp = client.responses.create(
|
| 118 |
+
model=model,
|
| 119 |
+
instructions=system,
|
| 120 |
+
input=prompt,
|
| 121 |
+
temperature=0.3,
|
| 122 |
+
)
|
| 123 |
+
return resp.output_text.strip()
|
| 124 |
+
|
| 125 |
+
def call_deepseek_case_study(input_text: str, model: str = "gpt-4.1-mini") -> str:
|
| 126 |
+
client = _openai_client()
|
| 127 |
+
system = build_case_study_instructions()
|
| 128 |
+
prompt = f"INPUT:\n{input_text}\n\nFollow the instructions strictly."
|
| 129 |
+
resp = client.responses.create(
|
| 130 |
+
model=model,
|
| 131 |
+
instructions=system,
|
| 132 |
+
input=prompt,
|
| 133 |
+
temperature=0.3,
|
| 134 |
+
)
|
| 135 |
+
return resp.output_text.strip()
|
| 136 |
+
|
| 137 |
+
def call_openai_manager(agent1: str, agent2: str, agent3: str,
|
| 138 |
+
model: str = "gpt-4o") -> Dict[str, Any]:
|
| 139 |
+
client = _openai_client()
|
| 140 |
+
manager_instr = build_manager_instructions()
|
| 141 |
+
payload = {
|
| 142 |
+
"agent1_draft": agent1,
|
| 143 |
+
"agent2_draft": agent2,
|
| 144 |
+
"agent3_draft": agent3,
|
| 145 |
+
}
|
| 146 |
+
resp = client.responses.create(
|
| 147 |
+
model=model,
|
| 148 |
+
instructions=manager_instr,
|
| 149 |
+
input=json.dumps(payload),
|
| 150 |
+
temperature=0.2,
|
| 151 |
+
response_format={"type": "json_object"},
|
| 152 |
+
)
|
| 153 |
+
raw = resp.output_text
|
| 154 |
+
try:
|
| 155 |
+
return json.loads(raw)
|
| 156 |
+
except Exception as e:
|
| 157 |
+
# Fallback JSON slice
|
| 158 |
+
s, e2 = raw.find("{"), raw.rfind("}")
|
| 159 |
+
if s != -1 and e2 != -1 and e2 > s:
|
| 160 |
+
return json.loads(raw[s:e2+1])
|
| 161 |
+
raise RuntimeError(f"Manager returned non-JSON: {raw}") from e
|
| 162 |
+
|
| 163 |
+
# ---------- Orchestration ----------
|
| 164 |
+
|
| 165 |
+
def run_pipeline(file: str,
|
| 166 |
+
oai_model: str = "gpt-4o-mini",
|
| 167 |
+
gem_model: str = "gpt-4.1-nano",
|
| 168 |
+
ds_model: str = "gpt-4.1-mini") -> Dict[str, Any]:
|
| 169 |
+
"""
|
| 170 |
+
- Reads text (string or path) with load_input_text
|
| 171 |
+
- Calls three agents
|
| 172 |
+
- Saves their drafts as agent1.md / agent2.md / agent3.md
|
| 173 |
+
- Calls manager and returns its JSON (scores + winner)
|
| 174 |
+
"""
|
| 175 |
+
source_text = load_input_text(file)
|
| 176 |
+
|
| 177 |
+
print("Generating case studies with three agents...")
|
| 178 |
+
print("Generating Agent 1 Output...")
|
| 179 |
+
a1 = call_openai_case_study(source_text, model=oai_model)
|
| 180 |
+
print("Generating Agent 2 Output...")
|
| 181 |
+
a2 = call_gemini_case_study(source_text, model=gem_model)
|
| 182 |
+
print("Generating Agent 3 Output...")
|
| 183 |
+
a3 = call_deepseek_case_study(source_text, model=ds_model)
|
| 184 |
+
|
| 185 |
+
pathlib.Path("agent1.md").write_text(a1, encoding="utf-8")
|
| 186 |
+
pathlib.Path("agent2.md").write_text(a2, encoding="utf-8")
|
| 187 |
+
pathlib.Path("agent3.md").write_text(a3, encoding="utf-8")
|
| 188 |
+
print("Saved agent outputs to agent1.md, agent2.md, agent3.md")
|
| 189 |
+
|
| 190 |
+
print("Manager evaluating...")
|
| 191 |
+
result = call_openai_manager(a1, a2, a3)
|
| 192 |
+
return result
|