@jokio/sdk 0.0.1 → 0.0.3

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/test/index.html CHANGED
@@ -9,29 +9,72 @@
9
9
  <body>
10
10
  <h1>Library Test</h1>
11
11
 
12
- <button onclick="playAudio()">Edge TTS</button>
13
-
12
+ <button onclick="playAudio()">TTS</button>
14
13
  <button onclick="playAudio2()">Voicevox TTS</button>
15
14
 
16
15
  <script type="module">
17
- import { jok } from './dist/jokio.sdk.es.js';
16
+ // import { jok } from 'https://esm.run/@jokio/sdk';
17
+ import { jok, VoicevoxTtsService } from './dist/jokio.sdk.es.js';
18
+
18
19
  window.jok = jok
19
- // jok.voicevoxTts.getVoices().then(console.log)
20
- // document.body.innerHTML += `<p>${}</p>`;
20
+
21
+ window.getVoicevoxVoices = async function () {
22
+ const voices = await jok.voicevoxTts.getVoices()
23
+
24
+ console.log(voices)
25
+ }
26
+
27
+ window.getVoices = async function () {
28
+ const voices = await jok.tts.getVoices()
29
+
30
+ console.log(voices)
31
+ }
21
32
 
22
33
  window.playAudio = async function () {
23
- const audio = await jok.edgeTts.getAudio("Hello there, how are you?", "en-US-AvaNeural")
34
+ const audio = await jok.tts.getAudio("Hello there, how are you?", "en-US-AvaNeural")
24
35
 
25
36
  audio.play()
26
37
  }
27
38
 
28
-
29
39
  window.playAudio2 = async function () {
30
- const audio = await jok.voicevoxTts.getAudio("こんにちわ、おげんきですか?あなたはあたまがいいですね。", 3)
40
+ const tts = new VoicevoxTtsService({ voicevoxUrl: 'https://voicevox.fly.dev' })
41
+
42
+ const audio = await tts.getAudio("こんにちわ、おげんきですか?あなたはあたまがいいですね。", 3)
31
43
 
32
44
  audio.play()
33
45
  }
34
46
 
47
+ window.requestEmailLogin = async function (email) {
48
+ const res = await jok.auth.requestEmailLogin(email, 'https://localhost:5173')
49
+
50
+ return res
51
+ }
52
+
53
+ window.completeEmailLogin = async function (email, otpCode) {
54
+ const res = await jok.auth.completeEmailLogin(email, otpCode)
55
+
56
+ return res
57
+ }
58
+
59
+ window.passkeyLogin = async function (displayName) {
60
+ const res = await jok.auth.requestPasskeyLogin(displayName)
61
+
62
+ return res
63
+ }
64
+
65
+ window.natsConnect = async function () {
66
+ await jok.nats.connect()
67
+ }
68
+
69
+ window.natsSubscribe = async function () {
70
+ await jok.nats.on('dev.test', (data, ctx) => {
71
+ console.lg({ data, ctx })
72
+ })
73
+ }
74
+
75
+ window.natsPublish = async function () {
76
+ await jok.nats.publish('dev.test', { name: 'User', age: 11 })
77
+ }
35
78
 
36
79
  window.p2pChat = async function () {
37
80
  const k1 = await jok.crypto.createSessionKeyPair()
@@ -1,13 +0,0 @@
1
- export declare class EdgeTtsService {
2
- getAudioBuffer(text: string, voice: string, options?: {
3
- pitch?: string;
4
- rate?: string;
5
- volume?: string;
6
- }): Promise<ArrayBuffer>;
7
- getAudio(text: string, voice: string, options?: {
8
- pitch?: string;
9
- rate?: string;
10
- volume?: string;
11
- }): Promise<HTMLAudioElement>;
12
- getVoices(): Promise<any[]>;
13
- }
@@ -1,153 +0,0 @@
1
- import { playAudioFromBuffer } from './common/playAudioFromBuffer'
2
-
3
- export class EdgeTtsService {
4
- async getAudioBuffer(
5
- text: string,
6
- voice: string,
7
- options?: { pitch?: string; rate?: string; volume?: string },
8
- ): Promise<ArrayBuffer> {
9
- const audioChunks: Uint8Array[] = []
10
- const reqId = crypto.randomUUID() // Supported in most modern browsers
11
-
12
- return new Promise((resolve, reject) => {
13
- const ws = new WebSocket(
14
- `${Constants.WSS_URL}?trustedclienttoken=${Constants.TRUSTED_CLIENT_TOKEN}&ConnectionId=${reqId}`,
15
- )
16
-
17
- ws.binaryType = 'arraybuffer'
18
-
19
- const SSML_text = getSSML(text, voice, options)
20
-
21
- ws.addEventListener('open', () => {
22
- const configMessage = buildTTSConfigMessage()
23
- ws.send(configMessage)
24
-
25
- const speechMessage =
26
- `X-RequestId:${reqId}\r\n` +
27
- `Content-Type:application/ssml+xml\r\n` +
28
- `X-Timestamp:${new Date().toISOString()}Z\r\n` +
29
- `Path:ssml\r\n\r\n` +
30
- SSML_text
31
-
32
- ws.send(speechMessage)
33
- })
34
-
35
- ws.addEventListener('message', event => {
36
- const data = event.data
37
-
38
- if (data instanceof ArrayBuffer) {
39
- const buffer = new Uint8Array(data)
40
- const needle = new TextEncoder().encode('Path:audio\r\n')
41
-
42
- const index = findSubarray(buffer, needle)
43
- if (index !== -1) {
44
- const audioData = buffer.subarray(index + needle.length)
45
- audioChunks.push(audioData)
46
- }
47
-
48
- const textData = new TextDecoder().decode(buffer)
49
- if (textData.includes('Path:turn.end')) {
50
- ws.close()
51
- }
52
- } else {
53
- if (data.includes('Path:turn.end')) {
54
- ws.close()
55
- }
56
- }
57
- })
58
-
59
- ws.addEventListener('close', () => {
60
- if (!audioChunks.length) {
61
- reject('No audio data available to save.')
62
- return
63
- }
64
-
65
- // Combine all Uint8Arrays into one ArrayBuffer
66
- const totalLength = audioChunks.reduce(
67
- (acc, chunk) => acc + chunk.length,
68
- 0,
69
- )
70
- const finalBuffer = new Uint8Array(totalLength)
71
- let offset = 0
72
- for (const chunk of audioChunks) {
73
- finalBuffer.set(chunk, offset)
74
- offset += chunk.length
75
- }
76
-
77
- resolve(finalBuffer.buffer) // ArrayBuffer
78
- })
79
-
80
- ws.addEventListener('error', err => {
81
- reject(err)
82
- })
83
- })
84
- }
85
-
86
- async getAudio(
87
- text: string,
88
- voice: string,
89
- options?: { pitch?: string; rate?: string; volume?: string },
90
- ) {
91
- return this.getAudioBuffer(text, voice, options).then(x =>
92
- playAudioFromBuffer(x),
93
- )
94
- }
95
-
96
- async getVoices(): Promise<any[]> {
97
- const response = await fetch(
98
- `${Constants.VOICES_URL}?trustedclienttoken=${Constants.TRUSTED_CLIENT_TOKEN}`,
99
- )
100
- const data = await response.json()
101
- return data.map((voice: any) => ({
102
- id: voice.ShortName,
103
- locale: voice.Locale,
104
- description: voice.FriendlyName,
105
- }))
106
- }
107
- }
108
-
109
- const Constants = {
110
- TRUSTED_CLIENT_TOKEN: '6A5AA1D4EAFF4E9FB37E23D68491D6F4',
111
- WSS_URL:
112
- 'wss://speech.platform.bing.com/consumer/speech/synthesize/readaloud/edge/v1',
113
- VOICES_URL:
114
- 'https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list',
115
- }
116
-
117
- const buildTTSConfigMessage = (): string => {
118
- return (
119
- `X-Timestamp:${new Date().toISOString()}Z\r\nContent-Type:application/json; charset=utf-8\r\nPath:speech.config\r\n\r\n` +
120
- `{"context":{"synthesis":{"audio":{"metadataoptions":{"sentenceBoundaryEnabled":false,"wordBoundaryEnabled":true},"outputFormat":"audio-24khz-48kbitrate-mono-mp3"}}}}`
121
- )
122
- }
123
-
124
- const getSSML = (
125
- text: string,
126
- voice: string,
127
- options: any = {},
128
- ): string => {
129
- options.pitch = options.pitch?.replace('hz', 'Hz')
130
- const pitch = options.pitch || '0Hz' // this.validatePitch(options.pitch || '0Hz');
131
- const rate = options.rate || '0%' // this.validateRate(options.rate || '0%');
132
- const volume = options.volume || '0%' // this.validateVolume(options.volume || '0%');
133
-
134
- return `<speak version='1.0' xml:lang='en-US'><voice name='${voice}'><prosody pitch='${pitch}' rate='${rate}' volume='${volume}'>${text}</prosody></voice></speak>`
135
- }
136
-
137
- // Helper: Finds a subarray inside another Uint8Array
138
- function findSubarray(
139
- haystack: Uint8Array,
140
- needle: Uint8Array,
141
- ): number {
142
- for (let i = 0; i <= haystack.length - needle.length; i++) {
143
- let match = true
144
- for (let j = 0; j < needle.length; j++) {
145
- if (haystack[i + j] !== needle[j]) {
146
- match = false
147
- break
148
- }
149
- }
150
- if (match) return i
151
- }
152
- return -1
153
- }