vorqard-ai-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # VORQARD AI Health Assistant SDK
2
+
3
+ [![GitHub](https://img.shields.io/badge/GitHub-AbhivornGroupIn%2FVORQARD__SDK__AI-blue?logo=github)](https://github.com/AbhivornGroupIn/VORQARD_SDK_AI)
4
+
5
+ The VORQARD AI SDK is a standalone React Native / Expo module that provides a conversational AI clinical health assistant and a structured medical report analyzer.
6
+
7
+ ---
8
+
9
+ ## 🚀 Step-by-Step Integration Guide
10
+
11
+ Follow these steps to integrate the AI SDK into your React Native / Expo application (such as the Groupin App):
12
+
13
+ ### Step 1: Copy the SDK Folder
14
+ Copy the `VORQARD_AI_SDK` directory into your project structure. A common setup is to place it side-by-side with your host application:
15
+ ```text
16
+ /my-workspace
17
+ ├── groupin-app/ (Your main mobile application directory)
18
+ └── VORQARD_AI_SDK/ (This SDK directory)
19
+ ```
20
+
21
+ ### Step 2: Install Peer Dependencies
22
+ The SDK relies on standard Expo and React Native libraries for image picking, safe area views, icons, and network requests.
23
+
24
+ Run the following command in your main application folder (`groupin-app/`):
25
+ ```bash
26
+ npx expo install axios expo-linear-gradient expo-image-picker expo-camera @expo/vector-icons react-native-safe-area-context
27
+ ```
28
+
29
+ ### Step 3: Link the SDK to Your App
30
+ In your main application folder (`groupin-app/`), install the SDK package as a local file dependency by running:
31
+ ```bash
32
+ npm install ../VORQARD_AI_SDK
33
+ ```
34
+ *(This automatically adds `"vorqard-ai-sdk": "file:../VORQARD_AI_SDK"` to your dependencies in `package.json` and configures node module resolution)*.
35
+
36
+ ### Step 4: Render the AI Assistant Screen
37
+ Import `VorqardAIAssistant` and add it to any screen, layout, or modal in your navigation stack.
38
+
39
+ Here is a basic template:
40
+
41
+ ```javascript
42
+ import React from 'react';
43
+ import { SafeAreaView, StyleSheet } from 'react-native';
44
+ import { VorqardAIAssistant } from 'vorqard-ai-sdk';
45
+
46
+ export default function AIExpertScreen({ navigation }) {
47
+ // Retrieve the patient's authenticated token and first name from your app's auth state
48
+ const userToken = "eyJhbGciOi..."; // Active patient JWT session token
49
+ const patientName = "Jagadish"; // Used for personalized greeting
50
+
51
+ return (
52
+ <SafeAreaView style={styles.container}>
53
+ <VorqardAIAssistant
54
+ backendUrl="https://app.vorqard.com/api" // VORQARD production API endpoint
55
+ userToken={userToken} // Authentication JWT
56
+ patientName={patientName} // Custom patient name
57
+ onClose={() => navigation.goBack()} // Callback when close/back button is pressed
58
+ aiLogo={require('./assets/AI_Icon.png')} // Optional: custom icon for AI replies
59
+ />
60
+ </SafeAreaView>
61
+ );
62
+ }
63
+
64
+ const styles = StyleSheet.create({
65
+ container: {
66
+ flex: 1,
67
+ },
68
+ });
69
+ ```
70
+
71
+ ---
72
+
73
+ ## 🛠 Advanced / Decoupled Usage
74
+
75
+ If you want to render your own custom user interface and only use the state management and API integration layer of the SDK, you can import the initialization client and custom hooks directly:
76
+
77
+ ```javascript
78
+ import { initSDKClient, getSDKClient, useHealthChat } from 'vorqard-ai-sdk';
79
+
80
+ // 1. Initialize the HTTP client configuration
81
+ initSDKClient('https://app.vorqard.com/api', 'JWT_TOKEN_HERE');
82
+
83
+ // 2. Consume the custom health chat state hook in your own component
84
+ const MyCustomChat = () => {
85
+ const { messages, sendMessage, loading } = useHealthChat('chat', 'Jagadish');
86
+ // messages contains: [{ id, role, content, ui_action, timestamp }]
87
+ // sendMessage is a function to send the next prompt
88
+ };
89
+ ```
90
+
91
+ ---
92
+
93
+ ## 🌐 Backend API Endpoints Reference
94
+
95
+ The SDK automatically communicates with the following backend routes. Ensure your API gateway/server allows the client's JWT token authorization on these endpoints:
96
+
97
+ ### 1. Patient Dashboard Context
98
+ * **Path:** `GET /patients/dashboard/me`
99
+ * **Headers:** `Authorization: Bearer <userToken>`
100
+ * **Description:** Fetches core summary details of the logged-in patient (e.g. name, date of last visit) to personalize the greeting.
101
+
102
+ ### 2. Patient Medical Records
103
+ * **Path:** `GET /patients/records/me`
104
+ * **Headers:** `Authorization: Bearer <userToken>`
105
+ * **Description:** Fetches past clinical records and consult history to provide relevant diagnostic context to the AI model.
106
+
107
+ ### 3. AI Health Chat Engine
108
+ * **Path:** `POST /patients/ai/chat`
109
+ * **Headers:** `Authorization: Bearer <userToken>`
110
+ * **Request Body:**
111
+ ```json
112
+ {
113
+ "message": "book appointment",
114
+ "history": [
115
+ { "role": "user", "content": "hello" },
116
+ { "role": "assistant", "content": "Hi there! How can I help you today?" }
117
+ ]
118
+ }
119
+ ```
120
+ * **Response Body:**
121
+ ```json
122
+ {
123
+ "response": "Here is a list of hospital-associated doctors...",
124
+ "ui_action": {
125
+ "type": "selection",
126
+ "title": "Select Doctor",
127
+ "options": [
128
+ { "id": "129", "label": "Dr. Veeha Reddy", "name": "Dr. Veeha Reddy" }
129
+ ]
130
+ }
131
+ }
132
+ ```
133
+ * **Description:** The chat router interface. It passes user utterances and conversational history to return clinical AI responses and rich-action metadata.
134
+
135
+ ### 4. AI Report Analyzer (Optional)
136
+ * **Path:** `POST /patients/ai/analyze-report`
137
+ * **Headers:** `Authorization: Bearer <userToken>`
138
+ * **Request Body:** `Multipart Form-Data` (keys: `file`)
139
+ * **Description:** Submits physical medical report images for OCR scanning and structured health scoring.
140
+
141
+ ---
142
+
143
+ ## 🤝 Integration Path Options
144
+
145
+ Groupin can choose one of two integration approaches based on their requirements:
146
+
147
+ ---
148
+
149
+ ### Option A: SDK Integration (Recommended — AI-powered)
150
+ Use the SDK component described in this README. The AI chat handles hospital search, doctor discovery, slot picking, and appointment booking — all through a single conversational interface.
151
+
152
+ **What Groupin needs to provide:**
153
+ - `backendUrl` — VORQARD API base URL
154
+ - `userToken` — Patient JWT token (from OTP login)
155
+
156
+ **Endpoints used internally by SDK (no manual calls needed):**
157
+
158
+ | Endpoint | Method | Purpose |
159
+ |---|---|---|
160
+ | `/auth/send-otp-mobile` | POST | Send OTP to patient phone |
161
+ | `/auth/verify-otp-mobile` | POST | Verify OTP → get JWT token |
162
+ | `/patients/ai/chat` | POST | Full AI booking + health chat |
163
+ | `/patients/ai/analyze-report` | POST | Medical report OCR analysis |
164
+
165
+ ---
166
+
167
+ ### Option B: Direct Partner API (Custom UI — no SDK required)
168
+ If Groupin prefers to build their own UI and call VORQARD APIs directly from their backend server.
169
+
170
+ **Authentication:** All requests must include the partner API key in the header:
171
+ ```
172
+ X-Api-Key: <provided_by_vorqard>
173
+ ```
174
+
175
+ **Backend URL:** `https://app.vorqard.com/api`
176
+
177
+ **Available Partner Endpoints:**
178
+
179
+ | Endpoint | Method | Purpose |
180
+ |---|---|---|
181
+ | `/partner/groupin/sync-user` | POST | Register/sync a Groupin user as a VORQARD patient |
182
+ | `/partner/groupin/hospitals` | GET | Fetch all available hospitals |
183
+ | `/partner/groupin/doctors` | GET | Fetch doctors (filter by specialty or hospital) |
184
+ | `/partner/groupin/book-appointment` | POST | Book an appointment directly |
185
+
186
+ **Example — Sync User Request Body:**
187
+ ```json
188
+ {
189
+ "phone_number": "9876543210",
190
+ "user_name": "Ravi Kumar",
191
+ "email": "ravi@example.com",
192
+ "gender": "Male",
193
+ "date_of_birth": "1990-05-15",
194
+ "blood_group": "O+",
195
+ "location": "Hyderabad"
196
+ }
197
+ ```
198
+
199
+ **Example — Book Appointment Request Body:**
200
+ ```json
201
+ {
202
+ "vorqard_patient_id": 42,
203
+ "vorqard_doctor_id": 7,
204
+ "date": "2026-06-20",
205
+ "time_slot": "10:00"
206
+ }
207
+ ```
208
+
209
+
Binary file
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "vorqard-ai-sdk",
3
+ "version": "1.0.0",
4
+ "description": "Standalone React Native SDK for VORQARD AI Health Assistant and Report Analyzer",
5
+ "main": "src/index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/AbhivornGroupIn/VORQARD_SDK_AI.git"
9
+ },
10
+ "homepage": "https://github.com/AbhivornGroupIn/VORQARD_SDK_AI#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/AbhivornGroupIn/VORQARD_SDK_AI/issues"
13
+ },
14
+ "peerDependencies": {
15
+ "react": ">=18.0.0",
16
+ "react-native": ">=0.70.0",
17
+ "axios": "^1.0.0",
18
+ "react-native-linear-gradient": "*",
19
+ "react-native-image-crop-picker": "*",
20
+ "react-native-vision-camera": "*",
21
+ "react-native-vector-icons": "*",
22
+ "react-native-safe-area-context": "*"
23
+ },
24
+ "keywords": [
25
+ "vorqard",
26
+ "ai",
27
+ "sdk",
28
+ "react-native",
29
+ "healthcare"
30
+ ],
31
+ "author": "VORQARD Developer",
32
+ "license": "Abhivorn Technologies"
33
+ }
34
+
@@ -0,0 +1,22 @@
1
+ import axios from 'axios';
2
+
3
+ let client = null;
4
+
5
+ export const initSDKClient = (backendUrl, token) => {
6
+ client = axios.create({
7
+ baseURL: backendUrl,
8
+ headers: {
9
+ 'Content-Type': 'application/json',
10
+ ...(token ? { Authorization: `Bearer ${token}` } : {})
11
+ }
12
+ });
13
+ };
14
+
15
+ export const getSDKClient = () => {
16
+ if (!client) {
17
+ console.warn('VORQARD AI SDK: Client was not initialized. Call initSDKClient(backendUrl, token) first.');
18
+ // Fallback to basic client
19
+ client = axios.create();
20
+ }
21
+ return client;
22
+ };
@@ -0,0 +1,5 @@
1
+ export { DoctorTypeSelectionCard } from './cards/DoctorTypeSelectionCard';
2
+ export { HospitalSelectionList, HospitalProfileCard } from './cards/HospitalCards';
3
+ export { DoctorSelectionList, DoctorProfileCard } from './cards/DoctorCards';
4
+ export { SlotSelectionCard } from './cards/SlotSelectionCard';
5
+ export { BookingConfirmationCard } from './cards/BookingConfirmationCard';
@@ -0,0 +1,208 @@
1
+ import React from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ TextInput,
6
+ TouchableOpacity,
7
+ Image,
8
+ StyleSheet,
9
+ Dimensions,
10
+ ActivityIndicator,
11
+ Linking,
12
+ Platform,
13
+ } from 'react-native';
14
+ import Ionicons from 'react-native-vector-icons/Ionicons';
15
+ import LinearGradient from 'react-native-linear-gradient';
16
+ import { styles } from './ChatStyles';
17
+ import {
18
+ DoctorTypeSelectionCard,
19
+ HospitalSelectionList,
20
+ HospitalProfileCard,
21
+ DoctorSelectionList,
22
+ DoctorProfileCard,
23
+ SlotSelectionCard,
24
+ BookingConfirmationCard
25
+ } from './ChatCards';
26
+
27
+ const { width: SCREEN_WIDTH } = Dimensions.get('window');
28
+
29
+ // ─── Message Bubble ───────────────────────────────────────────────────────────
30
+ export const MessageBubble = ({ item, aiLogo, onOptionPress }) => {
31
+ const isUser = item.role === 'user';
32
+
33
+ const renderAssistantText = (content) => {
34
+ const parts = content.split(/(VORQARD AI|Vorqard AI)/gi);
35
+ return (
36
+ <Text style={styles.assistantText}>
37
+ {parts.map((part, i) =>
38
+ /VORQARD AI/i.test(part) ? (
39
+ <Text key={i} style={styles.highlightText}>{part}</Text>
40
+ ) : (
41
+ <Text key={i}>{part}</Text>
42
+ )
43
+ )}
44
+ </Text>
45
+ );
46
+ };
47
+
48
+ // 7. Route UI Action to the correct Rich Component
49
+ const renderUIAction = () => {
50
+ if (!item.ui_action) return null;
51
+ const { type, title, options, doctor, hospital, selected_date } = item.ui_action;
52
+
53
+ if (type === 'selection') {
54
+ if (title === 'Select Doctor Type') {
55
+ return <DoctorTypeSelectionCard options={options} onOptionPress={onOptionPress} />;
56
+ }
57
+ if (title === 'Select Hospital') {
58
+ return <HospitalSelectionList options={options} onOptionPress={onOptionPress} />;
59
+ }
60
+ if (title === 'Select Doctor') {
61
+ return <DoctorSelectionList options={options} onOptionPress={onOptionPress} />;
62
+ }
63
+ // Fallback selection list
64
+ return (
65
+ <View style={styles.optionsContainer}>
66
+ {options.map((opt) => (
67
+ <TouchableOpacity
68
+ key={opt.id}
69
+ style={styles.optionButton}
70
+ onPress={() => onOptionPress?.(opt)}
71
+ activeOpacity={0.7}
72
+ >
73
+ <Text style={styles.optionButtonText}>{opt.label}</Text>
74
+ </TouchableOpacity>
75
+ ))}
76
+ </View>
77
+ );
78
+ }
79
+
80
+ if (type === 'doctor_profile') {
81
+ return <DoctorProfileCard doctor={doctor} options={options} onOptionPress={onOptionPress} />;
82
+ }
83
+
84
+ if (type === 'hospital_profile') {
85
+ return <HospitalProfileCard hospital={hospital} options={options} onOptionPress={onOptionPress} />;
86
+ }
87
+
88
+ if (type === 'slot_selection') {
89
+ return <SlotSelectionCard doctor={doctor} selectedDate={selected_date} options={options} onOptionPress={onOptionPress} />;
90
+ }
91
+
92
+ if (type === 'booking_confirmation') {
93
+ return <BookingConfirmationCard ui={item.ui_action} onOptionPress={onOptionPress} />;
94
+ }
95
+
96
+ return null;
97
+ };
98
+
99
+ return (
100
+ <View style={[styles.bubbleContainer, isUser ? styles.userAlign : styles.assistantAlign]}>
101
+ {!isUser && (
102
+ aiLogo ? (
103
+ <Image source={aiLogo} style={styles.avatarImage} />
104
+ ) : (
105
+ <View style={styles.avatarFallback}>
106
+ <Ionicons name="sparkles" size={14} color="#FFF" />
107
+ </View>
108
+ )
109
+ )}
110
+
111
+ {isUser ? (
112
+ <LinearGradient
113
+ colors={['#6366F1', '#3B82F6']}
114
+ start={{ x: 0, y: 0 }}
115
+ end={{ x: 1, y: 1 }}
116
+ style={[styles.bubble, styles.userBubble]}
117
+ >
118
+ <Text style={styles.userText}>{item.content}</Text>
119
+ {item.timestamp && (
120
+ <Text style={styles.userTime}>
121
+ {new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
122
+ </Text>
123
+ )}
124
+ </LinearGradient>
125
+ ) : (
126
+ <View style={{ flexDirection: 'column', maxWidth: SCREEN_WIDTH * 0.76 }}>
127
+ <View style={[styles.bubble, styles.assistantBubble]}>
128
+ {renderAssistantText(item.content)}
129
+ {item.timestamp && (
130
+ <Text style={styles.assistantTime}>
131
+ {new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
132
+ </Text>
133
+ )}
134
+ </View>
135
+ {renderUIAction()}
136
+ </View>
137
+ )}
138
+ </View>
139
+ );
140
+ };
141
+
142
+ // ─── Input Panel ──────────────────────────────────────────────────────────────
143
+ export const InputPanel = ({ value, onChangeText, onSend, onVoicePress, loading, aiLogo }) => {
144
+ const hasText = value.trim().length > 0;
145
+
146
+ return (
147
+ <View style={styles.inputOuterContainer}>
148
+ <LinearGradient
149
+ colors={['#6366F1', '#EC4899', '#F97316']}
150
+ start={{ x: 0, y: 0 }}
151
+ end={{ x: 1, y: 0 }}
152
+ style={styles.inputBorderGradient}
153
+ >
154
+ <View style={styles.inputInner}>
155
+ {aiLogo ? (
156
+ <Image source={aiLogo} style={{ width: 18, height: 18, marginLeft: 2, borderRadius: 4 }} />
157
+ ) : (
158
+ <Ionicons name="sparkles" size={18} color="#6366F1" style={{ marginLeft: 2 }} />
159
+ )}
160
+
161
+ <TextInput
162
+ placeholder="Ask Vorqard AI about reports, history..."
163
+ placeholderTextColor="#94A3B8"
164
+ value={value}
165
+ onChangeText={onChangeText}
166
+ style={styles.textInput}
167
+ multiline
168
+ maxLength={500}
169
+ />
170
+
171
+ <View style={styles.rightIcons}>
172
+ {!hasText && (
173
+ <TouchableOpacity style={styles.iconBtn} activeOpacity={0.7}>
174
+ <Ionicons name="attach" size={20} color="#94A3B8" />
175
+ </TouchableOpacity>
176
+ )}
177
+
178
+ {!hasText && (
179
+ <TouchableOpacity style={styles.iconBtn} onPress={onVoicePress} activeOpacity={0.7}>
180
+ <Ionicons name="mic" size={20} color="#94A3B8" />
181
+ </TouchableOpacity>
182
+ )}
183
+
184
+ <TouchableOpacity
185
+ onPress={() => onSend(value)}
186
+ disabled={!hasText || loading}
187
+ activeOpacity={0.8}
188
+ >
189
+ <LinearGradient
190
+ colors={hasText ? ['#10B981', '#3B82F6'] : ['#E2E8F0', '#E2E8F0']}
191
+ start={{ x: 0, y: 0 }}
192
+ end={{ x: 1, y: 1 }}
193
+ style={styles.sendButton}
194
+ >
195
+ {loading ? (
196
+ <ActivityIndicator color="#FFF" size="small" />
197
+ ) : (
198
+ <Ionicons name="arrow-up" size={18} color={hasText ? '#FFF' : '#94A3B8'} />
199
+ )}
200
+ </LinearGradient>
201
+ </TouchableOpacity>
202
+ </View>
203
+ </View>
204
+ </LinearGradient>
205
+ </View>
206
+ );
207
+ };
208
+