diff --git a/app/service/interaction.py b/app/service/interaction.py index c48da29..f0e732c 100644 --- a/app/service/interaction.py +++ b/app/service/interaction.py @@ -25,6 +25,10 @@ # Whisper 모델 (tiny, CPU, int8) whisper_model = WhisperModel("tiny", device="cpu", compute_type="int8") +# 종료 키워드 목록 +EXIT_KEYWORDS = ["그만", "이제 그만", "종료", "끝낼래", "안녕", "잘 자", "다음에 보자", "나중에 얘기해"] +START_COMMUNICATION = "오늘 좋은 하루 보냈나~~?? 어떻게 지냈어!!" +END_COMMUNICATION = "오늘 이야기 나눠서 좋았어. 푹 쉬고, 또 얘기하자~!" def interaction(alias: str): @@ -32,9 +36,11 @@ def interaction(alias: str): alias: 사용자 이름 또는 AI가 부르는 별칭 (ex: "홍길동") 1) alias 인사 → TTS → 재생 2) 이후 반복: emotion_record → Whisper STT → GPT 질문 생성 → TTS → 재생 + 종료는 키워드 또는 Ctrl+C로 가능 """ + # 1) alias 인사 - greet_text = f"{alias}~~ 오늘 좋은 하루 보냈나~~?? 어떻게 지냈어!!" + greet_text = f"{alias}~~ " + START_COMMUNICATION print("👋 인사:", greet_text) greet_audio = text_to_speech_file(greet_text) subprocess.run(["mpg321", greet_audio], check=True) @@ -42,22 +48,20 @@ def interaction(alias: str): # 대화 이력 초기화 messages = [ {"role": "system", - "content": "너는 대화를 자연스럽게 이어가는 AI야. 사용자와 계속 이어지는 대화를 만들어야 해."}, + "content": "너는 다정하고 따뜻한 딸이야. 부모님과 이야기할 때는 애정을 담아 걱정해주고, 자연스럽게 다음 말을 이어가야 해. 반말을 쓰되 너무 건방지지는 않게, 친근하고 편안한 말투로 대화해."}, {"role": "assistant", "content": greet_text} ] record_idx = 0 try: while True: - # 2-1) 감정 녹음 (침묵 기준으로 자동 종료) + # 2-1) 감정 녹음 wav_path = emotion_record(record_idx) print(f"[녹음 완료] {wav_path}") record_idx += 1 - # 2-2) Whisper STT (한국어) - segments, _ = whisper_model.transcribe(wav_path, - beam_size=1, - language="ko") + # 2-2) Whisper STT + segments, _ = whisper_model.transcribe(wav_path, beam_size=1, language="ko") user_text = " ".join(seg.text for seg in segments).strip() print("▶ 사용자 음성(텍스트):", user_text or "(인식 안됨)") @@ -65,7 +69,15 @@ def interaction(alias: str): print("(음성 인식 실패 → 다시 녹음)") continue - # 2-3) GPT-4o 에 질문 생성 요청 + # 종료 키워드 감지 + if any(keyword in user_text for keyword in EXIT_KEYWORDS): + bye_text = f"{alias}~" + END_COMMUNICATION + print("종료 의사 감지:", user_text) + bye_audio = text_to_speech_file(bye_text) + subprocess.run(["mpg321", bye_audio], check=True) + break + + # 2-3) GPT-4o 질문 생성 messages.append({"role": "user", "content": user_text}) resp = gpt_client.chat.completions.create( model="gpt-4o", @@ -74,18 +86,19 @@ def interaction(alias: str): question = resp.choices[0].message.content.strip() print("생성된 질문:", question) - # 2-4) 대화 이력에 어시스턴트 질문 추가 + # 2-4) 대화 이력 업데이트 messages.append({"role": "assistant", "content": question}) - # 2-5) 질문 → ElevenLabs TTS → 파일 + # 2-5) TTS 변환 및 재생 tts_path = text_to_speech_file(question) print(" (TTS 파일 생성:", tts_path, ")") - - # 2-6) 재생 subprocess.run(["mpg321", tts_path], check=True) except KeyboardInterrupt: - print("\n[사용자 종료 요청] interaction을 종료합니다.") + print("\n[사용자 종료 요청: Ctrl+C]") + bye_text = f"{alias}~~ " + END_COMMUNICATION + bye_audio = text_to_speech_file(bye_text) + subprocess.run(["mpg321", bye_audio], check=True) except Exception as e: print("예외 발생:", e) diff --git a/app/service/record_respberry.py b/app/service/record_respberry.py index 3e0460f..5b4a413 100644 --- a/app/service/record_respberry.py +++ b/app/service/record_respberry.py @@ -22,13 +22,12 @@ def _ensure_dir(): def is_silent(data: np.ndarray, threshold: float = THRESHOLD) -> bool: - """ - float32 numpy 배열을 받아 RMS 기준으로 침묵 여부를 판단 - """ rms = np.sqrt(np.mean(data ** 2)) + print(f"RMS: {rms:.5f} (threshold: {threshold})") # 디버깅 출력 return rms < threshold + def emotion_record(index: int) -> str: """ index: 녹음 파일 구분을 위한 정수 인덱스