Spaces:
Running
Running
Add 3 files
Browse files- README.md +6 -4
- index.html +587 -19
- prompts.txt +2 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: gray
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: cctc-assistantai
|
| 3 |
+
emoji: 🐳
|
| 4 |
+
colorFrom: red
|
| 5 |
colorTo: gray
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,587 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Virtual Physician Assistant | Canadian Cardiovascular Training Center</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 9 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/docx/7.1.0/docx.min.js"></script>
|
| 10 |
+
<style>
|
| 11 |
+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
|
| 12 |
+
|
| 13 |
+
body {
|
| 14 |
+
font-family: 'Poppins', sans-serif;
|
| 15 |
+
background-color: #f0f4f8;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.pulse {
|
| 19 |
+
animation: pulse 2s infinite;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
@keyframes pulse {
|
| 23 |
+
0% {
|
| 24 |
+
box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.7);
|
| 25 |
+
}
|
| 26 |
+
70% {
|
| 27 |
+
box-shadow: 0 0 0 10px rgba(220, 38, 38, 0);
|
| 28 |
+
}
|
| 29 |
+
100% {
|
| 30 |
+
box-shadow: 0 0 0 0 rgba(220, 38, 38, 0);
|
| 31 |
+
}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.typing {
|
| 35 |
+
position: relative;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.typing::after {
|
| 39 |
+
content: "|";
|
| 40 |
+
position: absolute;
|
| 41 |
+
right: -5px;
|
| 42 |
+
animation: blink 1s infinite;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
@keyframes blink {
|
| 46 |
+
0% { opacity: 0; }
|
| 47 |
+
50% { opacity: 1; }
|
| 48 |
+
100% { opacity: 0; }
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.card-gradient {
|
| 52 |
+
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.voice-wave {
|
| 56 |
+
display: flex;
|
| 57 |
+
justify-content: center;
|
| 58 |
+
align-items: center;
|
| 59 |
+
gap: 4px;
|
| 60 |
+
height: 40px;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
.voice-wave span {
|
| 64 |
+
display: block;
|
| 65 |
+
width: 4px;
|
| 66 |
+
height: 10px;
|
| 67 |
+
background: #3b82f6;
|
| 68 |
+
border-radius: 3px;
|
| 69 |
+
animation: voice-wave 1.5s infinite ease-in-out;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
.voice-wave span:nth-child(2) {
|
| 73 |
+
animation-delay: 0.2s;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.voice-wave span:nth-child(3) {
|
| 77 |
+
animation-delay: 0.4s;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
.voice-wave span:nth-child(4) {
|
| 81 |
+
animation-delay: 0.6s;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
.voice-wave span:nth-child(5) {
|
| 85 |
+
animation-delay: 0.8s;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
@keyframes voice-wave {
|
| 89 |
+
0% { height: 10px; }
|
| 90 |
+
50% { height: 30px; }
|
| 91 |
+
100% { height: 10px; }
|
| 92 |
+
}
|
| 93 |
+
</style>
|
| 94 |
+
</head>
|
| 95 |
+
<body class="min-h-screen flex flex-col">
|
| 96 |
+
<!-- Header -->
|
| 97 |
+
<header class="bg-red-700 text-white shadow-lg">
|
| 98 |
+
<div class="container mx-auto px-4 py-6 flex justify-between items-center">
|
| 99 |
+
<div class="flex items-center space-x-4">
|
| 100 |
+
<div class="bg-white rounded-full p-2">
|
| 101 |
+
<i class="fas fa-heartbeat text-red-700 text-2xl"></i>
|
| 102 |
+
</div>
|
| 103 |
+
<div>
|
| 104 |
+
<h1 class="text-2xl font-bold">Canadian Cardiovascular Training Center</h1>
|
| 105 |
+
<p class="text-sm opacity-80">Virtual Physician Assistant</p>
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
<div class="hidden md:flex items-center space-x-2">
|
| 109 |
+
<i class="fas fa-user-md text-xl"></i>
|
| 110 |
+
<span>Specialist Support System</span>
|
| 111 |
+
</div>
|
| 112 |
+
</div>
|
| 113 |
+
</header>
|
| 114 |
+
|
| 115 |
+
<!-- Main Content -->
|
| 116 |
+
<main class="flex-grow container mx-auto px-4 py-8">
|
| 117 |
+
<div class="max-w-4xl mx-auto">
|
| 118 |
+
<!-- Patient Info Card -->
|
| 119 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-8 card-gradient">
|
| 120 |
+
<div class="p-6">
|
| 121 |
+
<h2 class="text-xl font-semibold text-gray-800 mb-4">Patient Information</h2>
|
| 122 |
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
| 123 |
+
<div>
|
| 124 |
+
<label class="block text-sm font-medium text-gray-700">Full Name</label>
|
| 125 |
+
<p id="patient-name" class="mt-1 text-gray-900 font-medium">Not provided yet</p>
|
| 126 |
+
</div>
|
| 127 |
+
<div>
|
| 128 |
+
<label class="block text-sm font-medium text-gray-700">Date of Birth</label>
|
| 129 |
+
<p id="patient-dob" class="mt-1 text-gray-900 font-medium">Not provided yet</p>
|
| 130 |
+
</div>
|
| 131 |
+
</div>
|
| 132 |
+
</div>
|
| 133 |
+
</div>
|
| 134 |
+
|
| 135 |
+
<!-- Virtual Assistant Interface -->
|
| 136 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
|
| 137 |
+
<div class="p-6 border-b border-gray-200 bg-gray-50">
|
| 138 |
+
<div class="flex items-center justify-between">
|
| 139 |
+
<h2 class="text-xl font-semibold text-gray-800">Virtual Physician Assistant</h2>
|
| 140 |
+
<div id="status-indicator" class="flex items-center space-x-2">
|
| 141 |
+
<span class="relative flex h-3 w-3">
|
| 142 |
+
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
| 143 |
+
<span class="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
|
| 144 |
+
</span>
|
| 145 |
+
<span class="text-sm text-gray-600">Listening</span>
|
| 146 |
+
</div>
|
| 147 |
+
</div>
|
| 148 |
+
</div>
|
| 149 |
+
|
| 150 |
+
<!-- Conversation Display -->
|
| 151 |
+
<div class="p-6 h-96 overflow-y-auto" id="conversation-container">
|
| 152 |
+
<div class="flex mb-4">
|
| 153 |
+
<div class="flex-shrink-0 mr-3">
|
| 154 |
+
<div class="bg-blue-100 rounded-full p-2">
|
| 155 |
+
<i class="fas fa-heart text-blue-600"></i>
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
<div class="bg-blue-50 rounded-lg p-4 max-w-3xl">
|
| 159 |
+
<p id="assistant-message" class="text-gray-800 typing">Hello, I'm your Virtual Physician Assistant. I'll be asking you some preliminary questions before your appointment. Let's start with your full name.</p>
|
| 160 |
+
</div>
|
| 161 |
+
</div>
|
| 162 |
+
</div>
|
| 163 |
+
|
| 164 |
+
<!-- Controls -->
|
| 165 |
+
<div class="p-6 border-t border-gray-200 bg-gray-50">
|
| 166 |
+
<div class="flex items-center justify-between">
|
| 167 |
+
<button id="voice-btn" class="bg-red-600 hover:bg-red-700 text-white rounded-full p-4 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 pulse">
|
| 168 |
+
<i class="fas fa-microphone text-xl"></i>
|
| 169 |
+
</button>
|
| 170 |
+
<div id="voice-wave" class="voice-wave hidden">
|
| 171 |
+
<span></span>
|
| 172 |
+
<span></span>
|
| 173 |
+
<span></span>
|
| 174 |
+
<span></span>
|
| 175 |
+
<span></span>
|
| 176 |
+
</div>
|
| 177 |
+
<button id="complete-btn" class="hidden bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2">
|
| 178 |
+
Complete Screening
|
| 179 |
+
</button>
|
| 180 |
+
</div>
|
| 181 |
+
</div>
|
| 182 |
+
</div>
|
| 183 |
+
|
| 184 |
+
<!-- Patient Responses Summary -->
|
| 185 |
+
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
|
| 186 |
+
<div class="p-6 border-b border-gray-200 bg-gray-50">
|
| 187 |
+
<h2 class="text-xl font-semibold text-gray-800">Pre-Screening Summary</h2>
|
| 188 |
+
</div>
|
| 189 |
+
<div class="p-6">
|
| 190 |
+
<div class="overflow-x-auto">
|
| 191 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 192 |
+
<thead class="bg-gray-50">
|
| 193 |
+
<tr>
|
| 194 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Question</th>
|
| 195 |
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Response</th>
|
| 196 |
+
</tr>
|
| 197 |
+
</thead>
|
| 198 |
+
<tbody id="responses-table" class="bg-white divide-y divide-gray-200">
|
| 199 |
+
<!-- Responses will be added here dynamically -->
|
| 200 |
+
<tr>
|
| 201 |
+
<td colspan="2" class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 text-center">No responses recorded yet</td>
|
| 202 |
+
</tr>
|
| 203 |
+
</tbody>
|
| 204 |
+
</table>
|
| 205 |
+
</div>
|
| 206 |
+
</div>
|
| 207 |
+
</div>
|
| 208 |
+
|
| 209 |
+
<!-- Download Button -->
|
| 210 |
+
<div class="text-center mb-8">
|
| 211 |
+
<button id="download-btn" class="hidden bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
| 212 |
+
<i class="fas fa-download mr-2"></i> Download Summary
|
| 213 |
+
</button>
|
| 214 |
+
</div>
|
| 215 |
+
</div>
|
| 216 |
+
</main>
|
| 217 |
+
|
| 218 |
+
<!-- Footer -->
|
| 219 |
+
<footer class="bg-gray-800 text-white py-6">
|
| 220 |
+
<div class="container mx-auto px-4">
|
| 221 |
+
<div class="flex flex-col md:flex-row justify-between items-center">
|
| 222 |
+
<div class="mb-4 md:mb-0">
|
| 223 |
+
<p class="text-sm">© 2023 Canadian Cardiovascular Training Center. All rights reserved.</p>
|
| 224 |
+
</div>
|
| 225 |
+
<div class="flex space-x-6">
|
| 226 |
+
<a href="#" class="text-gray-300 hover:text-white">
|
| 227 |
+
<i class="fas fa-shield-alt"></i> Privacy Policy
|
| 228 |
+
</a>
|
| 229 |
+
<a href="#" class="text-gray-300 hover:text-white">
|
| 230 |
+
<i class="fas fa-file-alt"></i> Terms of Service
|
| 231 |
+
</a>
|
| 232 |
+
</div>
|
| 233 |
+
</div>
|
| 234 |
+
</div>
|
| 235 |
+
</footer>
|
| 236 |
+
|
| 237 |
+
<script>
|
| 238 |
+
document.addEventListener('DOMContentLoaded', function() {
|
| 239 |
+
// DOM Elements
|
| 240 |
+
const voiceBtn = document.getElementById('voice-btn');
|
| 241 |
+
const voiceWave = document.getElementById('voice-wave');
|
| 242 |
+
const completeBtn = document.getElementById('complete-btn');
|
| 243 |
+
const conversationContainer = document.getElementById('conversation-container');
|
| 244 |
+
const responsesTable = document.getElementById('responses-table');
|
| 245 |
+
const patientName = document.getElementById('patient-name');
|
| 246 |
+
const patientDob = document.getElementById('patient-dob');
|
| 247 |
+
const statusIndicator = document.getElementById('status-indicator');
|
| 248 |
+
const assistantMessage = document.getElementById('assistant-message');
|
| 249 |
+
const downloadBtn = document.getElementById('download-btn');
|
| 250 |
+
|
| 251 |
+
// Speech recognition setup
|
| 252 |
+
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
| 253 |
+
const recognition = new SpeechRecognition();
|
| 254 |
+
recognition.continuous = false;
|
| 255 |
+
recognition.interimResults = false;
|
| 256 |
+
recognition.lang = 'en-CA';
|
| 257 |
+
|
| 258 |
+
// Speech synthesis
|
| 259 |
+
const synth = window.speechSynthesis;
|
| 260 |
+
|
| 261 |
+
// Questions array (now split into separate name and DOB questions)
|
| 262 |
+
const questions = [
|
| 263 |
+
"What's your first and last name?",
|
| 264 |
+
"What's your date of birth?",
|
| 265 |
+
"Have you experienced any chest pains within the last 2 months?",
|
| 266 |
+
"Have you been experiencing any shortness of breath?",
|
| 267 |
+
"Do you struggle walking up or down flights of stairs?",
|
| 268 |
+
"Have you had any recent changes to your medication?",
|
| 269 |
+
"Have you had any surgical procedures within the last 10 years?",
|
| 270 |
+
"Are there any specific notes or details you'd like to mention to the doctor?"
|
| 271 |
+
];
|
| 272 |
+
|
| 273 |
+
// Responses object
|
| 274 |
+
const responses = {};
|
| 275 |
+
let currentQuestionIndex = 0;
|
| 276 |
+
let isListening = false;
|
| 277 |
+
|
| 278 |
+
// Initialize responses object
|
| 279 |
+
questions.forEach((question, index) => {
|
| 280 |
+
responses[index] = {
|
| 281 |
+
question: question,
|
| 282 |
+
answer: "Not answered yet"
|
| 283 |
+
};
|
| 284 |
+
});
|
| 285 |
+
|
| 286 |
+
// Speak function
|
| 287 |
+
function speak(text) {
|
| 288 |
+
if (synth.speaking) {
|
| 289 |
+
synth.cancel();
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
const utterance = new SpeechSynthesisUtterance(text);
|
| 293 |
+
utterance.rate = 0.9;
|
| 294 |
+
utterance.pitch = 1;
|
| 295 |
+
utterance.onend = function() {
|
| 296 |
+
// When the assistant finishes speaking, start listening
|
| 297 |
+
if (currentQuestionIndex < questions.length) {
|
| 298 |
+
startListening();
|
| 299 |
+
}
|
| 300 |
+
};
|
| 301 |
+
|
| 302 |
+
// Update UI to show assistant is speaking
|
| 303 |
+
assistantMessage.classList.add('typing');
|
| 304 |
+
assistantMessage.textContent = "";
|
| 305 |
+
|
| 306 |
+
// Simulate typing effect
|
| 307 |
+
let i = 0;
|
| 308 |
+
const typingInterval = setInterval(() => {
|
| 309 |
+
if (i < text.length) {
|
| 310 |
+
assistantMessage.textContent += text.charAt(i);
|
| 311 |
+
i++;
|
| 312 |
+
conversationContainer.scrollTop = conversationContainer.scrollHeight;
|
| 313 |
+
} else {
|
| 314 |
+
clearInterval(typingInterval);
|
| 315 |
+
assistantMessage.classList.remove('typing');
|
| 316 |
+
synth.speak(utterance);
|
| 317 |
+
}
|
| 318 |
+
}, 30);
|
| 319 |
+
}
|
| 320 |
+
|
| 321 |
+
// Start listening function
|
| 322 |
+
function startListening() {
|
| 323 |
+
isListening = true;
|
| 324 |
+
voiceWave.classList.remove('hidden');
|
| 325 |
+
voiceBtn.classList.add('bg-red-700', 'pulse');
|
| 326 |
+
voiceBtn.classList.remove('bg-red-600');
|
| 327 |
+
recognition.start();
|
| 328 |
+
|
| 329 |
+
// Update status indicator
|
| 330 |
+
statusIndicator.innerHTML = `
|
| 331 |
+
<span class="relative flex h-3 w-3">
|
| 332 |
+
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
|
| 333 |
+
<span class="relative inline-flex rounded-full h-3 w-3 bg-green-500"></span>
|
| 334 |
+
</span>
|
| 335 |
+
<span class="text-sm text-gray-600">Listening</span>
|
| 336 |
+
`;
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
// Stop listening function
|
| 340 |
+
function stopListening() {
|
| 341 |
+
isListening = false;
|
| 342 |
+
voiceWave.classList.add('hidden');
|
| 343 |
+
voiceBtn.classList.remove('bg-red-700', 'pulse');
|
| 344 |
+
voiceBtn.classList.add('bg-red-600');
|
| 345 |
+
|
| 346 |
+
// Update status indicator
|
| 347 |
+
statusIndicator.innerHTML = `
|
| 348 |
+
<span class="relative flex h-3 w-3">
|
| 349 |
+
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
| 350 |
+
<span class="relative inline-flex rounded-full h-3 w-3 bg-red-500"></span>
|
| 351 |
+
</span>
|
| 352 |
+
<span class="text-sm text-gray-600">Ready</span>
|
| 353 |
+
`;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
// Add message to conversation
|
| 357 |
+
function addMessage(speaker, message) {
|
| 358 |
+
const messageDiv = document.createElement('div');
|
| 359 |
+
messageDiv.className = 'flex mb-4';
|
| 360 |
+
|
| 361 |
+
if (speaker === 'assistant') {
|
| 362 |
+
messageDiv.innerHTML = `
|
| 363 |
+
<div class="flex-shrink-0 mr-3">
|
| 364 |
+
<div class="bg-blue-100 rounded-full p-2">
|
| 365 |
+
<i class="fas fa-heart text-blue-600"></i>
|
| 366 |
+
</div>
|
| 367 |
+
</div>
|
| 368 |
+
<div class="bg-blue-50 rounded-lg p-4 max-w-3xl">
|
| 369 |
+
<p class="text-gray-800">${message}</p>
|
| 370 |
+
</div>
|
| 371 |
+
`;
|
| 372 |
+
} else {
|
| 373 |
+
messageDiv.innerHTML = `
|
| 374 |
+
<div class="flex-shrink-0 mr-3 ml-auto">
|
| 375 |
+
<div class="bg-green-100 rounded-full p-2">
|
| 376 |
+
<i class="fas fa-user text-green-600"></i>
|
| 377 |
+
</div>
|
| 378 |
+
</div>
|
| 379 |
+
<div class="bg-green-50 rounded-lg p-4 max-w-3xl">
|
| 380 |
+
<p class="text-gray-800">${message}</p>
|
| 381 |
+
</div>
|
| 382 |
+
`;
|
| 383 |
+
}
|
| 384 |
+
|
| 385 |
+
conversationContainer.appendChild(messageDiv);
|
| 386 |
+
conversationContainer.scrollTop = conversationContainer.scrollHeight;
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
// Update responses table
|
| 390 |
+
function updateResponsesTable() {
|
| 391 |
+
responsesTable.innerHTML = '';
|
| 392 |
+
|
| 393 |
+
for (const key in responses) {
|
| 394 |
+
const response = responses[key];
|
| 395 |
+
const row = document.createElement('tr');
|
| 396 |
+
row.innerHTML = `
|
| 397 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${response.question}</td>
|
| 398 |
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${response.answer}</td>
|
| 399 |
+
`;
|
| 400 |
+
responsesTable.appendChild(row);
|
| 401 |
+
}
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
// Generate and download Word document
|
| 405 |
+
function generateWordDocument() {
|
| 406 |
+
const { Document, Paragraph, TextRun, Packer, HeadingLevel } = docx;
|
| 407 |
+
|
| 408 |
+
// Format current date
|
| 409 |
+
const today = new Date();
|
| 410 |
+
const dateString = today.toLocaleDateString('en-CA', {
|
| 411 |
+
year: 'numeric',
|
| 412 |
+
month: 'long',
|
| 413 |
+
day: 'numeric'
|
| 414 |
+
});
|
| 415 |
+
|
| 416 |
+
// Create document content
|
| 417 |
+
const doc = new Document({
|
| 418 |
+
sections: [{
|
| 419 |
+
properties: {},
|
| 420 |
+
children: [
|
| 421 |
+
new Paragraph({
|
| 422 |
+
text: "Canadian Cardiovascular Training Center",
|
| 423 |
+
heading: HeadingLevel.HEADING_1,
|
| 424 |
+
spacing: { after: 200 }
|
| 425 |
+
}),
|
| 426 |
+
new Paragraph({
|
| 427 |
+
text: "Virtual Physician Assistant - Pre-Screening Report",
|
| 428 |
+
heading: HeadingLevel.HEADING_2,
|
| 429 |
+
spacing: { after: 200 }
|
| 430 |
+
}),
|
| 431 |
+
new Paragraph({
|
| 432 |
+
text: `Report Date: ${dateString}`,
|
| 433 |
+
spacing: { after: 400 }
|
| 434 |
+
}),
|
| 435 |
+
new Paragraph({
|
| 436 |
+
text: `Patient Name: ${patientName.textContent}`,
|
| 437 |
+
spacing: { after: 100 }
|
| 438 |
+
}),
|
| 439 |
+
new Paragraph({
|
| 440 |
+
text: `Date of Birth: ${patientDob.textContent}`,
|
| 441 |
+
spacing: { after: 400 }
|
| 442 |
+
}),
|
| 443 |
+
new Paragraph({
|
| 444 |
+
text: "Pre-Screening Responses:",
|
| 445 |
+
heading: HeadingLevel.HEADING_3,
|
| 446 |
+
spacing: { after: 200 }
|
| 447 |
+
}),
|
| 448 |
+
// Add questions and answers
|
| 449 |
+
...Object.values(responses).map(response => {
|
| 450 |
+
return new Paragraph({
|
| 451 |
+
children: [
|
| 452 |
+
new TextRun({
|
| 453 |
+
text: response.question + ": ",
|
| 454 |
+
bold: true
|
| 455 |
+
}),
|
| 456 |
+
new TextRun({
|
| 457 |
+
text: response.answer
|
| 458 |
+
})
|
| 459 |
+
],
|
| 460 |
+
spacing: { after: 150 }
|
| 461 |
+
});
|
| 462 |
+
})
|
| 463 |
+
]
|
| 464 |
+
}]
|
| 465 |
+
});
|
| 466 |
+
|
| 467 |
+
// Generate and download the document
|
| 468 |
+
Packer.toBlob(doc).then(blob => {
|
| 469 |
+
const url = URL.createObjectURL(blob);
|
| 470 |
+
const a = document.createElement('a');
|
| 471 |
+
a.href = url;
|
| 472 |
+
a.download = `PreScreening_${patientName.textContent.replace(/\s+/g, '_')}_${dateString.replace(/,/g, '')}.docx`;
|
| 473 |
+
document.body.appendChild(a);
|
| 474 |
+
a.click();
|
| 475 |
+
document.body.removeChild(a);
|
| 476 |
+
URL.revokeObjectURL(url);
|
| 477 |
+
});
|
| 478 |
+
}
|
| 479 |
+
|
| 480 |
+
// Handle voice button click
|
| 481 |
+
voiceBtn.addEventListener('click', function() {
|
| 482 |
+
if (isListening) {
|
| 483 |
+
recognition.stop();
|
| 484 |
+
stopListening();
|
| 485 |
+
} else {
|
| 486 |
+
if (currentQuestionIndex === 0) {
|
| 487 |
+
speak(questions[currentQuestionIndex]);
|
| 488 |
+
} else {
|
| 489 |
+
startListening();
|
| 490 |
+
}
|
| 491 |
+
}
|
| 492 |
+
});
|
| 493 |
+
|
| 494 |
+
// Handle complete button click
|
| 495 |
+
completeBtn.addEventListener('click', function() {
|
| 496 |
+
speak("Thank you for completing the pre-screening questions. Please wait for the specialist to see you. Your responses have been recorded and will be reviewed by the doctor.");
|
| 497 |
+
addMessage('assistant', "Pre-screening completed. Please wait for the specialist to see you.");
|
| 498 |
+
completeBtn.classList.add('hidden');
|
| 499 |
+
downloadBtn.classList.remove('hidden');
|
| 500 |
+
|
| 501 |
+
// Disable voice button
|
| 502 |
+
voiceBtn.disabled = true;
|
| 503 |
+
voiceBtn.classList.remove('bg-red-600', 'bg-red-700', 'pulse');
|
| 504 |
+
voiceBtn.classList.add('bg-gray-400');
|
| 505 |
+
|
| 506 |
+
// Update status indicator
|
| 507 |
+
statusIndicator.innerHTML = `
|
| 508 |
+
<span class="relative flex h-3 w-3">
|
| 509 |
+
<span class="relative inline-flex rounded-full h-3 w-3 bg-gray-500"></span>
|
| 510 |
+
</span>
|
| 511 |
+
<span class="text-sm text-gray-600">Completed</span>
|
| 512 |
+
`;
|
| 513 |
+
});
|
| 514 |
+
|
| 515 |
+
// Handle download button click
|
| 516 |
+
downloadBtn.addEventListener('click', generateWordDocument);
|
| 517 |
+
|
| 518 |
+
// Speech recognition events
|
| 519 |
+
recognition.onresult = function(event) {
|
| 520 |
+
const transcript = event.results[0][0].transcript;
|
| 521 |
+
stopListening();
|
| 522 |
+
|
| 523 |
+
// Add user message to conversation
|
| 524 |
+
addMessage('user', transcript);
|
| 525 |
+
|
| 526 |
+
// Store response
|
| 527 |
+
responses[currentQuestionIndex].answer = transcript;
|
| 528 |
+
|
| 529 |
+
// Confirm the response back to the user
|
| 530 |
+
let confirmationMessage = "";
|
| 531 |
+
if (currentQuestionIndex === 0) {
|
| 532 |
+
// For name question
|
| 533 |
+
patientName.textContent = transcript;
|
| 534 |
+
confirmationMessage = `I have your name as ${transcript}.`;
|
| 535 |
+
} else if (currentQuestionIndex === 1) {
|
| 536 |
+
// For DOB question
|
| 537 |
+
patientDob.textContent = transcript;
|
| 538 |
+
confirmationMessage = `I have your date of birth as ${transcript}.`;
|
| 539 |
+
} else {
|
| 540 |
+
// For all other questions
|
| 541 |
+
confirmationMessage = `You answered: ${transcript}.`;
|
| 542 |
+
}
|
| 543 |
+
|
| 544 |
+
// Add confirmation message
|
| 545 |
+
setTimeout(() => {
|
| 546 |
+
addMessage('assistant', confirmationMessage);
|
| 547 |
+
|
| 548 |
+
// Update responses table
|
| 549 |
+
updateResponsesTable();
|
| 550 |
+
|
| 551 |
+
// Move to next question or complete
|
| 552 |
+
currentQuestionIndex++;
|
| 553 |
+
|
| 554 |
+
if (currentQuestionIndex < questions.length) {
|
| 555 |
+
setTimeout(() => {
|
| 556 |
+
speak(questions[currentQuestionIndex]);
|
| 557 |
+
}, 1000);
|
| 558 |
+
} else {
|
| 559 |
+
completeBtn.classList.remove('hidden');
|
| 560 |
+
}
|
| 561 |
+
}, 1000);
|
| 562 |
+
};
|
| 563 |
+
|
| 564 |
+
recognition.onerror = function(event) {
|
| 565 |
+
console.error('Speech recognition error', event.error);
|
| 566 |
+
stopListening();
|
| 567 |
+
|
| 568 |
+
if (event.error === 'no-speech') {
|
| 569 |
+
addMessage('assistant', "I didn't hear anything. Please try again.");
|
| 570 |
+
setTimeout(() => {
|
| 571 |
+
speak(questions[currentQuestionIndex]);
|
| 572 |
+
}, 1000);
|
| 573 |
+
} else {
|
| 574 |
+
addMessage('assistant', "There was an error with the speech recognition. Please try again.");
|
| 575 |
+
voiceBtn.classList.remove('bg-red-700', 'pulse');
|
| 576 |
+
voiceBtn.classList.add('bg-red-600');
|
| 577 |
+
}
|
| 578 |
+
};
|
| 579 |
+
|
| 580 |
+
// Start with the first question
|
| 581 |
+
setTimeout(() => {
|
| 582 |
+
speak(questions[0]);
|
| 583 |
+
}, 1000);
|
| 584 |
+
});
|
| 585 |
+
</script>
|
| 586 |
+
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=CCTCASSISTANT/cctc-assistantai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 587 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Create a webapp for Canadian Cardiovascular Training Center, the app will act as a Virtual Physician to assist specialist within their clinics. Currently, the patient would be seated in a room with the Physician assistant and asked pre screening questions to get a baseline of the patient whether they are having a follow up appointment or a new appointment. The questions routinely asked are "Whats your name and date of birth" "have you expirenced any chest pains within the last 2 mkmths?" "Have you been expirencing any shortness of breath?" "Do you struggle walking up or down flights of stairs?" "Have you had any recent changes to your medication?" "Have you have any surgical proceedures within the last 10 years?" "Are there any specific notes or details you'd like to mention to the doctor?",will specifically be using this virtual assistant to replace this role, all answers from the user must be noted down and written inorder for the specialist doctor to review when seeing the patient, addtionally i want the app main interface to be speech to speech allowing the user to directly talk to the app and having the app directly speak back and ask the pre screening questions. Once pre screening questions are done mention that the pre-screening is completed and to please wait for the specialist to see you
|
| 2 |
+
This is perfect so far, I just need you to confirm each of the patients given responses back to them before proceedings to the next question, also seperathe the question for "Whats your first and last name?" And "Whats your date of birth?", also at the end of the page before the footer I want you to place a clickable botton labeled "download summary" which will download the questions and client answers provided onto a word document, the word document must include a header with the Company name, app name and the report must include the current date. Addtionally, the virtual agent icon is a robot can you charge it to the heart icon instead. Otherwise keep everything else the same
|