voicci 1.0.8 → 1.0.10
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/package.json +1 -1
- package/scripts/postinstall.js +64 -65
- package/.github/workflows/publish.yml +0 -69
- package/.github/workflows/test.yml +0 -33
- package/install.sh +0 -198
- package/lib/book-finder-old.js.backup +0 -263
- package/lib/queue-sqlite.js.backup +0 -242
- package/lib/text-cleaner-v2.js +0 -612
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voicci",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "AI-Powered Audiobook Generator for Claude Code, OpenCode & AI Code Editors. Convert books and PDFs to audiobooks using natural language.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cli/index.js",
|
package/scripts/postinstall.js
CHANGED
|
@@ -9,12 +9,13 @@ import { execFileSync } from 'child_process';
|
|
|
9
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
10
10
|
const __dirname = path.dirname(__filename);
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
// Skills use directory-based format: skills/<name>/SKILL.md
|
|
13
|
+
const SKILLS = [
|
|
14
|
+
{
|
|
15
|
+
dirName: 'voicci',
|
|
16
|
+
content: `---
|
|
17
|
+
name: voicci
|
|
18
|
+
description: "Voicci - AI audiobook generator. Use when the user wants to convert books, PDFs, or documents to audiobooks."
|
|
18
19
|
argument-hint: "COMMAND_OR_FILE"
|
|
19
20
|
---
|
|
20
21
|
|
|
@@ -33,10 +34,13 @@ Convert books, PDFs, and documents to audiobooks using AI text-to-speech.
|
|
|
33
34
|
#!/bin/bash
|
|
34
35
|
voicci $ARGUMENTS
|
|
35
36
|
\`\`\`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
`
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
dirName: 'voicci-audiobook',
|
|
41
|
+
content: `---
|
|
42
|
+
name: voicci-audiobook
|
|
43
|
+
description: "Voicci - AI audiobook generator with full documentation. Use when the user needs detailed help with audiobook generation."
|
|
40
44
|
argument-hint: "COMMAND_OR_FILE"
|
|
41
45
|
---
|
|
42
46
|
|
|
@@ -101,7 +105,6 @@ voicci memory
|
|
|
101
105
|
|
|
102
106
|
\`\`\`!
|
|
103
107
|
#!/bin/bash
|
|
104
|
-
# Execute voicci with user-provided arguments
|
|
105
108
|
voicci $ARGUMENTS
|
|
106
109
|
\`\`\`
|
|
107
110
|
|
|
@@ -112,14 +115,9 @@ voicci $ARGUMENTS
|
|
|
112
115
|
- macOS: \`~/Library/Application Support/voicci/audiobooks/\`
|
|
113
116
|
- Linux: \`~/.local/share/voicci/audiobooks/\`
|
|
114
117
|
- Copyright warning will appear before first book search
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- \`/voicci-audiobook ~/Documents/book.pdf\` - Convert local file
|
|
119
|
-
- \`/voicci-audiobook -s\` - Check all job statuses
|
|
120
|
-
- \`/voicci-audiobook summary book.pdf\` - Generate summary only
|
|
121
|
-
- \`/voicci-audiobook --help\` - Show all options
|
|
122
|
-
`;
|
|
118
|
+
`
|
|
119
|
+
}
|
|
120
|
+
];
|
|
123
121
|
|
|
124
122
|
// Editor detection configurations
|
|
125
123
|
const EDITORS = {
|
|
@@ -127,7 +125,6 @@ const EDITORS = {
|
|
|
127
125
|
name: 'Claude Code',
|
|
128
126
|
detect: () => {
|
|
129
127
|
const homeDir = os.homedir();
|
|
130
|
-
// Check for claude command or .claude directory
|
|
131
128
|
if (fs.existsSync(path.join(homeDir, '.claude'))) return true;
|
|
132
129
|
try {
|
|
133
130
|
execFileSync('which', ['claude'], { stdio: 'ignore' });
|
|
@@ -142,7 +139,6 @@ const EDITORS = {
|
|
|
142
139
|
name: 'OpenCode',
|
|
143
140
|
detect: () => {
|
|
144
141
|
const homeDir = os.homedir();
|
|
145
|
-
// Check for opencode command or config directory
|
|
146
142
|
if (fs.existsSync(path.join(homeDir, '.opencode'))) return true;
|
|
147
143
|
try {
|
|
148
144
|
execFileSync('which', ['opencode'], { stdio: 'ignore' });
|
|
@@ -157,7 +153,6 @@ const EDITORS = {
|
|
|
157
153
|
name: 'Cursor',
|
|
158
154
|
detect: () => {
|
|
159
155
|
const homeDir = os.homedir();
|
|
160
|
-
// Check for cursor command or config directory
|
|
161
156
|
if (fs.existsSync(path.join(homeDir, '.cursor'))) return true;
|
|
162
157
|
if (fs.existsSync(path.join(homeDir, 'Library', 'Application Support', 'Cursor'))) return true;
|
|
163
158
|
try {
|
|
@@ -169,23 +164,20 @@ const EDITORS = {
|
|
|
169
164
|
},
|
|
170
165
|
skillsDir: () => {
|
|
171
166
|
const homeDir = os.homedir();
|
|
172
|
-
// Try common locations
|
|
173
167
|
const locations = [
|
|
174
168
|
path.join(homeDir, '.cursor', 'skills'),
|
|
175
169
|
path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'skills')
|
|
176
170
|
];
|
|
177
171
|
for (const loc of locations) {
|
|
178
|
-
|
|
179
|
-
if (fs.existsSync(parent)) return loc;
|
|
172
|
+
if (fs.existsSync(path.dirname(loc))) return loc;
|
|
180
173
|
}
|
|
181
|
-
return locations[0];
|
|
174
|
+
return locations[0];
|
|
182
175
|
}
|
|
183
176
|
},
|
|
184
177
|
'Windsurf': {
|
|
185
178
|
name: 'Windsurf',
|
|
186
179
|
detect: () => {
|
|
187
180
|
const homeDir = os.homedir();
|
|
188
|
-
// Check for windsurf command or config directory
|
|
189
181
|
if (fs.existsSync(path.join(homeDir, '.windsurf'))) return true;
|
|
190
182
|
try {
|
|
191
183
|
execFileSync('which', ['windsurf'], { stdio: 'ignore' });
|
|
@@ -198,55 +190,63 @@ const EDITORS = {
|
|
|
198
190
|
}
|
|
199
191
|
};
|
|
200
192
|
|
|
201
|
-
function
|
|
202
|
-
const
|
|
203
|
-
|
|
193
|
+
function installSkill(skillsDir, skill) {
|
|
194
|
+
const skillDir = path.join(skillsDir, skill.dirName);
|
|
195
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
196
|
+
|
|
204
197
|
// Check if already installed
|
|
205
198
|
if (fs.existsSync(skillFile)) {
|
|
206
199
|
const existingContent = fs.readFileSync(skillFile, 'utf8');
|
|
207
|
-
if (existingContent.includes('voicci
|
|
200
|
+
if (existingContent.includes('voicci')) {
|
|
208
201
|
return 'exists';
|
|
209
202
|
}
|
|
210
203
|
}
|
|
211
|
-
|
|
212
|
-
//
|
|
213
|
-
fs.
|
|
204
|
+
|
|
205
|
+
// Create skill directory and write SKILL.md
|
|
206
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
207
|
+
fs.writeFileSync(skillFile, skill.content, 'utf8');
|
|
208
|
+
|
|
209
|
+
// Clean up legacy flat file if it exists
|
|
210
|
+
const legacyFile = path.join(skillsDir, `${skill.dirName}.md`);
|
|
211
|
+
if (fs.existsSync(legacyFile)) {
|
|
212
|
+
fs.unlinkSync(legacyFile);
|
|
213
|
+
}
|
|
214
|
+
|
|
214
215
|
return 'new';
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
function detectAndInstall() {
|
|
218
|
-
const homeDir = os.homedir();
|
|
219
219
|
const installedEditors = [];
|
|
220
220
|
const failedEditors = [];
|
|
221
221
|
|
|
222
|
-
console.log('
|
|
222
|
+
console.log('Detecting AI code editors...\n');
|
|
223
223
|
|
|
224
|
-
// Detect and install for each editor
|
|
225
224
|
for (const [key, editor] of Object.entries(EDITORS)) {
|
|
226
225
|
try {
|
|
227
226
|
if (editor.detect()) {
|
|
228
|
-
console.log(
|
|
227
|
+
console.log(` Found ${editor.name}`);
|
|
229
228
|
|
|
230
229
|
const skillsDir = editor.skillsDir();
|
|
231
230
|
|
|
232
|
-
// Create skills directory if
|
|
231
|
+
// Create skills directory if needed
|
|
233
232
|
if (!fs.existsSync(skillsDir)) {
|
|
234
233
|
fs.mkdirSync(skillsDir, { recursive: true });
|
|
235
234
|
}
|
|
236
235
|
|
|
237
|
-
|
|
238
|
-
const simpleStatus = installSkillFile(skillsDir, SKILL_NAME_SIMPLE, SKILL_CONTENT_SIMPLE);
|
|
239
|
-
const detailedStatus = installSkillFile(skillsDir, SKILL_NAME_DETAILED, SKILL_CONTENT_DETAILED);
|
|
236
|
+
let anyNew = false;
|
|
240
237
|
|
|
241
|
-
const
|
|
242
|
-
|
|
238
|
+
for (const skill of SKILLS) {
|
|
239
|
+
const status = installSkill(skillsDir, skill);
|
|
240
|
+
if (status === 'new') {
|
|
241
|
+
anyNew = true;
|
|
242
|
+
console.log(` Installed: ${path.join(skillsDir, skill.dirName, 'SKILL.md')}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
243
245
|
|
|
244
|
-
if (
|
|
245
|
-
console.log(`
|
|
246
|
+
if (!anyNew) {
|
|
247
|
+
console.log(` Skills already installed`);
|
|
246
248
|
installedEditors.push({ name: editor.name, status: 'exists' });
|
|
247
249
|
} else {
|
|
248
|
-
if (simpleStatus === 'new') console.log(` ↳ Installed: ${simpleFile}`);
|
|
249
|
-
if (detailedStatus === 'new') console.log(` ↳ Installed: ${detailedFile}`);
|
|
250
250
|
installedEditors.push({ name: editor.name, status: 'new' });
|
|
251
251
|
}
|
|
252
252
|
}
|
|
@@ -256,37 +256,36 @@ function detectAndInstall() {
|
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
// Summary
|
|
259
|
-
console.log('\n' + '
|
|
259
|
+
console.log('\n' + '='.repeat(60));
|
|
260
260
|
|
|
261
261
|
if (installedEditors.length > 0) {
|
|
262
|
-
console.log('\
|
|
263
|
-
console.log('\n
|
|
264
|
-
console.log('
|
|
265
|
-
console.log('\n
|
|
262
|
+
console.log('\nVoicci CLI installed successfully!');
|
|
263
|
+
console.log('\n Command-line tool: voicci');
|
|
264
|
+
console.log(' Skill commands: /voicci OR /voicci-audiobook');
|
|
265
|
+
console.log('\n Installed in:');
|
|
266
266
|
installedEditors.forEach(editor => {
|
|
267
267
|
const status = editor.status === 'new' ? '(new)' : '(already installed)';
|
|
268
|
-
console.log(`
|
|
268
|
+
console.log(` ${editor.name} ${status}`);
|
|
269
269
|
});
|
|
270
270
|
|
|
271
|
-
console.log('\n
|
|
272
|
-
console.log('
|
|
273
|
-
console.log('
|
|
274
|
-
console.log('
|
|
275
|
-
console.log(' 4. Or CLI: voicci "your search query"');
|
|
271
|
+
console.log('\n Usage:');
|
|
272
|
+
console.log(' 1. Restart your AI code editor');
|
|
273
|
+
console.log(' 2. Type: /voicci "search query"');
|
|
274
|
+
console.log(' 3. Or CLI: voicci "your search query"');
|
|
276
275
|
} else {
|
|
277
|
-
console.log('\n
|
|
278
|
-
console.log('\
|
|
279
|
-
console.log('\n
|
|
276
|
+
console.log('\n No supported AI code editors detected');
|
|
277
|
+
console.log('\n Supported editors: Claude Code, OpenCode, Cursor, Windsurf');
|
|
278
|
+
console.log('\n You can still use the CLI: voicci <command>');
|
|
280
279
|
}
|
|
281
280
|
|
|
282
281
|
if (failedEditors.length > 0) {
|
|
283
|
-
console.log('\n
|
|
282
|
+
console.log('\n Failed to install for:');
|
|
284
283
|
failedEditors.forEach(({ name, error }) => {
|
|
285
|
-
console.log(`
|
|
284
|
+
console.log(` ${name}: ${error}`);
|
|
286
285
|
});
|
|
287
286
|
}
|
|
288
287
|
|
|
289
|
-
console.log('\n' + '
|
|
288
|
+
console.log('\n' + '='.repeat(60));
|
|
290
289
|
console.log();
|
|
291
290
|
}
|
|
292
291
|
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
name: Publish to npm
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*'
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
test:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
|
|
12
|
-
steps:
|
|
13
|
-
- name: Checkout code
|
|
14
|
-
uses: actions/checkout@v4
|
|
15
|
-
|
|
16
|
-
- name: Setup Node.js
|
|
17
|
-
uses: actions/setup-node@v4
|
|
18
|
-
with:
|
|
19
|
-
node-version: '18'
|
|
20
|
-
|
|
21
|
-
- name: Install dependencies
|
|
22
|
-
run: npm ci
|
|
23
|
-
|
|
24
|
-
- name: Run tests
|
|
25
|
-
run: npm test
|
|
26
|
-
|
|
27
|
-
publish:
|
|
28
|
-
needs: test
|
|
29
|
-
runs-on: ubuntu-latest
|
|
30
|
-
|
|
31
|
-
steps:
|
|
32
|
-
- name: Checkout code
|
|
33
|
-
uses: actions/checkout@v4
|
|
34
|
-
|
|
35
|
-
- name: Setup Node.js
|
|
36
|
-
uses: actions/setup-node@v4
|
|
37
|
-
with:
|
|
38
|
-
node-version: '18'
|
|
39
|
-
registry-url: 'https://registry.npmjs.org'
|
|
40
|
-
|
|
41
|
-
- name: Install dependencies
|
|
42
|
-
run: npm ci
|
|
43
|
-
|
|
44
|
-
- name: Publish to npm
|
|
45
|
-
run: npm publish
|
|
46
|
-
env:
|
|
47
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
48
|
-
|
|
49
|
-
- name: Create GitHub Release
|
|
50
|
-
uses: actions/create-release@v1
|
|
51
|
-
env:
|
|
52
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
53
|
-
with:
|
|
54
|
-
tag_name: ${{ github.ref }}
|
|
55
|
-
release_name: Release ${{ github.ref }}
|
|
56
|
-
body: |
|
|
57
|
-
## Installation
|
|
58
|
-
```bash
|
|
59
|
-
npm install -g voicci
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
Or via install script:
|
|
63
|
-
```bash
|
|
64
|
-
curl -fsSL https://voicci.com/voicci-cli/install.sh | bash
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
See [CHANGELOG.md](https://github.com/voicci/voicci-cli/blob/main/CHANGELOG.md) for details.
|
|
68
|
-
draft: false
|
|
69
|
-
prerelease: false
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
name: Run Tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ main ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
|
|
13
|
-
strategy:
|
|
14
|
-
matrix:
|
|
15
|
-
node-version: [18.x, 20.x]
|
|
16
|
-
|
|
17
|
-
steps:
|
|
18
|
-
- name: Checkout code
|
|
19
|
-
uses: actions/checkout@v4
|
|
20
|
-
|
|
21
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
22
|
-
uses: actions/setup-node@v4
|
|
23
|
-
with:
|
|
24
|
-
node-version: ${{ matrix.node-version }}
|
|
25
|
-
|
|
26
|
-
- name: Install dependencies
|
|
27
|
-
run: npm ci
|
|
28
|
-
|
|
29
|
-
- name: Run tests
|
|
30
|
-
run: npm test
|
|
31
|
-
|
|
32
|
-
- name: Check package can be packed
|
|
33
|
-
run: npm pack --dry-run
|
package/install.sh
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Voicci Installer
|
|
4
|
-
# Converts PDF/text files to high-quality audiobooks using XTTS v2 AI
|
|
5
|
-
|
|
6
|
-
set -e
|
|
7
|
-
|
|
8
|
-
# Colors for output
|
|
9
|
-
RED='\033[0;31m'
|
|
10
|
-
GREEN='\033[0;32m'
|
|
11
|
-
YELLOW='\033[1;33m'
|
|
12
|
-
BLUE='\033[0;34m'
|
|
13
|
-
NC='\033[0m' # No Color
|
|
14
|
-
|
|
15
|
-
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
|
|
16
|
-
echo -e "${BLUE}║ Voicci Installer v1.0 ║${NC}"
|
|
17
|
-
echo -e "${BLUE}║ AI Audiobook Generator (XTTS v2) ║${NC}"
|
|
18
|
-
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
|
|
19
|
-
echo ""
|
|
20
|
-
|
|
21
|
-
# Detect OS
|
|
22
|
-
OS="$(uname -s)"
|
|
23
|
-
case "${OS}" in
|
|
24
|
-
Linux*) OS_TYPE=Linux;;
|
|
25
|
-
Darwin*) OS_TYPE=Mac;;
|
|
26
|
-
*) OS_TYPE="UNKNOWN:${OS}"
|
|
27
|
-
esac
|
|
28
|
-
|
|
29
|
-
if [[ "$OS_TYPE" == "UNKNOWN"* ]]; then
|
|
30
|
-
echo -e "${RED}✗${NC} Unsupported operating system: ${OS}"
|
|
31
|
-
echo "Voicci currently supports macOS and Linux only."
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
|
|
35
|
-
echo -e "${GREEN}✓${NC} Detected OS: ${OS_TYPE}"
|
|
36
|
-
|
|
37
|
-
# Check dependencies
|
|
38
|
-
echo ""
|
|
39
|
-
echo "Checking dependencies..."
|
|
40
|
-
|
|
41
|
-
# Check Node.js
|
|
42
|
-
if command -v node &> /dev/null; then
|
|
43
|
-
NODE_VERSION=$(node --version)
|
|
44
|
-
echo -e "${GREEN}✓${NC} Node.js $NODE_VERSION found"
|
|
45
|
-
else
|
|
46
|
-
echo -e "${RED}✗${NC} Node.js not found"
|
|
47
|
-
echo "Please install Node.js 18+ from https://nodejs.org/"
|
|
48
|
-
exit 1
|
|
49
|
-
fi
|
|
50
|
-
|
|
51
|
-
# Check npm
|
|
52
|
-
if command -v npm &> /dev/null; then
|
|
53
|
-
NPM_VERSION=$(npm --version)
|
|
54
|
-
echo -e "${GREEN}✓${NC} npm $NPM_VERSION found"
|
|
55
|
-
else
|
|
56
|
-
echo -e "${RED}✗${NC} npm not found"
|
|
57
|
-
exit 1
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
# Check Python
|
|
61
|
-
if command -v python3 &> /dev/null; then
|
|
62
|
-
PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}')
|
|
63
|
-
PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1)
|
|
64
|
-
PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2)
|
|
65
|
-
|
|
66
|
-
if [[ $PYTHON_MAJOR -ge 3 ]] && [[ $PYTHON_MINOR -ge 9 ]]; then
|
|
67
|
-
echo -e "${GREEN}✓${NC} Python $PYTHON_VERSION found"
|
|
68
|
-
else
|
|
69
|
-
echo -e "${RED}✗${NC} Python 3.9+ required (found $PYTHON_VERSION)"
|
|
70
|
-
exit 1
|
|
71
|
-
fi
|
|
72
|
-
else
|
|
73
|
-
echo -e "${RED}✗${NC} Python 3 not found"
|
|
74
|
-
echo "Please install Python 3.9+ from https://www.python.org/"
|
|
75
|
-
exit 1
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
|
-
# Check pip
|
|
79
|
-
if command -v pip3 &> /dev/null; then
|
|
80
|
-
echo -e "${GREEN}✓${NC} pip3 found"
|
|
81
|
-
else
|
|
82
|
-
echo -e "${RED}✗${NC} pip3 not found"
|
|
83
|
-
exit 1
|
|
84
|
-
fi
|
|
85
|
-
|
|
86
|
-
# Check pdftotext (optional but recommended)
|
|
87
|
-
if command -v pdftotext &> /dev/null; then
|
|
88
|
-
echo -e "${GREEN}✓${NC} pdftotext found"
|
|
89
|
-
else
|
|
90
|
-
echo -e "${YELLOW}⚠${NC} pdftotext not found (optional, for PDF support)"
|
|
91
|
-
echo "Install with: brew install poppler (Mac) or apt-get install poppler-utils (Linux)"
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
# Determine installation directory
|
|
95
|
-
if [[ "$OS_TYPE" == "Mac" ]]; then
|
|
96
|
-
INSTALL_DIR="$HOME/Library/Application Support/voicci"
|
|
97
|
-
else
|
|
98
|
-
INSTALL_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/voicci"
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
echo ""
|
|
102
|
-
echo -e "Installation directory: ${BLUE}$INSTALL_DIR${NC}"
|
|
103
|
-
echo ""
|
|
104
|
-
|
|
105
|
-
# Ask for confirmation
|
|
106
|
-
read -p "Continue with installation? (y/n) " -n 1 -r
|
|
107
|
-
echo
|
|
108
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
109
|
-
echo "Installation cancelled."
|
|
110
|
-
exit 0
|
|
111
|
-
fi
|
|
112
|
-
|
|
113
|
-
# Create installation directory
|
|
114
|
-
echo ""
|
|
115
|
-
echo "Creating directories..."
|
|
116
|
-
mkdir -p "$INSTALL_DIR"/{lib,cli,backend}
|
|
117
|
-
echo -e "${GREEN}✓${NC} Directories created"
|
|
118
|
-
|
|
119
|
-
# Download Voicci files (in production, this would download from GitHub/website)
|
|
120
|
-
echo ""
|
|
121
|
-
echo "Installing Voicci..."
|
|
122
|
-
|
|
123
|
-
# For now, we'll create the files directly
|
|
124
|
-
# In production, this would be: curl -fsSL https://voicci.com/voicci-cli/voicci.tar.gz | tar -xz -C "$INSTALL_DIR"
|
|
125
|
-
|
|
126
|
-
# Install Node.js dependencies
|
|
127
|
-
cd "$INSTALL_DIR"
|
|
128
|
-
echo ""
|
|
129
|
-
echo "Installing Node.js dependencies..."
|
|
130
|
-
|
|
131
|
-
cat > package.json <<'EOF'
|
|
132
|
-
{
|
|
133
|
-
"name": "voicci",
|
|
134
|
-
"version": "1.0.0",
|
|
135
|
-
"description": "AI Audiobook Generator using XTTS v2",
|
|
136
|
-
"type": "module",
|
|
137
|
-
"bin": {
|
|
138
|
-
"voicci": "./cli/index.js"
|
|
139
|
-
},
|
|
140
|
-
"dependencies": {
|
|
141
|
-
"commander": "^11.1.0",
|
|
142
|
-
"better-sqlite3": "^9.2.2",
|
|
143
|
-
"uuid": "^9.0.1",
|
|
144
|
-
"ink": "^4.4.1",
|
|
145
|
-
"react": "^18.2.0",
|
|
146
|
-
"chalk": "^5.3.0"
|
|
147
|
-
},
|
|
148
|
-
"engines": {
|
|
149
|
-
"node": ">=18.0.0"
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
EOF
|
|
153
|
-
|
|
154
|
-
npm install --silent --no-audit --no-fund 2>&1 | grep -v "npm WARN"
|
|
155
|
-
echo -e "${GREEN}✓${NC} Node.js dependencies installed"
|
|
156
|
-
|
|
157
|
-
# Install Python dependencies
|
|
158
|
-
echo ""
|
|
159
|
-
echo "Installing Python dependencies..."
|
|
160
|
-
echo "This may take several minutes (downloading XTTS v2 model ~450MB)..."
|
|
161
|
-
|
|
162
|
-
pip3 install --quiet --upgrade pip
|
|
163
|
-
pip3 install --quiet TTS torch torchaudio
|
|
164
|
-
|
|
165
|
-
echo -e "${GREEN}✓${NC} Python dependencies installed"
|
|
166
|
-
|
|
167
|
-
# Download XTTS v2 model
|
|
168
|
-
echo ""
|
|
169
|
-
echo "Downloading XTTS v2 model (this may take a few minutes)..."
|
|
170
|
-
python3 -c "from TTS.api import TTS; TTS('tts_models/multilingual/multi-dataset/xtts_v2')" &>/dev/null || true
|
|
171
|
-
echo -e "${GREEN}✓${NC} XTTS v2 model downloaded"
|
|
172
|
-
|
|
173
|
-
# Create symlink for global access
|
|
174
|
-
BIN_DIR="/usr/local/bin"
|
|
175
|
-
if [[ -w "$BIN_DIR" ]]; then
|
|
176
|
-
ln -sf "$INSTALL_DIR/cli/index.js" "$BIN_DIR/voicci"
|
|
177
|
-
echo -e "${GREEN}✓${NC} Global command 'voicci' installed"
|
|
178
|
-
else
|
|
179
|
-
echo -e "${YELLOW}⚠${NC} Could not create global command (insufficient permissions)"
|
|
180
|
-
echo "Add to your PATH manually: export PATH=\"$INSTALL_DIR/cli:\$PATH\""
|
|
181
|
-
fi
|
|
182
|
-
|
|
183
|
-
# Final message
|
|
184
|
-
echo ""
|
|
185
|
-
echo -e "${GREEN}╔════════════════════════════════════════╗${NC}"
|
|
186
|
-
echo -e "${GREEN}║ Installation Complete! 🎉 ║${NC}"
|
|
187
|
-
echo -e "${GREEN}╚════════════════════════════════════════╝${NC}"
|
|
188
|
-
echo ""
|
|
189
|
-
echo "Usage:"
|
|
190
|
-
echo -e " ${BLUE}voicci mybook.pdf${NC} - Convert PDF to audiobook"
|
|
191
|
-
echo -e " ${BLUE}voicci -s${NC} - Check all job statuses"
|
|
192
|
-
echo -e " ${BLUE}voicci -l${NC} - List completed audiobooks"
|
|
193
|
-
echo -e " ${BLUE}voicci -o <jobId>${NC} - Open audiobook folder"
|
|
194
|
-
echo ""
|
|
195
|
-
echo "Installation location: $INSTALL_DIR"
|
|
196
|
-
echo ""
|
|
197
|
-
echo "Get started: voicci --help"
|
|
198
|
-
echo ""
|