@trainly/react 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/LICENSE +21 -0
- package/README.md +254 -0
- package/dist/TrainlyProvider.d.ts +12 -0
- package/dist/TrainlyProvider.js +250 -0
- package/dist/api/TrainlyClient.d.ts +18 -0
- package/dist/api/TrainlyClient.js +226 -0
- package/dist/components/TrainlyChat.d.ts +14 -0
- package/dist/components/TrainlyChat.js +101 -0
- package/dist/components/TrainlyStatus.d.ts +6 -0
- package/dist/components/TrainlyStatus.js +51 -0
- package/dist/components/TrainlyUpload.d.ts +10 -0
- package/dist/components/TrainlyUpload.js +136 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +15 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.js +3 -0
- package/dist/useTrainly.d.ts +18 -0
- package/dist/useTrainly.js +24 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Trainly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
# @trainly/react
|
|
2
|
+
|
|
3
|
+
**Dead simple RAG integration for React apps**
|
|
4
|
+
|
|
5
|
+
Go from `npm install` to working AI in under 5 minutes. No backend required, no complex setup, just install and use.
|
|
6
|
+
|
|
7
|
+
## 🚀 Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @trainly/react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Setup (2 lines)
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
// app/layout.tsx
|
|
19
|
+
import { TrainlyProvider } from "@trainly/react";
|
|
20
|
+
|
|
21
|
+
export default function RootLayout({ children }) {
|
|
22
|
+
return (
|
|
23
|
+
<html>
|
|
24
|
+
<body>
|
|
25
|
+
<TrainlyProvider appSecret="as_your_app_secret">
|
|
26
|
+
{children}
|
|
27
|
+
</TrainlyProvider>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Use anywhere (3 lines)
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
// Any component
|
|
38
|
+
import { useTrainly } from "@trainly/react";
|
|
39
|
+
|
|
40
|
+
function MyComponent() {
|
|
41
|
+
const { ask } = useTrainly();
|
|
42
|
+
|
|
43
|
+
const handleClick = async () => {
|
|
44
|
+
const answer = await ask("What is photosynthesis?");
|
|
45
|
+
console.log(answer); // Ready to use!
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return <button onClick={handleClick}>Ask AI</button>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**That's it!** No auth setup, no API routes, no session management.
|
|
53
|
+
|
|
54
|
+
## 📦 What's Included
|
|
55
|
+
|
|
56
|
+
### Core Hook
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
const {
|
|
60
|
+
ask, // (question: string) => Promise<string>
|
|
61
|
+
upload, // (file: File) => Promise<void>
|
|
62
|
+
isLoading, // boolean
|
|
63
|
+
isConnected, // boolean
|
|
64
|
+
error, // string | null
|
|
65
|
+
} = useTrainly();
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Pre-built Components
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { TrainlyChat, TrainlyUpload, TrainlyStatus } from '@trainly/react';
|
|
72
|
+
|
|
73
|
+
// Drop-in chat interface
|
|
74
|
+
<TrainlyChat height="400px" showCitations={true} />
|
|
75
|
+
|
|
76
|
+
// Drop-in file upload
|
|
77
|
+
<TrainlyUpload accept=".pdf,.doc,.txt" />
|
|
78
|
+
|
|
79
|
+
// Connection status indicator
|
|
80
|
+
<TrainlyStatus />
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 🎯 Complete Example
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { TrainlyProvider, TrainlyChat, TrainlyUpload } from "@trainly/react";
|
|
87
|
+
|
|
88
|
+
function App() {
|
|
89
|
+
return (
|
|
90
|
+
<TrainlyProvider appSecret="as_demo_secret_123">
|
|
91
|
+
<div>
|
|
92
|
+
<h1>My Document Assistant</h1>
|
|
93
|
+
|
|
94
|
+
{/* File upload area */}
|
|
95
|
+
<TrainlyUpload onUpload={(files) => console.log("Uploaded:", files)} />
|
|
96
|
+
|
|
97
|
+
{/* Chat interface */}
|
|
98
|
+
<TrainlyChat
|
|
99
|
+
height="500px"
|
|
100
|
+
placeholder="Ask about your documents..."
|
|
101
|
+
showCitations={true}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
</TrainlyProvider>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 🔧 Configuration Options
|
|
110
|
+
|
|
111
|
+
### Authentication Modes
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
// Mode 1: App Secret (recommended for multi-user apps)
|
|
115
|
+
<TrainlyProvider appSecret="as_secret_123" />
|
|
116
|
+
|
|
117
|
+
// Mode 2: With user context
|
|
118
|
+
<TrainlyProvider
|
|
119
|
+
appSecret="as_secret_123"
|
|
120
|
+
userId="user_123"
|
|
121
|
+
userEmail="user@example.com"
|
|
122
|
+
/>
|
|
123
|
+
|
|
124
|
+
// Mode 3: Direct API key (simple apps)
|
|
125
|
+
<TrainlyProvider apiKey="tk_chat_id_key" />
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Component Customization
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
<TrainlyChat
|
|
132
|
+
height="600px"
|
|
133
|
+
theme="dark"
|
|
134
|
+
placeholder="Ask me anything..."
|
|
135
|
+
showCitations={true}
|
|
136
|
+
enableFileUpload={true}
|
|
137
|
+
onMessage={(msg) => console.log(msg)}
|
|
138
|
+
onError={(err) => console.error(err)}
|
|
139
|
+
/>
|
|
140
|
+
|
|
141
|
+
<TrainlyUpload
|
|
142
|
+
variant="drag-drop" // or "button" or "minimal"
|
|
143
|
+
accept=".pdf,.doc,.txt"
|
|
144
|
+
maxSize="10MB"
|
|
145
|
+
multiple={false}
|
|
146
|
+
onUpload={(files) => console.log(files)}
|
|
147
|
+
/>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 🎨 Styling
|
|
151
|
+
|
|
152
|
+
Components use Tailwind classes by default but can be fully customized:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
<TrainlyChat
|
|
156
|
+
className="my-custom-chat"
|
|
157
|
+
height="400px"
|
|
158
|
+
/>
|
|
159
|
+
|
|
160
|
+
// Override with CSS
|
|
161
|
+
.my-custom-chat {
|
|
162
|
+
border: 2px solid blue;
|
|
163
|
+
border-radius: 12px;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 📖 API Reference
|
|
168
|
+
|
|
169
|
+
### useTrainly()
|
|
170
|
+
|
|
171
|
+
The main hook for interacting with Trainly.
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
const {
|
|
175
|
+
// Core functions
|
|
176
|
+
ask: (question: string) => Promise<string>,
|
|
177
|
+
askWithCitations: (question: string) => Promise<{answer: string, citations: Citation[]}>,
|
|
178
|
+
upload: (file: File) => Promise<UploadResult>,
|
|
179
|
+
|
|
180
|
+
// State
|
|
181
|
+
isLoading: boolean,
|
|
182
|
+
isConnected: boolean,
|
|
183
|
+
error: TrainlyError | null,
|
|
184
|
+
|
|
185
|
+
// Advanced
|
|
186
|
+
clearError: () => void,
|
|
187
|
+
reconnect: () => Promise<void>,
|
|
188
|
+
|
|
189
|
+
// For chat components
|
|
190
|
+
messages: ChatMessage[],
|
|
191
|
+
sendMessage: (content: string) => Promise<void>,
|
|
192
|
+
clearMessages: () => void,
|
|
193
|
+
} = useTrainly();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### TrainlyProvider Props
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
interface TrainlyProviderProps {
|
|
200
|
+
children: React.ReactNode;
|
|
201
|
+
appSecret?: string; // App secret from Trainly dashboard
|
|
202
|
+
apiKey?: string; // Direct API key (alternative to appSecret)
|
|
203
|
+
baseUrl?: string; // Custom API URL (defaults to trainly.com)
|
|
204
|
+
userId?: string; // Your app's user ID
|
|
205
|
+
userEmail?: string; // Your app's user email
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 🔍 Examples
|
|
210
|
+
|
|
211
|
+
Check out the `/examples` folder for complete implementations:
|
|
212
|
+
|
|
213
|
+
- **Simple Chat App** - Drop-in components
|
|
214
|
+
- **Custom Implementation** - Build your own UI
|
|
215
|
+
- **Multi-user App** - User-specific workspaces
|
|
216
|
+
- **File-focused App** - Document analysis focus
|
|
217
|
+
|
|
218
|
+
## 🛠️ Development
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Clone the repo
|
|
222
|
+
git clone https://github.com/trainly/react-sdk.git
|
|
223
|
+
cd react-sdk
|
|
224
|
+
|
|
225
|
+
# Install dependencies
|
|
226
|
+
npm install
|
|
227
|
+
|
|
228
|
+
# Build the package
|
|
229
|
+
npm run build
|
|
230
|
+
|
|
231
|
+
# Watch mode for development
|
|
232
|
+
npm run dev
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 📝 License
|
|
236
|
+
|
|
237
|
+
MIT - see LICENSE file for details.
|
|
238
|
+
|
|
239
|
+
## 🤝 Contributing
|
|
240
|
+
|
|
241
|
+
Contributions welcome! Please read CONTRIBUTING.md for guidelines.
|
|
242
|
+
|
|
243
|
+
## 🆘 Support
|
|
244
|
+
|
|
245
|
+
- 📖 [Documentation](https://trainly.com/docs/react-sdk)
|
|
246
|
+
- 💬 [Discord Community](https://discord.gg/trainly)
|
|
247
|
+
- 📧 [Email Support](mailto:support@trainly.com)
|
|
248
|
+
- 🐛 [Report Issues](https://github.com/trainly/react-sdk/issues)
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
**Made with ❤️ by the Trainly team**
|
|
253
|
+
|
|
254
|
+
_The simplest way to add AI to your React app_
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { TrainlyContextValue } from "./types";
|
|
3
|
+
export interface TrainlyProviderProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
appSecret?: string;
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
userId?: string;
|
|
9
|
+
userEmail?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function TrainlyProvider({ children, appSecret, apiKey, baseUrl, userId, userEmail, }: TrainlyProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function useTrainlyContext(): TrainlyContextValue;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.TrainlyProvider = TrainlyProvider;
|
|
49
|
+
exports.useTrainlyContext = useTrainlyContext;
|
|
50
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
51
|
+
var react_1 = require("react");
|
|
52
|
+
var TrainlyClient_1 = require("./api/TrainlyClient");
|
|
53
|
+
var TrainlyContext = (0, react_1.createContext)(undefined);
|
|
54
|
+
function TrainlyProvider(_a) {
|
|
55
|
+
var _this = this;
|
|
56
|
+
var children = _a.children, appSecret = _a.appSecret, apiKey = _a.apiKey, _b = _a.baseUrl, baseUrl = _b === void 0 ? "https://api.trainly.com" : _b, userId = _a.userId, userEmail = _a.userEmail;
|
|
57
|
+
var client = (0, react_1.useState)(function () {
|
|
58
|
+
return new TrainlyClient_1.TrainlyClient({
|
|
59
|
+
appSecret: appSecret,
|
|
60
|
+
apiKey: apiKey,
|
|
61
|
+
baseUrl: baseUrl,
|
|
62
|
+
userId: userId,
|
|
63
|
+
userEmail: userEmail,
|
|
64
|
+
});
|
|
65
|
+
})[0];
|
|
66
|
+
var _c = (0, react_1.useState)(false), isLoading = _c[0], setIsLoading = _c[1];
|
|
67
|
+
var _d = (0, react_1.useState)(false), isConnected = _d[0], setIsConnected = _d[1];
|
|
68
|
+
var _e = (0, react_1.useState)(null), error = _e[0], setError = _e[1];
|
|
69
|
+
var _f = (0, react_1.useState)([]), messages = _f[0], setMessages = _f[1];
|
|
70
|
+
// Auto-connect on mount
|
|
71
|
+
(0, react_1.useEffect)(function () {
|
|
72
|
+
connect();
|
|
73
|
+
}, []);
|
|
74
|
+
var connect = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
75
|
+
var err_1;
|
|
76
|
+
return __generator(this, function (_a) {
|
|
77
|
+
switch (_a.label) {
|
|
78
|
+
case 0:
|
|
79
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
80
|
+
setIsLoading(true);
|
|
81
|
+
setError(null);
|
|
82
|
+
return [4 /*yield*/, client.connect()];
|
|
83
|
+
case 1:
|
|
84
|
+
_a.sent();
|
|
85
|
+
setIsConnected(true);
|
|
86
|
+
return [3 /*break*/, 4];
|
|
87
|
+
case 2:
|
|
88
|
+
err_1 = _a.sent();
|
|
89
|
+
setError({
|
|
90
|
+
code: "CONNECTION_FAILED",
|
|
91
|
+
message: "Failed to connect to Trainly",
|
|
92
|
+
details: err_1,
|
|
93
|
+
});
|
|
94
|
+
setIsConnected(false);
|
|
95
|
+
return [3 /*break*/, 4];
|
|
96
|
+
case 3:
|
|
97
|
+
setIsLoading(false);
|
|
98
|
+
return [7 /*endfinally*/];
|
|
99
|
+
case 4: return [2 /*return*/];
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}); };
|
|
103
|
+
var ask = function (question) { return __awaiter(_this, void 0, void 0, function () {
|
|
104
|
+
var response, err_2, error_1;
|
|
105
|
+
return __generator(this, function (_a) {
|
|
106
|
+
switch (_a.label) {
|
|
107
|
+
case 0:
|
|
108
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
109
|
+
setIsLoading(true);
|
|
110
|
+
setError(null);
|
|
111
|
+
return [4 /*yield*/, client.ask(question)];
|
|
112
|
+
case 1:
|
|
113
|
+
response = _a.sent();
|
|
114
|
+
return [2 /*return*/, response.answer];
|
|
115
|
+
case 2:
|
|
116
|
+
err_2 = _a.sent();
|
|
117
|
+
error_1 = {
|
|
118
|
+
code: "QUERY_FAILED",
|
|
119
|
+
message: "Failed to get answer",
|
|
120
|
+
details: err_2,
|
|
121
|
+
};
|
|
122
|
+
setError(error_1);
|
|
123
|
+
throw error_1;
|
|
124
|
+
case 3:
|
|
125
|
+
setIsLoading(false);
|
|
126
|
+
return [7 /*endfinally*/];
|
|
127
|
+
case 4: return [2 /*return*/];
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}); };
|
|
131
|
+
var askWithCitations = function (question) { return __awaiter(_this, void 0, void 0, function () {
|
|
132
|
+
var response, err_3, error_2;
|
|
133
|
+
return __generator(this, function (_a) {
|
|
134
|
+
switch (_a.label) {
|
|
135
|
+
case 0:
|
|
136
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
137
|
+
setIsLoading(true);
|
|
138
|
+
setError(null);
|
|
139
|
+
return [4 /*yield*/, client.ask(question, { includeCitations: true })];
|
|
140
|
+
case 1:
|
|
141
|
+
response = _a.sent();
|
|
142
|
+
return [2 /*return*/, {
|
|
143
|
+
answer: response.answer,
|
|
144
|
+
citations: response.citations || [],
|
|
145
|
+
}];
|
|
146
|
+
case 2:
|
|
147
|
+
err_3 = _a.sent();
|
|
148
|
+
error_2 = {
|
|
149
|
+
code: "QUERY_FAILED",
|
|
150
|
+
message: "Failed to get answer with citations",
|
|
151
|
+
details: err_3,
|
|
152
|
+
};
|
|
153
|
+
setError(error_2);
|
|
154
|
+
throw error_2;
|
|
155
|
+
case 3:
|
|
156
|
+
setIsLoading(false);
|
|
157
|
+
return [7 /*endfinally*/];
|
|
158
|
+
case 4: return [2 /*return*/];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}); };
|
|
162
|
+
var upload = function (file) { return __awaiter(_this, void 0, void 0, function () {
|
|
163
|
+
var result, err_4, error_3;
|
|
164
|
+
return __generator(this, function (_a) {
|
|
165
|
+
switch (_a.label) {
|
|
166
|
+
case 0:
|
|
167
|
+
_a.trys.push([0, 2, 3, 4]);
|
|
168
|
+
setIsLoading(true);
|
|
169
|
+
setError(null);
|
|
170
|
+
return [4 /*yield*/, client.upload(file)];
|
|
171
|
+
case 1:
|
|
172
|
+
result = _a.sent();
|
|
173
|
+
return [2 /*return*/, result];
|
|
174
|
+
case 2:
|
|
175
|
+
err_4 = _a.sent();
|
|
176
|
+
error_3 = {
|
|
177
|
+
code: "UPLOAD_FAILED",
|
|
178
|
+
message: "Failed to upload file",
|
|
179
|
+
details: err_4,
|
|
180
|
+
};
|
|
181
|
+
setError(error_3);
|
|
182
|
+
throw error_3;
|
|
183
|
+
case 3:
|
|
184
|
+
setIsLoading(false);
|
|
185
|
+
return [7 /*endfinally*/];
|
|
186
|
+
case 4: return [2 /*return*/];
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}); };
|
|
190
|
+
var sendMessage = function (content) { return __awaiter(_this, void 0, void 0, function () {
|
|
191
|
+
var userMessage, response, assistantMessage_1, err_5;
|
|
192
|
+
return __generator(this, function (_a) {
|
|
193
|
+
switch (_a.label) {
|
|
194
|
+
case 0:
|
|
195
|
+
userMessage = {
|
|
196
|
+
id: Date.now().toString(),
|
|
197
|
+
role: "user",
|
|
198
|
+
content: content,
|
|
199
|
+
timestamp: new Date(),
|
|
200
|
+
};
|
|
201
|
+
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [userMessage], false); });
|
|
202
|
+
_a.label = 1;
|
|
203
|
+
case 1:
|
|
204
|
+
_a.trys.push([1, 3, , 4]);
|
|
205
|
+
return [4 /*yield*/, askWithCitations(content)];
|
|
206
|
+
case 2:
|
|
207
|
+
response = _a.sent();
|
|
208
|
+
assistantMessage_1 = {
|
|
209
|
+
id: (Date.now() + 1).toString(),
|
|
210
|
+
role: "assistant",
|
|
211
|
+
content: response.answer,
|
|
212
|
+
timestamp: new Date(),
|
|
213
|
+
citations: response.citations,
|
|
214
|
+
};
|
|
215
|
+
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantMessage_1], false); });
|
|
216
|
+
return [3 /*break*/, 4];
|
|
217
|
+
case 3:
|
|
218
|
+
err_5 = _a.sent();
|
|
219
|
+
// Error is already set by askWithCitations
|
|
220
|
+
console.error("Failed to send message:", err_5);
|
|
221
|
+
return [3 /*break*/, 4];
|
|
222
|
+
case 4: return [2 /*return*/];
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
}); };
|
|
226
|
+
var clearError = function () { return setError(null); };
|
|
227
|
+
var reconnect = function () { return connect(); };
|
|
228
|
+
var clearMessages = function () { return setMessages([]); };
|
|
229
|
+
var value = {
|
|
230
|
+
ask: ask,
|
|
231
|
+
askWithCitations: askWithCitations,
|
|
232
|
+
upload: upload,
|
|
233
|
+
isLoading: isLoading,
|
|
234
|
+
isConnected: isConnected,
|
|
235
|
+
error: error,
|
|
236
|
+
clearError: clearError,
|
|
237
|
+
reconnect: reconnect,
|
|
238
|
+
messages: messages,
|
|
239
|
+
sendMessage: sendMessage,
|
|
240
|
+
clearMessages: clearMessages,
|
|
241
|
+
};
|
|
242
|
+
return ((0, jsx_runtime_1.jsx)(TrainlyContext.Provider, { value: value, children: children }));
|
|
243
|
+
}
|
|
244
|
+
function useTrainlyContext() {
|
|
245
|
+
var context = (0, react_1.useContext)(TrainlyContext);
|
|
246
|
+
if (context === undefined) {
|
|
247
|
+
throw new Error("useTrainlyContext must be used within a TrainlyProvider");
|
|
248
|
+
}
|
|
249
|
+
return context;
|
|
250
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TrainlyConfig, Citation, UploadResult } from "../types";
|
|
2
|
+
interface QueryResponse {
|
|
3
|
+
answer: string;
|
|
4
|
+
citations?: Citation[];
|
|
5
|
+
}
|
|
6
|
+
export declare class TrainlyClient {
|
|
7
|
+
private config;
|
|
8
|
+
private scopedToken;
|
|
9
|
+
constructor(config: TrainlyConfig);
|
|
10
|
+
connect(): Promise<void>;
|
|
11
|
+
ask(question: string, options?: {
|
|
12
|
+
includeCitations?: boolean;
|
|
13
|
+
}): Promise<QueryResponse>;
|
|
14
|
+
upload(file: File): Promise<UploadResult>;
|
|
15
|
+
private extractChatId;
|
|
16
|
+
private generateAnonymousId;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.TrainlyClient = void 0;
|
|
40
|
+
var TrainlyClient = /** @class */ (function () {
|
|
41
|
+
function TrainlyClient(config) {
|
|
42
|
+
this.scopedToken = null;
|
|
43
|
+
this.config = config;
|
|
44
|
+
}
|
|
45
|
+
TrainlyClient.prototype.connect = function () {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
47
|
+
var response, error, data;
|
|
48
|
+
return __generator(this, function (_a) {
|
|
49
|
+
switch (_a.label) {
|
|
50
|
+
case 0:
|
|
51
|
+
if (this.config.apiKey) {
|
|
52
|
+
// Direct API key mode - no additional setup needed
|
|
53
|
+
this.scopedToken = this.config.apiKey;
|
|
54
|
+
return [2 /*return*/];
|
|
55
|
+
}
|
|
56
|
+
if (!this.config.appSecret) {
|
|
57
|
+
throw new Error("Either appSecret or apiKey must be provided");
|
|
58
|
+
}
|
|
59
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/privacy/apps/users/provision"), {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: "Bearer ".concat(this.config.appSecret),
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify({
|
|
66
|
+
end_user_id: this.config.userId || this.generateAnonymousId(),
|
|
67
|
+
capabilities: ["ask", "upload"],
|
|
68
|
+
}),
|
|
69
|
+
})];
|
|
70
|
+
case 1:
|
|
71
|
+
response = _a.sent();
|
|
72
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
73
|
+
return [4 /*yield*/, response.json()];
|
|
74
|
+
case 2:
|
|
75
|
+
error = _a.sent();
|
|
76
|
+
throw new Error("Failed to connect: ".concat(error.detail || response.statusText));
|
|
77
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
78
|
+
case 4:
|
|
79
|
+
data = _a.sent();
|
|
80
|
+
this.scopedToken = data.scoped_token;
|
|
81
|
+
return [2 /*return*/];
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
TrainlyClient.prototype.ask = function (question_1) {
|
|
87
|
+
return __awaiter(this, arguments, void 0, function (question, options) {
|
|
88
|
+
var url, headers, body, response, error, data;
|
|
89
|
+
if (options === void 0) { options = {}; }
|
|
90
|
+
return __generator(this, function (_a) {
|
|
91
|
+
switch (_a.label) {
|
|
92
|
+
case 0:
|
|
93
|
+
if (!this.scopedToken) {
|
|
94
|
+
throw new Error("Not connected. Call connect() first.");
|
|
95
|
+
}
|
|
96
|
+
url = this.config.apiKey
|
|
97
|
+
? "".concat(this.config.baseUrl, "/v1/").concat(this.extractChatId(), "/answer_question")
|
|
98
|
+
: "".concat(this.config.baseUrl, "/v1/privacy/query");
|
|
99
|
+
headers = {
|
|
100
|
+
"Content-Type": "application/json",
|
|
101
|
+
};
|
|
102
|
+
body = { question: question };
|
|
103
|
+
if (this.config.apiKey) {
|
|
104
|
+
headers["Authorization"] = "Bearer ".concat(this.config.apiKey);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
headers["x-scoped-token"] = this.scopedToken;
|
|
108
|
+
body.end_user_id = this.config.userId || this.generateAnonymousId();
|
|
109
|
+
body.include_citations = options.includeCitations || false;
|
|
110
|
+
}
|
|
111
|
+
return [4 /*yield*/, fetch(url, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: headers,
|
|
114
|
+
body: JSON.stringify(body),
|
|
115
|
+
})];
|
|
116
|
+
case 1:
|
|
117
|
+
response = _a.sent();
|
|
118
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
119
|
+
return [4 /*yield*/, response.json()];
|
|
120
|
+
case 2:
|
|
121
|
+
error = _a.sent();
|
|
122
|
+
throw new Error("Query failed: ".concat(error.detail || response.statusText));
|
|
123
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
124
|
+
case 4:
|
|
125
|
+
data = _a.sent();
|
|
126
|
+
return [2 /*return*/, {
|
|
127
|
+
answer: data.answer,
|
|
128
|
+
citations: data.citations || [],
|
|
129
|
+
}];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
TrainlyClient.prototype.upload = function (file) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
136
|
+
var formData, response, error, presignedResponse, error, upload_url, uploadResponse;
|
|
137
|
+
return __generator(this, function (_a) {
|
|
138
|
+
switch (_a.label) {
|
|
139
|
+
case 0:
|
|
140
|
+
if (!this.scopedToken) {
|
|
141
|
+
throw new Error("Not connected. Call connect() first.");
|
|
142
|
+
}
|
|
143
|
+
if (!this.config.apiKey) return [3 /*break*/, 4];
|
|
144
|
+
formData = new FormData();
|
|
145
|
+
formData.append("file", file);
|
|
146
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/").concat(this.extractChatId(), "/upload_file"), {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: {
|
|
149
|
+
Authorization: "Bearer ".concat(this.config.apiKey),
|
|
150
|
+
},
|
|
151
|
+
body: formData,
|
|
152
|
+
})];
|
|
153
|
+
case 1:
|
|
154
|
+
response = _a.sent();
|
|
155
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
156
|
+
return [4 /*yield*/, response.json()];
|
|
157
|
+
case 2:
|
|
158
|
+
error = _a.sent();
|
|
159
|
+
throw new Error("Upload failed: ".concat(error.detail || response.statusText));
|
|
160
|
+
case 3: return [2 /*return*/, {
|
|
161
|
+
success: true,
|
|
162
|
+
filename: file.name,
|
|
163
|
+
size: file.size,
|
|
164
|
+
message: "File uploaded successfully",
|
|
165
|
+
}];
|
|
166
|
+
case 4: return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/privacy/upload/presigned-url"), {
|
|
167
|
+
method: "POST",
|
|
168
|
+
headers: {
|
|
169
|
+
"Content-Type": "application/json",
|
|
170
|
+
"x-scoped-token": this.scopedToken,
|
|
171
|
+
},
|
|
172
|
+
body: JSON.stringify({
|
|
173
|
+
end_user_id: this.config.userId || this.generateAnonymousId(),
|
|
174
|
+
filename: file.name,
|
|
175
|
+
file_type: file.type,
|
|
176
|
+
}),
|
|
177
|
+
})];
|
|
178
|
+
case 5:
|
|
179
|
+
presignedResponse = _a.sent();
|
|
180
|
+
if (!!presignedResponse.ok) return [3 /*break*/, 7];
|
|
181
|
+
return [4 /*yield*/, presignedResponse.json()];
|
|
182
|
+
case 6:
|
|
183
|
+
error = _a.sent();
|
|
184
|
+
throw new Error("Failed to get upload URL: ".concat(error.detail || presignedResponse.statusText));
|
|
185
|
+
case 7: return [4 /*yield*/, presignedResponse.json()];
|
|
186
|
+
case 8:
|
|
187
|
+
upload_url = (_a.sent()).upload_url;
|
|
188
|
+
return [4 /*yield*/, fetch(upload_url, {
|
|
189
|
+
method: "PUT",
|
|
190
|
+
body: file,
|
|
191
|
+
headers: {
|
|
192
|
+
"Content-Type": file.type,
|
|
193
|
+
},
|
|
194
|
+
})];
|
|
195
|
+
case 9:
|
|
196
|
+
uploadResponse = _a.sent();
|
|
197
|
+
if (!uploadResponse.ok) {
|
|
198
|
+
throw new Error("Failed to upload file");
|
|
199
|
+
}
|
|
200
|
+
return [2 /*return*/, {
|
|
201
|
+
success: true,
|
|
202
|
+
filename: file.name,
|
|
203
|
+
size: file.size,
|
|
204
|
+
message: "File uploaded to your private workspace",
|
|
205
|
+
}];
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
TrainlyClient.prototype.extractChatId = function () {
|
|
211
|
+
if (!this.config.apiKey) {
|
|
212
|
+
throw new Error("API key not provided");
|
|
213
|
+
}
|
|
214
|
+
// Extract chat ID from API key format: tk_chat_id_rest
|
|
215
|
+
var parts = this.config.apiKey.split("_");
|
|
216
|
+
if (parts.length < 3) {
|
|
217
|
+
throw new Error("Invalid API key format");
|
|
218
|
+
}
|
|
219
|
+
return parts[1];
|
|
220
|
+
};
|
|
221
|
+
TrainlyClient.prototype.generateAnonymousId = function () {
|
|
222
|
+
return "anon_".concat(Math.random().toString(36).substr(2, 9));
|
|
223
|
+
};
|
|
224
|
+
return TrainlyClient;
|
|
225
|
+
}());
|
|
226
|
+
exports.TrainlyClient = TrainlyClient;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TrainlyChatProps {
|
|
2
|
+
height?: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
showCitations?: boolean;
|
|
6
|
+
enableFileUpload?: boolean;
|
|
7
|
+
theme?: "light" | "dark" | "auto";
|
|
8
|
+
onMessage?: (message: {
|
|
9
|
+
role: "user" | "assistant";
|
|
10
|
+
content: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
onError?: (error: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function TrainlyChat({ height, className, placeholder, showCitations, enableFileUpload, theme, onMessage, onError, }: TrainlyChatProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.TrainlyChat = TrainlyChat;
|
|
40
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
|
+
var react_1 = require("react");
|
|
42
|
+
var useTrainly_1 = require("../useTrainly");
|
|
43
|
+
function TrainlyChat(_a) {
|
|
44
|
+
var _this = this;
|
|
45
|
+
var _b = _a.height, height = _b === void 0 ? "400px" : _b, _c = _a.className, className = _c === void 0 ? "" : _c, _d = _a.placeholder, placeholder = _d === void 0 ? "Ask me anything..." : _d, _e = _a.showCitations, showCitations = _e === void 0 ? true : _e, _f = _a.enableFileUpload, enableFileUpload = _f === void 0 ? true : _f, _g = _a.theme, theme = _g === void 0 ? "auto" : _g, onMessage = _a.onMessage, onError = _a.onError;
|
|
46
|
+
var _h = (0, useTrainly_1.useTrainly)(), messages = _h.messages, sendMessage = _h.sendMessage, isLoading = _h.isLoading, error = _h.error, clearError = _h.clearError;
|
|
47
|
+
var _j = (0, react_1.useState)(""), input = _j[0], setInput = _j[1];
|
|
48
|
+
var messagesEndRef = (0, react_1.useRef)(null);
|
|
49
|
+
var fileInputRef = (0, react_1.useRef)(null);
|
|
50
|
+
// Auto-scroll to bottom
|
|
51
|
+
(0, react_1.useEffect)(function () {
|
|
52
|
+
var _a;
|
|
53
|
+
(_a = messagesEndRef.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: "smooth" });
|
|
54
|
+
}, [messages]);
|
|
55
|
+
// Handle errors
|
|
56
|
+
(0, react_1.useEffect)(function () {
|
|
57
|
+
if (error && onError) {
|
|
58
|
+
onError(error.message);
|
|
59
|
+
}
|
|
60
|
+
}, [error, onError]);
|
|
61
|
+
var handleSubmit = function (e) { return __awaiter(_this, void 0, void 0, function () {
|
|
62
|
+
var messageContent, err_1;
|
|
63
|
+
return __generator(this, function (_a) {
|
|
64
|
+
switch (_a.label) {
|
|
65
|
+
case 0:
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
if (!input.trim() || isLoading)
|
|
68
|
+
return [2 /*return*/];
|
|
69
|
+
messageContent = input.trim();
|
|
70
|
+
setInput("");
|
|
71
|
+
_a.label = 1;
|
|
72
|
+
case 1:
|
|
73
|
+
_a.trys.push([1, 3, , 4]);
|
|
74
|
+
return [4 /*yield*/, sendMessage(messageContent)];
|
|
75
|
+
case 2:
|
|
76
|
+
_a.sent();
|
|
77
|
+
onMessage === null || onMessage === void 0 ? void 0 : onMessage({ role: "user", content: messageContent });
|
|
78
|
+
return [3 /*break*/, 4];
|
|
79
|
+
case 3:
|
|
80
|
+
err_1 = _a.sent();
|
|
81
|
+
console.error("Failed to send message:", err_1);
|
|
82
|
+
return [3 /*break*/, 4];
|
|
83
|
+
case 4: return [2 /*return*/];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}); };
|
|
87
|
+
var handleFileUpload = function (e) {
|
|
88
|
+
var _a;
|
|
89
|
+
var file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
90
|
+
if (file) {
|
|
91
|
+
// This would trigger upload and add a system message
|
|
92
|
+
console.log("File selected:", file.name);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var baseClasses = "\n flex flex-col border border-gray-200 rounded-lg overflow-hidden\n ".concat(theme === "dark" ? "bg-gray-900 text-white border-gray-700" : "bg-white text-gray-900", "\n ").concat(className, "\n ");
|
|
96
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: baseClasses, style: { height: height }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex-1 overflow-y-auto p-4 space-y-4", children: [messages.length === 0 && ((0, jsx_runtime_1.jsx)("div", { className: "text-center text-gray-500 py-8", children: (0, jsx_runtime_1.jsx)("p", { children: "Start a conversation by asking a question!" }) })), messages.map(function (message) { return ((0, jsx_runtime_1.jsx)("div", { className: "flex ".concat(message.role === "user" ? "justify-end" : "justify-start"), children: (0, jsx_runtime_1.jsxs)("div", { className: "\n max-w-[80%] p-3 rounded-lg\n ".concat(message.role === "user"
|
|
97
|
+
? "bg-blue-500 text-white rounded-br-none"
|
|
98
|
+
: "bg-gray-100 text-gray-900 rounded-bl-none", "\n "), children: [(0, jsx_runtime_1.jsx)("p", { className: "whitespace-pre-wrap", children: message.content }), showCitations &&
|
|
99
|
+
message.citations &&
|
|
100
|
+
message.citations.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-3 pt-3 border-t border-gray-300", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs font-semibold mb-2", children: "Sources:" }), message.citations.map(function (citation, idx) { return ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs bg-white bg-opacity-20 p-2 rounded mb-1", children: [(0, jsx_runtime_1.jsx)("p", { className: "font-medium", children: citation.source }), (0, jsx_runtime_1.jsxs)("p", { className: "opacity-75", children: ["\"", citation.snippet, "\""] })] }, idx)); })] }))] }) }, message.id)); }), isLoading && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-start", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-gray-100 text-gray-900 p-3 rounded-lg rounded-bl-none", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500" }), (0, jsx_runtime_1.jsx)("span", { children: "Thinking..." })] }) }) })), (0, jsx_runtime_1.jsx)("div", { ref: messagesEndRef })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "px-4 py-2 bg-red-50 border-t border-red-200 text-red-700 text-sm", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { children: error.message }), (0, jsx_runtime_1.jsx)("button", { onClick: clearError, className: "text-red-500 hover:text-red-700", children: "\u00D7" })] }) })), (0, jsx_runtime_1.jsx)("div", { className: "border-t border-gray-200 p-4", children: (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "flex gap-2", children: [enableFileUpload && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: ".pdf,.doc,.docx,.txt,.md", onChange: handleFileUpload, className: "hidden" }), (0, jsx_runtime_1.jsx)("button", { type: "button", onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: "px-3 py-2 text-gray-500 hover:text-gray-700 border border-gray-300 rounded-lg", title: "Upload file", children: "\uD83D\uDCCE" })] })), (0, jsx_runtime_1.jsx)("input", { type: "text", value: input, onChange: function (e) { return setInput(e.target.value); }, placeholder: placeholder, disabled: isLoading, className: "flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" }), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: isLoading || !input.trim(), className: "px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed", children: "Send" })] }) })] }));
|
|
101
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface TrainlyStatusProps {
|
|
2
|
+
showDetails?: boolean;
|
|
3
|
+
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "inline";
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function TrainlyStatus({ showDetails, position, className, }: TrainlyStatusProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TrainlyStatus = TrainlyStatus;
|
|
4
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
var useTrainly_1 = require("../useTrainly");
|
|
6
|
+
function TrainlyStatus(_a) {
|
|
7
|
+
var _b = _a.showDetails, showDetails = _b === void 0 ? true : _b, _c = _a.position, position = _c === void 0 ? "inline" : _c, _d = _a.className, className = _d === void 0 ? "" : _d;
|
|
8
|
+
var _e = (0, useTrainly_1.useTrainly)(), isConnected = _e.isConnected, isLoading = _e.isLoading, error = _e.error;
|
|
9
|
+
var getStatusInfo = function () {
|
|
10
|
+
if (error) {
|
|
11
|
+
return {
|
|
12
|
+
icon: "❌",
|
|
13
|
+
text: "Connection failed",
|
|
14
|
+
color: "text-red-600 bg-red-50 border-red-200",
|
|
15
|
+
details: error.message,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (isLoading) {
|
|
19
|
+
return {
|
|
20
|
+
icon: "🔄",
|
|
21
|
+
text: "Connecting...",
|
|
22
|
+
color: "text-yellow-600 bg-yellow-50 border-yellow-200",
|
|
23
|
+
details: "Establishing connection to Trainly",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (isConnected) {
|
|
27
|
+
return {
|
|
28
|
+
icon: "✅",
|
|
29
|
+
text: "Connected",
|
|
30
|
+
color: "text-green-600 bg-green-50 border-green-200",
|
|
31
|
+
details: "Ready to answer questions",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
icon: "⚠️",
|
|
36
|
+
text: "Disconnected",
|
|
37
|
+
color: "text-gray-600 bg-gray-50 border-gray-200",
|
|
38
|
+
details: "Not connected to Trainly",
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
var status = getStatusInfo();
|
|
42
|
+
var positionClasses = {
|
|
43
|
+
"top-left": "fixed top-4 left-4 z-50",
|
|
44
|
+
"top-right": "fixed top-4 right-4 z-50",
|
|
45
|
+
"bottom-left": "fixed bottom-4 left-4 z-50",
|
|
46
|
+
"bottom-right": "fixed bottom-4 right-4 z-50",
|
|
47
|
+
inline: "",
|
|
48
|
+
};
|
|
49
|
+
var baseClasses = "\n inline-flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium\n ".concat(status.color, "\n ").concat(positionClasses[position], "\n ").concat(className, "\n ");
|
|
50
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: baseClasses, children: [(0, jsx_runtime_1.jsx)("span", { className: status.icon === "🔄" ? "animate-spin" : "", children: status.icon }), (0, jsx_runtime_1.jsx)("span", { children: status.text }), showDetails && status.details && ((0, jsx_runtime_1.jsxs)("span", { className: "text-xs opacity-75 ml-1", children: ["- ", status.details] }))] }));
|
|
51
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface TrainlyUploadProps {
|
|
2
|
+
variant?: "drag-drop" | "button" | "minimal";
|
|
3
|
+
accept?: string;
|
|
4
|
+
maxSize?: string;
|
|
5
|
+
multiple?: boolean;
|
|
6
|
+
className?: string;
|
|
7
|
+
onUpload?: (files: File[]) => void;
|
|
8
|
+
onError?: (error: string) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function TrainlyUpload({ variant, accept, maxSize, multiple, className, onUpload, onError, }: TrainlyUploadProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.TrainlyUpload = TrainlyUpload;
|
|
40
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
|
+
var react_1 = require("react");
|
|
42
|
+
var useTrainly_1 = require("../useTrainly");
|
|
43
|
+
function TrainlyUpload(_a) {
|
|
44
|
+
var _this = this;
|
|
45
|
+
var _b = _a.variant, variant = _b === void 0 ? "drag-drop" : _b, _c = _a.accept, accept = _c === void 0 ? ".pdf,.doc,.docx,.txt,.md" : _c, _d = _a.maxSize, maxSize = _d === void 0 ? "10MB" : _d, _e = _a.multiple, multiple = _e === void 0 ? false : _e, _f = _a.className, className = _f === void 0 ? "" : _f, onUpload = _a.onUpload, onError = _a.onError;
|
|
46
|
+
var _g = (0, useTrainly_1.useTrainly)(), upload = _g.upload, isLoading = _g.isLoading;
|
|
47
|
+
var _h = (0, react_1.useState)(false), isDragOver = _h[0], setIsDragOver = _h[1];
|
|
48
|
+
var fileInputRef = (0, react_1.useRef)(null);
|
|
49
|
+
var maxSizeBytes = parseMaxSize(maxSize);
|
|
50
|
+
var handleFiles = function (files) { return __awaiter(_this, void 0, void 0, function () {
|
|
51
|
+
var fileArray, _i, fileArray_1, file, error, _a, fileArray_2, file, err_1;
|
|
52
|
+
return __generator(this, function (_b) {
|
|
53
|
+
switch (_b.label) {
|
|
54
|
+
case 0:
|
|
55
|
+
if (!files)
|
|
56
|
+
return [2 /*return*/];
|
|
57
|
+
fileArray = Array.from(files);
|
|
58
|
+
// Validate files
|
|
59
|
+
for (_i = 0, fileArray_1 = fileArray; _i < fileArray_1.length; _i++) {
|
|
60
|
+
file = fileArray_1[_i];
|
|
61
|
+
if (maxSizeBytes && file.size > maxSizeBytes) {
|
|
62
|
+
error = "File \"".concat(file.name, "\" is too large. Maximum size is ").concat(maxSize, ".");
|
|
63
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
64
|
+
return [2 /*return*/];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
_b.label = 1;
|
|
68
|
+
case 1:
|
|
69
|
+
_b.trys.push([1, 6, , 7]);
|
|
70
|
+
_a = 0, fileArray_2 = fileArray;
|
|
71
|
+
_b.label = 2;
|
|
72
|
+
case 2:
|
|
73
|
+
if (!(_a < fileArray_2.length)) return [3 /*break*/, 5];
|
|
74
|
+
file = fileArray_2[_a];
|
|
75
|
+
return [4 /*yield*/, upload(file)];
|
|
76
|
+
case 3:
|
|
77
|
+
_b.sent();
|
|
78
|
+
_b.label = 4;
|
|
79
|
+
case 4:
|
|
80
|
+
_a++;
|
|
81
|
+
return [3 /*break*/, 2];
|
|
82
|
+
case 5:
|
|
83
|
+
onUpload === null || onUpload === void 0 ? void 0 : onUpload(fileArray);
|
|
84
|
+
return [3 /*break*/, 7];
|
|
85
|
+
case 6:
|
|
86
|
+
err_1 = _b.sent();
|
|
87
|
+
onError === null || onError === void 0 ? void 0 : onError(err_1 instanceof Error ? err_1.message : "Upload failed");
|
|
88
|
+
return [3 /*break*/, 7];
|
|
89
|
+
case 7: return [2 /*return*/];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}); };
|
|
93
|
+
var handleDrop = function (e) {
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
setIsDragOver(false);
|
|
96
|
+
handleFiles(e.dataTransfer.files);
|
|
97
|
+
};
|
|
98
|
+
var handleDragOver = function (e) {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
setIsDragOver(true);
|
|
101
|
+
};
|
|
102
|
+
var handleDragLeave = function (e) {
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
setIsDragOver(false);
|
|
105
|
+
};
|
|
106
|
+
var handleFileSelect = function (e) {
|
|
107
|
+
handleFiles(e.target.files);
|
|
108
|
+
};
|
|
109
|
+
if (variant === "button") {
|
|
110
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileSelect, className: "hidden" }), (0, jsx_runtime_1.jsx)("button", { onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: isLoading, className: "\n px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600\n disabled:opacity-50 disabled:cursor-not-allowed\n ".concat(className, "\n "), children: isLoading ? "Uploading..." : "Upload Files" })] }));
|
|
111
|
+
}
|
|
112
|
+
if (variant === "minimal") {
|
|
113
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileSelect, className: "hidden" }), (0, jsx_runtime_1.jsx)("button", { onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: isLoading, className: "text-blue-500 hover:text-blue-600 underline ".concat(className), children: isLoading ? "Uploading..." : "Upload" })] }));
|
|
114
|
+
}
|
|
115
|
+
// Default: drag-drop variant
|
|
116
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, onChange: handleFileSelect, className: "hidden" }), (0, jsx_runtime_1.jsx)("div", { onDrop: handleDrop, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, className: "\n border-2 border-dashed border-gray-300 rounded-lg p-8 text-center cursor-pointer\n transition-colors duration-200\n ".concat(isDragOver ? "border-blue-500 bg-blue-50" : "hover:border-gray-400", "\n ").concat(isLoading ? "opacity-50 cursor-not-allowed" : "", "\n ").concat(className, "\n "), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-4xl", children: "\uD83D\uDCC4" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-lg font-medium text-gray-700", children: isLoading
|
|
117
|
+
? "Uploading..."
|
|
118
|
+
: "Drop files here or click to upload" }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-gray-500 mt-2", children: ["Supports: ", accept.replace(/\./g, "").toUpperCase(), " files up to", " ", maxSize] })] })] }) })] }));
|
|
119
|
+
}
|
|
120
|
+
function parseMaxSize(maxSize) {
|
|
121
|
+
var match = maxSize.match(/^(\d+)\s*(GB|MB|KB)?$/i);
|
|
122
|
+
if (!match)
|
|
123
|
+
return null;
|
|
124
|
+
var value = parseInt(match[1]);
|
|
125
|
+
var unit = (match[2] || "B").toUpperCase();
|
|
126
|
+
switch (unit) {
|
|
127
|
+
case "GB":
|
|
128
|
+
return value * 1024 * 1024 * 1024;
|
|
129
|
+
case "MB":
|
|
130
|
+
return value * 1024 * 1024;
|
|
131
|
+
case "KB":
|
|
132
|
+
return value * 1024;
|
|
133
|
+
default:
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { TrainlyProvider } from "./TrainlyProvider";
|
|
2
|
+
export { useTrainly } from "./useTrainly";
|
|
3
|
+
export { TrainlyChat } from "./components/TrainlyChat";
|
|
4
|
+
export { TrainlyUpload } from "./components/TrainlyUpload";
|
|
5
|
+
export { TrainlyStatus } from "./components/TrainlyStatus";
|
|
6
|
+
export type { TrainlyProviderProps, TrainlyConfig, ChatMessage, Citation, UploadResult, TrainlyError, } from "./types";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TrainlyStatus = exports.TrainlyUpload = exports.TrainlyChat = exports.useTrainly = exports.TrainlyProvider = void 0;
|
|
4
|
+
// Main exports for @trainly/react SDK
|
|
5
|
+
var TrainlyProvider_1 = require("./TrainlyProvider");
|
|
6
|
+
Object.defineProperty(exports, "TrainlyProvider", { enumerable: true, get: function () { return TrainlyProvider_1.TrainlyProvider; } });
|
|
7
|
+
var useTrainly_1 = require("./useTrainly");
|
|
8
|
+
Object.defineProperty(exports, "useTrainly", { enumerable: true, get: function () { return useTrainly_1.useTrainly; } });
|
|
9
|
+
// Pre-built components
|
|
10
|
+
var TrainlyChat_1 = require("./components/TrainlyChat");
|
|
11
|
+
Object.defineProperty(exports, "TrainlyChat", { enumerable: true, get: function () { return TrainlyChat_1.TrainlyChat; } });
|
|
12
|
+
var TrainlyUpload_1 = require("./components/TrainlyUpload");
|
|
13
|
+
Object.defineProperty(exports, "TrainlyUpload", { enumerable: true, get: function () { return TrainlyUpload_1.TrainlyUpload; } });
|
|
14
|
+
var TrainlyStatus_1 = require("./components/TrainlyStatus");
|
|
15
|
+
Object.defineProperty(exports, "TrainlyStatus", { enumerable: true, get: function () { return TrainlyStatus_1.TrainlyStatus; } });
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface TrainlyConfig {
|
|
2
|
+
appSecret?: string;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
userId?: string;
|
|
6
|
+
userEmail?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface TrainlyProviderProps {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
appSecret?: string;
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
userId?: string;
|
|
14
|
+
userEmail?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ChatMessage {
|
|
17
|
+
id: string;
|
|
18
|
+
role: "user" | "assistant";
|
|
19
|
+
content: string;
|
|
20
|
+
timestamp: Date;
|
|
21
|
+
citations?: Citation[];
|
|
22
|
+
}
|
|
23
|
+
export interface Citation {
|
|
24
|
+
snippet: string;
|
|
25
|
+
score: number;
|
|
26
|
+
source: string;
|
|
27
|
+
page?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface UploadResult {
|
|
30
|
+
success: boolean;
|
|
31
|
+
filename: string;
|
|
32
|
+
size: number;
|
|
33
|
+
message?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface TrainlyError {
|
|
36
|
+
code: string;
|
|
37
|
+
message: string;
|
|
38
|
+
details?: any;
|
|
39
|
+
}
|
|
40
|
+
export interface TrainlyContextValue {
|
|
41
|
+
ask: (question: string) => Promise<string>;
|
|
42
|
+
askWithCitations: (question: string) => Promise<{
|
|
43
|
+
answer: string;
|
|
44
|
+
citations: Citation[];
|
|
45
|
+
}>;
|
|
46
|
+
upload: (file: File) => Promise<UploadResult>;
|
|
47
|
+
isLoading: boolean;
|
|
48
|
+
isConnected: boolean;
|
|
49
|
+
error: TrainlyError | null;
|
|
50
|
+
clearError: () => void;
|
|
51
|
+
reconnect: () => Promise<void>;
|
|
52
|
+
messages: ChatMessage[];
|
|
53
|
+
sendMessage: (content: string) => Promise<void>;
|
|
54
|
+
clearMessages: () => void;
|
|
55
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main hook for using Trainly in your React components
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* function MyComponent() {
|
|
7
|
+
* const { ask, upload, isLoading } = useTrainly();
|
|
8
|
+
*
|
|
9
|
+
* const handleQuestion = async () => {
|
|
10
|
+
* const answer = await ask("What is photosynthesis?");
|
|
11
|
+
* console.log(answer);
|
|
12
|
+
* };
|
|
13
|
+
*
|
|
14
|
+
* return <button onClick={handleQuestion}>Ask AI</button>;
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function useTrainly(): import("./types").TrainlyContextValue;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useTrainly = useTrainly;
|
|
4
|
+
var TrainlyProvider_1 = require("./TrainlyProvider");
|
|
5
|
+
/**
|
|
6
|
+
* Main hook for using Trainly in your React components
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const { ask, upload, isLoading } = useTrainly();
|
|
12
|
+
*
|
|
13
|
+
* const handleQuestion = async () => {
|
|
14
|
+
* const answer = await ask("What is photosynthesis?");
|
|
15
|
+
* console.log(answer);
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* return <button onClick={handleQuestion}>Ask AI</button>;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function useTrainly() {
|
|
23
|
+
return (0, TrainlyProvider_1.useTrainlyContext)();
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trainly/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Dead simple RAG integration for React apps",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"clean": "rm -rf dist",
|
|
11
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
12
|
+
"test": "echo \"No tests yet\" && exit 0"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"rag",
|
|
16
|
+
"ai",
|
|
17
|
+
"chatbot",
|
|
18
|
+
"documents",
|
|
19
|
+
"react",
|
|
20
|
+
"trainly",
|
|
21
|
+
"retrieval-augmented-generation",
|
|
22
|
+
"semantic-search",
|
|
23
|
+
"document-chat"
|
|
24
|
+
],
|
|
25
|
+
"author": "Trainly",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"react": ">=16.8.0",
|
|
29
|
+
"react-dom": ">=16.8.0"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/react": "^18.0.0",
|
|
34
|
+
"@types/react-dom": "^18.0.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist/**/*",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/trainly/react-sdk.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://trainly.com/docs/react-sdk",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/trainly/react-sdk/issues"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|