-
-
Notifications
You must be signed in to change notification settings - Fork 143
話終わったあとに表情をneutralに戻す #207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import { Screenplay } from './messages' | ||
| import homeStore from '@/features/stores/home' | ||
|
|
||
| type SpeakTask = { | ||
| audioBuffer: ArrayBuffer | ||
| screenplay: Screenplay | ||
| isNeedDecode: boolean | ||
| onComplete?: () => void | ||
| } | ||
|
|
||
| export class SpeakQueue { | ||
| private static readonly QUEUE_CHECK_DELAY = 1500 | ||
| private queue: SpeakTask[] = [] | ||
| private isProcessing = false | ||
|
|
||
| async addTask(task: SpeakTask) { | ||
| this.queue.push(task) | ||
| await this.processQueue() | ||
| } | ||
|
|
||
| private async processQueue() { | ||
| if (this.isProcessing) return | ||
| this.isProcessing = true | ||
| const hs = homeStore.getState() | ||
|
|
||
| while (this.queue.length > 0) { | ||
| const task = this.queue.shift() | ||
| if (task) { | ||
| try { | ||
| const { audioBuffer, screenplay, isNeedDecode, onComplete } = task | ||
| await hs.viewer.model?.speak(audioBuffer, screenplay, isNeedDecode) | ||
| onComplete?.() | ||
| } catch (error) { | ||
| console.error( | ||
| 'An error occurred while processing the speech synthesis task:', | ||
| error | ||
| ) | ||
| if (error instanceof Error) { | ||
| console.error('Error details:', error.message) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| this.isProcessing = false | ||
| this.scheduleNeutralExpression() | ||
| } | ||
|
|
||
| private async scheduleNeutralExpression() { | ||
| const initialLength = this.queue.length | ||
| await new Promise((resolve) => | ||
| setTimeout(resolve, SpeakQueue.QUEUE_CHECK_DELAY) | ||
| ) | ||
|
|
||
| if (this.shouldResetToNeutral(initialLength)) { | ||
| const hs = homeStore.getState() | ||
| console.log('play neutral') | ||
| await hs.viewer.model?.playEmotion('neutral') | ||
| } | ||
| } | ||
|
|
||
| private shouldResetToNeutral(initialLength: number): boolean { | ||
| return initialLength === 0 && this.queue.length === 0 && !this.isProcessing | ||
| } | ||
|
|
||
| clearQueue() { | ||
| this.queue = [] | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,10 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import * as THREE from 'three' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { VRM, VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||
| VRM, | ||||||||||||||||||||||||||||||||||||||||||||||||
| VRMExpressionPresetName, | ||||||||||||||||||||||||||||||||||||||||||||||||
| VRMLoaderPlugin, | ||||||||||||||||||||||||||||||||||||||||||||||||
| VRMUtils, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@pixiv/three-vrm' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { VRMAnimation } from '../../lib/VRMAnimation/VRMAnimation' | ||||||||||||||||||||||||||||||||||||||||||||||||
| import { VRMLookAtSmootherLoaderPlugin } from '@/lib/VRMLookAtSmootherLoaderPlugin/VRMLookAtSmootherLoaderPlugin' | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -86,6 +91,13 @@ export class Model { | |||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||
| * 感情表現を再生する | ||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||
| public async playEmotion(preset: VRMExpressionPresetName) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| this.emoteController?.playEmotion(preset) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+94
to
+99
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 安全性とドキュメンテーションの改善が必要です 以下の改善点を提案させていただきます:
以下の実装を提案します: /**
* 感情表現を再生する
+ * @param preset - 感情表現のプリセット
+ * - 'neutral' - 通常表情
+ * - 'happy' - 笑顔
+ * - 'angry' - 怒り
+ * - 'sad' - 悲しみ
+ * - etc...
+ * @throws Error emoteControllerが初期化されていない場合
+ * @returns Promise<void>
*/
- public async playEmotion(preset: VRMExpressionPresetName) {
+ public async playEmotion(preset: VRMExpressionPresetName): Promise<void> {
+ if (!this.emoteController) {
+ throw new Error('EmoteController is not initialized. Please load VRM first.');
+ }
- this.emoteController?.playEmotion(preset)
+ this.emoteController.playEmotion(preset)
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| public update(delta: number): void { | ||||||||||||||||||||||||||||||||||||||||||||||||
| if (this._lipSync) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| const { volume } = this._lipSync.update() | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
addTaskメソッドにエラーハンドリングの追加を推奨します
タスク追加時の例外処理を実装することで、より堅牢な実装になります。
async addTask(task: SpeakTask) { + try { this.queue.push(task) await this.processQueue() + } catch (error) { + console.error('タスクの追加中にエラーが発生しました:', error) + throw error + } }📝 Committable suggestion