File size: 3,596 Bytes
9e8bf4c f6e6270 9e8bf4c 49e21bd 9e8bf4c f6e6270 9e8bf4c 72878ad f6e6270 72878ad f6e6270 9e8bf4c 72878ad f6e6270 72878ad f6e6270 72878ad f6e6270 9e8bf4c f6e6270 72878ad 9e8bf4c 72878ad f6e6270 72878ad f6e6270 9e8bf4c f6e6270 72878ad f6e6270 9e8bf4c 72878ad f6e6270 72878ad 9e8bf4c f6e6270 9e8bf4c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | import yaml, json, os
from crewai import Agent, Task, Crew, Process
from langchain_openai import ChatOpenAI
class PatientChartCrewEngine:
def __init__(self, folder_path: str, measure_name: str):
if not measure_name.endswith(".yml"):
measure_name += ".yml"
file_path = os.path.join(folder_path, measure_name)
if not os.path.exists(file_path):
raise FileNotFoundError(f"Measure file not found at: {file_path}")
with open(file_path, 'r') as f:
self.cfg = yaml.safe_load(f)
# Using a slightly lower temperature for the Architect to ensure syntax stability
self.llm = ChatOpenAI(model="gpt-4o", temperature=0.5)
def run(self):
# AGENT 1: Scribe - Focuses on clinical density
scribe = Agent(
role="Senior Clinical Quality Scribe",
goal="Generate high-density clinical narratives for patient charts.",
backstory="""You are a senior scribe. You provide extremely detailed HPIs
and expanded Social Histories. You avoid symbols like & or %;
instead, you write 'and' or 'percent' to ensure data compatibility.""",
llm=self.llm,
allow_delegation=False
)
# AGENT 2: Architect - Focuses on LaTeX Syntax and escaping
architect = Agent(
role="LaTeX Document Architect",
goal="Convert clinical text into error-free, top-aligned LaTeX source code.",
backstory="""You are a LaTeX expert. You know that characters like %, &, $, #,
and _ must be escaped (e.g., \%) or the code will crash. You prioritize
structural integrity and use packages like 'geometry' and 'microtype'
to ensure professional formatting.""",
llm=self.llm,
allow_delegation=False
)
# TASK 1: Narrative Volume
content_task = Task(
description=f"""
RULES: {json.dumps(self.cfg.get('target_rules', {}), indent=2)}
1. IDENTITY: Unique Name and MRN (e.g., Emily Carter, 92837465).
2. DENSE HPI: Write a massive clinical narrative (minimum 800 words).
Focus on Transition to Hospice (Z51.5) and Hysterectomy (58150).
3. DATES: Use MM/DD/YYYY format for all entries.
""",
agent=scribe,
expected_output="A JSON-like structure containing the clinical narrative sections."
)
# TASK 2: Rigid LaTeX Construction
latex_task = Task(
description="""
Assemble the clinical text into a single RAW LaTeX document.
STRICT REQUIREMENTS:
- Start with \\documentclass{article}.
- Use \\usepackage[utf8]{inputenc} and \\usepackage[margin=0.8in]{geometry}.
- Include \\raggedbottom to keep all text top-aligned.
- ESCAPE special characters: Change '%' to '\%', '&' to '\&', and '_' to '\_'.
- Ensure there is a \\begin{document} and \\end{document}.
- OUTPUT ONLY THE RAW LATEX. DO NOT USE MARKDOWN CODE BLOCKS (```).
""",
agent=architect,
context=[content_task],
expected_output="Valid LaTeX source code starting with \\documentclass."
)
crew = Crew(
agents=[scribe, architect],
tasks=[content_task, latex_task],
process=Process.sequential
)
result = crew.kickoff()
return result.raw if hasattr(result, 'raw') else str(result) |