feat: chatbot screenshot-only eligibility detect, Sun Life/DentaQuest auto-check, chatbot attachment handoff to preauth; fix TuftsSCO preauth Selenium reliability
- Chatbot: submitting with only a screenshot attached (no text) now triggers the same "AI Detect & Check Eligibility" flow as the Copy Agent page - detect-eligibility-info now also extracts the visible insurance payer name and picks Tufts SCO auto-check when both Sun Life and DentaQuest are detected, else MassHealth - Chatbot-attached files are now handed off to both claim and preauth forms unconditionally, not just claims - TuftsSCO preauth Selenium worker: verify-and-retry the Tooth field (typing was silently getting reset by duplicate-procedure-code warning banners), add a final re-verification pass across all rows, fix acknowledgement-checkbox targeting/verification, and verify the "Next step" click actually advances the wizard instead of trusting a blind click
This commit is contained in:
@@ -378,7 +378,8 @@ router.post(
|
||||
type: "text",
|
||||
text:
|
||||
"Extract the Member ID and Date of Birth from this dental/insurance eligibility screenshot. " +
|
||||
'Respond with strict JSON only, no prose, no markdown fences: {"memberId": string|null, "dob": "YYYY-MM-DD"|null}',
|
||||
"Also read any visible insurance payer/plan name text (e.g. \"Sun Life\", \"DentaQuest\", \"MassHealth\") exactly as shown. " +
|
||||
'Respond with strict JSON only, no prose, no markdown fences: {"memberId": string|null, "dob": "YYYY-MM-DD"|null, "insuranceProvider": string|null}',
|
||||
},
|
||||
...files.map((f) => ({
|
||||
type: "image_url",
|
||||
@@ -390,10 +391,11 @@ router.post(
|
||||
|
||||
let memberId: string | null = null;
|
||||
let dob: string | null = null;
|
||||
let insuranceProvider: string | null = null;
|
||||
try {
|
||||
const raw = String(response.content).trim();
|
||||
const jsonStr = raw.replace(/^```json\s*/i, "").replace(/```\s*$/, "").trim();
|
||||
const parsed = JSON.parse(jsonStr) as { memberId?: string | null; dob?: string | null };
|
||||
const parsed = JSON.parse(jsonStr) as { memberId?: string | null; dob?: string | null; insuranceProvider?: string | null };
|
||||
// Sanitize once here so this is the single source of truth for the memberId
|
||||
// used downstream (temp-patient creation, chatbot prefill, real eligibility check) —
|
||||
// any mismatch in formatting would cause createOrUpdatePatientByInsuranceId to create
|
||||
@@ -401,11 +403,19 @@ router.post(
|
||||
const cleanedMemberId = (parsed.memberId || "").replace(/[^A-Za-z0-9]/g, "");
|
||||
memberId = cleanedMemberId || null;
|
||||
dob = parsed.dob || null;
|
||||
insuranceProvider = parsed.insuranceProvider || null;
|
||||
} catch (parseErr) {
|
||||
console.error("[detect-eligibility-info] failed to parse AI response", parseErr);
|
||||
}
|
||||
|
||||
return res.status(200).json({ error: false, data: { memberId, dob } });
|
||||
// Sun Life now brands the DentaQuest/Tufts SCO portal — screenshots showing both
|
||||
// names together mean the Tufts SCO auto-check, not the MassHealth default.
|
||||
const providerText = (insuranceProvider || "").toLowerCase();
|
||||
const hasSunLife = /sun\s*life/.test(providerText);
|
||||
const hasDentaQuest = /denta\s*quest/.test(providerText);
|
||||
const autoCheck = hasSunLife && hasDentaQuest ? "tufts-sco" : "mh";
|
||||
|
||||
return res.status(200).json({ error: false, data: { memberId, dob, insuranceProvider, autoCheck } });
|
||||
} catch (err) {
|
||||
console.error("[detect-eligibility-info]", err);
|
||||
return res.status(500).json({ error: true, message: "Failed to detect eligibility info", details: String(err) });
|
||||
|
||||
Reference in New Issue
Block a user