verbalcoding 0.2.4 → 0.2.5
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/app-node/cli_install.test.mjs +13 -1
- package/app-node/install_config.mjs +3 -2
- package/app-node/tts_backends.mjs +1 -1
- package/app-node/tts_backends.test.mjs +1 -1
- package/docs/CONFIGURATION.md +1 -1
- package/docs/FRESH_INSTALL.md +1 -1
- package/docs/i18n/CONFIGURATION.ko.md +1 -1
- package/docs/i18n/FRESH_INSTALL.ko.md +1 -1
- package/integrations/openvoice/__pycache__/synth.cpython-311.pyc +0 -0
- package/package.json +2 -2
- package/scripts/doctor.mjs +1 -1
- package/scripts/install.mjs +14 -0
- package/scripts/install.sh +2 -1
- package/scripts/setup_openvoice.sh +2 -1
- package/scripts/openvoice_smoke.py +0 -34
- /package/{scripts/openvoice_synth.py → integrations/openvoice/synth.py} +0 -0
|
@@ -19,7 +19,8 @@ test('package exposes a short vc shell command', () => {
|
|
|
19
19
|
assert.ok(pkg.files.includes('app-node/'));
|
|
20
20
|
assert.ok(pkg.files.includes('scripts/*.mjs'));
|
|
21
21
|
assert.ok(pkg.files.includes('scripts/*.sh'));
|
|
22
|
-
assert.ok(pkg.files.includes('
|
|
22
|
+
assert.ok(pkg.files.includes('integrations/openvoice/'));
|
|
23
|
+
assert.ok(!pkg.files.includes('scripts/*.py'));
|
|
23
24
|
assert.ok(pkg.files.includes('run.sh'));
|
|
24
25
|
assert.ok(pkg.files.includes('LICENSE'));
|
|
25
26
|
});
|
|
@@ -39,12 +40,23 @@ test('installer shell script links the vc command during setup', () => {
|
|
|
39
40
|
|
|
40
41
|
assert.match(script, /bootstrap_prereqs\.sh/);
|
|
41
42
|
assert.match(script, /--no-wizard/);
|
|
43
|
+
assert.match(script, /--yes\) BOOTSTRAP_ARGS\+=\("\$arg"\); INSTALL_ARGS\+=\("\$arg"\)/);
|
|
42
44
|
assert.match(script, /VERBALCODING_SKIP_BOOTSTRAP/);
|
|
43
45
|
assert.match(script, /npm link/);
|
|
44
46
|
assert.match(script, /Installed shell CLI: vc/);
|
|
45
47
|
assert.match(script, /VERBALCODING_SKIP_CLI_LINK/);
|
|
46
48
|
});
|
|
47
49
|
|
|
50
|
+
test('npm setup supports non-interactive --yes mode', () => {
|
|
51
|
+
const installer = fs.readFileSync(path.join(ROOT, 'scripts', 'install.mjs'), 'utf8');
|
|
52
|
+
const config = fs.readFileSync(path.join(ROOT, 'app-node', 'install_config.mjs'), 'utf8');
|
|
53
|
+
|
|
54
|
+
assert.match(installer, /args\.includes\('--yes'\)/);
|
|
55
|
+
assert.match(installer, /normalizeInstallAnswers\(process\.env\)/);
|
|
56
|
+
assert.match(config, /vc start/);
|
|
57
|
+
assert.doesNotMatch(config, /npm install -g \.\s+#/);
|
|
58
|
+
});
|
|
59
|
+
|
|
48
60
|
test('bootstrap script installs cross-platform prerequisites and local model helpers', () => {
|
|
49
61
|
const script = fs.readFileSync(path.join(ROOT, 'scripts', 'bootstrap_prereqs.sh'), 'utf8');
|
|
50
62
|
|
|
@@ -247,13 +247,14 @@ export function renderInstallSummary(values = {}) {
|
|
|
247
247
|
`Configured Discord voice bridge for harness: ${backend}`,
|
|
248
248
|
'',
|
|
249
249
|
'Next commands:',
|
|
250
|
-
' npm install -g . # or ./scripts/install.sh to install the vc command',
|
|
251
250
|
' vc doctor',
|
|
252
|
-
'
|
|
251
|
+
' vc start',
|
|
253
252
|
'',
|
|
254
253
|
'Legacy project-local equivalents still work:',
|
|
255
254
|
' npm install',
|
|
255
|
+
' ./scripts/install.sh',
|
|
256
256
|
' npm run doctor',
|
|
257
|
+
' ./run.sh',
|
|
257
258
|
'',
|
|
258
259
|
`Auto-join voice channels: ${values.AUTO_JOIN_VOICE_CHANNELS || '일반,General,general'}`,
|
|
259
260
|
`TTS backend: ${values.TTS_BACKEND || 'edge'}`,
|
|
@@ -135,7 +135,7 @@ export function createOpenVoiceBackend(settings, deps = {}) {
|
|
|
135
135
|
return edge.synthesize(text, { signal, kind });
|
|
136
136
|
}
|
|
137
137
|
const out = uniquePath(tmpdir, 'verbalcoding-openvoice', 'wav');
|
|
138
|
-
const script = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '
|
|
138
|
+
const script = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', 'integrations', 'openvoice', 'synth.py');
|
|
139
139
|
const args = [
|
|
140
140
|
script,
|
|
141
141
|
'--openvoice-dir', openvoice.dir,
|
|
@@ -121,7 +121,7 @@ test('OpenVoice final synthesis calls Python wrapper with reference audio and ou
|
|
|
121
121
|
const out = await backend.synthesize('복제 음성 테스트', { kind: 'final' });
|
|
122
122
|
|
|
123
123
|
assert.equal(calls[0].cmd, path.join('/project/.venv-openvoice', 'bin', 'python'));
|
|
124
|
-
assert.ok(calls[0].args.some(arg => String(arg).endsWith('
|
|
124
|
+
assert.ok(calls[0].args.some(arg => String(arg).endsWith('integrations/openvoice/synth.py')));
|
|
125
125
|
assert.ok(calls[0].args.includes('--ref-audio'));
|
|
126
126
|
assert.ok(calls[0].args.includes('/project/voice-samples/me.wav'));
|
|
127
127
|
assert.ok(calls[0].args.includes('--text'));
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -171,7 +171,7 @@ Edge TTS remains the default and fallback. To try local voice cloning with OpenV
|
|
|
171
171
|
mkdir -p voice-samples
|
|
172
172
|
# Put a permitted reference sample at voice-samples/user-reference.wav,
|
|
173
173
|
# or capture one from Discord with !voice-clone capture.
|
|
174
|
-
python3
|
|
174
|
+
python3 integrations/openvoice/synth.py --openvoice-dir vendor/OpenVoice --ref-audio voice-samples/user-reference.wav --text '안녕하세요. 버벌코딩 목소리 복제 테스트입니다.' --output /tmp/verbalcoding-openvoice-smoke.wav
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
Then set:
|
package/docs/FRESH_INSTALL.md
CHANGED
|
@@ -170,7 +170,7 @@ OpenVoice voice cloning is optional. Keep `TTS_BACKEND=edge` for a fresh public
|
|
|
170
170
|
# Download OpenVoice V2 checkpoints into vendor/OpenVoice/checkpoints_v2/
|
|
171
171
|
# Add a permitted local sample at voice-samples/user-reference.wav,
|
|
172
172
|
# or run the bot, say "목소리 샘플 녹음 시작해", then speak 10-30 seconds.
|
|
173
|
-
python3
|
|
173
|
+
python3 integrations/openvoice/synth.py --openvoice-dir vendor/OpenVoice --ref-audio voice-samples/user-reference.wav --text '안녕하세요. 버벌코딩 목소리 복제 테스트입니다.' --output /tmp/verbalcoding-openvoice-smoke.wav
|
|
174
174
|
```
|
|
175
175
|
|
|
176
176
|
Then set `TTS_BACKEND=openvoice`, run `vc doctor`, and test `!voice-test <text>` in Discord.
|
|
@@ -179,7 +179,7 @@ Edge TTS가 기본값이자 fallback입니다. OpenVoice V2로 로컬 음성 복
|
|
|
179
179
|
mkdir -p voice-samples
|
|
180
180
|
# 허가된 기준 샘플을 voice-samples/user-reference.wav에 넣거나,
|
|
181
181
|
# Discord에서 !voice-clone capture로 샘플을 캡처합니다.
|
|
182
|
-
python3
|
|
182
|
+
python3 integrations/openvoice/synth.py --openvoice-dir vendor/OpenVoice --ref-audio voice-samples/user-reference.wav --text '안녕하세요. 버벌코딩 목소리 복제 테스트입니다.' --output /tmp/verbalcoding-openvoice-smoke.wav
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
그 뒤 설정:
|
|
@@ -170,7 +170,7 @@ OpenVoice 음성 복제는 선택 기능입니다. 공개 설치 직후에는 `T
|
|
|
170
170
|
# OpenVoice V2 체크포인트를 vendor/OpenVoice/checkpoints_v2/ 아래에 넣습니다.
|
|
171
171
|
# 허가된 로컬 샘플을 voice-samples/user-reference.wav에 두거나,
|
|
172
172
|
# 봇 실행 후 “목소리 샘플 녹음 시작해”라고 말하고 10~30초 발화합니다.
|
|
173
|
-
python3
|
|
173
|
+
python3 integrations/openvoice/synth.py --openvoice-dir vendor/OpenVoice --ref-audio voice-samples/user-reference.wav --text '안녕하세요. 버벌코딩 목소리 복제 테스트입니다.' --output /tmp/verbalcoding-openvoice-smoke.wav
|
|
174
174
|
```
|
|
175
175
|
|
|
176
176
|
그 뒤 `TTS_BACKEND=openvoice`로 설정하고 `vc doctor`, Discord의 `!voice-test <text>`로 테스트합니다.
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "verbalcoding",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Discord voice bridge for CLI coding agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"docs/",
|
|
35
35
|
"scripts/*.mjs",
|
|
36
36
|
"scripts/*.sh",
|
|
37
|
-
"
|
|
37
|
+
"integrations/openvoice/",
|
|
38
38
|
"run.sh",
|
|
39
39
|
".env.example",
|
|
40
40
|
"README.md",
|
package/scripts/doctor.mjs
CHANGED
|
@@ -86,7 +86,7 @@ if (ttsBackend === 'edge') {
|
|
|
86
86
|
ok = check('OpenVoice repo', fs.existsSync(openvoiceDir), path.relative(ROOT, openvoiceDir)) && ok;
|
|
87
87
|
ok = check('OpenVoice venv', fs.existsSync(openvoiceVenv), path.relative(ROOT, openvoiceVenv)) && ok;
|
|
88
88
|
ok = check('OpenVoice reference audio', fs.existsSync(refAudio), path.relative(ROOT, refAudio)) && ok;
|
|
89
|
-
ok = check('OpenVoice synth wrapper help', spawnSync('python3', ['
|
|
89
|
+
ok = check('OpenVoice synth wrapper help', spawnSync('python3', ['integrations/openvoice/synth.py', '--help'], { cwd: ROOT, encoding: 'utf8' }).status === 0, 'integrations/openvoice/synth.py') && ok;
|
|
90
90
|
note('OpenVoice progress prompts', ['1', 'true', 'yes', 'on'].includes(String(env.OPENVOICE_PROGRESS || '0').toLowerCase()) ? 'openvoice' : 'edge fallback');
|
|
91
91
|
} else if (ttsBackend === 'speechswift') {
|
|
92
92
|
const mode = String(env.SPEECHSWIFT_MODE || 'cli').toLowerCase() === 'server' ? 'server' : 'cli';
|
package/scripts/install.mjs
CHANGED
|
@@ -17,6 +17,7 @@ async function ask(question, fallback = '', options = {}) {
|
|
|
17
17
|
|
|
18
18
|
async function main() {
|
|
19
19
|
const args = process.argv.slice(2);
|
|
20
|
+
const yes = args.includes('--yes') || args.includes('-y');
|
|
20
21
|
if (args[0] === 'instance' || args.includes('--instance')) {
|
|
21
22
|
const { spawnSync } = await import('node:child_process');
|
|
22
23
|
const pass = args[0] === 'instance'
|
|
@@ -26,6 +27,19 @@ async function main() {
|
|
|
26
27
|
process.exitCode = result.status ?? 1;
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
30
|
+
if (yes) {
|
|
31
|
+
const values = normalizeInstallAnswers(process.env);
|
|
32
|
+
const envPath = path.join(ROOT, '.env');
|
|
33
|
+
if (fs.existsSync(envPath)) {
|
|
34
|
+
const backup = `${envPath}.bak-${Date.now()}`;
|
|
35
|
+
fs.copyFileSync(envPath, backup);
|
|
36
|
+
console.log(`Backed up existing .env to ${backup}`);
|
|
37
|
+
}
|
|
38
|
+
fs.writeFileSync(envPath, buildEnvFile(values), { mode: 0o600 });
|
|
39
|
+
console.log(`Wrote ${envPath}`);
|
|
40
|
+
console.log(renderInstallSummary(values));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
29
43
|
globalThis.__rl = readline.createInterface({ input, output });
|
|
30
44
|
try {
|
|
31
45
|
console.log('VerbalCoding installer');
|
package/scripts/install.sh
CHANGED
|
@@ -9,7 +9,8 @@ for arg in "$@"; do
|
|
|
9
9
|
case "$arg" in
|
|
10
10
|
--no-wizard) RUN_WIZARD=0 ;;
|
|
11
11
|
--skip-bootstrap) export VERBALCODING_SKIP_BOOTSTRAP=1 ;;
|
|
12
|
-
--yes
|
|
12
|
+
--yes) BOOTSTRAP_ARGS+=("$arg"); INSTALL_ARGS+=("$arg") ;;
|
|
13
|
+
--skip-system|--skip-model|--skip-edge-tts) BOOTSTRAP_ARGS+=("$arg") ;;
|
|
13
14
|
*) INSTALL_ARGS+=("$arg") ;;
|
|
14
15
|
esac
|
|
15
16
|
done
|
|
@@ -29,6 +29,7 @@ Next manual steps:
|
|
|
29
29
|
https://myshell-public-repo-host.s3.amazonaws.com/openvoice/checkpoints_v2_0417.zip
|
|
30
30
|
2. Extract them under vendor/OpenVoice/checkpoints_v2/
|
|
31
31
|
3. Put a permitted reference sample at voice-samples/user-reference.wav
|
|
32
|
-
4.
|
|
32
|
+
4. Smoke test manually if needed:
|
|
33
|
+
python3 integrations/openvoice/synth.py --openvoice-dir vendor/OpenVoice --ref-audio voice-samples/user-reference.wav --text '안녕하세요. 버벌코딩 목소리 복제 테스트입니다.' --output /tmp/verbalcoding-openvoice-smoke.wav
|
|
33
34
|
5. Set TTS_BACKEND=openvoice in .env and restart VerbalCoding.
|
|
34
35
|
MSG
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Small OpenVoice smoke-test helper for VerbalCoding."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import argparse
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
import subprocess
|
|
9
|
-
import sys
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def main() -> int:
|
|
13
|
-
parser = argparse.ArgumentParser(description="Run a short Korean OpenVoice smoke test")
|
|
14
|
-
parser.add_argument("--openvoice-dir", default="./vendor/OpenVoice")
|
|
15
|
-
parser.add_argument("--ref-audio", default="./voice-samples/user-reference.wav")
|
|
16
|
-
parser.add_argument("--output", default="/tmp/verbalcoding-openvoice-smoke.wav")
|
|
17
|
-
parser.add_argument("--text", default="안녕하세요. 버벌코딩 목소리 복제 테스트입니다.")
|
|
18
|
-
args = parser.parse_args()
|
|
19
|
-
script = Path(__file__).with_name("openvoice_synth.py")
|
|
20
|
-
cmd = [
|
|
21
|
-
sys.executable,
|
|
22
|
-
str(script),
|
|
23
|
-
"--openvoice-dir", args.openvoice_dir,
|
|
24
|
-
"--ref-audio", args.ref_audio,
|
|
25
|
-
"--text", args.text,
|
|
26
|
-
"--language", "KR",
|
|
27
|
-
"--style", "default",
|
|
28
|
-
"--output", args.output,
|
|
29
|
-
]
|
|
30
|
-
return subprocess.call(cmd)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if __name__ == "__main__":
|
|
34
|
-
raise SystemExit(main())
|
|
File without changes
|