@aituber-onair/core 0.1.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 +723 -0
- package/dist/constants/api.d.ts +4 -0
- package/dist/constants/api.js +13 -0
- package/dist/constants/api.js.map +1 -0
- package/dist/constants/index.d.ts +23 -0
- package/dist/constants/index.js +25 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/constants/openaiApi.d.ts +15 -0
- package/dist/constants/openaiApi.js +15 -0
- package/dist/constants/openaiApi.js.map +1 -0
- package/dist/constants/prompts.d.ts +2 -0
- package/dist/constants/prompts.js +13 -0
- package/dist/constants/prompts.js.map +1 -0
- package/dist/core/AITuberOnAirCore.d.ts +142 -0
- package/dist/core/AITuberOnAirCore.js +316 -0
- package/dist/core/AITuberOnAirCore.js.map +1 -0
- package/dist/core/ChatProcessor.d.ts +86 -0
- package/dist/core/ChatProcessor.js +246 -0
- package/dist/core/ChatProcessor.js.map +1 -0
- package/dist/core/EventEmitter.d.ts +35 -0
- package/dist/core/EventEmitter.js +72 -0
- package/dist/core/EventEmitter.js.map +1 -0
- package/dist/core/MemoryManager.d.ts +98 -0
- package/dist/core/MemoryManager.js +208 -0
- package/dist/core/MemoryManager.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/services/chat/ChatService.d.ts +21 -0
- package/dist/services/chat/ChatService.js +2 -0
- package/dist/services/chat/ChatService.js.map +1 -0
- package/dist/services/chat/ChatServiceFactory.d.ts +38 -0
- package/dist/services/chat/ChatServiceFactory.js +55 -0
- package/dist/services/chat/ChatServiceFactory.js.map +1 -0
- package/dist/services/chat/OpenAIChatService.d.ts +38 -0
- package/dist/services/chat/OpenAIChatService.js +166 -0
- package/dist/services/chat/OpenAIChatService.js.map +1 -0
- package/dist/services/chat/OpenAISummarizer.d.ts +25 -0
- package/dist/services/chat/OpenAISummarizer.js +70 -0
- package/dist/services/chat/OpenAISummarizer.js.map +1 -0
- package/dist/services/chat/providers/ChatServiceProvider.d.ts +44 -0
- package/dist/services/chat/providers/ChatServiceProvider.js +2 -0
- package/dist/services/chat/providers/ChatServiceProvider.js.map +1 -0
- package/dist/services/chat/providers/OpenAIChatServiceProvider.d.ts +33 -0
- package/dist/services/chat/providers/OpenAIChatServiceProvider.js +44 -0
- package/dist/services/chat/providers/OpenAIChatServiceProvider.js.map +1 -0
- package/dist/services/voice/VoiceEngineAdapter.d.ts +46 -0
- package/dist/services/voice/VoiceEngineAdapter.js +173 -0
- package/dist/services/voice/VoiceEngineAdapter.js.map +1 -0
- package/dist/services/voice/VoiceService.d.ts +55 -0
- package/dist/services/voice/VoiceService.js +2 -0
- package/dist/services/voice/VoiceService.js.map +1 -0
- package/dist/services/voice/engines/AivisSpeechEngine.d.ts +10 -0
- package/dist/services/voice/engines/AivisSpeechEngine.js +70 -0
- package/dist/services/voice/engines/AivisSpeechEngine.js.map +1 -0
- package/dist/services/voice/engines/NijiVoiceEngine.d.ts +12 -0
- package/dist/services/voice/engines/NijiVoiceEngine.js +105 -0
- package/dist/services/voice/engines/NijiVoiceEngine.js.map +1 -0
- package/dist/services/voice/engines/OpenAiEngine.d.ts +9 -0
- package/dist/services/voice/engines/OpenAiEngine.js +34 -0
- package/dist/services/voice/engines/OpenAiEngine.js.map +1 -0
- package/dist/services/voice/engines/VoiceEngine.d.ts +21 -0
- package/dist/services/voice/engines/VoiceEngine.js +2 -0
- package/dist/services/voice/engines/VoiceEngine.js.map +1 -0
- package/dist/services/voice/engines/VoiceEngineFactory.d.ts +14 -0
- package/dist/services/voice/engines/VoiceEngineFactory.js +34 -0
- package/dist/services/voice/engines/VoiceEngineFactory.js.map +1 -0
- package/dist/services/voice/engines/VoicePeakEngine.d.ts +13 -0
- package/dist/services/voice/engines/VoicePeakEngine.js +46 -0
- package/dist/services/voice/engines/VoicePeakEngine.js.map +1 -0
- package/dist/services/voice/engines/VoiceVoxEngine.d.ts +13 -0
- package/dist/services/voice/engines/VoiceVoxEngine.js +67 -0
- package/dist/services/voice/engines/VoiceVoxEngine.js.map +1 -0
- package/dist/services/voice/engines/index.d.ts +7 -0
- package/dist/services/voice/engines/index.js +7 -0
- package/dist/services/voice/engines/index.js.map +1 -0
- package/dist/services/voice/messages.d.ts +38 -0
- package/dist/services/voice/messages.js +49 -0
- package/dist/services/voice/messages.js.map +1 -0
- package/dist/services/youtube/YouTubeDataApiService.d.ts +69 -0
- package/dist/services/youtube/YouTubeDataApiService.js +255 -0
- package/dist/services/youtube/YouTubeDataApiService.js.map +1 -0
- package/dist/services/youtube/YouTubeService.d.ts +63 -0
- package/dist/services/youtube/YouTubeService.js +2 -0
- package/dist/services/youtube/YouTubeService.js.map +1 -0
- package/dist/types/index.d.ts +82 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/nijiVoice.d.ts +27 -0
- package/dist/types/nijiVoice.js +2 -0
- package/dist/types/nijiVoice.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/screenplay.d.ts +19 -0
- package/dist/utils/screenplay.js +42 -0
- package/dist/utils/screenplay.js.map +1 -0
- package/dist/utils/screenshot.d.ts +19 -0
- package/dist/utils/screenshot.js +44 -0
- package/dist/utils/screenshot.js.map +1 -0
- package/dist/utils/storage.d.ts +44 -0
- package/dist/utils/storage.js +103 -0
- package/dist/utils/storage.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { NIJI_VOICE_API_URL } from '../../../constants';
|
|
2
|
+
/**
|
|
3
|
+
* NijiVoice voice synthesis engine
|
|
4
|
+
*/
|
|
5
|
+
export class NijiVoiceEngine {
|
|
6
|
+
async fetchAudio(input, speaker, apiKey, voiceActor) {
|
|
7
|
+
if (!apiKey) {
|
|
8
|
+
throw new Error('NijiVoice API key is required');
|
|
9
|
+
}
|
|
10
|
+
const talk = input;
|
|
11
|
+
const script = talk.message.trim();
|
|
12
|
+
// get emotion from talk.style and process parameters
|
|
13
|
+
const emotion = talk.style || 'neutral';
|
|
14
|
+
const emotionParams = this.processEmotionParams(emotion, script, voiceActor);
|
|
15
|
+
const generateResponse = await fetch(`${NIJI_VOICE_API_URL}/voice-actors/${speaker}/generate-encoded-voice`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'x-api-key': apiKey,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
accept: 'application/json',
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
script: emotionParams.script,
|
|
24
|
+
speed: emotionParams.speed,
|
|
25
|
+
emotionalLevel: emotionParams.emotionalLevel,
|
|
26
|
+
format: 'mp3',
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
if (!generateResponse.ok) {
|
|
30
|
+
const errorBody = await generateResponse.text();
|
|
31
|
+
console.error('NijiVoice generate-encoded-voice error:', errorBody);
|
|
32
|
+
throw new Error('Failed to generate voice from NijiVoice');
|
|
33
|
+
}
|
|
34
|
+
const generateResult = (await generateResponse.json());
|
|
35
|
+
const base64Audio = generateResult.generatedVoice?.base64Audio;
|
|
36
|
+
if (!base64Audio) {
|
|
37
|
+
throw new Error('Base64 audio not found in NijiVoice response');
|
|
38
|
+
}
|
|
39
|
+
return this.base64ToArrayBuffer(base64Audio);
|
|
40
|
+
}
|
|
41
|
+
processEmotionParams(emotion, script, voiceActor) {
|
|
42
|
+
// set default values
|
|
43
|
+
const defaultEmotionalLevel = 0.7; // default emotional level
|
|
44
|
+
const defaultSpeed = 1.0; // default speed
|
|
45
|
+
let emotionalLevel;
|
|
46
|
+
// if voiceActor does not exist, use default values
|
|
47
|
+
let speed = voiceActor?.recommendedVoiceSpeed
|
|
48
|
+
? String(voiceActor.recommendedVoiceSpeed)
|
|
49
|
+
: String(defaultSpeed);
|
|
50
|
+
// base emotional level (use voiceActor's recommendedEmotionalLevel or default values)
|
|
51
|
+
const baseEmotionalLevel = voiceActor?.recommendedEmotionalLevel
|
|
52
|
+
? Number(voiceActor.recommendedEmotionalLevel)
|
|
53
|
+
: defaultEmotionalLevel;
|
|
54
|
+
// base speed (use voiceActor's recommendedVoiceSpeed or default values)
|
|
55
|
+
let baseSpeed = voiceActor?.recommendedVoiceSpeed
|
|
56
|
+
? Number(voiceActor.recommendedVoiceSpeed)
|
|
57
|
+
: defaultSpeed;
|
|
58
|
+
// adjust according to emotion
|
|
59
|
+
let adjustment = '0.0';
|
|
60
|
+
switch (emotion.toLowerCase()) {
|
|
61
|
+
case 'happy':
|
|
62
|
+
adjustment = '0.2';
|
|
63
|
+
baseSpeed *= 1.1;
|
|
64
|
+
break;
|
|
65
|
+
case 'sad':
|
|
66
|
+
adjustment = '-0.4';
|
|
67
|
+
baseSpeed *= 0.9;
|
|
68
|
+
break;
|
|
69
|
+
case 'angry':
|
|
70
|
+
adjustment = '0.4';
|
|
71
|
+
baseSpeed *= 1.0;
|
|
72
|
+
break;
|
|
73
|
+
case 'surprised':
|
|
74
|
+
adjustment = '0.3';
|
|
75
|
+
baseSpeed *= 1.2;
|
|
76
|
+
break;
|
|
77
|
+
default:
|
|
78
|
+
// if default, set emotional level
|
|
79
|
+
emotionalLevel = String(baseEmotionalLevel);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
if (adjustment !== '0.0') {
|
|
83
|
+
emotionalLevel = (Math.round(Math.min(Math.max(baseEmotionalLevel + Number(adjustment), 0), 1.5) *
|
|
84
|
+
10) / 10).toString();
|
|
85
|
+
}
|
|
86
|
+
// ensure speed is always between 0.4 and 3.0
|
|
87
|
+
speed = (Math.round(Math.min(Math.max(baseSpeed, 0.4), 3.0) * 10) / 10).toString();
|
|
88
|
+
return { script, emotionalLevel, speed };
|
|
89
|
+
}
|
|
90
|
+
base64ToArrayBuffer(base64) {
|
|
91
|
+
const sanitizedBase64 = base64.replace(/[\r\n\s]/g, '');
|
|
92
|
+
const binaryString = atob(sanitizedBase64);
|
|
93
|
+
const len = binaryString.length;
|
|
94
|
+
const buffer = new ArrayBuffer(len);
|
|
95
|
+
const view = new Uint8Array(buffer);
|
|
96
|
+
for (let i = 0; i < len; i++) {
|
|
97
|
+
view[i] = binaryString.charCodeAt(i);
|
|
98
|
+
}
|
|
99
|
+
return buffer;
|
|
100
|
+
}
|
|
101
|
+
getTestMessage(textVoiceText) {
|
|
102
|
+
return textVoiceText || 'にじボイスを使用します';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=NijiVoiceEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NijiVoiceEngine.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/NijiVoiceEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Talk } from '../messages';
|
|
2
|
+
import { VoiceEngine } from './VoiceEngine';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI TTS voice synthesis engine
|
|
5
|
+
*/
|
|
6
|
+
export declare class OpenAiEngine implements VoiceEngine {
|
|
7
|
+
fetchAudio(input: Talk, speaker: string, apiKey?: string): Promise<ArrayBuffer>;
|
|
8
|
+
getTestMessage(textVoiceText?: string): string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI TTS voice synthesis engine
|
|
3
|
+
*/
|
|
4
|
+
export class OpenAiEngine {
|
|
5
|
+
async fetchAudio(input, speaker, apiKey) {
|
|
6
|
+
if (!apiKey) {
|
|
7
|
+
throw new Error('OpenAI API key is required');
|
|
8
|
+
}
|
|
9
|
+
const talk = input;
|
|
10
|
+
const text = talk.message.trim();
|
|
11
|
+
const response = await fetch('https://api.openai.com/v1/audio/speech', {
|
|
12
|
+
method: 'POST',
|
|
13
|
+
headers: {
|
|
14
|
+
'Content-Type': 'application/json',
|
|
15
|
+
Authorization: `Bearer ${apiKey}`,
|
|
16
|
+
},
|
|
17
|
+
body: JSON.stringify({
|
|
18
|
+
model: 'tts-1',
|
|
19
|
+
voice: speaker,
|
|
20
|
+
input: text,
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
console.error('Failed to fetch TTS from OpenAI TTS:', response.status);
|
|
25
|
+
throw new Error('Failed to fetch TTS from OpenAI TTS.');
|
|
26
|
+
}
|
|
27
|
+
const blob = await response.blob();
|
|
28
|
+
return await blob.arrayBuffer();
|
|
29
|
+
}
|
|
30
|
+
getTestMessage(textVoiceText) {
|
|
31
|
+
return textVoiceText || 'OpenAI TTSを使用します';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=OpenAiEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAiEngine.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/OpenAiEngine.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,YAAY;IACvB,KAAK,CAAC,UAAU,CACd,KAAW,EACX,OAAe,EACf,MAAe;QAEf,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,IAAI,GAAG,KAAa,CAAC;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAEjC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,wCAAwC,EAAE;YACrE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,MAAM,EAAE;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,IAAI;aACZ,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED,cAAc,CAAC,aAAsB;QACnC,OAAO,aAAa,IAAI,kBAAkB,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Talk } from '../messages';
|
|
2
|
+
import { VoiceActor } from '../../../types/nijiVoice';
|
|
3
|
+
/**
|
|
4
|
+
* Common interface for voice engines
|
|
5
|
+
*/
|
|
6
|
+
export interface VoiceEngine {
|
|
7
|
+
/**
|
|
8
|
+
* Get voice data
|
|
9
|
+
* @param input script
|
|
10
|
+
* @param speaker speaker ID
|
|
11
|
+
* @param apiKey API key (if needed)
|
|
12
|
+
* @param voiceActor voice actor information (for NijiVoice)
|
|
13
|
+
* @returns ArrayBuffer of voice data
|
|
14
|
+
*/
|
|
15
|
+
fetchAudio(input: Talk, speaker: string, apiKey?: string, voiceActor?: VoiceActor): Promise<ArrayBuffer>;
|
|
16
|
+
/**
|
|
17
|
+
* Get a test message
|
|
18
|
+
* @returns test message
|
|
19
|
+
*/
|
|
20
|
+
getTestMessage(textVoiceText?: string): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceEngine.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/VoiceEngine.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { VoiceEngine } from './VoiceEngine';
|
|
2
|
+
/**
|
|
3
|
+
* Voice engine factory
|
|
4
|
+
* Generate appropriate voice engine instances based on voice engine type
|
|
5
|
+
*/
|
|
6
|
+
export declare class VoiceEngineFactory {
|
|
7
|
+
/**
|
|
8
|
+
* Get the voice engine for the specified engine type
|
|
9
|
+
* @param engineType string of engine type ('voicevox', 'voicepeak', etc.)
|
|
10
|
+
* @returns voice engine instance
|
|
11
|
+
* @throws error if engine type is unknown
|
|
12
|
+
*/
|
|
13
|
+
static getEngine(engineType: string): VoiceEngine;
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { VoiceVoxEngine } from './VoiceVoxEngine';
|
|
2
|
+
import { VoicePeakEngine } from './VoicePeakEngine';
|
|
3
|
+
import { AivisSpeechEngine } from './AivisSpeechEngine';
|
|
4
|
+
import { OpenAiEngine } from './OpenAiEngine';
|
|
5
|
+
import { NijiVoiceEngine } from './NijiVoiceEngine';
|
|
6
|
+
/**
|
|
7
|
+
* Voice engine factory
|
|
8
|
+
* Generate appropriate voice engine instances based on voice engine type
|
|
9
|
+
*/
|
|
10
|
+
export class VoiceEngineFactory {
|
|
11
|
+
/**
|
|
12
|
+
* Get the voice engine for the specified engine type
|
|
13
|
+
* @param engineType string of engine type ('voicevox', 'voicepeak', etc.)
|
|
14
|
+
* @returns voice engine instance
|
|
15
|
+
* @throws error if engine type is unknown
|
|
16
|
+
*/
|
|
17
|
+
static getEngine(engineType) {
|
|
18
|
+
switch (engineType) {
|
|
19
|
+
case 'voicevox':
|
|
20
|
+
return new VoiceVoxEngine();
|
|
21
|
+
case 'voicepeak':
|
|
22
|
+
return new VoicePeakEngine();
|
|
23
|
+
case 'aivisSpeech':
|
|
24
|
+
return new AivisSpeechEngine();
|
|
25
|
+
case 'openai':
|
|
26
|
+
return new OpenAiEngine();
|
|
27
|
+
case 'nijivoice':
|
|
28
|
+
return new NijiVoiceEngine();
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`Unsupported voice engine type: ${engineType}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=VoiceEngineFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceEngineFactory.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/VoiceEngineFactory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,UAAkB;QACjC,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,UAAU;gBACb,OAAO,IAAI,cAAc,EAAE,CAAC;YAC9B,KAAK,WAAW;gBACd,OAAO,IAAI,eAAe,EAAE,CAAC;YAC/B,KAAK,aAAa;gBAChB,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACjC,KAAK,QAAQ;gBACX,OAAO,IAAI,YAAY,EAAE,CAAC;YAC5B,KAAK,WAAW;gBACd,OAAO,IAAI,eAAe,EAAE,CAAC;YAC/B;gBACE,MAAM,IAAI,KAAK,CAAC,kCAAkC,UAAU,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Talk } from '../messages';
|
|
2
|
+
import { VoiceEngine } from './VoiceEngine';
|
|
3
|
+
/**
|
|
4
|
+
* VoicePeak voice synthesis engine
|
|
5
|
+
*/
|
|
6
|
+
export declare class VoicePeakEngine implements VoiceEngine {
|
|
7
|
+
fetchAudio(input: Talk, speaker: string): Promise<ArrayBuffer>;
|
|
8
|
+
/**
|
|
9
|
+
* Map emotion style to VoicePeak's emotion parameters
|
|
10
|
+
*/
|
|
11
|
+
private mapEmotionStyle;
|
|
12
|
+
getTestMessage(textVoiceText?: string): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { VOICEPEAK_API_URL } from '../../../constants';
|
|
2
|
+
/**
|
|
3
|
+
* VoicePeak voice synthesis engine
|
|
4
|
+
*/
|
|
5
|
+
export class VoicePeakEngine {
|
|
6
|
+
async fetchAudio(input, speaker) {
|
|
7
|
+
const talk = input;
|
|
8
|
+
const ttsQueryResponse = await fetch(`${VOICEPEAK_API_URL}/audio_query?speaker=${speaker}&text=${encodeURIComponent(talk.message)}`, { method: 'POST' });
|
|
9
|
+
if (!ttsQueryResponse.ok) {
|
|
10
|
+
throw new Error('Failed to fetch TTS query.');
|
|
11
|
+
}
|
|
12
|
+
const ttsQueryJson = await ttsQueryResponse.json();
|
|
13
|
+
// set emotion from talk.style
|
|
14
|
+
ttsQueryJson['emotion'] = this.mapEmotionStyle(talk.style || 'neutral');
|
|
15
|
+
const synthesisResponse = await fetch(`${VOICEPEAK_API_URL}/synthesis?speaker=${speaker}`, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { 'Content-Type': 'application/json' },
|
|
18
|
+
body: JSON.stringify(ttsQueryJson),
|
|
19
|
+
});
|
|
20
|
+
if (!synthesisResponse.ok) {
|
|
21
|
+
throw new Error('Failed to fetch TTS synthesis result.');
|
|
22
|
+
}
|
|
23
|
+
const blob = await synthesisResponse.blob();
|
|
24
|
+
return await blob.arrayBuffer();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Map emotion style to VoicePeak's emotion parameters
|
|
28
|
+
*/
|
|
29
|
+
mapEmotionStyle(style) {
|
|
30
|
+
switch (style.toLowerCase()) {
|
|
31
|
+
case 'happy':
|
|
32
|
+
case 'fun':
|
|
33
|
+
return 'happy';
|
|
34
|
+
case 'angry':
|
|
35
|
+
return 'angry';
|
|
36
|
+
case 'sad':
|
|
37
|
+
return 'sad';
|
|
38
|
+
default:
|
|
39
|
+
return 'neutral';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
getTestMessage(textVoiceText) {
|
|
43
|
+
return textVoiceText || 'ボイスピークを使用します';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=VoicePeakEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoicePeakEngine.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/VoicePeakEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAIvD;;GAEG;AACH,MAAM,OAAO,eAAe;IAC1B,KAAK,CAAC,UAAU,CAAC,KAAW,EAAE,OAAe;QAC3C,MAAM,IAAI,GAAG,KAAa,CAAC;QAE3B,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAClC,GAAG,iBAAiB,wBAAwB,OAAO,SAAS,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAC9F,EAAE,MAAM,EAAE,MAAM,EAAE,CACnB,CAAC;QAEF,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,CAAC;QAEnD,8BAA8B;QAC9B,YAAY,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,CAAC;QAExE,MAAM,iBAAiB,GAAG,MAAM,KAAK,CACnC,GAAG,iBAAiB,sBAAsB,OAAO,EAAE,EACnD;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;SACnC,CACF,CAAC;QAEF,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,KAAa;QACnC,QAAQ,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YAC5B,KAAK,OAAO,CAAC;YACb,KAAK,KAAK;gBACR,OAAO,OAAO,CAAC;YACjB,KAAK,OAAO;gBACV,OAAO,OAAO,CAAC;YACjB,KAAK,KAAK;gBACR,OAAO,KAAK,CAAC;YACf;gBACE,OAAO,SAAS,CAAC;QACrB,CAAC;IACH,CAAC;IAED,cAAc,CAAC,aAAsB;QACnC,OAAO,aAAa,IAAI,cAAc,CAAC;IACzC,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Talk } from '../messages';
|
|
2
|
+
import { VoiceEngine } from './VoiceEngine';
|
|
3
|
+
/**
|
|
4
|
+
* VoiceVox voice synthesis engine
|
|
5
|
+
*/
|
|
6
|
+
export declare class VoiceVoxEngine implements VoiceEngine {
|
|
7
|
+
fetchAudio(input: Talk, speaker: string): Promise<ArrayBuffer>;
|
|
8
|
+
/**
|
|
9
|
+
* Adjust parameters according to emotion
|
|
10
|
+
*/
|
|
11
|
+
private adjustEmotionParameters;
|
|
12
|
+
getTestMessage(textVoiceText?: string): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { VOICE_VOX_API_URL } from '../../../constants';
|
|
2
|
+
/**
|
|
3
|
+
* VoiceVox voice synthesis engine
|
|
4
|
+
*/
|
|
5
|
+
export class VoiceVoxEngine {
|
|
6
|
+
async fetchAudio(input, speaker) {
|
|
7
|
+
const talk = input;
|
|
8
|
+
// get emotion from talk.style
|
|
9
|
+
const emotion = talk.style || 'neutral';
|
|
10
|
+
const ttsQueryResponse = await fetch(`${VOICE_VOX_API_URL}/audio_query?speaker=${speaker}&text=${encodeURIComponent(talk.message)}`, { method: 'POST' });
|
|
11
|
+
if (!ttsQueryResponse.ok) {
|
|
12
|
+
throw new Error('Failed to fetch TTS query.');
|
|
13
|
+
}
|
|
14
|
+
const ttsQueryJson = await ttsQueryResponse.json();
|
|
15
|
+
// adjust parameters according to emotion
|
|
16
|
+
this.adjustEmotionParameters(ttsQueryJson, emotion);
|
|
17
|
+
const synthesisResponse = await fetch(`${VOICE_VOX_API_URL}/synthesis?speaker=${speaker}`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'Transfer-Encoding': 'chunked',
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify(ttsQueryJson),
|
|
24
|
+
});
|
|
25
|
+
if (!synthesisResponse.ok) {
|
|
26
|
+
throw new Error('Failed to fetch TTS synthesis result.');
|
|
27
|
+
}
|
|
28
|
+
const blob = await synthesisResponse.blob();
|
|
29
|
+
return await blob.arrayBuffer();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Adjust parameters according to emotion
|
|
33
|
+
*/
|
|
34
|
+
adjustEmotionParameters(ttsQueryJson, emotion) {
|
|
35
|
+
// default values
|
|
36
|
+
ttsQueryJson.speedScale = 1.16;
|
|
37
|
+
ttsQueryJson.pitchScale = -0.02;
|
|
38
|
+
ttsQueryJson.intonationScale = 1.26;
|
|
39
|
+
switch (emotion.toLowerCase()) {
|
|
40
|
+
case 'happy':
|
|
41
|
+
ttsQueryJson.speedScale = 1.25;
|
|
42
|
+
ttsQueryJson.pitchScale = 0.05;
|
|
43
|
+
ttsQueryJson.intonationScale = 1.4;
|
|
44
|
+
break;
|
|
45
|
+
case 'sad':
|
|
46
|
+
ttsQueryJson.speedScale = 1.0;
|
|
47
|
+
ttsQueryJson.pitchScale = -0.1;
|
|
48
|
+
ttsQueryJson.intonationScale = 1.0;
|
|
49
|
+
break;
|
|
50
|
+
case 'angry':
|
|
51
|
+
ttsQueryJson.speedScale = 1.2;
|
|
52
|
+
ttsQueryJson.pitchScale = -0.05;
|
|
53
|
+
ttsQueryJson.intonationScale = 1.5;
|
|
54
|
+
break;
|
|
55
|
+
case 'surprised':
|
|
56
|
+
ttsQueryJson.speedScale = 1.3;
|
|
57
|
+
ttsQueryJson.pitchScale = 0.1;
|
|
58
|
+
ttsQueryJson.intonationScale = 1.4;
|
|
59
|
+
break;
|
|
60
|
+
// default: "neutral" etc. other than default values
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
getTestMessage(textVoiceText) {
|
|
64
|
+
return textVoiceText || 'ボイスボックスを使用します';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=VoiceVoxEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceVoxEngine.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/VoiceVoxEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAIvD;;GAEG;AACH,MAAM,OAAO,cAAc;IACzB,KAAK,CAAC,UAAU,CAAC,KAAW,EAAE,OAAe;QAC3C,MAAM,IAAI,GAAG,KAAa,CAAC;QAC3B,8BAA8B;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;QAExC,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAClC,GAAG,iBAAiB,wBAAwB,OAAO,SAAS,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAC9F,EAAE,MAAM,EAAE,MAAM,EAAE,CACnB,CAAC;QAEF,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,CAAC;QACnD,yCAAyC;QACzC,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAEpD,MAAM,iBAAiB,GAAG,MAAM,KAAK,CACnC,GAAG,iBAAiB,sBAAsB,OAAO,EAAE,EACnD;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,mBAAmB,EAAE,SAAS;aAC/B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;SACnC,CACF,CAAC;QAEF,IAAI,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAC5C,OAAO,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACK,uBAAuB,CAAC,YAAiB,EAAE,OAAe;QAChE,iBAAiB;QACjB,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC;QAC/B,YAAY,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC;QAChC,YAAY,CAAC,eAAe,GAAG,IAAI,CAAC;QAEpC,QAAQ,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9B,KAAK,OAAO;gBACV,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC;gBAC/B,YAAY,CAAC,UAAU,GAAG,IAAI,CAAC;gBAC/B,YAAY,CAAC,eAAe,GAAG,GAAG,CAAC;gBACnC,MAAM;YACR,KAAK,KAAK;gBACR,YAAY,CAAC,UAAU,GAAG,GAAG,CAAC;gBAC9B,YAAY,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC;gBAC/B,YAAY,CAAC,eAAe,GAAG,GAAG,CAAC;gBACnC,MAAM;YACR,KAAK,OAAO;gBACV,YAAY,CAAC,UAAU,GAAG,GAAG,CAAC;gBAC9B,YAAY,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC;gBAChC,YAAY,CAAC,eAAe,GAAG,GAAG,CAAC;gBACnC,MAAM;YACR,KAAK,WAAW;gBACd,YAAY,CAAC,UAAU,GAAG,GAAG,CAAC;gBAC9B,YAAY,CAAC,UAAU,GAAG,GAAG,CAAC;gBAC9B,YAAY,CAAC,eAAe,GAAG,GAAG,CAAC;gBACnC,MAAM;YACR,oDAAoD;QACtD,CAAC;IACH,CAAC;IAED,cAAc,CAAC,aAAsB;QACnC,OAAO,aAAa,IAAI,eAAe,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { VoiceEngine } from './VoiceEngine';
|
|
2
|
+
export { VoiceEngineFactory } from './VoiceEngineFactory';
|
|
3
|
+
export { VoiceVoxEngine } from './VoiceVoxEngine';
|
|
4
|
+
export { VoicePeakEngine } from './VoicePeakEngine';
|
|
5
|
+
export { AivisSpeechEngine } from './AivisSpeechEngine';
|
|
6
|
+
export { OpenAiEngine } from './OpenAiEngine';
|
|
7
|
+
export { NijiVoiceEngine } from './NijiVoiceEngine';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { VoiceEngineFactory } from './VoiceEngineFactory';
|
|
2
|
+
export { VoiceVoxEngine } from './VoiceVoxEngine';
|
|
3
|
+
export { VoicePeakEngine } from './VoicePeakEngine';
|
|
4
|
+
export { AivisSpeechEngine } from './AivisSpeechEngine';
|
|
5
|
+
export { OpenAiEngine } from './OpenAiEngine';
|
|
6
|
+
export { NijiVoiceEngine } from './NijiVoiceEngine';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/voice/engines/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { VRMExpressionPresetName } from '@pixiv/three-vrm';
|
|
2
|
+
export type Message = {
|
|
3
|
+
role: 'assistant' | 'system' | 'user';
|
|
4
|
+
content: string;
|
|
5
|
+
timestamp?: number;
|
|
6
|
+
};
|
|
7
|
+
type VisionBlock = {
|
|
8
|
+
type: 'text';
|
|
9
|
+
text: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'image_url';
|
|
12
|
+
image_url: {
|
|
13
|
+
url: string;
|
|
14
|
+
detail?: 'low' | 'high' | 'auto';
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export type MessageWithVision = {
|
|
18
|
+
role: 'assistant' | 'system' | 'user';
|
|
19
|
+
content: string | VisionBlock[];
|
|
20
|
+
};
|
|
21
|
+
declare const talkStyles: readonly ["talk", "happy", "sad", "angry", "fear", "surprised"];
|
|
22
|
+
export type TalkStyle = (typeof talkStyles)[number];
|
|
23
|
+
export type Talk = {
|
|
24
|
+
style: TalkStyle;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
declare const emotions: readonly ["neutral", "happy", "angry", "sad", "relaxed"];
|
|
28
|
+
export type EmotionType = (typeof emotions)[number] & VRMExpressionPresetName;
|
|
29
|
+
/**
|
|
30
|
+
* Set of talk text and emotion, and model's emotion expression
|
|
31
|
+
*/
|
|
32
|
+
export type Screenplay = {
|
|
33
|
+
expression: EmotionType;
|
|
34
|
+
talk: Talk;
|
|
35
|
+
};
|
|
36
|
+
export declare const splitSentence: (text: string) => string[];
|
|
37
|
+
export declare const textsToScreenplay: (texts: string[]) => Screenplay[];
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const talkStyles = [
|
|
2
|
+
'talk',
|
|
3
|
+
'happy',
|
|
4
|
+
'sad',
|
|
5
|
+
'angry',
|
|
6
|
+
'fear',
|
|
7
|
+
'surprised',
|
|
8
|
+
];
|
|
9
|
+
const emotions = ['neutral', 'happy', 'angry', 'sad', 'relaxed'];
|
|
10
|
+
export const splitSentence = (text) => {
|
|
11
|
+
const splitMessages = text.split(/(?<=[。.!?\n])/g);
|
|
12
|
+
return splitMessages.filter((msg) => msg !== '');
|
|
13
|
+
};
|
|
14
|
+
export const textsToScreenplay = (texts) => {
|
|
15
|
+
const screenplays = [];
|
|
16
|
+
let prevExpression = 'neutral';
|
|
17
|
+
for (let i = 0; i < texts.length; i++) {
|
|
18
|
+
const text = texts[i];
|
|
19
|
+
const match = text.match(/\[(.*?)\]/);
|
|
20
|
+
const tag = (match && match[1]) || prevExpression;
|
|
21
|
+
const message = text.replace(/\[(.*?)\]/g, '');
|
|
22
|
+
let expression = prevExpression;
|
|
23
|
+
if (emotions.includes(tag)) {
|
|
24
|
+
expression = tag;
|
|
25
|
+
prevExpression = tag;
|
|
26
|
+
}
|
|
27
|
+
screenplays.push({
|
|
28
|
+
expression: expression,
|
|
29
|
+
talk: {
|
|
30
|
+
style: emotionToTalkStyle(expression),
|
|
31
|
+
message: message,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return screenplays;
|
|
36
|
+
};
|
|
37
|
+
const emotionToTalkStyle = (emotion) => {
|
|
38
|
+
switch (emotion) {
|
|
39
|
+
case 'angry':
|
|
40
|
+
return 'angry';
|
|
41
|
+
case 'happy':
|
|
42
|
+
return 'happy';
|
|
43
|
+
case 'sad':
|
|
44
|
+
return 'sad';
|
|
45
|
+
default:
|
|
46
|
+
return 'talk';
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../../../src/services/voice/messages.ts"],"names":[],"mappings":"AAyBA,MAAM,UAAU,GAAG;IACjB,MAAM;IACN,OAAO;IACP,KAAK;IACL,OAAO;IACP,MAAM;IACN,WAAW;CACH,CAAC;AAQX,MAAM,QAAQ,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,CAAU,CAAC;AAY1E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAY,EAAE;IACtD,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACnD,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAe,EAAgB,EAAE;IACjE,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,IAAI,cAAc,GAAG,SAAS,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAEtC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC;QAElD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAE/C,IAAI,UAAU,GAAG,cAAc,CAAC;QAChC,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAU,CAAC,EAAE,CAAC;YAClC,UAAU,GAAG,GAAG,CAAC;YACjB,cAAc,GAAG,GAAG,CAAC;QACvB,CAAC;QAED,WAAW,CAAC,IAAI,CAAC;YACf,UAAU,EAAE,UAAyB;YACrC,IAAI,EAAE;gBACJ,KAAK,EAAE,kBAAkB,CAAC,UAAyB,CAAC;gBACpD,OAAO,EAAE,OAAO;aACjB;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,OAAoB,EAAa,EAAE;IAC7D,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,OAAO,CAAC;QACjB,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf;YACE,OAAO,MAAM,CAAC;IAClB,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { EventEmitter } from '../../core/EventEmitter';
|
|
2
|
+
import { YouTubeService, YouTubeServiceOptions, YouTubeComment } from './YouTubeService';
|
|
3
|
+
/**
|
|
4
|
+
* YouTube Data API implementation using YouTube service
|
|
5
|
+
*/
|
|
6
|
+
export declare class YouTubeDataApiService extends EventEmitter implements YouTubeService {
|
|
7
|
+
private options;
|
|
8
|
+
private isWatchingLive;
|
|
9
|
+
private watchingIntervalId;
|
|
10
|
+
private nextPageToken;
|
|
11
|
+
private currentLiveId;
|
|
12
|
+
/**
|
|
13
|
+
* Constructor
|
|
14
|
+
* @param options Service settings options
|
|
15
|
+
*/
|
|
16
|
+
constructor(options: YouTubeServiceOptions);
|
|
17
|
+
/**
|
|
18
|
+
* Start watching live comments
|
|
19
|
+
* @param liveId Live ID
|
|
20
|
+
*/
|
|
21
|
+
startWatching(liveId: string): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Stop watching live comments
|
|
24
|
+
*/
|
|
25
|
+
stopWatching(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Return whether currently fetching
|
|
28
|
+
*/
|
|
29
|
+
isWatching(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Set comment fetch interval
|
|
32
|
+
* @param interval Interval in milliseconds
|
|
33
|
+
*/
|
|
34
|
+
setFetchInterval(interval: number): void;
|
|
35
|
+
/**
|
|
36
|
+
* Set comment selection strategy
|
|
37
|
+
* @param strategy Selection strategy ('random' or 'latest')
|
|
38
|
+
*/
|
|
39
|
+
setSelectionStrategy(strategy: 'random' | 'latest'): void;
|
|
40
|
+
/**
|
|
41
|
+
* Fetch latest comments (for manual retrieval)
|
|
42
|
+
* @param liveId Live ID
|
|
43
|
+
* @returns Comments array
|
|
44
|
+
*/
|
|
45
|
+
fetchLatestComments(liveId: string): Promise<YouTubeComment[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Subscribe to comment reception event
|
|
48
|
+
* @param callback Callback when comment is received
|
|
49
|
+
*/
|
|
50
|
+
onComment(callback: (comment: YouTubeComment) => void): void;
|
|
51
|
+
/**
|
|
52
|
+
* Get live chat ID
|
|
53
|
+
* @param liveId Live ID
|
|
54
|
+
* @returns Live chat ID
|
|
55
|
+
*/
|
|
56
|
+
private getLiveChatId;
|
|
57
|
+
/**
|
|
58
|
+
* Fetch live comments
|
|
59
|
+
* @param liveChatId Live chat ID
|
|
60
|
+
* @param usePageToken Whether to use page token
|
|
61
|
+
* @returns Comments array
|
|
62
|
+
*/
|
|
63
|
+
private retrieveLiveComments;
|
|
64
|
+
/**
|
|
65
|
+
* Fetch and process comments
|
|
66
|
+
* @param liveChatId Live chat ID
|
|
67
|
+
*/
|
|
68
|
+
private fetchAndProcessComments;
|
|
69
|
+
}
|