o
    li*D                     @   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 Z.dd Z/dd Z0dd Z1e+)ddd  Z2e+3d!d"e
fd#d$Z4e+3d%ed&fd'efd(d)Z5d*Z6e+3d+d,efd-d.Z7dS )/    )	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GEMINI_API_KEY)info	timestampi  c               
      sX  t jd} d}| sdtd< dS d}|| ddd	}zvt 4 I dH `}|j||d
I dH }|jdkrb| }|d d d }t|d d }| d| d}	|	td< t		 td< t
d|	  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   error	Exception)r   	city_nameurlr(   clientresponsedatar+   r-   formatted_weatherer   r   r   update_weather_cache.   s>   
2rA   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   天気情報不明)r7   r1   CACHE_EXPIRY_SECr   r   rA   r0   )current_timer   r   r   get_current_weather_cachedZ   s   
rD   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-D)languageCodenameaudioEncodingMP3)inputvoiceaudioConfigu    --- Google TTS 요청 시작 ---g      N@r(   r5   timeoutr)   u   Google TTS 오류: zGoogle TTS Errorr4   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/)r7   r   r   r   r2   r3   postr4   r8   r   r   r5   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   synthesize_speechn   sR   

(

rs   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r^dk rcn nd}nd}|d|d||dS )uO   [신규] 현재 JST 기준 시간, 계절, 시간대 인사를 반환합니다.	   )hoursJST      u   春      u   夏   u   秋u   冬u   朝   u   昼u   夜u   %Y年%m月%d日z%H:%M)dater7   seasontime_greeting)datetimetimezone	timedeltanowmonthhourstrftime)jstr   r   r   r~   r   r   r   r   get_current_season_and_time   s*   r   z/healthc                      s
   ddiS )Nstatushealthyr   r   r   r   r   health_check   s   r   z/apige/speechspeech_textc                    s6   | j }| j}|stdddt||I d H }d|iS )N  zText is requiredrP   
audio_file)r   
chat_tokenr   rs   )r   r   r   r   r   r   r   speech   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!   오디오 파일이 없습니다.rP   u   STT 파일 수신: z, type=uT   >>> [Async] 天気情報の更新をバックグラウンドで開始しました。Nzutf-8z1https://speech.googleapis.com/v1/speech:recognizerE   rJ   i>  rF   Tdefault)encodingsampleRateHertzrG   enableAutomaticPunctuationmodelcontent)configaudiog      $@rN   u   Google STT 호출 시간: rX   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' 처리 중 오류: rS   u   STT 변환 실패: )r   r   r   rl   content_typeasynciocreate_taskrA   readr[   	b64encodedecoder   r2   r3   r7   rZ   r4   r8   r   r5   r9   )r   
file_bytesaudio_content_base64stt_urlr(   rh   r<   	stt_startr=   stt_endresult_jsontranscribed_textr@   r   r   r   process_stt_from_file   sT   

(r   uE   良い一日をお過ごしください。お名前は何ですか？z/demo/api/process-textrequestc                    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>T  s    z,process_robot_multi_turn.<locals>.<listcomp>u  
          # あなたの役割
          あなたは、キャンパスに展示されている、親しみやすく知的な対話型ロボットです。
          あなたの主な目的は、学生、教職員、訪問者と自然で、役に立ち、時宜にかなった（その時々に合った）会話を行うことです。

          # 会話のルール
          1. 常に礼儀正しく、親しみやすいトーンで応答してください。
          2. 質問に対して、単に情報で答えるだけでなく、会話を広げるような（キャッチボールするような）応答を心がけてください。
          3. 以下の「現在のコンテキスト」情報を、会話の中に**自然に**織り込んでください。
          4. **回答は簡潔にし、文字数を40〜50文字程度に制限してください。長くなりすぎないように注意してください。**

          # 現在のコンテキスト
          * 現在の日付: r}   u   
          * 現在の時刻: r7   z (r   u   )
          * 現在の季節: r~   u   
          * 今日の天気: uC   
          * あなたの場所: 大学 エントランス
        systemr   u  
            🛑 [緊急指令: 会話終了モード] 🛑
            
            これが最後のターンです。これまでの文脈やルールに関係なく、以下の指示を**最優先**で実行してください。

            1. **【質問絶対禁止】** いかなる理由があっても、ユーザーに質問をしてはいけません。（「〜はいかがですか？」なども禁止）
            
            2. **【共感 + 感謝】** - まず、ユーザーの発言に短く共感してください。
               - その直後に、「お話しできて楽しかったです」や「お話ししてくれてありがとう」といった**感謝や喜びの言葉**を自然に続けてください。

            3. **【お元気でね】** - 応答の最後は、必ず「**お元気でね**」というフレーズだけで締めくくってください。
               - 文末は必ず「〜。お元気でね」の形になります。
            zgpt-4o-mini   )r   messages
max_tokensr   u   GPT 자연 대화 응답: rS   u'   TTS S3 업로드에 실패했습니다.rP   )	audio_url
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_historyr   rD   appendr<   chatcompletionscreatechoicesmessager   rs   r   r9   r8   )r   	user_textr   r   history_rowshistory_messagescontextr*   base_system_promptmessages_for_gptlast_turn_instructionchat_responsegpt_response_texts3_audio_urlr@   r   r   r   process_robot_multi_turn=  sb   r   )8fastapir   r   r   fastapi.responsesr   boto3r.   r7   schemasr   r   r   r	   r
   r   r   dbr   openair   r   r   r   r   r   r2   r   r   r   googler   r[   r   strr   r<   r`   rb   Clientr/   r0   gemini_clientrouterr1   rB   rA   rD   rs   r   r   rZ   r   r   r   r   r   r   r   r   <module>   sV    

,N!
L