nextjs-chatbot-ui 1.4.0 ā 1.5.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 +145 -5
- package/api/chat.ts +97 -0
- package/api/database/collections.ts +80 -0
- package/api/database/columns.ts +80 -0
- package/api/database/process-embeddings.ts +154 -0
- package/api/database/test.ts +67 -0
- package/hooks/useAdminSetup.ts +86 -0
- package/hooks/useChatbot.ts +27 -0
- package/index.tsx +9 -5
- package/package.json +27 -5
- package/scripts/setup.js +550 -0
package/scripts/setup.js
ADDED
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
console.log('š Setting up nextjs-chatbot-ui API routes...\n');
|
|
7
|
+
|
|
8
|
+
const projectRoot = process.cwd();
|
|
9
|
+
const isAppRouter = fs.existsSync(path.join(projectRoot, 'app'));
|
|
10
|
+
|
|
11
|
+
if (!isAppRouter && !fs.existsSync(path.join(projectRoot, 'pages'))) {
|
|
12
|
+
console.error('ā Error: Next.js project not found. Please run this in a Next.js project directory.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const apiDir = isAppRouter
|
|
17
|
+
? path.join(projectRoot, 'app', 'api')
|
|
18
|
+
: path.join(projectRoot, 'pages', 'api');
|
|
19
|
+
|
|
20
|
+
// Create API directory if it doesn't exist
|
|
21
|
+
if (!fs.existsSync(apiDir)) {
|
|
22
|
+
fs.mkdirSync(apiDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// API route templates
|
|
26
|
+
const routes = {
|
|
27
|
+
'chat': `import { NextRequest, NextResponse } from 'next/server';
|
|
28
|
+
import { ChromaClient } from 'chromadb';
|
|
29
|
+
import OpenAI from 'openai';
|
|
30
|
+
|
|
31
|
+
const openai = new OpenAI({
|
|
32
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const chromaClient = new ChromaClient({
|
|
36
|
+
path: process.env.CHROMADB_URL || 'http://localhost:8000',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export async function POST(request: NextRequest) {
|
|
40
|
+
try {
|
|
41
|
+
const { message, userInfo } = await request.json();
|
|
42
|
+
|
|
43
|
+
if (!message) {
|
|
44
|
+
return NextResponse.json(
|
|
45
|
+
{ error: 'Message is required' },
|
|
46
|
+
{ status: 400 }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
51
|
+
return NextResponse.json(
|
|
52
|
+
{ error: 'OPENAI_API_KEY is not set in environment variables' },
|
|
53
|
+
{ status: 500 }
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Get query embedding
|
|
58
|
+
const queryEmbedding = await openai.embeddings.create({
|
|
59
|
+
model: 'text-embedding-3-small',
|
|
60
|
+
input: message,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Search in ChromaDB
|
|
64
|
+
const collectionName = process.env.CHROMA_COLLECTION_NAME || 'db_default';
|
|
65
|
+
let chromaCollection;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
chromaCollection = await chromaClient.getCollection({
|
|
69
|
+
name: collectionName,
|
|
70
|
+
});
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return NextResponse.json({
|
|
73
|
+
message: 'Vector database not initialized. Please use AdminSetup to process embeddings first.',
|
|
74
|
+
response: 'Vector database not initialized. Please use AdminSetup to process embeddings first.',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const results = await chromaCollection.query({
|
|
79
|
+
queryEmbeddings: [queryEmbedding.data[0].embedding],
|
|
80
|
+
nResults: 5,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const contexts = results.documents[0] || [];
|
|
84
|
+
const contextText = contexts.length > 0
|
|
85
|
+
? contexts.join('\\n\\n')
|
|
86
|
+
: 'No relevant context found.';
|
|
87
|
+
|
|
88
|
+
const completion = await openai.chat.completions.create({
|
|
89
|
+
model: process.env.OPENAI_MODEL || 'gpt-3.5-turbo',
|
|
90
|
+
messages: [
|
|
91
|
+
{
|
|
92
|
+
role: 'system',
|
|
93
|
+
content: 'You are a helpful assistant that answers questions based on the provided context. If the context does not contain relevant information, say so politely.',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
role: 'user',
|
|
97
|
+
content: \`Context:\\n\${contextText}\\n\\nQuestion: \${message}\\n\\nAnswer:\`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
temperature: 0.7,
|
|
101
|
+
max_tokens: 500,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const answer = completion.choices[0].message.content;
|
|
105
|
+
|
|
106
|
+
return NextResponse.json({
|
|
107
|
+
message: answer,
|
|
108
|
+
response: answer,
|
|
109
|
+
});
|
|
110
|
+
} catch (error: any) {
|
|
111
|
+
console.error('Chat error:', error);
|
|
112
|
+
return NextResponse.json(
|
|
113
|
+
{
|
|
114
|
+
message: error.message || 'Failed to process message',
|
|
115
|
+
response: error.message || 'Failed to process message',
|
|
116
|
+
},
|
|
117
|
+
{ status: 500 }
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
`,
|
|
122
|
+
'database/test': `import { NextRequest, NextResponse } from 'next/server';
|
|
123
|
+
import { MongoClient } from 'mongodb';
|
|
124
|
+
import { Client } from 'pg';
|
|
125
|
+
|
|
126
|
+
export async function POST(request: NextRequest) {
|
|
127
|
+
try {
|
|
128
|
+
const { databaseType, connection } = await request.json();
|
|
129
|
+
|
|
130
|
+
if (!databaseType || !connection) {
|
|
131
|
+
return NextResponse.json(
|
|
132
|
+
{ success: false, message: 'Database type and connection details are required' },
|
|
133
|
+
{ status: 400 }
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (databaseType === 'mongodb') {
|
|
138
|
+
try {
|
|
139
|
+
const uri = connection.connectionString ||
|
|
140
|
+
\`mongodb://\${connection.username ? \`\${connection.username}:\${connection.password}@\` : ''}\${connection.host}:\${connection.port || 27017}/\${connection.database}\`;
|
|
141
|
+
|
|
142
|
+
const client = new MongoClient(uri);
|
|
143
|
+
await client.connect();
|
|
144
|
+
await client.db().admin().ping();
|
|
145
|
+
await client.close();
|
|
146
|
+
|
|
147
|
+
return NextResponse.json({ success: true, message: 'Connection successful' });
|
|
148
|
+
} catch (error: any) {
|
|
149
|
+
return NextResponse.json(
|
|
150
|
+
{ success: false, message: error.message || 'MongoDB connection failed' },
|
|
151
|
+
{ status: 500 }
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
} else if (databaseType === 'postgresql') {
|
|
155
|
+
try {
|
|
156
|
+
const client = new Client({
|
|
157
|
+
host: connection.host,
|
|
158
|
+
port: connection.port || 5432,
|
|
159
|
+
database: connection.database,
|
|
160
|
+
user: connection.username,
|
|
161
|
+
password: connection.password,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await client.connect();
|
|
165
|
+
await client.query('SELECT 1');
|
|
166
|
+
await client.end();
|
|
167
|
+
|
|
168
|
+
return NextResponse.json({ success: true, message: 'Connection successful' });
|
|
169
|
+
} catch (error: any) {
|
|
170
|
+
return NextResponse.json(
|
|
171
|
+
{ success: false, message: error.message || 'PostgreSQL connection failed' },
|
|
172
|
+
{ status: 500 }
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
return NextResponse.json(
|
|
177
|
+
{ success: false, message: 'Unsupported database type' },
|
|
178
|
+
{ status: 400 }
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
} catch (error: any) {
|
|
182
|
+
console.error('Test connection error:', error);
|
|
183
|
+
return NextResponse.json(
|
|
184
|
+
{ success: false, message: error.message || 'Connection test failed' },
|
|
185
|
+
{ status: 500 }
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`,
|
|
190
|
+
'database/collections': `import { NextRequest, NextResponse } from 'next/server';
|
|
191
|
+
import { MongoClient } from 'mongodb';
|
|
192
|
+
import { Client } from 'pg';
|
|
193
|
+
|
|
194
|
+
export async function POST(request: NextRequest) {
|
|
195
|
+
try {
|
|
196
|
+
const { databaseType, connection } = await request.json();
|
|
197
|
+
|
|
198
|
+
if (!databaseType || !connection) {
|
|
199
|
+
return NextResponse.json(
|
|
200
|
+
{ collections: [], tables: [] },
|
|
201
|
+
{ status: 400 }
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (databaseType === 'mongodb') {
|
|
206
|
+
try {
|
|
207
|
+
const uri = connection.connectionString ||
|
|
208
|
+
\`mongodb://\${connection.username ? \`\${connection.username}:\${connection.password}@\` : ''}\${connection.host}:\${connection.port || 27017}/\${connection.database}\`;
|
|
209
|
+
|
|
210
|
+
const client = new MongoClient(uri);
|
|
211
|
+
await client.connect();
|
|
212
|
+
const db = client.db(connection.database);
|
|
213
|
+
const collections = await db.listCollections().toArray();
|
|
214
|
+
await client.close();
|
|
215
|
+
|
|
216
|
+
return NextResponse.json({
|
|
217
|
+
collections: collections.map(c => c.name),
|
|
218
|
+
tables: collections.map(c => c.name),
|
|
219
|
+
});
|
|
220
|
+
} catch (error: any) {
|
|
221
|
+
return NextResponse.json(
|
|
222
|
+
{ collections: [], tables: [], error: error.message },
|
|
223
|
+
{ status: 500 }
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
} else if (databaseType === 'postgresql') {
|
|
227
|
+
try {
|
|
228
|
+
const client = new Client({
|
|
229
|
+
host: connection.host,
|
|
230
|
+
port: connection.port || 5432,
|
|
231
|
+
database: connection.database,
|
|
232
|
+
user: connection.username,
|
|
233
|
+
password: connection.password,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await client.connect();
|
|
237
|
+
const result = await client.query(\`
|
|
238
|
+
SELECT table_name
|
|
239
|
+
FROM information_schema.tables
|
|
240
|
+
WHERE table_schema = 'public'
|
|
241
|
+
\`);
|
|
242
|
+
await client.end();
|
|
243
|
+
|
|
244
|
+
const tables = result.rows.map(row => row.table_name);
|
|
245
|
+
|
|
246
|
+
return NextResponse.json({
|
|
247
|
+
collections: tables,
|
|
248
|
+
tables: tables,
|
|
249
|
+
});
|
|
250
|
+
} catch (error: any) {
|
|
251
|
+
return NextResponse.json(
|
|
252
|
+
{ collections: [], tables: [], error: error.message },
|
|
253
|
+
{ status: 500 }
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
return NextResponse.json(
|
|
258
|
+
{ collections: [], tables: [] },
|
|
259
|
+
{ status: 400 }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
} catch (error: any) {
|
|
263
|
+
console.error('Fetch collections error:', error);
|
|
264
|
+
return NextResponse.json(
|
|
265
|
+
{ collections: [], tables: [], error: error.message },
|
|
266
|
+
{ status: 500 }
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
`,
|
|
271
|
+
'database/columns': `import { NextRequest, NextResponse } from 'next/server';
|
|
272
|
+
import { MongoClient } from 'mongodb';
|
|
273
|
+
import { Client } from 'pg';
|
|
274
|
+
|
|
275
|
+
export async function POST(request: NextRequest) {
|
|
276
|
+
try {
|
|
277
|
+
const { databaseType, connection, collection } = await request.json();
|
|
278
|
+
|
|
279
|
+
if (!databaseType || !connection || !collection) {
|
|
280
|
+
return NextResponse.json(
|
|
281
|
+
{ columns: [] },
|
|
282
|
+
{ status: 400 }
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (databaseType === 'mongodb') {
|
|
287
|
+
try {
|
|
288
|
+
const uri = connection.connectionString ||
|
|
289
|
+
\`mongodb://\${connection.username ? \`\${connection.username}:\${connection.password}@\` : ''}\${connection.host}:\${connection.port || 27017}/\${connection.database}\`;
|
|
290
|
+
|
|
291
|
+
const client = new MongoClient(uri);
|
|
292
|
+
await client.connect();
|
|
293
|
+
const db = client.db(connection.database);
|
|
294
|
+
const mongoCollection = db.collection(collection);
|
|
295
|
+
|
|
296
|
+
const sampleDoc = await mongoCollection.findOne({});
|
|
297
|
+
await client.close();
|
|
298
|
+
|
|
299
|
+
const columns = sampleDoc ? Object.keys(sampleDoc).filter(key => key !== '_id') : [];
|
|
300
|
+
|
|
301
|
+
return NextResponse.json({ columns });
|
|
302
|
+
} catch (error: any) {
|
|
303
|
+
return NextResponse.json(
|
|
304
|
+
{ columns: [], error: error.message },
|
|
305
|
+
{ status: 500 }
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
} else if (databaseType === 'postgresql') {
|
|
309
|
+
try {
|
|
310
|
+
const client = new Client({
|
|
311
|
+
host: connection.host,
|
|
312
|
+
port: connection.port || 5432,
|
|
313
|
+
database: connection.database,
|
|
314
|
+
user: connection.username,
|
|
315
|
+
password: connection.password,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
await client.connect();
|
|
319
|
+
const result = await client.query(\`
|
|
320
|
+
SELECT column_name
|
|
321
|
+
FROM information_schema.columns
|
|
322
|
+
WHERE table_schema = 'public'
|
|
323
|
+
AND table_name = $1
|
|
324
|
+
\`, [collection]);
|
|
325
|
+
await client.end();
|
|
326
|
+
|
|
327
|
+
const columns = result.rows.map(row => row.column_name);
|
|
328
|
+
|
|
329
|
+
return NextResponse.json({ columns });
|
|
330
|
+
} catch (error: any) {
|
|
331
|
+
return NextResponse.json(
|
|
332
|
+
{ columns: [], error: error.message },
|
|
333
|
+
{ status: 500 }
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
return NextResponse.json(
|
|
338
|
+
{ columns: [] },
|
|
339
|
+
{ status: 400 }
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
} catch (error: any) {
|
|
343
|
+
console.error('Fetch columns error:', error);
|
|
344
|
+
return NextResponse.json(
|
|
345
|
+
{ columns: [], error: error.message },
|
|
346
|
+
{ status: 500 }
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
`,
|
|
351
|
+
'database/process-embeddings': `import { NextRequest, NextResponse } from 'next/server';
|
|
352
|
+
import { MongoClient } from 'mongodb';
|
|
353
|
+
import { Client } from 'pg';
|
|
354
|
+
import { ChromaClient } from 'chromadb';
|
|
355
|
+
import OpenAI from 'openai';
|
|
356
|
+
|
|
357
|
+
const openai = new OpenAI({
|
|
358
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const chromaClient = new ChromaClient({
|
|
362
|
+
path: process.env.CHROMADB_URL || 'http://localhost:8000',
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
export async function POST(request: NextRequest) {
|
|
366
|
+
try {
|
|
367
|
+
const { connection, collections, columnSelection } = await request.json();
|
|
368
|
+
|
|
369
|
+
if (!process.env.OPENAI_API_KEY) {
|
|
370
|
+
return NextResponse.json(
|
|
371
|
+
{ success: false, message: 'OPENAI_API_KEY is not set in environment variables' },
|
|
372
|
+
{ status: 500 }
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (!connection || !collections || !Array.isArray(collections) || collections.length === 0) {
|
|
377
|
+
return NextResponse.json(
|
|
378
|
+
{ success: false, message: 'Connection and collections are required' },
|
|
379
|
+
{ status: 400 }
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const databaseType = connection.type || 'mongodb';
|
|
384
|
+
const dbName = connection.database;
|
|
385
|
+
|
|
386
|
+
let db: any;
|
|
387
|
+
let client: any;
|
|
388
|
+
|
|
389
|
+
if (databaseType === 'mongodb') {
|
|
390
|
+
const uri = connection.connectionString ||
|
|
391
|
+
\`mongodb://\${connection.username ? \`\${connection.username}:\${connection.password}@\` : ''}\${connection.host}:\${connection.port || 27017}/\${dbName}\`;
|
|
392
|
+
client = new MongoClient(uri);
|
|
393
|
+
await client.connect();
|
|
394
|
+
db = client.db(dbName);
|
|
395
|
+
} else if (databaseType === 'postgresql' || databaseType === 'postgres') {
|
|
396
|
+
client = new Client({
|
|
397
|
+
host: connection.host,
|
|
398
|
+
port: connection.port || 5432,
|
|
399
|
+
database: dbName,
|
|
400
|
+
user: connection.username,
|
|
401
|
+
password: connection.password,
|
|
402
|
+
});
|
|
403
|
+
await client.connect();
|
|
404
|
+
} else {
|
|
405
|
+
return NextResponse.json(
|
|
406
|
+
{ success: false, message: 'Unsupported database type' },
|
|
407
|
+
{ status: 400 }
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const collectionName = process.env.CHROMA_COLLECTION_NAME || \`db_\${dbName}\`;
|
|
412
|
+
let chromaCollection;
|
|
413
|
+
try {
|
|
414
|
+
chromaCollection = await chromaClient.getOrCreateCollection({
|
|
415
|
+
name: collectionName,
|
|
416
|
+
});
|
|
417
|
+
} catch (error) {
|
|
418
|
+
chromaCollection = await chromaClient.createCollection({
|
|
419
|
+
name: collectionName,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let totalProcessed = 0;
|
|
424
|
+
|
|
425
|
+
for (const collConfig of collections) {
|
|
426
|
+
const { collection: collName, columns } = collConfig;
|
|
427
|
+
|
|
428
|
+
if (!columns || columns.length === 0) continue;
|
|
429
|
+
|
|
430
|
+
let documents: any[] = [];
|
|
431
|
+
|
|
432
|
+
if (databaseType === 'mongodb') {
|
|
433
|
+
const mongoCollection = db.collection(collName);
|
|
434
|
+
documents = await mongoCollection.find({}).toArray();
|
|
435
|
+
} else if (databaseType === 'postgresql' || databaseType === 'postgres') {
|
|
436
|
+
const query = \`SELECT \${columns.join(', ')} FROM \${collName}\`;
|
|
437
|
+
const result = await client.query(query);
|
|
438
|
+
documents = result.rows;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
for (const doc of documents) {
|
|
442
|
+
const text = columns
|
|
443
|
+
.map((col: string) => {
|
|
444
|
+
const value = doc[col];
|
|
445
|
+
return value !== null && value !== undefined ? \`\${col}: \${value}\` : '';
|
|
446
|
+
})
|
|
447
|
+
.filter(Boolean)
|
|
448
|
+
.join(' ');
|
|
449
|
+
|
|
450
|
+
if (!text.trim()) continue;
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
const embeddingResponse = await openai.embeddings.create({
|
|
454
|
+
model: 'text-embedding-3-small',
|
|
455
|
+
input: text,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const embedding = embeddingResponse.data[0].embedding;
|
|
459
|
+
const docId = \`\${collName}_\${doc._id || doc.id || Date.now()}_\${totalProcessed}\`;
|
|
460
|
+
|
|
461
|
+
await chromaCollection.add({
|
|
462
|
+
ids: [docId],
|
|
463
|
+
embeddings: [embedding],
|
|
464
|
+
documents: [text],
|
|
465
|
+
metadatas: [{
|
|
466
|
+
collection: collName,
|
|
467
|
+
documentId: (doc._id || doc.id || totalProcessed).toString(),
|
|
468
|
+
columns: columns.join(','),
|
|
469
|
+
}],
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
totalProcessed++;
|
|
473
|
+
} catch (error: any) {
|
|
474
|
+
console.error(\`Error processing document in \${collName}:\`, error);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (databaseType === 'mongodb') {
|
|
480
|
+
await client.close();
|
|
481
|
+
} else if (databaseType === 'postgresql' || databaseType === 'postgres') {
|
|
482
|
+
await client.end();
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return NextResponse.json({
|
|
486
|
+
success: true,
|
|
487
|
+
message: \`Successfully processed \${totalProcessed} documents\`,
|
|
488
|
+
totalProcessed,
|
|
489
|
+
});
|
|
490
|
+
} catch (error: any) {
|
|
491
|
+
console.error('Process embeddings error:', error);
|
|
492
|
+
return NextResponse.json(
|
|
493
|
+
{ success: false, message: error.message || 'Failed to process embeddings' },
|
|
494
|
+
{ status: 500 }
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
`,
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
// Create routes
|
|
502
|
+
let createdCount = 0;
|
|
503
|
+
for (const [routePath, content] of Object.entries(routes)) {
|
|
504
|
+
const routeDir = path.join(apiDir, routePath);
|
|
505
|
+
const routeFile = isAppRouter
|
|
506
|
+
? path.join(routeDir, 'route.ts')
|
|
507
|
+
: path.join(routeDir, 'index.ts');
|
|
508
|
+
|
|
509
|
+
// Create directory if it doesn't exist
|
|
510
|
+
if (!fs.existsSync(routeDir)) {
|
|
511
|
+
fs.mkdirSync(routeDir, { recursive: true });
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Check if file already exists
|
|
515
|
+
if (fs.existsSync(routeFile)) {
|
|
516
|
+
console.log(\`āļø Skipping \${routePath} (already exists)\`);
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Write route file
|
|
521
|
+
fs.writeFileSync(routeFile, content, 'utf8');
|
|
522
|
+
console.log(\`ā
Created \${routePath}\`);
|
|
523
|
+
createdCount++;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Create .env.example if it doesn't exist
|
|
527
|
+
const envExamplePath = path.join(projectRoot, '.env.example');
|
|
528
|
+
if (!fs.existsSync(envExamplePath)) {
|
|
529
|
+
const envExample = \`# OpenAI API Key
|
|
530
|
+
OPENAI_API_KEY=your_openai_api_key_here
|
|
531
|
+
|
|
532
|
+
# ChromaDB URL (default: http://localhost:8000)
|
|
533
|
+
CHROMADB_URL=http://localhost:8000
|
|
534
|
+
|
|
535
|
+
# Optional: ChromaDB Collection Name (default: db_<database_name>)
|
|
536
|
+
# CHROMA_COLLECTION_NAME=db_default
|
|
537
|
+
|
|
538
|
+
# Optional: OpenAI Model (default: gpt-3.5-turbo)
|
|
539
|
+
# OPENAI_MODEL=gpt-3.5-turbo
|
|
540
|
+
\`;
|
|
541
|
+
fs.writeFileSync(envExamplePath, envExample, 'utf8');
|
|
542
|
+
console.log('ā
Created .env.example');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
console.log(\`\\n⨠Setup complete! \${createdCount} API route(s) created.\`);
|
|
546
|
+
console.log('\\nš Next steps:');
|
|
547
|
+
console.log('1. Copy .env.example to .env.local and add your API keys');
|
|
548
|
+
console.log('2. Install dependencies: npm install mongodb pg chromadb openai');
|
|
549
|
+
console.log('3. Use <Chatbot /> and <AdminSetup /> components in your app');
|
|
550
|
+
console.log('\\nš You\\'re all set!');
|