diff --git a/admin/src/components/ThemeImportDialog.tsx b/admin/src/components/ThemeImportDialog.tsx index 52f30f0..5fd0833 100644 --- a/admin/src/components/ThemeImportDialog.tsx +++ b/admin/src/components/ThemeImportDialog.tsx @@ -6,7 +6,6 @@ import { type CreateThemeDto, } from '@/api/themes' import { Button } from '@/components/ui/button' -import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { diff --git a/admin/src/pages/ThemesPage.tsx b/admin/src/pages/ThemesPage.tsx index 4e6fb34..e306f28 100644 --- a/admin/src/pages/ThemesPage.tsx +++ b/admin/src/pages/ThemesPage.tsx @@ -36,7 +36,6 @@ import { Checkbox } from '@/components/ui/checkbox' import { Plus, Search, Edit, Trash2, ChevronLeft, ChevronRight, Upload } from 'lucide-react' import { ThemeEditorDialog } from '@/components/ThemeEditorDialog' import { ThemeImportDialog } from '@/components/ThemeImportDialog' -import type { CreateThemeDto } from '@/api/themes' export default function ThemesPage() { const queryClient = useQueryClient() diff --git a/backend/src/rooms/rooms.service.ts b/backend/src/rooms/rooms.service.ts index 39e9272..92843e3 100644 --- a/backend/src/rooms/rooms.service.ts +++ b/backend/src/rooms/rooms.service.ts @@ -102,8 +102,7 @@ export class RoomsService { } // Не возвращаем пароль в ответе - const roomWithoutPassword = { ...room }; - delete roomWithoutPassword.password; + const { password, ...roomWithoutPassword } = room; return roomWithoutPassword; } diff --git a/backend/src/voice/voice.controller.ts b/backend/src/voice/voice.controller.ts index c982a75..68dca9f 100644 --- a/backend/src/voice/voice.controller.ts +++ b/backend/src/voice/voice.controller.ts @@ -74,6 +74,29 @@ export class VoiceController { } } + @Post('test') + async testVoice(@Res() res: Response) { + this.logger.log('POST /voice/test - Test voice request received'); + try { + const testText = 'Привет! Это тестовое сообщение голосового режима.'; + const audioBuffer = await this.voiceService.generateTTS(testText); + + this.logger.log(`POST /voice/test - Success, sending ${audioBuffer.length} bytes`); + res.setHeader('Content-Type', 'audio/mpeg'); + res.setHeader('Content-Length', audioBuffer.length.toString()); + res.send(audioBuffer); + } catch (error) { + const status = error instanceof HttpException + ? error.getStatus() + : HttpStatus.INTERNAL_SERVER_ERROR; + const message = error.message || 'Failed to generate test speech'; + this.logger.error(`POST /voice/test - Error: ${message} (status: ${status})`); + return res.status(status).json({ + error: message, + }); + } + } + @Get('effects/:effectType') async getEffect( @Param('effectType') effectType: string, diff --git a/src/components/Answer.jsx b/src/components/Answer.jsx index 67cee4e..6cb18f4 100644 --- a/src/components/Answer.jsx +++ b/src/components/Answer.jsx @@ -1,7 +1,12 @@ +import { useEffect, useRef } from 'react' import VoicePlayer from './VoicePlayer' +import { useVoice } from '../hooks/useVoice' import './Answer.css' const Answer = ({ answer, onClick, isRevealed, roomId, questionId }) => { + const { autoPlayAnswers, speak } = useVoice() + const wasRevealedRef = useRef(false) + const getAnswerClass = () => { if (!isRevealed) return 'answer-hidden' return 'answer-revealed' @@ -15,6 +20,18 @@ const Answer = ({ answer, onClick, isRevealed, roomId, questionId }) => { return '#ff6b6b' } + // Auto-play answer when it becomes revealed + useEffect(() => { + if (isRevealed && !wasRevealedRef.current && autoPlayAnswers && roomId && questionId && answer.id) { + console.log('[Answer] Auto-playing answer:', { roomId, questionId, answerId: answer.id }) + speak({ roomId, questionId, contentType: 'answer', answerId: answer.id }) + wasRevealedRef.current = true + } + if (!isRevealed) { + wasRevealedRef.current = false + } + }, [isRevealed, autoPlayAnswers, roomId, questionId, answer.id, speak]) + return ( + {/* Auto-play Answers */} +
+ +
+ {/* Effects Volume */}