Study Assistant (AI-Powered)¶
AI-powered study configuration from protocol documents using Large Language Models.
Overview¶
The Study Assistant ingests study protocol PDFs and automatically generates:
- Study metadata
- Visit schedules
- Battery configurations
- Form definitions
- Consent documents
ChangeSet Workflow¶
All AI-generated configurations use a ChangeSet approval workflow:
Benefits: - Review before apply - Human oversight of AI decisions - Incremental changes - Apply changes step-by-step - Rollback support - Undo applied changes - Audit trail - Track all AI-generated configs
Protocol Ingestion¶
Upload Protocol¶
// Upload PDF protocol
const response = await api.uploadProtocol({
study_id: study_id,
file: protocolPdf,
});
// AI extracts key information
const extraction = response.extraction;
Extracted Information¶
AI extracts:
{
"study_metadata": {
"title": "Neurocognitive Assessment in Mild Cognitive Impairment",
"phase": "Observational",
"duration_weeks": 52,
"target_enrollment": 100
},
"visits": [
{
"visit_name": "Baseline",
"visit_number": 1,
"window_start_days": 0,
"window_end_days": 7,
"procedures": ["Cognitive assessment", "Demographics", "Medical history"]
},
{
"visit_name": "Month 3",
"visit_number": 2,
"window_start_days": 84,
"window_end_days": 98,
"procedures": ["Cognitive assessment", "Adverse events"]
}
],
"assessments": [
{
"name": "Cognitive Battery",
"tasks": ["Simple RT", "CPT", "N-Back", "Digit Span"],
"estimated_minutes": 30
}
]
}
ChangeSet Generation¶
Create ChangeSet¶
// Generate ChangeSet from extraction
const changeSet = await api.createChangeSet({
study_id: study_id,
extraction_id: extraction.id,
changes: [
{
entity_type: "visit",
operation: "create",
data: {
visit_name: "Baseline",
visit_number: 1,
window_start_days: 0,
window_end_days: 7,
}
},
{
entity_type: "battery",
operation: "create",
data: {
name: "Cognitive Battery",
tasks: ["simple_rt", "cpt", "nback", "digit_span"]
}
}
]
});
ChangeSet Structure¶
interface ChangeSet {
id: string;
study_id: string;
status: "pending" | "approved" | "rejected" | "applied";
changes: Change[];
created_by: "ai" | "user";
created_at: string;
}
interface Change {
entity_type: "study" | "visit" | "battery" | "form" | "consent";
operation: "create" | "update" | "delete";
entity_id?: string; // For update/delete
data: object;
validation_errors?: string[];
}
Review Interface¶
Portal provides ChangeSet review UI:
// ChangeSetReview.tsx
function ChangeSetReview({ changeSetId }: { changeSetId: string }) {
const { data: changeSet } = useChangeSet(changeSetId);
return (
<div>
<h1>Review AI-Generated Configuration</h1>
{changeSet.changes.map((change, index) => (
<ChangeCard
key={index}
change={change}
onAccept={() => acceptChange(change.id)}
onReject={() => rejectChange(change.id)}
onModify={(data) => modifyChange(change.id, data)}
/>
))}
<button onClick={() => applyChangeSet(changeSetId)}>
Apply All Changes
</button>
</div>
);
}
Change Review Actions¶
- Accept - Approve change as-is
- Reject - Remove change from ChangeSet
- Modify - Edit AI-generated data before applying
Apply ChangeSet¶
Once reviewed, apply changes to study:
// Apply all approved changes
await api.applyChangeSet(changeSetId);
// Apply selectively
await api.applyChangeSet(changeSetId, {
change_ids: ["change_1", "change_3", "change_5"]
});
Changes are applied transactionally: - All changes succeed or none are applied - Rollback on error - Create audit log entry
Form Definition Extraction¶
AI extracts form structures from protocol:
{
"form_name": "Demographics",
"fields": [
{
"field_name": "age",
"field_label": "Age",
"field_type": "number",
"validation": { "min": 18, "max": 120 }
},
{
"field_name": "gender",
"field_label": "Gender",
"field_type": "radio",
"choices": ["Male", "Female", "Other", "Prefer not to say"]
},
{
"field_name": "race",
"field_label": "Race/Ethnicity",
"field_type": "checkbox",
"choices": [
"American Indian or Alaska Native",
"Asian",
"Black or African American",
"Hispanic or Latino",
"Native Hawaiian or Other Pacific Islander",
"White"
]
}
]
}
AI Model Configuration¶
# app/services/ai_assistant.py
from openai import AsyncOpenAI
class StudyAssistant:
def __init__(self):
self.client = AsyncOpenAI(api_key=settings.OPENAI_API_KEY)
self.model = "gpt-4-turbo"
async def extract_protocol(self, pdf_text: str) -> dict:
response = await self.client.chat.completions.create(
model=self.model,
messages=[
{
"role": "system",
"content": "Extract study information from protocol..."
},
{
"role": "user",
"content": pdf_text
}
],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
Validation¶
AI-generated configs are validated before applying:
// Validate visit schedule
function validateVisitSchedule(visits: Visit[]): ValidationError[] {
const errors = [];
// Check for overlapping windows
for (let i = 0; i < visits.length - 1; i++) {
if (visits[i].window_end_days > visits[i + 1].window_start_days) {
errors.push({
field: `visits[${i}].window_end_days`,
message: "Visit windows overlap"
});
}
}
// Check for missing visit numbers
const visitNumbers = visits.map(v => v.visit_number).sort();
for (let i = 1; i <= visitNumbers.length; i++) {
if (!visitNumbers.includes(i)) {
errors.push({
field: "visits",
message: `Missing visit number ${i}`
});
}
}
return errors;
}
Rollback¶
Revert applied ChangeSets:
Rollback creates inverse ChangeSet: - Create → Delete - Update → Revert to previous values - Delete → Recreate
Audit Trail¶
All AI-assisted operations are logged:
{
"timestamp": "2026-01-24T12:34:56Z",
"operation": "apply_changeset",
"changeset_id": "cs_123",
"user_id": 42,
"changes_applied": 5,
"changes_rejected": 2,
"entities_created": {
"visits": 3,
"batteries": 1,
"forms": 2
}
}
Future Enhancements¶
- Iterative refinement - Chat with AI to refine configurations
- Template learning - AI learns from approved ChangeSets
- Multi-protocol support - Compare protocols from multiple studies
- Automated testing - AI generates test data for validation
Next Steps¶
- Cognitive Assessments - Task configuration
- Data Entry - Form builder
- Portal Pages - UI reference
- Server Architecture - Technical details