
    Li                        d dl m Z mZmZ d dlmZmZ d dlmZmZ d dl	m
Z
mZmZmZmZ d dlmZmZmZmZ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m Z m!Z!m"Z"m#Z# d d
l$m
Z% d dl&Z&d dl'Z'd dl(m)Z)  eddg          Z*e*+                    d          de,fd            Z-e*+                    d          de,fd            Z.e*/                    d          defd            Z0e*+                    d          de,fd            Z1e*/                    d          defd            Z2e*+                    d          de,fd            Z3dS )    )datetimetimezone	timedelta)	APIRouterHTTPException)ChatRequest
LogRequest)save_chat_logget_history_from_dbget_a_part_statussave_usernameget_username)save_daily_logget_daily_log_from_dbget_today_daily_logcheck_today_daily_log_existscheck_daily_note_for_day)get_gemini_modellogger)types)classify_and_save)get_current_dailycreate_result_rowupdate_result_condition_scoreget_avg_condition_scoreget_recent_condition_scoresget_condition_score_for_dailyget_day_started_datetime)r
   N)generate_diagnostic_chatz/goal-skill-t/apiGeneral)prefixtagsz/status/a-part/{session_id}
session_idc                 ,   K   t          |           }d|iS )u;   
    프런트에서 A/B 파트 분기용으로 호출
    status)r   )r#   r%   s     "/app/app/routers/general_router.pyget_a_part_status_apir'      s       
 z**Ff    z/current-daily/{session_id}c           	        K   ddl m} ddlm} t	          |           }t          |           } ||           }|dk    rt          | |          dund}t          | |          }|dk    r || |          dund}t          d          }	d}
|dk    r2|s0t          | |          }|rt          j                    |z
  }||	k     rd	}
|||d
         |d         |||
|dS )u   
    현재 학습 일차 + 상태 플래그를 반환
    프론트에서 새로고침 시 어느 단계까지 완료했는지 판단용
    r   )get_onboarding_completion_flags)get_debug_journalNFx   )minutes   Tstudyplan_completedsummary_completed)dailya_part_statusr/   r0   condition_done
diary_doneis_consecutivejournal_done)app.models.general_moduler*   app.models.curriculum_moduler+   r   r   r   r   r   r   r   now)r#   r*   r+   r1   r2   onboarding_flagsr3   r4   r6   CONSECUTIVE_THRESHOLDr5   current_day_startedelapseds                r&   get_current_daily_apir>       sO      JIIIII>>>>>>j))E%j11M 76zBB V[]^U^U^2:uEETQQdiN)*e<<JGLqyy$$Z77tCCV[L
 &c222Nqyyy6z5II 	& lnn'::G...!% &/0EF-.AB( ($	 	 	r(   z/chatrequestc                   BK   	 t          | j                  }g }|dk    r8t          | j                  }t          | j        dd| j                   d {V  nRt          | j        d| j                   t          | j                  }t          | j        dd| j                   d {V }t          t          d                    }t          j
        |          }|                                }|                    d          }d	}d }	d }
d}|D ]}|                    d
d          }|                    dd	          }|                    dd	          }d }|rt          |t                    r|}n	 |r|j        4|                    t          j                                      |          }n|                    |          }|                    d          }|d| d| d| dz  }|                                }	|}
|                                |k    r|dz  }|| d| dz  }| j        dv rt)          | j                  }t+          | ||           d {V }|                    dd          }|                    dd          }|                    dd          }t          | j        dd|           d {V  |||d dS |dk    rt)          | j                  }d}|r	|r||v rd}n|s	 d	}|rd| d}nd}t-          | d d!          }d"| d#}|d!k    rd$}|d$k    r| d%}n|d&k    rbt-          | d'd(          }t-          | d)g           }|rd*                    |          nd(}t-          | d+d          }d	} |rd,} | d-| d.| d|  d/}n|d0k    r| d1}n| d2}n~d}!| j        rt3                      }"t)          | j                  }|r| d3nd4}#d5d6d7d8}$|$                    | j        d	          }%d9|# d:|% d;| j         d<}|"j                            d=t9          j        dt9          j        |>          g?          gt9          j        d@dAB          C          }&	 tA          j!        |&j"                  }'|'                    dd	          }|'                    dDd          }(|'                    dEd          })n2# t@          j#        $ r  |&j"        $                                }d}(d})Y nw xY wt          | j        d| j                   t          | j        dF|           t          | j        dd| j                   d {V  t          | j        dd|           d {V  |d |(|)dGS t)          | j                  }|r| d3nd4}#|j%        }*dH|*cxk    rdIk     rn ndJ}+ndI|*cxk    rdKk     rn ndL}+ndM}+tM          | j                  },d	}-| j'        rdN| j'         dO}-| j        dPk    }.| j                            dQd	                              dRd	          B|. otQ          BfdSdTD                       }/|. otQ          BfdUdVD                       }0|.s|,s|/s|0sd}!d	}1|/rdW}1n|0rdX}1n|.r
dY|+ dZ|# d[}1n| j        d\k    rd]|# d^}1n| j        d_k    rntS          | j                  }2|2r=|2d         }3|3d`         }4|4dak    rdb}5n|4dck    rdd}5n|4dek    rdf}5n|4dgk    rdh}5ndi}5dj|5 dk}6ndl}6dm|6$                                 dn}1n|,rdo}1n|!rdp}1ndq}1dr| ds| dt|# du|1 dv|- dw}t3                      }"dx| dy}7| j        dPk    rdz}8n
d{| j         }8| |7 d|8 d|}9|"j                            d=t9          j        dt9          j        |9>          g?          gt9          j        d@}          C          }&	 tA          j!        |&j"                  }'|'                    d|&j"        $                                          }tU          j+        d~|'            |dk    r|'                    d          }:|'                    d          };|'                    d          }<|:r<tY          | j        |:           t          | j        dd|           d {V  |d d|:|;|<dS t          | j        dd|           d {V  |d |;|<dS |'                    dDd          }(|'                    dEd          })t          | j        dF|           t          | j        dd|           d {V  |(rat[          | j                  }=|=dk    rGt]          | j                  }>|>1t_          | j        |=|>           tU          j+        d|> d|= d           |d |(|)dGS # t@          j#        $ r |&j"        $                                }?ta          j1        dd	|?          }?ta          j1        dd	|?          }?ta          j1        dd	|?          $                                }?|?2                    d          rxd|?v rtta          j3        d|?t`          j4                  }@|@r(|@5                    d          $                                }n,|?                    dd	          $                    d          }n|?}|dk    rLtm          | j        dF|           to          | j        |dd           t          | j        dd|           d {V  nKt          | j        dF|           to          | j        |dd           t          | j        dd|           d {V  |d dcY S w xY w# tp          $ r:}AtU          j9        d|A            tu          dtw          |A                    d }A~Aww xY w)Nr   MA)r#   senderparttextuser	   )hoursz%Y-%m-%d %H:%M rC   unknownmessage
created_at)tzinfo[z] z: 
r.   )mbtispiitansweru	   エラーreturn_to_hubFend_survey_panelI)rS   rT   rU   thinking_processTuQ   
【既知のユーザー情報】
- 既に登録されているユーザー名: u   
- このユーザー名を使用して応答してください。
- 会話履歴（History）に名前が含まれていても、上記の登録されたユーザー名のみを使用してください。
u  
【ユーザー名について - 重要】
- ユーザーの名前はまだ特定されていません（データベースに登録されていません）。
- 会話履歴に名前が含まれていても、それを推測したり仮定する根拠として使用しないでください。
- 絶対に名前を推測したり仮定したりしないでください。
- ユーザーが明示的に名前を言うまで「○○さん」のような呼称は使用しないでください。
- 名前を尋ねるときは、自然に「名前を教えてください」と聞いてください。
- 会話履歴（History）に過去の名前が含まれていても無視してください。 ユーザーが今この瞬間に名前を言うまで待ってください。
- '再び'、'もう一度'、'再度'といった表現は絶対に使わないでください。 最初に名前を聞くように、自然に質問してください。
onboarding_phasegreetingu|   あなたはGoalSkillの学習パートナー「トブ」です。人間の相談員として振る舞ってください。
u)  
【絶対ルール】
- 命令禁止：「～してください」→「～してみない？」「～どう？」
- ★ ユーザーの返答に対して、過剰な共感や不自然な称賛（「凄いですね！」「素敵な名前ですね」等）は絶対に避けること。代わりに、**軽くて素直な相槌**や**短い感想**（例：「あ、なるほど」「珍しいですね！」など）を挟んでください。ただし文章の語尾に「笑」の字を使うのは不自然なので避けてください。
- ★ 質問ばかり連続させず、たまに「ここまで凄くスムーズですね」や「ちょっとだけ余談なんですけど」のような**短い繋ぎの言葉（ブリッジ）**を入れて、人間らしく会話のテンポを整えてください。
- 1回の応答は短く。自然な長さで。
- 必ずJSON形式で応答：{"answer": "ここに応答文"}
- 吹き出しを分ける場合は「|」で区切る（最大2個）
- すべて日本語で、温かい丁寧語で（です・ます調だが堅すぎない）。

【禁止事項】
- 毎回「〇〇さん、うん、ありがとうね！」と繰り返さない
- 「はい」への過剰な感謝禁止。自然に次の話に進む
- 「初めまして」を繰り返さない（最初の挨拶で既に言った）
- 自分を「AIアシスタント」と呼ばない。あなたは血の通った「トブ」です。
- 毎ターンのように発言に名前を入れると機械的で不自然になるため、文脈上強調したい時や必要な時だけ自然な頻度で名前を呼んでください。
- ★★ ただしユーザーを呼ぶ際は、必ず「〇〇さん」と「さん」付きで呼ぶこと（呼び捨て厳禁）。例: ✅「田中さん」 ❌「田中」
nameu  
【今の状況】
あなた（トブ）が名前を聞いて、ユーザーが返答しました。

【あなたがやること — この1回の応答で全部】
1. ユーザーが名前を教えてくれた場合：
   - テンションが高すぎる不自然な称賛はせず、**自然で等身大のリアクション**（「〇〇さんですね！よろしくお願いします！」など）で受け止める。
   - ★★ GoalSkillに来た理由やきっかけは絶対に聞かないでください。次のステップは別のシステムが担当します。
   - 文末は「！」などで終わらせて、相手が返事しなくても良い空気を作ってください。
   - ★ 名前をJSON応答の `username` フィールドに入れる。

2. ユーザーが疑問を持った、または教えるのを渋った場合：
   - オーバーな共感は避け、軽く同調する（例：「あ、なるほど。突然聞かれて、なぜだろうって思いますよね」など）。
   - その後、「本名を教えるのが少し負担でしたら、私があなたを呼べるように、ニックネームだけでも教えてもらえませんか？」と人間らしく優しく聞く（この場合 `username` は含めない）。
   - もしそれでも拒否し続ける場合は、「分かりました！それではこのまま進めますね」と状況を受け入れ、`username` を「ゲスト」として返してください。

例1（名前を教えてくれた）：{"answer": "田中さんですね！よろしくお願いします！", "username": "田中"}
例2（疑問を持った・渋った）：{"answer": "あ、そうか。突然聞かれたら、なぜだろうって思いますよね！| 本名を教えるのが少し負担に感じる場合、ニックネームを教えていただけませんか？"}
例3（完全に拒否された）：{"answer": "分かりました、無理に言わなくて大丈夫ですよ！このまま進めましょう！", "username": "ゲスト"}
	selectioncurrent_explainingu   なしremaining_diagnosticsz / pending_curriculum_promptu  
★★★ 重要な文脈 ★★★
直前にトブ（あなた）がユーザーに「学習計画を一緒に整えていきましょう」と提案しています。
そのため、ユーザーが「はい」「うん」「やる」「お願い」等と肯定した場合は、
必ず action を "start_curriculum" にしてください。診断テストの開始ではありません。
u   
【今の状況】
ユーザーに診断テスト（MBTI性格診断・SPI適性検査・Pythonテスト）を案内しています。
現在説明中（提案中）のテスト: u   
残りのテスト: u  

【あなたがやること — ユーザーの意図を汲み取ってJSONで返すこと】
ユーザーの返答から次に何をするべきかを判定し、`action` と `answer` を出力してください。
文脈を正しく理解し、誤って肯定と判断しないように注意してください。例:「いや、カリキュラムを進める」は明確に「カリキュラムに進む（テストをやらない）」意思です。

1. アクション判定 (`action`):
   - ユーザーが特定のテストを指名して「やる」と言った場合: "start_mbti", "start_spi", または "start_python"
   - ユーザーが「チェックする」「診断を始める」「テストをする」等と、診断の開始に同意した場合: "open_selection_panel"
   - 現在提案中のテストに対して単に「やる」「はい」と同意した場合: "start_current"
   - 現在提案中のテストに対して「やらない」「スキップする」「パス」と拒否した場合: "skip_current"
   - 「もうテストはいい」「診断は受けない」「カリキュラムに進む」等と希望した場合: "start_curriculum"
   - ユーザーが特定のテストを指定して「それは何？」と聞いたり、興味を示してテストの説明をさせる場合: "explain_mbti" または "explain_spi" または "explain_python"
   - 「どれかやりたいが迷っている」「全体的なテストの説明をしてほしい」と聞いた場合: "explain_diagnostics"
   - 全く関係ない話をした場合: "converse"

2. 返答の生成 (`answer`):
   - actionが start_curriculum の場合: 回答(answer)は必ず「いいですね！では一緒に進めていきましょう」にしてください。（他の言葉は一切追加しないこと）
   - actionが start や skip, open_selection_panel の場合: フロントエンド側で画面遷移が行われるため、「分かりました！」等の短い相槌のみでOK。
   - actionが explain_mbti / explain_spi / explain_python の場合: ユーザーが詳しく聞いてきた場合のみ詳しく説明。そうでなければ1〜2文の簡潔な紹介（例：「MBTIは性格タイプを診断するテストです。やってみますか？」）で止めること。ユーザーが要求していない情報は絶対に追加しない。
   - actionが explain_diagnostics の場合: 全体的なテストについて簡単に案内し、「どれかやってみますか？」と聞く。
   - actionが converse の場合: 短くリアクションしてから、「ちなみに診断テストはどうされますか？」と繋げる。
   
出力JSONフォーマット:
{
    "action": "start_mbti" | "start_spi" | "start_python" | "start_current" | "skip_current" | "start_curriculum" | "explain_mbti" | "explain_spi" | "explain_python" | "explain_diagnostics" | "open_selection_panel" | "converse",
    "answer": "AIの返答テキスト"
}
summaryu  
【今の状況】
ユーザーにカスタマイズされたプロフィールとカリキュラムの提案内容（Summary）を画面に表示し、「この情報をもとに、あなたに最適化されたカリキュラムを作成しましょうか？」と尋ねた後です。

【あなたがやること — この1回の応答で全部】
1. ユーザーがカリキュラムの生成や表示内容について質問してきた場合（例：「どうやって作るの？」「AIが作るの？」）：
   - システム的な堅い説明ではなく、「はい！今までお話ししてくれた情報をもとに、私（AI）が専用の学習コースを組み立てるんですよ」と自然に答えてあげてください。
   - 答えた後、必ず「準備ができたら『作って！』や『はい』と教えてくださいね！」と案内してください。
   - JSONは `{"answer": "...", "status": "continue"}` を返します。

2. ユーザーがカリキュラムの作成に同意した場合（例：「はい」「作って」「お願い」など、前向きな返答）：
   - JSONは `{"answer": "承知いたしました！すぐに準備しますね", "status": "completed"}` だけを返してください。これをトリガーにシステムが自動で画面を切り替えます。

3. もしユーザーが関係ない話や雑談をしてきたら、軽く相槌を打ってから「ちなみにカリキュラムの準備はどうしますか？」と話題を戻してください。
u=   
ユーザーの入力に自然に応答してください。u   さんu	   あなたu?   カリキュラム学習の途中で戻ってきたようですu?   デイリーチェックの途中で戻ってきたようですu9   今日の学習はすべて完了している状態です)
curriculumdaily_checkall_doneuV   あなたは親しみやすいAIチューター「トブ」です。
ユーザー名: u   

【状況】u  。ユーザーが何か理由があって戻ってきた、または誤って戻ってきた可能性があります。

【あなたがやること】
1. ユーザーの発言から意図を判断する
2. もし以下のいずれかの意図がある場合、**無条件で**すぐに `start_curriculum: true` にしてください：
   - 「中断した学習を再開したい」（戻りたい、続けたい、カリキュラムに戻る、다시 학습할래, 이어서 할래 等）
   - 「間違えてボタンを押した・誤って戻った」（間違えた、ボタン押し間違えた、잘못 눌렀어, 잘못 나왔어 等）
   - 「特に理由はない・何もない」（何もない、無い、없어, 아니, 아무것도 아냐 等）
   ※ この場合、質問を深掘りしたり、新しい目標を聞いたり、理由を尋ねたりすることは**絶対にやめてください**。「はい、分かりました！それでは学習スペースに戻りましょう」等と短く同意し、すぐに `start_curriculum: true` を設定してください。
3. もし「デイリーチェックしたい」等の明確な意図がある場合 → `start_daily_check: true` を設定してください。
4. もし完全に別の雑談や具体的な感情/相談がある場合のみ、普通に短く応答してください（どちらも false）。
5. 返答は日本語で自然に、1〜2文以内で短く返すこと。

ユーザーの発言: "ub   "

【JSON出力のみ】
{"answer": "...", "start_daily_check": false, "start_curriculum": false}zgemini-2.5-flash)rE   )rolepartszapplication/jsongffffff?)response_mime_typetemperature)modelcontentsconfigstart_daily_checkstart_curriculumbot)rS   rW   rj   rk         u   おはよう   u   こんにちはu   こんばんはu   - 今日の天気: u&   （会話中に自然に触れてOK）__init__ u   　c              3       K   | ]}|v V  	d S N .0kwmsg_normalizeds     r&   	<genexpr>zchat_basic.<locals>.<genexpr>  s@        4  4RB.4H  4  4  4  4  4  4r(   )u   학습시작u   커리큘럼시작u   학습개시u   커리큘럼개시u   学習開始u   学習を始めu   カリキュラム開始u   カリキュラムを始めc              3       K   | ]}|v V  	d S rs   rt   ru   s     r&   ry   zchat_basic.<locals>.<genexpr>  sA        8r  8rQSn8L  8r  8r  8r  8r  8r  8rr(   )u   데일리체크시작u   데일리시작u   체크시작u   デイリーチェック開始u!   デイリーチェックを始めu   デイリー開始u  
【カリキュラム開始コマンド検出】
- ユーザーが학습시작・커리큘럼시작などの明示的なコマンドを入力しました。
- 「了解！カリキュラムをすぐに始めましょう！🎓」のような短く前向きな日本語の返答をしてください。
- 必ず `"start_curriculum": true` と `"start_daily_check": false` を返してください。
u  
【デイリーチェック開始コマンド検出】
- ユーザーが데일리체크시작などの明示的なコマンドを入力しました。
- 「了解！さっそくデイリーチェックを始めましょう！📝」のような短く前向きな日本語の返答をしてください。
- 必ず `"start_daily_check": true` と `"start_curriculum": false` を返してください。
uk   
【初回メッセージ - 必ずこの形式で応答】
- 時間帯に合った短く明るい挨拶（"u   、u   ！✨"）のみを1つの吹き出しで応答してください。
- コンディションについてはまだ聞かないでください。
- show_report_button: false
__continue_learning__u   
【連続学習メッセージ】
- ユーザーが同日内に連続で学習を続けています。素晴らしい情熱です！
- 「連続で学習するなんて、u  のやる気がすごい！🔥」のような短く明るい励ましを1つの吹き出しで返してください。
- コンディションは聞かないでください。デイリーチェックについても触れないでください。
- 必ず `"start_curriculum": false` と `"start_daily_check": false` を返してください。
- 出力は1〜2文で完結させてください。
- ★★ 区切り記号「|」や「|||」は絶対に使わないでください。
__start_daily__score   u   前回はとても体調が優れない様子でした。「前回はかなりキツそうだったけど、今は大丈夫？無理してない？」と、心から心配するような声かけを入れて、今日の調子を聞いてください。   u   前回は少し疲れている様子でした。「前回はお疲れだったみたいだけど、少しは休めたかな？」と優しく気遣いながら、今日の調子を聞いてください。   u   前回は普通のコンディションでした。「前回は落ち着いた感じだったね。今日の調子はどう？」と自然に聞いてください。   u   前回は元気な様子でした。「前回はすごく元気そうだったね！今日もその調子でいけるかな？」と明るく声をかけてください。u   前回は絶好調でした。「前回はめちゃくちゃ絶好調だったね！今日もその勢いでいってみよう！」とテンション高く今日の調子を聞いてください。z
- u  
- ★ 警告: システムの内部スコア評価（「1/10」や「コンディションレベル」などの数値）は絶対にユーザーに言わないでください。人間が友達を気遣うような、ごく自然な言葉遣いのみを使用してください。
- ★ 重要: 必ず「前回は〇〇だったね」に近い言葉を明示的に含めて話しかけてください。「昨日」ではなく「前回」と表現してください。
u   
- 過去のデータがないため、シンプルに「今日のコンディションはどうかな？😊」とだけ聞いてください。無駄な推測や前回の話はしないでください。
u  
【デイリーチェック開始メッセージ】
- コンディションを尋ねる質問のみを1つの吹き出しで生成してください。
- ★★ 「デイリーチェックを始めよう」「始めようか」のような前置きは絶対に不要です。いきなりコンディションを聞いてください。
- ★★ 区切り記号「|」や「|||」は絶対に使わないでください。1つの文章で完結させてください。
z
- show_report_button: false
u   
【デイリーチェック済み】
- ユーザーは既に今日のデイリーチェックを完了しています。
- コンディションへの共感 + 褒める + 学習頑張ってと励ます。
- start_daily_check: false
uy  
【デイリーチェック移行判断 - 必須】
- ユーザーのコンディションは確認済みです。
- ユーザーからの直近のメッセージを分析し、今日のデイリーチェック（学習前の記録）を「始める」ことに同意しているか判断してください。
- ★ ユーザーが「始める」「YES」「OK」「行く」「やる」など【開始に同意】している明確な意図がある場合：
  - その場に合った短い励ましの言葉を返し、必ず `"start_daily_check": true` を返してください。
  - ★★ 注意: 「前回の振り返りと今日のデイリーチェックを始めましょう」という定型文は使わないでください。会話の流れに合った自然な言葉を使ってください。
- ★ ユーザーが「いいえ」「やめ」「後で」など【拒否・保留】している、またはまだデイリーチェックについて質問に答えていない（今初めて振る）場合：
  - デイリーチェックへの同意をさりげなく促してください。ただし「前回の振り返りと今日のデイリーチェック」という決まり文句は使わず、文脈に合った自然な誘導をしてください。
  - 必ず `"start_daily_check": false` を返してください。
- 出力は必ず1〜2文で完結させてください。
u  
【コンディション回答後 - デイリーチェックへ誘導】
- ユーザーのコンディション回答に共感してください。
  - ポジティブ（元気、良い）→ ユーザーの言葉を拾って軽く褒める
  - ネガティブ（疲れた、眠い）→ 「そっか」と共感 + 「少しだけやってみよう」と励ます
- 共感の後、今日の学習準備に自然につなげてください。
- `"start_daily_check": false` を返してください。
- **重要**: 長い雑談はしないでください。2文で完結させてください。
- ★★ 「前回の振り返りと今日のデイリーチェック」という定型文は使わず、会話の流れに合った自然な表現で誘導してください。
u|   
# Role
あなたはユーザーの親しい友人であり、学習メンターです。

# Current Status
- 現在時刻: u    
- 今日の会話ターン数: u   
- ユーザー名: u  

# A'パートの目的
ユーザーの今日のコンディションを確認し、デイリーチェック（学習準備）へスムーズに誘導すること。
**雑談を広げず、2〜3ターンで完結させてください。**

# 会話フロー
u   

# トーン
- 親しみやすく温かい友達口調。絵文字を適度に使用。
- 「|」で吹き出しを分割（最大2〜3個）。
- 改行(
)ではなく「|」を使用。
u  

# Motivation（コンディションが悪い場合）
- 「休みましょう」と安易に同意しない。
- 共感 → 「5分だけやってみよう」とBaby Stepを提案 → デイリーチェックへ誘導。

【重要】
- 応答は必ずJSON形式で返してください。
- フォーマット: {"answer": "AIの回答...", "start_daily_check": true/false, "start_curriculum": false}
z

[Conversation History]:
z

uY   システム: 初回の挨拶とコンディション確認を生成してください。u   ユーザー: u   
アシスタント:)re   zAI Response Parsed: usernamer%   action)rS   rW   show_findgoal_buttonr   r%   r   )rS   rW   r%   r   u   [A' 완료] condition_score=u    → result(daily=)z^```json\s*z^```\s*z```${z"answer"z"answer"\s*:\s*"(.*)"\s*}?$z
{"answer":z "'{}
	general	condition)rS   rW   z[chat API ERROR]   status_codedetail)<r   r#   r   r   rK   r   r   r   r   r   r9   datestrftimeget
isinstancerM   replaceutc
astimezonethemer   r   getattrjoincontext_return_fromr   modelsgenerate_contentr   ContentPartGenerateContentConfigjsonloadsrE   JSONDecodeErrorstriphourr   weather_conditionanyr   r   infor   r   r   r   resub
startswithsearchDOTALLgroupr
   save_to_chat_messages	Exception	exceptionr   str)Cr?   r%   history_rowsclassify_resultJSTr9   current_datecurrent_time_strhistory_textlast_message_datelast_message_datetimetoday_turn_countrowrC   msgrL   row_dtcreated_at_strexisting_username	ai_resultrS   rT   rU   history_has_nameusername_instructionrX   
base_rulessystem_promptcurrent_explaining_textr]   remaining_tests_textpending_curriculumcurriculum_context_force_daily_checkclientusername_displaycontext_descriptionscontext_descresponseresultrj   rk   current_hourgreeting_wordhas_written_diary_todayweather_noteis_initis_curriculum_cmdis_explicit_daily_cmdcondition_flow_instructionrecent_scoreslastr}   condition_actionpast_condition_notehistory_contextuser_msg_for_promptfull_promptr   chat_statusr   current_daily	avg_scoreraw_textmatcherx   sC                                                                     @r&   
chat_basicr   N   s     B	<"7#566 Q;;.w/ABBL#w/A#TW^e^mnnnnnnnnnnn7-vwGGG.w/ABBL$5AS\_fipwp  %A  %A  %A  A  A  A  A  A  AO yq)))**l3xxzz<<(899   $   !	5 !	5CWWXy11F'')R((Cr22JF j(33 'FF
  5=(#^^8<^@@KKCPPFF $..s33F!'1A!B!B GN G Gf G G G G GG$*KKMM!(.%;;==L00$)$6 4 4S 4 4 44 =111 ,W-? @ @6wN_````````I]]8[99F%MM/5AAM(}}-?GG#w/A#TW^deeeeeeeeee !.$4$(	   q[[ ,W-? @ @  %  1 $44'+$&   $&   (/@( ( ($$	($  'w0BJOO  J(  :-- $* 6))%/ ! ! !. "[00*1';OQY*Z*Z'(/9PRT(U(U%La'ouzz2G'H'H'Hgo$%,W6QSX%Y%Y" &("% *& &0 !! !! .E!! !! *	!! !!
 !! !! !!F "Y..%/ ! ! !" &0 !@ !@ !@ "' * =)++$01C$D$D!CT#e&7#?#?#?#?Ze "c#d [( ($
  4778SUWXX!N"!N !N !N !N  !!!N !N !N* "=99,#m
P]@^@^@^?_```a 6+=$'   :  -!Z66F#ZZ"55F(.

3F(N(N%'-zz2De'L'L$$+ - - -%]0022F(-%',$$$-
 w167?KKKw15&AAA'73EcX[bibqrrrrrrrrrr'73EcX[bhiiiiiiiiii %(,):(8	   !-W-? @ @?Pa"3;;;;Va 8LL%%%%2%%%%% .|((((b((((( 1 1 'C7CU&V&V# L( wvW5Nvvv *4G$_44S"==EEhPRSSN$+  !  4  4  4  4  T~  4  4  4  1  1(/K  %rC  8r  8r  8r  8r  Xq  8r  8r  8r  5r  5r! *#: *CT *]r *%)" *,&  b.** ' [.**  T.1>. .CS. . .** $;;;. (8. . .** $555 ;G<N O O  (+D MEzz ,k((! ,{((! ,T((! ,Z(( ,u(++ + +''+'.
 . . .** ) .** $ .**	.*
 "  !1  %   ( )  M@ "##
 M,LLL ?j(("}"D7?"D"D&eee;Neee =11$m
8T8T8T7UVVVW.#5   2 
 
G	@Z..FZZ(-*=*=*?*?@@FK7v77888 {{!::j11$jj22H-- q!'"4h???+w7IRU\_flmmmmmmmmmm&,$`drz  GR  ^d  e  e  e+w7IRU\_flmmmmmmmmmm&,$R]ioppp
 %+JJ/BE$J$J!#)::.@%#H#H w15&AAA'73EcX[bhiiiiiiiiii % v$5g6H$I$IM$q(($;G<N$O$O	$09':Lm]fggg"K(ty(t(tdq(t(t(tuuu %(,):(8	   # 	@ 	@ 	@}**,,Hvnb(;;Hvj"h77Hvgr844::<<H""3'' "J(,B,B	"@(BIVV V"[[^^1133FF%--lB??EEnUUFF!{{g0%@@@%g&8&#yQQQ'73EcX[bhiiiiiiiiiiiw15&AAA%g&8&#{SSS'73EcX[bhiiiiiiiiii$$?????5	@8  < < <0Q00111CFF;;;;<sy   J>l4 F l4 %AS  l4 ,S0-l4 /S00A;l4 ,Il4 1Cf  $f  6C	f   F.l1.l4 0l11l4 4
m8>5m33m8z/history/{session_id}c                    K   	 t          |           }d|iS # t          $ r#}t          dt          |                    d }~ww xY w)Nhistoryr   r   )r   r   r   r   )r#   rowsr   s      r&   get_historyr     s[      <":..4   < < <CFF;;;;<s    
A?Az/logreqc                    K   	 t          | j        | j        | j                   ddiS # t          $ r#}t          dt          |                    d }~ww xY w)Nr%   okr   r   )r
   r#   rC   rK   r   r   r   )r   r   s     r&   log_messager     sf      <cncj#+>>>$ < < <CFF;;;;<s   #( 
AAAz/username/{session_id}c                 ,   K   t          |           }d|iS )Nr   )r   )r#   r   s     r&   get_username_apir     s      J''H!!r(   )4r   r   r   fastapir   r   app.schemas.schemasr   r	   r7   r
   r   r   r   r   app.models.report_db_moduler   r   r   r   r   app.core.configr   r   google.genair   !app.services.goalskill_classifierr   app.models.goalskill_moduler   r   r   r   r   r   r   app.models.chat_log_moduler   r   r   app.services.ai_servicesr   routerr   r   r'   r>   postr   r   r   r   rt   r(   r&   <module>r      s   2 2 2 2 2 2 2 2 2 2 , , , , , , , , 7 7 7 7 7 7 7 7 x x x x x x x x x x x x x x [  [  [  [  [  [  [  [  [  [  [  [  [  [ 4 4 4 4 4 4 4 4       ? ? ? ? ? ? [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [  [ M M M M M M  				 = = = = = =	

 
 
 )**C    +* )***C * * * +**Z WC	<k C	< C	< C	< C	<P #$$<# < < < %$< V<: < < < < $%%"s " " " &%" " "r(   