diff --git a/backend/app/api/routers/ws.py b/backend/app/api/routers/ws.py index f9f5519..f659b54 100644 --- a/backend/app/api/routers/ws.py +++ b/backend/app/api/routers/ws.py @@ -137,7 +137,7 @@ def cut_fragment_video(self, path: str, start_ms: int, end_ms: int) -> bool: def extract_audio_from_video(self, video_path: str) -> str | None: """Extract audio from video file and save as WAV with same base filename.""" - # Generate audio file path with .wav extension + # Generate audio file path with .wav extensionu audio_path = video_path.replace(".webm", ".wav") logger.debug("Extracting audio from %s to %s", video_path, audio_path) @@ -439,36 +439,6 @@ async def websocket_video_stream( if text_data == "audio-ready": await service.handle_audio_marker() continue - if text_data is not None: - # Treat any other text frame as a direct user answer (debug mode support) - logger.info( - "Received direct text on WS for interview %s: %s", - interview_id, - text_data[:200], - ) - await service.update_state(InterviewSocketState.GENERATING_RESPONSE) - latest_message = await service.submit_user_answer( - interview_id, text_data.strip() - ) - if latest_message is None: - logger.warning( - "Failed to submit direct text for interview %s", - interview_id, - ) - else: - logger.info( - "Direct text submitted successfully for interview %s", - interview_id, - ) - if settings.use_yandex_speech_synthesis: - await service.update_state( - InterviewSocketState.SPEECH_SYNTHESIS - ) - await service.send_message_to_user(latest_message) - await service.update_state( - InterviewSocketState.AWAITING_USER_ANSWER - ) - continue if data_bytes and len(data_bytes) > 0: service.add_video_chunk(data_bytes) diff --git a/backend/app/services/pdf_parser.py b/backend/app/services/pdf_parser.py index 27f9250..7a1ab30 100644 --- a/backend/app/services/pdf_parser.py +++ b/backend/app/services/pdf_parser.py @@ -158,7 +158,7 @@ async def parse_cv( # Generate JSON schema for precise parsing json_schema = self._get_cv_json_schema() - result = self.gigachat_client.chat( + result = await self.gigachat_client.achat( { "messages": [ { @@ -339,7 +339,7 @@ async def parse_vacancy( # Generate JSON schema for precise parsing json_schema = self._get_vacancy_json_schema() - result = self.gigachat_client.chat( + result = await self.gigachat_client.achat( { "messages": [ { @@ -472,7 +472,7 @@ async def analyze_cv_with_gigachat(self, file_id: str, question: str) -> str: PDFParsingError: If analysis fails """ try: - result = self.gigachat_client.chat( + result = await self.gigachat_client.achat( { "function_call": "auto", "messages": [ @@ -502,7 +502,7 @@ async def analyze_vacancy_with_gigachat(self, file_id: str, question: str) -> st PDFParsingError: If analysis fails """ try: - result = self.gigachat_client.chat( + result = await self.gigachat_client.achat( { "function_call": "auto", "messages": [ diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 6c25588..99ab337 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -74,6 +74,23 @@ http { } } + # WebSocket proxy for /ws/ endpoints + location /ws/ { + proxy_pass http://backend:8000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket specific timeouts + proxy_read_timeout 86400; + proxy_send_timeout 86400; + proxy_connect_timeout 60; + } + # Proxy regular API requests to backend location /api/ { proxy_pass http://backend:8000/; diff --git a/frontend/src/components/interviews/interview-chat.tsx b/frontend/src/components/interviews/interview-chat.tsx index 7e5e80a..fdab759 100644 --- a/frontend/src/components/interviews/interview-chat.tsx +++ b/frontend/src/components/interviews/interview-chat.tsx @@ -32,10 +32,12 @@ export function InterviewChat({ interviewId }: Props) { refetchInterval: 1000, }); const isFinished = interview.data.state === "done"; - const { webcamRef, sendAudioReadyMarker, socketState, sendTextMessage } = - useWebcamStreaming(interviewId, { + const { webcamRef, sendAudioReadyMarker, socketState } = useWebcamStreaming( + interviewId, + { disabled: isFinished, - }); + }, + ); const candidate = useSuspenseQuery( candidateQueryOptions(interview.data.candidate_id), ); @@ -170,7 +172,6 @@ export function InterviewChat({ interviewId }: Props) { e.key === "Enter" && debugPrompt.trim().length > 0 ) { - sendTextMessage(debugPrompt.trim()); setDebugPrompt(""); } }} @@ -178,7 +179,6 @@ export function InterviewChat({ interviewId }: Props) {