Update memory: Camie Tagger v2 upgrade results

This commit is contained in:
root
2026-03-30 12:27:20 +02:00
commit c3033db6a7
1082 changed files with 649864 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 SchneeHertz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,98 @@
# node-edge-tts
node-edge-tts is a module that utilizes Microsoft Edge's online TTS (Text-to-Speech) service on Node.js
## Installation
```
npm install node-edge-tts
```
#### Or you can directly use it in the command line.
```
npx node-edge-tts -t 'Hello world'
```
## Command line usage
```
Usage: npx node-edge-tts [options]
Options:
--help Show help [boolean]
--version Show version number [boolean]
-t, --text The text to be converted to speech [string] [required]
-f, --filepath The output file path [string] [default: "./output.mp3"]
-v, --voice The voice to be used
[string] [default: "zh-CN-XiaoyiNeural"]
-l, --lang The language to be used [string] [default: "zh-CN"]
-o, --outputFormat The output format
[string] [default: "audio-24khz-48kbitrate-mono-mp3"]
--pitch The pitch of the voice [string] [default: "default"]
-r, --rate The rate of the voice [string] [default: "default"]
--volume The volume of the voice [string] [default: "default"]
-s, --saveSubtitles Whether to save subtitles [boolean] [default: false]
-p, --proxy example: http://localhost:7890 [string]
--timeout The timeout of the request [number] [default: 10000]
Examples:
npx node-edge-tts -t 'Hello world' -f './output.mp3'
```
## Module usage
```
const { EdgeTTS } = require('node-edge-tts')
```
or
```
import { EdgeTTS } from 'node-edge-tts'
```
```
const tts = new EdgeTTS()
await tts.ttsPromise('Hello world', path_to_audiofile_with_extension)
```
### configure
```
const tts = new EdgeTTS({
voice: 'en-US-AriaNeural',
lang: 'en-US',
outputFormat: 'audio-24khz-96kbitrate-mono-mp3',
saveSubtitles: true,
proxy: 'http://localhost:7890',
pitch: '-10%',
rate: '+10%',
volume: '-50%',
timeout: 10000
})
```
You can find the available options for speechconfig at [voice/lang](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts)|[outputFormat](https://learn.microsoft.com/en-us/dotnet/api/microsoft.cognitiveservices.speech.speechsynthesisoutputformat?view=azure-dotnet)|[pitch/rate/volume](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/speech-synthesis-markup-voice), but not all options are available due to limitations of the services provided by Microsoft Edge.
### subtitles
Subtitles are json files with the same name as the audio file, as shown below:
```
\\ the *start* is the time point at which the *part* begins,
\\ the *end* is the time point at which the *part* ends,
\\ measured in milliseconds.
[
{ "part": "node-edge-tts ", "start": 100, "end": 1287 },
{ "part": "is ", "start": 1287, "end": 1450 },
{ "part": "a ", "start": 1450, "end": 1500 },
{ "part": "module ", "start": 1500, "end": 2037 },
{ "part": "that ", "start": 2037, "end": 2350 },
{ "part": "utilizes ", "start": 2350, "end": 3162 },
{ "part": "Microsoft ", "start": 3162, "end": 3762 },
{ "part": "Edge's ", "start": 3762, "end": 4212 },
{ "part": "online ", "start": 4212, "end": 4750 },
{ "part": "TTS (", "start": 4750, "end": 5450 },
{ "part": "Text-to-Speech) ", "start": 5600, "end": 6637 },
{ "part": "service ", "start": 6800, "end": 7387 },
{ "part": "on ", "start": 7387, "end": 7600 },
{ "part": "Node.", "start": 7600, "end": 7950 },
{ "part": "js", "start": 8012, "end": 8762 }
]
```

44
skills/edge-tts/scripts/node_modules/node-edge-tts/bin.js generated vendored Executable file
View File

@@ -0,0 +1,44 @@
#!/usr/bin/env node
const { EdgeTTS } = require('./dist/edge-tts.js')
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const argv = yargs(hideBin(process.argv))
.usage('Usage: npx node-edge-tts [options]')
.options({
text: { type: 'string', demandOption: true, alias: 't', describe: 'The text to be converted to speech' },
filepath: { type: 'string', alias: 'f', describe: 'The output file path' },
voice: { type: 'string', alias: 'v', describe: 'The voice to be used' },
lang: { type: 'string', alias: 'l', describe: 'The language to be used' },
outputFormat: { type: 'string', alias: 'o', describe: 'The output format' },
pitch: { type: 'string', describe: 'The pitch of the voice' },
rate: { type: 'string', alias: 'r', describe: 'The rate of the voice' },
volume: { type: 'string', describe: 'The volume of the voice'},
saveSubtitles: { type: 'boolean', alias: 's', describe: 'Whether to save subtitles' },
proxy: { type: 'string', alias: 'p', describe: 'example: http://localhost:7890' },
timeout: { type: 'number', describe: 'The timeout of the request' }
})
.default({
filepath: `./output.mp3`,
voice: 'zh-CN-XiaoyiNeural',
lang: 'zh-CN',
outputFormat: 'audio-24khz-48kbitrate-mono-mp3',
pitch: 'default',
rate: 'default',
volume: 'default',
saveSubtitles: false,
timeout: 10000
})
.example(`npx node-edge-tts -t 'Hello world' -f './output.mp3'`)
.argv
const { text, filepath, voice, lang, outputFormat, pitch, rate, volume, saveSubtitles, proxy } = argv
const tts = new EdgeTTS({ voice, lang, outputFormat, pitch, rate, volume, saveSubtitles, proxy })
;(async () => {
await tts.ttsPromise(text, filepath)
console.log(`Converted to ${filepath}`)
if (saveSubtitles) {
console.log(`Saved subtitles to ${filepath}.json`)
}
process.exit()
})()

View File

@@ -0,0 +1,3 @@
export declare const CHROMIUM_FULL_VERSION = "130.0.2849.68";
export declare const TRUSTED_CLIENT_TOKEN = "6A5AA1D4EAFF4E9FB37E23D68491D6F4";
export declare function generateSecMsGecToken(): string;

View File

@@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateSecMsGecToken = exports.TRUSTED_CLIENT_TOKEN = exports.CHROMIUM_FULL_VERSION = void 0;
const node_crypto_1 = require("node:crypto");
exports.CHROMIUM_FULL_VERSION = '130.0.2849.68';
exports.TRUSTED_CLIENT_TOKEN = '6A5AA1D4EAFF4E9FB37E23D68491D6F4';
const WINDOWS_FILE_TIME_EPOCH = 11644473600n;
function generateSecMsGecToken() {
const ticks = BigInt(Math.floor((Date.now() / 1000) + Number(WINDOWS_FILE_TIME_EPOCH))) * 10000000n;
const roundedTicks = ticks - (ticks % 3000000000n);
const strToHash = `${roundedTicks}${exports.TRUSTED_CLIENT_TOKEN}`;
const hash = (0, node_crypto_1.createHash)('sha256');
hash.update(strToHash, 'ascii');
return hash.digest('hex').toUpperCase();
}
exports.generateSecMsGecToken = generateSecMsGecToken;

View File

@@ -0,0 +1,33 @@
import { WebSocket } from 'ws';
type subLine = {
part: string;
start: number;
end: number;
};
type configure = {
voice?: string;
lang?: string;
outputFormat?: string;
saveSubtitles?: boolean;
proxy?: string;
rate?: string;
pitch?: string;
volume?: string;
timeout?: number;
};
declare class EdgeTTS {
private voice;
private lang;
private outputFormat;
private saveSubtitles;
private proxy;
private rate;
private pitch;
private volume;
private timeout;
constructor({ voice, lang, outputFormat, saveSubtitles, proxy, rate, pitch, volume, timeout }?: configure);
_connectWebSocket(): Promise<WebSocket>;
_saveSubFile(subFile: subLine[], text: string, audioPath: string): void;
ttsPromise(text: string, audioPath: string): Promise<unknown>;
}
export { EdgeTTS };

View File

@@ -0,0 +1,127 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EdgeTTS = void 0;
const node_crypto_1 = require("node:crypto");
const node_fs_1 = require("node:fs");
const ws_1 = require("ws");
const https_proxy_agent_1 = require("https-proxy-agent");
const drm_1 = require("./drm");
class EdgeTTS {
constructor({ voice = 'zh-CN-XiaoyiNeural', lang = 'zh-CN', outputFormat = 'audio-24khz-48kbitrate-mono-mp3', saveSubtitles = false, proxy, rate = 'default', pitch = 'default', volume = 'default', timeout = 10000 } = {}) {
this.voice = voice;
this.lang = lang;
this.outputFormat = outputFormat;
this.saveSubtitles = saveSubtitles;
this.proxy = proxy;
this.rate = rate;
this.pitch = pitch;
this.volume = volume;
this.timeout = timeout;
}
async _connectWebSocket() {
const wsConnect = new ws_1.WebSocket(`wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1?TrustedClientToken=${drm_1.TRUSTED_CLIENT_TOKEN}&Sec-MS-GEC=${(0, drm_1.generateSecMsGecToken)()}&Sec-MS-GEC-Version=1-${drm_1.CHROMIUM_FULL_VERSION}`, {
host: 'speech.platform.bing.com',
origin: 'chrome-extension://jdiccldimpdaibmpdkjnbmckianbfold',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0',
},
agent: this.proxy ? new https_proxy_agent_1.HttpsProxyAgent(this.proxy) : undefined
});
return new Promise((resolve) => {
wsConnect.on('open', () => {
wsConnect.send(`Content-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n
{
"context": {
"synthesis": {
"audio": {
"metadataoptions": {
"sentenceBoundaryEnabled": "false",
"wordBoundaryEnabled": "true"
},
"outputFormat": "${this.outputFormat}"
}
}
}
}
`);
resolve(wsConnect);
});
});
}
_saveSubFile(subFile, text, audioPath) {
let subPath = audioPath + '.json';
let subChars = text.split('');
let subCharIndex = 0;
subFile.forEach((cue, index) => {
let fullPart = '';
let stepIndex = 0;
for (let sci = subCharIndex; sci < subChars.length; sci++) {
if (subChars[sci] === cue.part[stepIndex]) {
fullPart = fullPart + subChars[sci];
stepIndex += 1;
}
else if (subChars[sci] === subFile?.[index + 1]?.part?.[0]) {
subCharIndex = sci;
break;
}
else {
fullPart = fullPart + subChars[sci];
}
}
cue.part = fullPart;
});
(0, node_fs_1.writeFileSync)(subPath, JSON.stringify(subFile, null, ' '), { encoding: 'utf-8' });
}
async ttsPromise(text, audioPath) {
const _wsConnect = await this._connectWebSocket();
return new Promise((resolve, reject) => {
let audioStream = (0, node_fs_1.createWriteStream)(audioPath);
let subFile = [];
let timeout = setTimeout(() => reject('Timed out'), this.timeout);
_wsConnect.on('message', async (data, isBinary) => {
if (isBinary) {
let separator = 'Path:audio\r\n';
let index = data.indexOf(separator) + separator.length;
let audioData = data.subarray(index);
audioStream.write(audioData);
}
else {
let message = data.toString();
if (message.includes('Path:turn.end')) {
audioStream.end();
_wsConnect.close();
if (this.saveSubtitles) {
this._saveSubFile(subFile, text, audioPath);
}
clearTimeout(timeout);
resolve();
}
else if (message.includes('Path:audio.metadata')) {
let splitTexts = message.split('\r\n');
try {
let metadata = JSON.parse(splitTexts[splitTexts.length - 1]);
metadata['Metadata'].forEach((element) => {
subFile.push({
part: element['Data']['text']['Text'],
start: Math.floor(element['Data']['Offset'] / 10000),
end: Math.floor((element['Data']['Offset'] + element['Data']['Duration']) / 10000)
});
});
}
catch { }
}
}
});
let requestId = (0, node_crypto_1.randomBytes)(16).toString('hex');
_wsConnect.send(`X-RequestId:${requestId}\r\nContent-Type:application/ssml+xml\r\nPath:ssml\r\n\r\n
` + `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="https://www.w3.org/2001/mstts" xml:lang="${this.lang}">
<voice name="${this.voice}">
<prosody rate="${this.rate}" pitch="${this.pitch}" volume="${this.volume}">
${text}
</prosody>
</voice>
</speak>`);
});
}
}
exports.EdgeTTS = EdgeTTS;

View File

@@ -0,0 +1,40 @@
{
"name": "node-edge-tts",
"version": "1.2.9",
"description": "node-edge-tts is a module that using Microsoft Edge's online TTS (Text-to-Speech) service on the Node.js",
"keywords": [
"TTS",
"Text-to-Speech",
"Edge"
],
"main": "dist/edge-tts.js",
"types": "dist/edge-tts.d.ts",
"files": [
"/dist",
"bin.js"
],
"repository": {
"type": "git",
"url": "git+https://github.com/SchneeHertz/node-edge-tts.git"
},
"homepage": "https://github.com/SchneeHertz/node-edge-tts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"author": "SchneeHertz",
"license": "MIT",
"dependencies": {
"https-proxy-agent": "^7.0.1",
"ws": "^8.13.0",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/ws": "^8.5.5",
"@types/yargs": "^17.0.24",
"typescript": "^5.2.2"
},
"bin": {
"node-edge-tts": "bin.js"
}
}