tx-ai-db-chat 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 +85 -0
- package/package.json +38 -0
- package/src/import-conversations.js +106 -0
- package/src/index.js +151 -0
- package/src/postinstall.js +20 -0
- package/src/setup-wizard.js +186 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# tx-ai-db-chat
|
|
2
|
+
|
|
3
|
+
Free chat-focused SQLite wrapper for AI conversations.
|
|
4
|
+
|
|
5
|
+
**OpenAI API Compatible Format only.**
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 3 simple operations: retrieve, update, delete
|
|
10
|
+
- Works out of the box
|
|
11
|
+
- Smart upsert logic (conversation_id detection)
|
|
12
|
+
- Manual conversation ID list (one ID per row)
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install tx-ai-db-chat
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run setup
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The setup wizard will:
|
|
27
|
+
1. Ask for your SDK/API endpoint
|
|
28
|
+
2. Fetch the schema
|
|
29
|
+
3. List all fields containing "id"
|
|
30
|
+
4. You select which field is your conversation ID
|
|
31
|
+
5. Database is created
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Retrieve Conversation
|
|
36
|
+
Drop a JSON file in `retrieve/` folder with:
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"conversation_id": "conv_123"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Update/Save Conversation
|
|
44
|
+
Drop a JSON file in `update/` folder with:
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"conversation_id": "conv_123",
|
|
48
|
+
"messages": [...]
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Delete Conversation
|
|
53
|
+
Drop a JSON file in `delete/` folder with:
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"conversation_id": "conv_123"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Upgrade to Pro
|
|
61
|
+
|
|
62
|
+
Want auto-migration of 2,000+ conversations, search, and formatted responses?
|
|
63
|
+
|
|
64
|
+
Upgrade to **tx-ai-db-pro** ($40 one-time payment):
|
|
65
|
+
```bash
|
|
66
|
+
npm install tx-ai-db-pro
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Pro Features:**
|
|
70
|
+
- Auto-discover and import ALL conversations from a folder
|
|
71
|
+
- Search conversations with customizable response formatting
|
|
72
|
+
- File cleanup/backup after import
|
|
73
|
+
- Setup wizard with auto-migration
|
|
74
|
+
- 4 installations per license
|
|
75
|
+
|
|
76
|
+
**Unlock Pro Features:**
|
|
77
|
+
1. Install: `npm install tx-ai-db-pro`
|
|
78
|
+
2. Pay $40 to receive 4 license keys
|
|
79
|
+
3. Create a `.license` file with all 4 keys (one per row)
|
|
80
|
+
4. Run: `npm run unlock`
|
|
81
|
+
5. Pro features unlocked!
|
|
82
|
+
|
|
83
|
+
## Funding
|
|
84
|
+
|
|
85
|
+
If you find this useful, consider sponsoring: https://github.com/sponsors/TX-AI-Series
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tx-ai-db-chat",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Free chat-focused SQLite wrapper for AI conversations. OpenAI API Compatible Format only.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node tests/test.js",
|
|
8
|
+
"setup": "node src/setup-wizard.js",
|
|
9
|
+
"postinstall": "node src/postinstall.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"sqlite",
|
|
13
|
+
"ai",
|
|
14
|
+
"chat",
|
|
15
|
+
"conversation",
|
|
16
|
+
"openai",
|
|
17
|
+
"database",
|
|
18
|
+
"file-driven"
|
|
19
|
+
],
|
|
20
|
+
"author": "TX-AI-Series",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/TX-AI-Series/tx-ai-db-chat"
|
|
25
|
+
},
|
|
26
|
+
"funding": {
|
|
27
|
+
"type": "github",
|
|
28
|
+
"url": "https://github.com/sponsors/TX-AI-Series"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"better-sqlite3": "^9.4.3"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"src/",
|
|
35
|
+
"README.md",
|
|
36
|
+
"sqlite-source/"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const TXAIDbChat = require('./index');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Import conversations from ID list file
|
|
7
|
+
*/
|
|
8
|
+
async function importConversations() {
|
|
9
|
+
// Load config
|
|
10
|
+
const configPath = path.join(process.cwd(), 'chat-config.json');
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
console.error('Error: chat-config.json not found. Run "npm run setup" first.');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
17
|
+
|
|
18
|
+
// Load conversation IDs
|
|
19
|
+
const idListPath = path.join(process.cwd(), 'conversation-ids.txt');
|
|
20
|
+
if (!fs.existsSync(idListPath)) {
|
|
21
|
+
console.error('Error: conversation-ids.txt not found. Add your conversation IDs first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const idContent = fs.readFileSync(idListPath, 'utf8');
|
|
26
|
+
const conversationIds = idContent
|
|
27
|
+
.split('\n')
|
|
28
|
+
.map(line => line.trim())
|
|
29
|
+
.filter(line => line && !line.startsWith('#'));
|
|
30
|
+
|
|
31
|
+
if (conversationIds.length === 0) {
|
|
32
|
+
console.log('No conversation IDs found in conversation-ids.txt');
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log(`Found ${conversationIds.length} conversation IDs to import.\n`);
|
|
37
|
+
|
|
38
|
+
// Initialize database
|
|
39
|
+
const db = new TXAIDbChat({
|
|
40
|
+
dbPath: config.dbPath,
|
|
41
|
+
conversationIdField: config.conversationIdField
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Import each conversation
|
|
45
|
+
let successCount = 0;
|
|
46
|
+
let errorCount = 0;
|
|
47
|
+
|
|
48
|
+
for (const convId of conversationIds) {
|
|
49
|
+
try {
|
|
50
|
+
// Look for conversation file (named with ID)
|
|
51
|
+
const possiblePaths = [
|
|
52
|
+
path.join(config.folderPath, `${convId}.json`),
|
|
53
|
+
path.join(config.folderPath, convId, 'conversation.json'),
|
|
54
|
+
path.join(process.cwd(), 'conversations', `${convId}.json`)
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
let conversationData = null;
|
|
58
|
+
let foundPath = null;
|
|
59
|
+
|
|
60
|
+
for (const filePath of possiblePaths) {
|
|
61
|
+
if (fs.existsSync(filePath)) {
|
|
62
|
+
conversationData = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
63
|
+
foundPath = filePath;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!conversationData) {
|
|
69
|
+
console.log(`⚠️ Not found: ${convId}`);
|
|
70
|
+
errorCount++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Ensure the conversation ID field is set
|
|
75
|
+
if (!conversationData[config.conversationIdField]) {
|
|
76
|
+
conversationData[config.conversationIdField] = convId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Save to database
|
|
80
|
+
db.update(conversationData);
|
|
81
|
+
console.log(`✅ Imported: ${convId}`);
|
|
82
|
+
successCount++;
|
|
83
|
+
|
|
84
|
+
// Optional: move file to backup after import
|
|
85
|
+
if (foundPath && config.backupAfterImport) {
|
|
86
|
+
const backupPath = foundPath.replace('/databases/', '/databases/imported/');
|
|
87
|
+
fs.mkdirSync(path.dirname(backupPath), { recursive: true });
|
|
88
|
+
fs.renameSync(foundPath, backupPath);
|
|
89
|
+
}
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.log(`❌ Error importing ${convId}: ${err.message}`);
|
|
92
|
+
errorCount++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(`\n========================================`);
|
|
97
|
+
console.log(` Import Complete`);
|
|
98
|
+
console.log(`========================================`);
|
|
99
|
+
console.log(` Success: ${successCount}`);
|
|
100
|
+
console.log(` Errors: ${errorCount}`);
|
|
101
|
+
console.log(`========================================\n`);
|
|
102
|
+
|
|
103
|
+
db.close();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
importConversations().catch(console.error);
|
package/src/index.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const Database = require('better-sqlite3');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
class TXAIDbChat {
|
|
6
|
+
constructor(config = {}) {
|
|
7
|
+
this.dbPath = config.dbPath || path.join(process.cwd(), 'chat.db');
|
|
8
|
+
this.conversationIdField = config.conversationIdField || 'id';
|
|
9
|
+
this.db = null;
|
|
10
|
+
this.init();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
init() {
|
|
14
|
+
this.db = new Database(this.dbPath);
|
|
15
|
+
this.db.pragma('journal_mode = WAL');
|
|
16
|
+
this.db.pragma('foreign_keys = ON');
|
|
17
|
+
this.createTables();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
createTables() {
|
|
21
|
+
this.db.exec(`
|
|
22
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
23
|
+
id TEXT PRIMARY KEY,
|
|
24
|
+
raw_data JSON NOT NULL,
|
|
25
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
26
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
30
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
31
|
+
conversation_id TEXT NOT NULL,
|
|
32
|
+
message_index INTEGER NOT NULL,
|
|
33
|
+
role TEXT NOT NULL,
|
|
34
|
+
content TEXT,
|
|
35
|
+
raw_data JSON NOT NULL,
|
|
36
|
+
FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id);
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_messages_role ON messages(role);
|
|
41
|
+
`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Retrieve a conversation by ID
|
|
46
|
+
* @param {string} conversationId - The conversation ID to retrieve
|
|
47
|
+
* @returns {object|null} - The conversation data or null if not found
|
|
48
|
+
*/
|
|
49
|
+
retrieve(conversationId) {
|
|
50
|
+
const conversation = this.db.prepare(
|
|
51
|
+
'SELECT * FROM conversations WHERE id = ?'
|
|
52
|
+
).get(conversationId);
|
|
53
|
+
|
|
54
|
+
if (!conversation) return null;
|
|
55
|
+
|
|
56
|
+
const messages = this.db.prepare(
|
|
57
|
+
'SELECT * FROM messages WHERE conversation_id = ? ORDER BY message_index'
|
|
58
|
+
).all(conversationId);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
...conversation,
|
|
62
|
+
messages: messages.map(m => JSON.parse(m.raw_data))
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Update or insert a conversation (smart upsert)
|
|
68
|
+
* @param {object} conversationData - The conversation data (OpenAI API format)
|
|
69
|
+
* @returns {boolean} - True if successful
|
|
70
|
+
*/
|
|
71
|
+
update(conversationData) {
|
|
72
|
+
const conversationId = conversationData[this.conversationIdField];
|
|
73
|
+
if (!conversationId) {
|
|
74
|
+
throw new Error(`Missing conversation ID field: ${this.conversationIdField}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const existing = this.db.prepare(
|
|
78
|
+
'SELECT id FROM conversations WHERE id = ?'
|
|
79
|
+
).get(conversationId);
|
|
80
|
+
|
|
81
|
+
const tx = this.db.transaction(() => {
|
|
82
|
+
if (existing) {
|
|
83
|
+
this.db.prepare(
|
|
84
|
+
'UPDATE conversations SET raw_data = ?, updated_at = datetime(\'now\') WHERE id = ?'
|
|
85
|
+
).run(JSON.stringify(conversationData), conversationId);
|
|
86
|
+
|
|
87
|
+
this.db.prepare(
|
|
88
|
+
'DELETE FROM messages WHERE conversation_id = ?'
|
|
89
|
+
).run(conversationId);
|
|
90
|
+
} else {
|
|
91
|
+
this.db.prepare(
|
|
92
|
+
'INSERT INTO conversations (id, raw_data) VALUES (?, ?)'
|
|
93
|
+
).run(conversationId, JSON.stringify(conversationData));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Insert messages
|
|
97
|
+
const messages = conversationData.messages || [];
|
|
98
|
+
const insertMsg = this.db.prepare(
|
|
99
|
+
'INSERT INTO messages (conversation_id, message_index, role, content, raw_data) VALUES (?, ?, ?, ?, ?)'
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < messages.length; i++) {
|
|
103
|
+
const msg = messages[i];
|
|
104
|
+
insertMsg.run(
|
|
105
|
+
conversationId,
|
|
106
|
+
i,
|
|
107
|
+
msg.role || 'unknown',
|
|
108
|
+
typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
|
|
109
|
+
JSON.stringify(msg)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
tx();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Delete a conversation by ID
|
|
120
|
+
* @param {string} conversationId - The conversation ID to delete
|
|
121
|
+
* @returns {boolean} - True if deleted, false if not found
|
|
122
|
+
*/
|
|
123
|
+
delete(conversationId) {
|
|
124
|
+
const result = this.db.prepare(
|
|
125
|
+
'DELETE FROM conversations WHERE id = ?'
|
|
126
|
+
).run(conversationId);
|
|
127
|
+
|
|
128
|
+
return result.changes > 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get list of all conversation IDs
|
|
133
|
+
* @returns {string[]} - Array of conversation IDs
|
|
134
|
+
*/
|
|
135
|
+
listConversations() {
|
|
136
|
+
return this.db.prepare(
|
|
137
|
+
'SELECT id, created_at, updated_at FROM conversations ORDER BY updated_at DESC'
|
|
138
|
+
).all();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Close the database connection
|
|
143
|
+
*/
|
|
144
|
+
close() {
|
|
145
|
+
if (this.db) {
|
|
146
|
+
this.db.close();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = TXAIDbChat;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
console.log(`
|
|
2
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
3
|
+
║ ║
|
|
4
|
+
║ tx-ai-db-chat installed successfully! ║
|
|
5
|
+
║ ║
|
|
6
|
+
║ Next steps: ║
|
|
7
|
+
║ 1. Run setup: npm run setup ║
|
|
8
|
+
║ 2. Add conversation IDs to conversation-ids.txt ║
|
|
9
|
+
║ 3. Import: node src/import-conversations.js ║
|
|
10
|
+
║ ║
|
|
11
|
+
║ ───────────────────────────────────────────────────── ║
|
|
12
|
+
║ ║
|
|
13
|
+
║ 💚 Love this project? Consider sponsoring us! ║
|
|
14
|
+
║ https://github.com/sponsors/TX-AI-Series ║
|
|
15
|
+
║ ║
|
|
16
|
+
║ Want auto-import for 2,000+ conversations? ║
|
|
17
|
+
║ Upgrade to tx-ai-db-pro ($40) ║
|
|
18
|
+
║ ║
|
|
19
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
20
|
+
`);
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const readline = require('readline');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
const http = require('http');
|
|
6
|
+
|
|
7
|
+
const rl = readline.createInterface({
|
|
8
|
+
input: process.stdin,
|
|
9
|
+
output: process.stdout
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
function askQuestion(question) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
rl.question(question, (answer) => {
|
|
15
|
+
resolve(answer.trim());
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Fetch schema from SDK/API endpoint
|
|
22
|
+
*/
|
|
23
|
+
async function fetchSchema(endpoint) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const url = new URL(endpoint);
|
|
26
|
+
const lib = url.protocol === 'https:' ? https : http;
|
|
27
|
+
|
|
28
|
+
const options = {
|
|
29
|
+
method: 'GET',
|
|
30
|
+
hostname: url.hostname,
|
|
31
|
+
path: url.pathname + url.search,
|
|
32
|
+
headers: {
|
|
33
|
+
'Accept': 'application/json'
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const req = lib.request(options, (res) => {
|
|
38
|
+
let data = '';
|
|
39
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
40
|
+
res.on('end', () => {
|
|
41
|
+
try {
|
|
42
|
+
resolve(JSON.parse(data));
|
|
43
|
+
} catch (e) {
|
|
44
|
+
reject(new Error('Failed to parse JSON response'));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
req.on('error', reject);
|
|
50
|
+
req.end();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find all fields containing "id" in the schema
|
|
56
|
+
*/
|
|
57
|
+
function findIdFields(schema, prefix = '') {
|
|
58
|
+
let idFields = [];
|
|
59
|
+
|
|
60
|
+
if (typeof schema === 'object' && schema !== null) {
|
|
61
|
+
if (Array.isArray(schema)) {
|
|
62
|
+
schema.forEach((item, index) => {
|
|
63
|
+
idFields = idFields.concat(findIdFields(item, `${prefix}[${index}]`));
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
67
|
+
const fullPath = prefix ? `${prefix}.${key}` : key;
|
|
68
|
+
if (key.toLowerCase().includes('id')) {
|
|
69
|
+
idFields.push({
|
|
70
|
+
field: fullPath,
|
|
71
|
+
type: typeof value,
|
|
72
|
+
value: value
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
idFields = idFields.concat(findIdFields(value, fullPath));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return idFields;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Main setup wizard
|
|
85
|
+
*/
|
|
86
|
+
async function runSetupWizard() {
|
|
87
|
+
console.log('========================================');
|
|
88
|
+
console.log(' tx-ai-db-chat Setup Wizard');
|
|
89
|
+
console.log('========================================\n');
|
|
90
|
+
|
|
91
|
+
// Step 1: Get SDK/API endpoint
|
|
92
|
+
console.log('Step 1: SDK/API Configuration');
|
|
93
|
+
console.log('Enter your OpenAI-compatible API endpoint to fetch schema.');
|
|
94
|
+
console.log('Or press Enter to skip and use default schema.\n');
|
|
95
|
+
|
|
96
|
+
const endpoint = await askQuestion('API Endpoint (or press Enter to skip): ');
|
|
97
|
+
|
|
98
|
+
let schema = null;
|
|
99
|
+
let idFields = [];
|
|
100
|
+
|
|
101
|
+
if (endpoint) {
|
|
102
|
+
try {
|
|
103
|
+
console.log('\nFetching schema from API...');
|
|
104
|
+
schema = await fetchSchema(endpoint);
|
|
105
|
+
idFields = findIdFields(schema);
|
|
106
|
+
console.log(`Found ${idFields.length} fields containing "id":\n`);
|
|
107
|
+
|
|
108
|
+
idFields.forEach((field, index) => {
|
|
109
|
+
console.log(` ${index + 1}. ${field.field} (${field.type}) - Example: ${JSON.stringify(field.value).substring(0, 50)}`);
|
|
110
|
+
});
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.log(`\nFailed to fetch schema: ${err.message}`);
|
|
113
|
+
console.log('Using default schema...\n');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Default ID fields if no API provided
|
|
118
|
+
if (idFields.length === 0) {
|
|
119
|
+
idFields = [
|
|
120
|
+
{ field: 'id', type: 'string', value: 'thread_abc123' },
|
|
121
|
+
{ field: 'thread_id', type: 'string', value: 'thread_abc123' },
|
|
122
|
+
{ field: 'conversation_id', type: 'string', value: 'conv_123' },
|
|
123
|
+
{ field: 'session_id', type: 'string', value: 'sess_456' }
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
console.log('Default conversation ID fields:');
|
|
127
|
+
idFields.forEach((field, index) => {
|
|
128
|
+
console.log(` ${index + 1}. ${field.field}`);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Step 2: Select conversation ID field
|
|
133
|
+
console.log('\nStep 2: Select Conversation ID Field');
|
|
134
|
+
console.log('Which field identifies your conversations?\n');
|
|
135
|
+
|
|
136
|
+
const selection = await askQuestion(`Enter number (1-${idFields.length}): `);
|
|
137
|
+
const selectedIndex = parseInt(selection) - 1;
|
|
138
|
+
|
|
139
|
+
if (selectedIndex < 0 || selectedIndex >= idFields.length) {
|
|
140
|
+
console.log('Invalid selection. Using default: id');
|
|
141
|
+
idFields[0];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const conversationIdField = idFields[selectedIndex].field;
|
|
145
|
+
console.log(`\nSelected: ${conversationIdField}\n`);
|
|
146
|
+
|
|
147
|
+
// Step 3: Create config file
|
|
148
|
+
console.log('Step 3: Creating configuration...');
|
|
149
|
+
|
|
150
|
+
const config = {
|
|
151
|
+
conversationIdField: conversationIdField,
|
|
152
|
+
dbPath: path.join(process.cwd(), 'chat.db'),
|
|
153
|
+
folderPath: path.join(process.cwd(), 'databases'),
|
|
154
|
+
version: '1.0.0'
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const configPath = path.join(process.cwd(), 'chat-config.json');
|
|
158
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
159
|
+
console.log(`Config saved to: ${configPath}\n`);
|
|
160
|
+
|
|
161
|
+
// Step 4: Create conversation ID list file
|
|
162
|
+
console.log('Step 4: Create Conversation ID List');
|
|
163
|
+
console.log('Create a file with one conversation ID per line:');
|
|
164
|
+
console.log(` ${path.join(process.cwd(), 'conversation-ids.txt')}\n`);
|
|
165
|
+
|
|
166
|
+
const idListPath = path.join(process.cwd(), 'conversation-ids.txt');
|
|
167
|
+
if (!fs.existsSync(idListPath)) {
|
|
168
|
+
fs.writeFileSync(idListPath, '# Add your conversation IDs here, one per line\n# Example:\n# conv_123\n# conv_456\n');
|
|
169
|
+
console.log(`Created empty ID list file: ${idListPath}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Step 5: Upgrade prompt
|
|
173
|
+
console.log('\n========================================');
|
|
174
|
+
console.log(' Setup Complete!');
|
|
175
|
+
console.log('========================================\n');
|
|
176
|
+
console.log('To import conversations:');
|
|
177
|
+
console.log(` 1. Add conversation IDs to: ${idListPath}`);
|
|
178
|
+
console.log(' 2. Run: node src/import-conversations.js\n');
|
|
179
|
+
console.log('Want to auto-import 2,000+ conversations?');
|
|
180
|
+
console.log('Upgrade to tx-ai-db-pro ($40): https://github.com/sponsors/TX-AI-Series\n');
|
|
181
|
+
|
|
182
|
+
rl.close();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Run the wizard
|
|
186
|
+
runSetupWizard().catch(console.error);
|