feat: AI chat system with LangGraph, multi-step patient flows, and appointment rescheduling

- Add floating chat window Hand-off to AI toggle (per-patient) and after-hours AI toggle (global)
- Add LangGraph-powered appointment reminder flow: AI introduces itself, classifies YES/NO, handles confirmation with appointment date/time
- Add multi-step rescheduling flow: ASAP vs next week, tomorrow offer, Mon/Tue/Wed picker, morning/afternoon time slot — automatically updates appointment in DB
- Add new patient / after-hours flow: new vs existing patient, dental insurance check, MassHealth Selenium eligibility check (auto-uses saved member ID + DOB for existing patients), self-pay fallback
- Add AI Chat Settings page (Settings → Advanced) with editable greeting templates and LangGraph flow diagrams for both reminder and new-patient flows
- Add Schedule a New Patient template option in chat window, starts new-patient conversation flow
- Add GET/PUT endpoints for AI handoff, after-hours handoff, and AI chat templates
- Add multilingual support (7 languages) across all AI reply nodes with LLM generation and hardcoded fallbacks
- Add pending reschedule in-memory store and conversation stage tracking across all flows

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-07 23:21:06 -04:00
parent 86dd685342
commit 9908e5b5fd
317 changed files with 6533 additions and 274 deletions

View File

@@ -13,6 +13,7 @@ import {
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Switch } from "@/components/ui/switch";
import {
Phone,
PhoneCall,
@@ -22,6 +23,7 @@ import {
MessageSquare,
Send,
X,
MoonStar,
} from "lucide-react";
import { SmsTemplateDialog } from "@/components/patient-connection/sms-template-diaog";
import { MessageThread } from "@/components/patient-connection/message-thread";
@@ -35,8 +37,36 @@ export default function PatientConnectionPage() {
const [selectedPatient, setSelectedPatient] = useState<Patient | null>(null);
const [isSmsDialogOpen, setIsSmsDialogOpen] = useState(false);
const [showMessaging, setShowMessaging] = useState(false);
const [afterHoursEnabled, setAfterHoursEnabled] = useState(true);
const { toast } = useToast();
useQuery<{ enabled: boolean }>({
queryKey: ["/api/twilio/after-hours-handoff"],
queryFn: async () => {
const res = await apiRequest("GET", "/api/twilio/after-hours-handoff");
return res.json();
},
onSuccess: (data: { enabled: boolean }) => setAfterHoursEnabled(data.enabled),
} as any);
const afterHoursMutation = useMutation({
mutationFn: async (enabled: boolean) =>
apiRequest("PUT", "/api/twilio/after-hours-handoff", { enabled }),
onSuccess: (_: any, enabled: boolean) => {
toast({
title: enabled ? "After-hours AI enabled" : "After-hours AI disabled",
description: enabled
? "AI will automatically handle messages outside office hours."
: "After-hours messages will not receive an automatic AI reply.",
});
},
});
const handleAfterHoursToggle = (enabled: boolean) => {
setAfterHoursEnabled(enabled);
afterHoursMutation.mutate(enabled);
};
const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
@@ -175,6 +205,16 @@ export default function PatientConnectionPage() {
Search and communicate with patients
</p>
</div>
{/* After-hours AI toggle */}
<div className="flex items-center gap-2 px-4 py-2 rounded-lg border bg-white shadow-sm">
<MoonStar className={`h-4 w-4 ${afterHoursEnabled ? "text-primary" : "text-muted-foreground"}`} />
<span className="text-sm font-medium">Hand off to AI after hours</span>
<Switch
checked={afterHoursEnabled}
onCheckedChange={handleAfterHoursToggle}
/>
</div>
</div>
</div>

View File

@@ -19,6 +19,7 @@ import { OfficeHoursCard } from "@/components/settings/office-hours-card";
import { OfficeContactCard } from "@/components/settings/office-contact-card";
import { ProcedureTimeslotCard } from "@/components/settings/procedure-timeslot-card";
import { InsuranceContactCard } from "@/components/settings/insurance-contact-card";
import { AiChatSettingsCard } from "@/components/settings/ai-chat-settings-card";
type SectionId =
| "staff"
@@ -29,6 +30,7 @@ type SectionId =
| "programs"
| "twilio"
| "ai"
| "aichat"
| "officehours"
| "officecontact"
| "proceduretimeslot"
@@ -259,6 +261,9 @@ export default function SettingsPage() {
case "ai":
return <AiSettingsCard />;
case "aichat":
return <AiChatSettingsCard />;
case "officehours":
return <OfficeHoursCard />;