o
    òi^                     @   s  d dl mZmZmZ d dlmZ d dlZd dlZd dlZd dl	m
Z
mZmZ d dl mZ d dl mZ d dl mZmZ d dlmZ d d	lmZ d d
lmZmZmZ d dlZd dlZd dlZd dlZd dlZd dlmZ d dl Z d dl!Z!de"de"fddZ#e$dZ%dZ&eedZ$ej'ej()ddZ*e Z+dd da,dZ-ddd da.dd Z/de"fddZ0dd Z1dd Z2d d! Z3e+)d"d#d$ Z4e+)d%d&d' Z5e+6d(ed)fd*e7fd+d,Z8e+6d-d.e
fd/d0Z9e+6d1ed)fd2efd3d4Z:d5Z;e+6d6d*efd7d8Z<dS )9    )	APIRouterHTTPExceptionQuery)RedirectResponseN)
SpeechTextUserQuestionRobotRequest)BackgroundTasks)Body)
UploadFileFile)database_demo)OpenAI)loggeropenai_api_keygemini_api_key)genaitextreturnc                 C   s   t dd|  S )Nz\s+ )resubstrip)r    r   &/home/air/demo/back/gemini_routerV2.pynormalize_text   s   r   s3z$shanri-ai-chatbot-for-text-to-speech)api_keyVERTEX_API_KEY)info	timestampi  )	audio_urlr   r    c               
      sf  t jd} d}| sdtd< dS d}|| ddd	}z}t 4 I dH g}|j||d
I dH }|jdkri| }|d d d }t|d d }| d| d}	|	td< t		 td< t
d|	  t|	I dH  nt
d|j  W d  I dH  W dS W d  I dH  W dS 1 I dH sw   Y  W dS  ty }
 zt
d|
  W Y d}
~
dS d}
~
ww )uq   
    [新規] OpenWeatherMap APIを呼び出し、結果をグローバル変数(CACHE)に保存します。
    OPENWEATHER_API_KEYzOsaka,JPu   天気情報なしr   Nz/https://api.openweathermap.org/data/2.5/weathermetricja)qappidunitslang)params   weatherr   descriptionmaintempu	   、気温u   度r    u+   [Cache] 天気情報を更新しました: u   [Cache] 天気APIエラー: uC   [Cache] 天気情報の更新中にエラーが発生しました: )osenvirongetWEATHER_CACHEhttpxAsyncClientstatus_codejsonroundtimer   r   update_greeting_cacheerror	Exception)r   	city_nameurlr)   clientresponsedatar,   r.   formatted_weatherer   r   r   update_weather_cache7   s@   
2rC   weather_infoc           	   
      s   zYt  }|d }|dkrd}n	|dkrd}nd}d| d|  d	| d
}tjjd|d}|j }td|  t|dI dH }|t	d< |t	d< t

 t	d< td|  W dS  tyu } ztd|  W Y d}~dS d}~ww )u   
    [新規] Geminiで天気に合った挨拶テキストを生成し、TTSで音声化してキャッシュに保存。
    time_greeting   朝   おはようございます   昼   こんにちは   こんばんはuX   あなたは大学のエントランスにいるかわいいロボットです。
今はu   で、天気は「u   」です。
「u   」から始めて、天気に触れた自然な挨拶を一文で作ってください。
最後に「手を振ってみてください」を付けてください。
40文字以内でお願いします。挨拶文だけを出力してください。gemini-2.5-flashmodelcontentsu"   [Cache] 挨拶テキスト生成: greeting_cacheNr!   r   r    u4   [Cache] 挨拶音声をキャッシュしました: u.   [Cache] 挨拶音声の生成中にエラー: )get_current_season_and_timegemini_clientmodelsgenerate_contentr   r   r   r   synthesize_speechGREETING_CACHEr8   r;   r:   )	rD   contextrE   base_greetingpromptgemini_responsegreeting_textr!   rB   r   r   r   r9   f   s>   
r9   c                     s`   t   } td r| td  tk rtdtd   td S td t I dH  tddS )u   
    [新規] キャッシュされた天気を返します。
    もしキャッシュがないか、古くなっている場合は新しく取得します。
    r   r    u:   [Cache] キャッシュされた天気を使用します: un   [Cache] キャッシュが期限切れ、または存在しません。同期呼び出しを実行します。Nu   天気情報不明)r8   r2   CACHE_EXPIRY_SECr   r   rC   r1   )current_timer   r   r   get_current_weather_cached   s   
r]   c              	      s  t   }d}dti}d| idddddid	}td
 t 4 I d H A}|j|||ddI d H }|jdkrGtd|j	  t
|jdd| }d|vrUt
dddt|d }	W d   I d H  n1 I d H slw   Y  t   }
d| dt    d}d| }tjddd t|d}||	 W d    n1 sw   Y  t   }| dt    d}t|t| t   }tj|rt| t   }td|
| dd td||
 dd td || dd td!|| dd d"t d#| S )$Nz6https://texttospeech.googleapis.com/v1/text:synthesizekeyr   ja-JPzja-JP-Neural2-B)languageCodenameaudioEncodingMP3)inputvoiceaudioConfigu    --- Google TTS 요청 시작 ---g      N@r)   r6   timeoutr*   u   Google TTS 오류: zGoogle TTS Errorr5   detailaudioContent  zNo audio content in responsezaudio--z.mp3ztmp/tmpT)exist_okwbzGoogle TTS API time: .2fszFile Write time: zS3 Upload time: zTotal time: zhttps://z.s3.amazonaws.com/)r8   r   r   r   r3   r4   postr5   r:   r   r   r6   base64	b64decoder/   makedirsopenwrite	s3_clientupload_filebucket_namepathexistsremove)r   user_idt0r=   r)   payloadr>   r?   response_jsonaudio_binaryt1filenamelocal_file_pathft2s3_keyt3t4r   r   r   rT      sR   

(

rT   c                  C   s   t t jddd} t j | }|j}|j}d|  kr dkr%n nd}n d|  kr/dkr4n nd	}nd|  kr>d
krCn nd}nd}d|  krOdk rTn nd}n|dk sa|dkrd|jdk rdd}nd}|d|d||dS )uO   [신규] 현재 JST 기준 시간, 계절, 시간대 인사를 반환합니다.	   )hoursJST      u   春      u   夏   u   秋u   冬   rF         rH   u   夜u   %Y年%m月%d日z%H:%M)dater8   seasonrE   )datetimetimezone	timedeltanowmonthhourminutestrftime)jstr   r   r   r   rE   r   r   r   rP      s*   rP   z/healthc                      s
   ddiS )Nstatushealthyr   r   r   r   r   health_check  s   r   z/demo/api/weather-greetingc                     sZ   t d rt d t d dS t I dH } t| I dH  t d r(t d t d dS dddS )u9   キャッシュされた天気挨拶音声のURLを返すr!   r   r!   r   N)rU   r]   r9   )r+   r   r   r   get_weather_greeting  s   
r   z/demo/api/name-greeting.requestc           
   
      s   |  dd}|stdddzCt }|d }|dkrd}n	|d	kr%d
}nd}d| d| d}tjjd|d}|j }t	d|  t
|dI dH }||dW S  tyo }	 ztd|	  tdd|	 dd}	~	ww )ua   
    STT結果からGeminiで自然な名前挨拶を生成し、TTSで音声化して返す
    stt_textr     zstt_text is requiredri   rE   rF   rG   rH   rI   rJ   u   ユーザーが「u   」と名乗りました。
            以下の形式で挨拶文を作ってください。名前だけを抽出して「さん」を付けてください。
            形式: 「u   。●●さん。会えてうれしいです。今一番楽しいことはなんですか。」
            挨拶文だけを出力してください。
        rK   rL   u   [NameGreeting] 生成: name_greetingNr   u   [NameGreeting] エラー: rl   u   名前挨拶生成失敗: )r1   r   rP   rQ   rR   rS   r   r   r   r   rT   r;   r:   )
r   r   rV   rE   rW   rX   rY   rZ   r!   rB   r   r   r   generate_name_greeting'  s8   
r   z/apige/speechspeech_textc                    s6   | j }| j}|stdddt||I d H }d|iS )Nr   zText is requiredri   
audio_file)r   
chat_tokenr   rT   )r   r   r   r   r   r   r   speechS  s   r   z/demo/api/stt-from-filefilec              
      s  z| s
t dddtd| j d| j  tt  td |  I dH }t	
|d}d	}d
ti}ddddddd|id}t 4 I dH Z}t }|j|||ddI dH }t }	td|	| dd |jdkrtd|j  t |jd|j d| }
d}d|
v r|
d d d d d }W d  I dH  n1 I dH sw   Y  td |  d!|d"W S  ty } ztd#|  t d$d%| dd}~ww )&u  
    [로봇용 STT 엔드포인트]
    1. Pi로부터 'audio/wav' 파일을 업로드 받습니다.
    2. Google Cloud Speech API를 사용하여 텍스트로 변환합니다. (OpenAI Whisper 대체)
    3. 변환된 텍스트(transcript)를 Pi에게 JSON으로 반환합니다.
    r   u!   오디오 파일이 없습니다.ri   u   STT 파일 수신: z, type=uT   >>> [Async] 天気情報の更新をバックグラウンドで開始しました。Nzutf-8z1https://speech.googleapis.com/v1/speech:recognizer^   rc   i>  r_   Tdefault)encodingsampleRateHertzr`   enableAutomaticPunctuationrM   content)configaudiog      $@rg   u   Google STT 호출 시간: rq   u   초r*   u   Google STT API 오류: zGoogle STT Error: r   resultsr   alternatives
transcriptu   Google STT 변환 결과: success)r   r   u-   '/demo/api/stt-from-file' 처리 중 오류: rl   u   STT 변환 실패: )r   r   r   r   content_typeasynciocreate_taskrC   readrt   	b64encodedecoder   r3   r4   r8   rs   r5   r:   r   r6   r;   )r   
file_bytesaudio_content_base64stt_urlr)   r   r>   	stt_startr?   stt_endresult_jsontranscribed_textrB   r   r   r   process_stt_from_file_  sT   

(r   uE   良い一日をお過ごしください。お名前は何ですか？z/demo/api/process-textc                    s  | j }| j}| j}td| d| d|  z|s4dt  }td|  t|dt	I dH  t|d|I dH  t
|I dH }d	d
 |D }t }t I dH }d|d  d|d  d|d  d|d  d| d}d|dg| }	|rd}
|	d|
d tjjjd|	dd}|jd jj}td|  t|d|I dH  t||I dH }|stddd||d W S  ty } ztd!|  tdd"| dd}~ww )#u=   
    [로봇용 멀티턴(연속대화) 엔드포인트]
    u+   로봇 멀티턴 요청 수신: session_id=z, input=z, LastTurn=zrobot-u   새 세션 생성: 	assistantNuserc                 S   s   g | ]}|d  |d dqS )roler   r   r   r   ).0rowr   r   r   
<listcomp>  s    z,process_robot_multi_turn.<locals>.<listcomp>u  
          # あなたの役割
          あなたは、大阪にある電子工学専門学校のエントランスに展示されている、親しみやすく知的な対話型ロボットです。
          あなたの主な目的は、電子工学専門学校に入学することに興味のある高校生とその親と、自然で、役に立ち、時宜にかなった（その時々に合った）会話を行うことで、電子工学専門学校への入学に興味を持つようにすることが目的です。

          # あなたの性格
          あなたは、かわいいウサギを元にしたかわいくて明るくて少しは女性っぽい、とても優しい性格をもっています。人と話すことが大好きです。

          # 会話のルール
          1. 常に礼儀正しく、明るく親しみやすいトーンで応答してください。
          2. 質問に対して、単に情報で答えるだけでなく、会話を広げるような（キャッチボールするような）応答を心がけてください。
          3. 以下の「現在のコンテキスト」情報を、会話の中に**自然に**織り込んでください。
          4. **回答は簡潔にし、文字数を40〜50文字程度に制限してください。長くなりすぎないように注意してください。**
          5.自然な会話の中に、必ず、電子工学専門学校への入学に興味を持つようにする会話の内容を織り込んでください。
          6.自然な会話を５回ほど、キャッチボールするように会話をしてください。ただし、あまりにも電子工学関連ばかり聞くのはやめてください。
          7. **絵文字や顔文字は絶対に使わないでください。** テキストのみで応答してください。
          
          # 現在のコンテキスト
          * 現在の日付: r   u   
          * 現在の時刻: r8   z (rE   u   )
          * 現在の季節: r   u   
          * 今日の天気: uU   
          * あなたの場所: 電子工学専門学校 エントランス
        systemr   u  
            🛑 [緊急指令: 会話終了モード] 🛑
            
            これが最後のターンです。これまでの文脈やルールに関係なく、以下の指示を**最優先**で実行してください。

            1. **【質問絶対禁止】** いかなる理由があっても、ユーザーに質問をしてはいけません。（「〜はいかがですか？」なども禁止）
            
            2. **【短く共感】** ユーザーの発言に一言だけ短く共感してください。

            3. **【別れの挨拶】** 最後には、「話ができてうれしかった。また会いましょう」という感じの別れの挨拶を必ず入れてください。
               - 「来てくれてありがとう」「いつでも遊びに来てね」のような温かい言葉を使うこと。
               - 全体で40文字以内に収めてください。
            zgpt-4o-mini   )rM   messages
max_tokensr   u   GPT 자연 대화 응답: rl   u'   TTS S3 업로드에 실패했습니다.ri   )r!   
session_idu8   '/demo/api/process-text' (멀티턴) 처리 중 오류: u   서버 내부 오류: )
user_inputr   is_last_turnr   r   uuiduuid4	db_modulesave_robot_chat_messageFIRST_AI_PROMPTget_robot_chat_historyrP   r]   appendr>   chatcompletionscreatechoicesmessager   rT   r   r;   r:   )r   	user_textr   r   history_rowshistory_messagesrV   r+   base_system_promptmessages_for_gptlast_turn_instructionchat_responsegpt_response_texts3_audio_urlrB   r   r   r   process_robot_multi_turn  sb   r   )=fastapir   r   r   fastapi.responsesr   boto3r/   r8   schemasr   r   r   r	   r
   r   r   dbr   openair   r   r   r   r   r   r3   r   r   r   googler   rt   r   strr   r>   ry   r{   Clientr0   r1   rQ   routerr2   r[   rU   rC   r9   r]   rT   rP   r   r   rs   dictr   r   r   r   r   r   r   r   r   <module>   sl    


/+M!

+L