@coeiro-operator/audio 1.0.1 → 1.0.2

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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/dist/audio-player.d.ts +134 -0
  3. package/dist/audio-player.d.ts.map +1 -0
  4. package/dist/audio-player.js +707 -0
  5. package/dist/audio-player.js.map +1 -0
  6. package/dist/audio-stream-controller.d.ts +52 -0
  7. package/dist/audio-stream-controller.d.ts.map +1 -0
  8. package/dist/audio-stream-controller.js +121 -0
  9. package/dist/audio-stream-controller.js.map +1 -0
  10. package/dist/audio-synthesizer.d.ts +86 -0
  11. package/dist/audio-synthesizer.d.ts.map +1 -0
  12. package/dist/audio-synthesizer.js +437 -0
  13. package/dist/audio-synthesizer.js.map +1 -0
  14. package/dist/chunk-generation-manager.d.ts +77 -0
  15. package/dist/chunk-generation-manager.d.ts.map +1 -0
  16. package/dist/chunk-generation-manager.js +178 -0
  17. package/dist/chunk-generation-manager.js.map +1 -0
  18. package/dist/constants.d.ts +180 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +219 -0
  21. package/dist/constants.js.map +1 -0
  22. package/dist/index.d.ts +77 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +194 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/speech-queue.d.ts +52 -0
  27. package/dist/speech-queue.d.ts.map +1 -0
  28. package/dist/speech-queue.js +143 -0
  29. package/dist/speech-queue.js.map +1 -0
  30. package/dist/synthesis-processor.d.ts +39 -0
  31. package/dist/synthesis-processor.d.ts.map +1 -0
  32. package/dist/synthesis-processor.js +131 -0
  33. package/dist/synthesis-processor.js.map +1 -0
  34. package/dist/test-helpers.d.ts +19 -0
  35. package/dist/test-helpers.d.ts.map +1 -0
  36. package/dist/test-helpers.js +167 -0
  37. package/dist/test-helpers.js.map +1 -0
  38. package/dist/types.d.ts +63 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +5 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/voice-resolver.d.ts +25 -0
  43. package/dist/voice-resolver.d.ts.map +1 -0
  44. package/dist/voice-resolver.js +141 -0
  45. package/dist/voice-resolver.js.map +1 -0
  46. package/package.json +16 -13
@@ -0,0 +1,167 @@
1
+ /**
2
+ * テスト用ヘルパー関数とモックファクトリ
3
+ */
4
+ import { vi } from 'vitest';
5
+ /**
6
+ * Speakerモックインスタンスを作成
7
+ * Node.js StreamのWritableインターフェースを完全に実装
8
+ */
9
+ export function createMockSpeakerInstance() {
10
+ const mockInstance = {
11
+ write: vi.fn((chunk, encoding, callback) => {
12
+ // 引数の数に応じて適切にコールバックを処理
13
+ const cb = typeof encoding === 'function' ? encoding : callback;
14
+ if (cb)
15
+ cb();
16
+ return true;
17
+ }),
18
+ end: vi.fn((chunk, encoding, callback) => {
19
+ // 引数の数に応じて適切にコールバックを処理
20
+ let cb;
21
+ if (typeof chunk === 'function') {
22
+ cb = chunk;
23
+ }
24
+ else if (typeof encoding === 'function') {
25
+ cb = encoding;
26
+ }
27
+ else {
28
+ cb = callback;
29
+ }
30
+ if (cb)
31
+ setTimeout(cb, 10);
32
+ }),
33
+ on: vi.fn(function (event, callback) {
34
+ if (event === 'close') {
35
+ setTimeout(callback, 10);
36
+ }
37
+ return this;
38
+ }),
39
+ once: vi.fn(function (event, callback) {
40
+ if (event === 'close') {
41
+ setTimeout(callback, 10);
42
+ }
43
+ return this;
44
+ }),
45
+ emit: vi.fn(),
46
+ removeListener: vi.fn(function () { return this; }),
47
+ removeAllListeners: vi.fn(function () { return this; }),
48
+ pipe: vi.fn(),
49
+ unpipe: vi.fn(),
50
+ destroy: vi.fn(),
51
+ _writableState: { ended: false },
52
+ writable: true,
53
+ readable: false,
54
+ };
55
+ // thisバインディングを修正
56
+ mockInstance.on = mockInstance.on.bind(mockInstance);
57
+ mockInstance.once = mockInstance.once.bind(mockInstance);
58
+ mockInstance.removeListener = mockInstance.removeListener.bind(mockInstance);
59
+ mockInstance.removeAllListeners = mockInstance.removeAllListeners.bind(mockInstance);
60
+ return mockInstance;
61
+ }
62
+ /**
63
+ * エラーを発生させるSpeakerモックインスタンスを作成
64
+ */
65
+ export function createErrorMockSpeakerInstance() {
66
+ const mockInstance = createMockSpeakerInstance();
67
+ mockInstance.on = vi.fn(function (event, callback) {
68
+ if (event === 'error') {
69
+ setTimeout(() => callback(new Error('Mock speaker error')), 10);
70
+ }
71
+ return this;
72
+ }).bind(mockInstance);
73
+ mockInstance.once = vi.fn(function (event, callback) {
74
+ if (event === 'error') {
75
+ setTimeout(() => callback(new Error('Mock speaker error')), 10);
76
+ }
77
+ return this;
78
+ }).bind(mockInstance);
79
+ return mockInstance;
80
+ }
81
+ /**
82
+ * テスト用のConfigManagerモックを作成
83
+ */
84
+ export function createMockConfigManager(overrides = {}) {
85
+ const defaultConfig = {
86
+ connection: {
87
+ host: 'localhost',
88
+ port: '50032',
89
+ },
90
+ operator: {
91
+ rate: 200,
92
+ timeout: 14400000,
93
+ assignmentStrategy: 'random',
94
+ },
95
+ audio: {
96
+ latencyMode: 'balanced',
97
+ splitMode: 'punctuation',
98
+ bufferSize: 256,
99
+ parallelGeneration: {
100
+ maxConcurrency: 2,
101
+ delayBetweenRequests: 50,
102
+ bufferAheadCount: 1,
103
+ pauseUntilFirstComplete: true,
104
+ },
105
+ },
106
+ characters: {},
107
+ };
108
+ // overridesで深くマージ
109
+ const mergedConfig = deepMerge(defaultConfig, overrides);
110
+ // ConfigManagerのモックオブジェクトを作成
111
+ const mockConfigManager = {
112
+ getFullConfig: async () => mergedConfig,
113
+ buildDynamicConfig: async () => { },
114
+ getCharacterConfig: async (characterId) => {
115
+ // テスト用のキャラクター設定を返す
116
+ // test-speaker-1などのテスト用IDの場合は適切な設定を返す
117
+ if (characterId === 'test-speaker-1' || characterId === 'test-speaker-uuid') {
118
+ return {
119
+ speakerId: 'test-speaker-1', // テストのモックと一致させる
120
+ name: 'テストスピーカー1',
121
+ defaultStyle: 'ノーマル',
122
+ availableStyles: ['ノーマル'],
123
+ };
124
+ }
125
+ // tsukuyomiなど他のキャラクターも対応
126
+ if (characterId === 'tsukuyomi') {
127
+ return {
128
+ speakerId: '3c37646f-3881-5374-2a83-149267990abc', // 実際のtsukuyomiのspeakerId
129
+ name: 'つくよみちゃん',
130
+ defaultStyle: 'れいせい',
131
+ availableStyles: ['れいせい', 'おしとやか', 'げんき'],
132
+ };
133
+ }
134
+ // デフォルトのキャラクター設定
135
+ return {
136
+ speakerId: characterId + '-uuid',
137
+ name: characterId,
138
+ defaultStyle: 'ノーマル',
139
+ availableStyles: ['ノーマル'],
140
+ };
141
+ },
142
+ getAvailableCharacterIds: async () => ['test-speaker-1', 'tsukuyomi'],
143
+ getOperatorTimeout: async () => mergedConfig.operator.timeout,
144
+ getRate: async () => mergedConfig.operator.rate,
145
+ getAudioConfig: async () => mergedConfig.audio,
146
+ getConnectionConfig: async () => mergedConfig.connection,
147
+ };
148
+ return mockConfigManager;
149
+ }
150
+ /**
151
+ * オブジェクトの深いマージ
152
+ */
153
+ function deepMerge(target, source) {
154
+ const result = { ...target };
155
+ for (const key in source) {
156
+ if (source[key] !== undefined) {
157
+ if (typeof source[key] === 'object' && source[key] !== null && !Array.isArray(source[key])) {
158
+ result[key] = deepMerge(result[key], source[key]);
159
+ }
160
+ else {
161
+ result[key] = source[key];
162
+ }
163
+ }
164
+ }
165
+ return result;
166
+ }
167
+ //# sourceMappingURL=test-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../src/test-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * src/say/types.ts: 音声合成システムの型定義
3
+ */
4
+ import { FullConfig, AudioConfig, ConnectionConfig } from '@coeiro-operator/core';
5
+ export type Config = FullConfig;
6
+ export type { AudioConfig, ConnectionConfig };
7
+ export interface StreamConfig {
8
+ chunkSizeChars: number;
9
+ overlapChars: number;
10
+ bufferSize: number;
11
+ audioBufferMs: number;
12
+ silencePaddingMs: number;
13
+ preloadChunks: number;
14
+ }
15
+ export interface Chunk {
16
+ text: string;
17
+ index: number;
18
+ isFirst: boolean;
19
+ isLast: boolean;
20
+ overlap: number;
21
+ }
22
+ export interface AudioResult {
23
+ chunk: Chunk;
24
+ audioBuffer: ArrayBuffer;
25
+ latency: number;
26
+ }
27
+ import type { Speaker } from '@coeiro-operator/core';
28
+ /**
29
+ * VoiceConfig: 音声合成に必要な最小限の情報
30
+ * Speaker情報と選択されたスタイルIDを含む
31
+ */
32
+ export interface VoiceConfig {
33
+ speaker: Speaker;
34
+ selectedStyleId: number;
35
+ }
36
+ export type SpeechTaskType = 'speech';
37
+ export interface SpeechTask {
38
+ id: number;
39
+ type: SpeechTaskType;
40
+ text: string;
41
+ options: SynthesizeOptions;
42
+ timestamp: number;
43
+ resolve?: () => void;
44
+ reject?: (error: Error) => void;
45
+ }
46
+ export interface SynthesizeOptions {
47
+ voice?: string | VoiceConfig | null;
48
+ rate?: number;
49
+ outputFile?: string | null;
50
+ style?: string;
51
+ chunkMode?: 'none' | 'small' | 'medium' | 'large' | 'punctuation';
52
+ bufferSize?: number;
53
+ allowFallback?: boolean;
54
+ }
55
+ export interface SynthesizeResult {
56
+ success: boolean;
57
+ taskId?: number;
58
+ queueLength?: number;
59
+ outputFile?: string;
60
+ latency?: number;
61
+ mode?: string;
62
+ }
63
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGlF,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAGhC,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;AAE9C,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD,OAAO,KAAK,EAAa,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;AAEtC,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,aAAa,CAAC;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * src/say/types.ts: 音声合成システムの型定義
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * voice-resolver.ts: 音声設定の解決を担当
3
+ */
4
+ import { OperatorManager, ConfigManager } from '@coeiro-operator/core';
5
+ import { AudioSynthesizer } from './audio-synthesizer.js';
6
+ import type { VoiceConfig } from './types.js';
7
+ export declare class VoiceResolver {
8
+ private configManager;
9
+ private operatorManager;
10
+ private audioSynthesizer;
11
+ constructor(configManager: ConfigManager, operatorManager: OperatorManager, audioSynthesizer: AudioSynthesizer);
12
+ /**
13
+ * 現在のオペレータの音声設定を取得
14
+ */
15
+ getCurrentVoiceConfig(styleName?: string | null): Promise<VoiceConfig | null>;
16
+ /**
17
+ * CharacterIdからVoiceConfigを生成
18
+ */
19
+ resolveCharacterToConfig(characterId: string, styleName?: string | null): Promise<VoiceConfig>;
20
+ /**
21
+ * 音声設定を解決
22
+ */
23
+ resolveVoiceConfig(voice: string | VoiceConfig | null | undefined, style?: string, allowFallback?: boolean): Promise<VoiceConfig>;
24
+ }
25
+ //# sourceMappingURL=voice-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-resolver.d.ts","sourceRoot":"","sources":["../src/voice-resolver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,qBAAa,aAAa;IAEtB,OAAO,CAAC,aAAa;IACrB,OAAO,CAAC,eAAe;IACvB,OAAO,CAAC,gBAAgB;gBAFhB,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,gBAAgB,EAAE,gBAAgB;IAG5C;;OAEG;IACG,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAgDnF;;OAEG;IACG,wBAAwB,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,WAAW,CAAC;IAuCvB;;OAEG;IACG,kBAAkB,CACtB,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,GAAG,SAAS,EAC9C,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,GAAE,OAAc,GAC5B,OAAO,CAAC,WAAW,CAAC;CA6CxB"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * voice-resolver.ts: 音声設定の解決を担当
3
+ */
4
+ import { logger } from '@coeiro-operator/common';
5
+ export class VoiceResolver {
6
+ configManager;
7
+ operatorManager;
8
+ audioSynthesizer;
9
+ constructor(configManager, operatorManager, audioSynthesizer) {
10
+ this.configManager = configManager;
11
+ this.operatorManager = operatorManager;
12
+ this.audioSynthesizer = audioSynthesizer;
13
+ }
14
+ /**
15
+ * 現在のオペレータの音声設定を取得
16
+ */
17
+ async getCurrentVoiceConfig(styleName) {
18
+ try {
19
+ const currentStatus = await this.operatorManager.showCurrentOperator();
20
+ if (!currentStatus.characterId) {
21
+ return null;
22
+ }
23
+ const character = await this.operatorManager.getCharacterInfo(currentStatus.characterId);
24
+ if (character && character.speaker && character.speaker.speakerId) {
25
+ // 保存されたセッション情報からスタイルを取得
26
+ const session = await this.operatorManager.getCurrentOperatorSession();
27
+ let selectedStyle;
28
+ if (styleName) {
29
+ // 明示的にスタイルが指定された場合はそれを使用
30
+ selectedStyle = this.operatorManager.selectStyle(character, styleName);
31
+ }
32
+ else if (session?.styleId !== undefined) {
33
+ // セッションに保存されたスタイルIDがある場合はそれを使用
34
+ const savedStyle = character.speaker.styles.find(s => s.styleId === session.styleId);
35
+ if (savedStyle) {
36
+ selectedStyle = savedStyle;
37
+ logger.debug(`保存されたスタイルを使用: ${savedStyle.styleName} (ID:${savedStyle.styleId})`);
38
+ }
39
+ else {
40
+ // 保存されたスタイルが見つからない場合はデフォルトを使用
41
+ selectedStyle = this.operatorManager.selectStyle(character, null);
42
+ }
43
+ }
44
+ else {
45
+ // セッション情報がない場合はデフォルトスタイルを使用
46
+ selectedStyle = this.operatorManager.selectStyle(character, null);
47
+ }
48
+ return {
49
+ speaker: character.speaker,
50
+ selectedStyleId: selectedStyle.styleId,
51
+ };
52
+ }
53
+ return null;
54
+ }
55
+ catch (error) {
56
+ logger.error(`オペレータ音声取得エラー: ${error.message}`);
57
+ return null;
58
+ }
59
+ }
60
+ /**
61
+ * CharacterIdからVoiceConfigを生成
62
+ */
63
+ async resolveCharacterToConfig(characterId, styleName) {
64
+ try {
65
+ // ConfigManagerからCharacter設定を取得
66
+ const characterConfig = await this.configManager.getCharacterConfig(characterId);
67
+ if (!characterConfig) {
68
+ throw new Error(`Character not found: ${characterId}`);
69
+ }
70
+ // speakerIdからspeaker情報を取得(COEIROINKサーバーから)
71
+ const speakers = await this.audioSynthesizer.getSpeakers();
72
+ const speaker = speakers.find(s => s.speakerUuid === characterConfig.speakerId);
73
+ if (!speaker) {
74
+ throw new Error(`Speaker '${characterConfig.speakerId}' not found for character '${characterId}'`);
75
+ }
76
+ // スタイル選択(styleNameが指定されていればそれを使用、そうでなければdefaultStyle)
77
+ let selectedStyle = speaker.styles.find(s => s.styleName === (styleName || characterConfig.defaultStyle));
78
+ if (!selectedStyle) {
79
+ // デフォルトスタイルが見つからない場合は最初のスタイルを使用
80
+ selectedStyle = speaker.styles[0];
81
+ }
82
+ // speaker-provider.Speakerからoperator.Speakerへ変換
83
+ const operatorSpeaker = {
84
+ speakerId: speaker.speakerUuid,
85
+ speakerName: speaker.speakerName,
86
+ styles: speaker.styles,
87
+ };
88
+ return {
89
+ speaker: operatorSpeaker,
90
+ selectedStyleId: selectedStyle.styleId,
91
+ };
92
+ }
93
+ catch (error) {
94
+ logger.error(`Character解決エラー: ${error.message}`);
95
+ throw new Error(`Failed to resolve character '${characterId}': ${error.message}`);
96
+ }
97
+ }
98
+ /**
99
+ * 音声設定を解決
100
+ */
101
+ async resolveVoiceConfig(voice, style, allowFallback = true) {
102
+ if (!voice) {
103
+ // オペレータから音声を取得(スタイル指定も渡す)
104
+ const operatorVoice = await this.getCurrentVoiceConfig(style);
105
+ if (operatorVoice) {
106
+ // スタイル情報を取得して詳細ログ出力
107
+ const selectedStyle = operatorVoice.speaker.styles.find(s => s.styleId === operatorVoice.selectedStyleId);
108
+ const styleName = selectedStyle?.styleName || `ID:${operatorVoice.selectedStyleId}`;
109
+ logger.info(`オペレータ音声を使用: ${operatorVoice.speaker.speakerName} (スタイル: ${styleName})`);
110
+ return operatorVoice;
111
+ }
112
+ else if (allowFallback) {
113
+ // CLIのみ: デフォルトキャラクターを使用(つくよみちゃん)
114
+ const defaultCharacterId = 'tsukuyomi';
115
+ logger.info(`デフォルトキャラクターを使用: ${defaultCharacterId}`);
116
+ return await this.resolveCharacterToConfig(defaultCharacterId, style);
117
+ }
118
+ else {
119
+ // MCP: オペレータが必須
120
+ throw new Error('オペレータが割り当てられていません。まず operator_assign を実行してください。');
121
+ }
122
+ }
123
+ else if (typeof voice === 'string') {
124
+ // string型の場合はCharacterIdとして解決
125
+ logger.info(`キャラクター解決: ${voice}`);
126
+ const voiceConfig = await this.resolveCharacterToConfig(voice, style);
127
+ const selectedStyle = voiceConfig.speaker.styles.find(s => s.styleId === voiceConfig.selectedStyleId);
128
+ const styleName = selectedStyle?.styleName || `ID:${voiceConfig.selectedStyleId}`;
129
+ logger.info(` → ${voiceConfig.speaker.speakerName} (スタイル: ${styleName})`);
130
+ return voiceConfig;
131
+ }
132
+ else {
133
+ // すでにVoiceConfig型の場合はそのまま使用
134
+ const selectedStyle = voice.speaker.styles.find(s => s.styleId === voice.selectedStyleId);
135
+ const styleName = selectedStyle?.styleName || `ID:${voice.selectedStyleId}`;
136
+ logger.info(`VoiceConfig使用: ${voice.speaker.speakerName} (スタイル: ${styleName})`);
137
+ return voice;
138
+ }
139
+ }
140
+ }
141
+ //# sourceMappingURL=voice-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-resolver.js","sourceRoot":"","sources":["../src/voice-resolver.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@coeiro-operator/audio",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Audio synthesis and playback module for COEIRO Operator",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
8
11
  "os": [
9
12
  "darwin",
10
13
  "linux",
@@ -15,21 +18,13 @@
15
18
  "arm64",
16
19
  "ia32"
17
20
  ],
18
- "scripts": {
19
- "build": "tsc --build",
20
- "test": "vitest",
21
- "test:watch": "vitest --watch",
22
- "type-check": "tsc --noEmit",
23
- "lint": "eslint src --ext .ts,.js",
24
- "format": "prettier --write \"src/**/*.{ts,js,json,md}\""
25
- },
26
21
  "dependencies": {
27
- "@coeiro-operator/common": "^1.0.1",
28
- "@coeiro-operator/core": "^1.0.1",
29
22
  "dsp.js": "^1.0.1",
30
23
  "echogarden": "^2.10.1",
31
24
  "node-fetch": "^3.3.2",
32
- "wav": "^1.0.2"
25
+ "wav": "^1.0.2",
26
+ "@coeiro-operator/core": "1.0.2",
27
+ "@coeiro-operator/common": "1.0.2"
33
28
  },
34
29
  "optionalDependencies": {
35
30
  "speaker": "^0.5.5"
@@ -58,5 +53,13 @@
58
53
  },
59
54
  "publishConfig": {
60
55
  "access": "public"
56
+ },
57
+ "scripts": {
58
+ "build": "tsc --build",
59
+ "test": "vitest",
60
+ "test:watch": "vitest --watch",
61
+ "type-check": "tsc --noEmit",
62
+ "lint": "eslint src --ext .ts,.js",
63
+ "format": "prettier --write \"src/**/*.{ts,js,json,md}\""
61
64
  }
62
- }
65
+ }