sirochild commited on
Commit
27f915e
·
verified ·
1 Parent(s): f0cd12a

Upload 2 files

Browse files
Files changed (2) hide show
  1. main_app.py +154 -29
  2. persistent_user_manager.py +15 -3
main_app.py CHANGED
@@ -482,17 +482,28 @@ def initialize_session_state(managers, force_reset_override=False):
482
  user_id_manager = managers["user_id_manager"] # フォールバック用
483
  session_api_client = managers["session_api_client"]
484
 
485
- # セッションIDを取得または生成(複数回呼び出し防止)
486
  if 'user_id' not in st.session_state or force_reset:
 
 
 
487
  try:
488
  # 永続ストレージからCookieベースでユーザーIDを取得
489
  session_id = persistent_user_manager.get_or_create_user_id()
490
  logger.info(f"永続ストレージからユーザーIDを取得: {session_id[:8]}...")
491
  except Exception as e:
492
- logger.error(f"永続ストレージ取得エラー、フォールバック使用: {e}")
493
- # フォールバック: 従来のローカルファイル方式
494
- session_id = user_id_manager.get_or_create_user_id()
495
- logger.info(f"フォールバック: ローカルファイルからユーザーIDを取得: {session_id[:8]}...")
 
 
 
 
 
 
 
 
496
  else:
497
  session_id = st.session_state.user_id
498
  logger.debug(f"既存ユーザーID使用: {session_id[:8]}...")
@@ -534,18 +545,29 @@ def initialize_session_state(managers, force_reset_override=False):
534
  st.session_state.chat_initialized = False
535
 
536
  if not st.session_state.chat_initialized:
537
- # 保存されたゲームデータを読み込み(永続ストレージ優先)
538
  saved_game_data = None
 
 
539
  try:
540
  saved_game_data = persistent_user_manager.load_user_game_data(st.session_state.user_id)
541
  if saved_game_data:
542
  logger.info(f"永続ストレージからゲームデータを読み込み: {st.session_state.user_id[:8]}...")
 
 
543
  except Exception as e:
544
- logger.error(f"永続ストレージ読み込みエラー、フォールバック使用: {e}")
545
- # フォールバック: 従来のローカルファイル方式
546
- saved_game_data = user_id_manager.load_game_data(st.session_state.user_id)
547
- if saved_game_data:
548
- logger.info(f"フォールバック: ローカルファイルからゲームデータを読み込み")
 
 
 
 
 
 
 
549
 
550
  if saved_game_data and not force_reset:
551
  # 保存データから復元
@@ -2219,24 +2241,7 @@ Streamlit情報:
2219
  st.session_state.chat['messages'] = []
2220
  if "affection_notifications" not in st.session_state:
2221
  st.session_state.affection_notifications = []
2222
- # ユーザー入力受付(送信時に一度だけ rerun が起きる)
2223
- user_input = st.chat_input("麻理に話しかける...")
2224
- if user_input and not st.session_state.awaiting_response:
2225
- st.session_state.latest_prompt = user_input
2226
- st.session_state.awaiting_response = True
2227
-
2228
- # タブ増殖防止:rerun前にチャット再レンダリングフラグを設定
2229
- st.session_state.force_chat_rerender = True
2230
-
2231
- # rerun回数を制限(無限ループ防止)
2232
- rerun_count = st.session_state.get('rerun_count', 0)
2233
- if rerun_count < 10: # 最大10回まで
2234
- st.session_state.rerun_count = rerun_count + 1
2235
- logger.info(f"メッセージ送信によるrerun実行 (回数: {st.session_state.rerun_count})")
2236
- st.rerun()
2237
- else:
2238
- logger.warning("rerun回数制限に達しました。処理を継続します。")
2239
- st.session_state.rerun_count = 0
2240
 
2241
  # 応答処理(rerun 後にこのブロックが実行される)
2242
  if st.session_state.awaiting_response:
@@ -3182,6 +3187,126 @@ def main():
3182
 
3183
  tutorial_manager.render_tutorial_tab()
3184
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3185
  if __name__ == "__main__":
3186
  if not Config.validate_config():
3187
  logger.critical("手紙機能の設定にエラーがあります。アプリケーションを起動できません。")
 
482
  user_id_manager = managers["user_id_manager"] # フォールバック用
483
  session_api_client = managers["session_api_client"]
484
 
485
+ # セッションIDを取得または生成(重複防止・統一化)
486
  if 'user_id' not in st.session_state or force_reset:
487
+ # 永続ストレージを優先、エラー時のみフォールバック
488
+ session_id = None
489
+
490
  try:
491
  # 永続ストレージからCookieベースでユーザーIDを取得
492
  session_id = persistent_user_manager.get_or_create_user_id()
493
  logger.info(f"永続ストレージからユーザーIDを取得: {session_id[:8]}...")
494
  except Exception as e:
495
+ logger.warning(f"永続ストレージ取得エラー、フォールバック使用: {e}")
496
+
497
+ try:
498
+ # フォールバック: 従来のローカルファイル方式
499
+ session_id = user_id_manager.get_or_create_user_id()
500
+ logger.info(f"フォールバック: ローカルファイルからユーザーIDを取得: {session_id[:8]}...")
501
+ except Exception as e2:
502
+ logger.error(f"フォールバックも失敗: {e2}")
503
+ # 最終フォールバック: 一時的なIDを生成
504
+ import uuid
505
+ session_id = str(uuid.uuid4())
506
+ logger.warning(f"最終フォールバック: 一時的なIDを生成: {session_id[:8]}...")
507
  else:
508
  session_id = st.session_state.user_id
509
  logger.debug(f"既存ユーザーID使用: {session_id[:8]}...")
 
545
  st.session_state.chat_initialized = False
546
 
547
  if not st.session_state.chat_initialized:
548
+ # 保存されたゲームデータを読み込み(重複防止・統一化)
549
  saved_game_data = None
550
+
551
+ # 永続ストレージを優先、失敗時のみフォールバック
552
  try:
553
  saved_game_data = persistent_user_manager.load_user_game_data(st.session_state.user_id)
554
  if saved_game_data:
555
  logger.info(f"永続ストレージからゲームデータを読み込み: {st.session_state.user_id[:8]}...")
556
+ else:
557
+ logger.debug("永続ストレージにゲームデータなし")
558
  except Exception as e:
559
+ logger.warning(f"永続ストレージ読み込みエラー、フォールバック試行: {e}")
560
+
561
+ try:
562
+ # フォールバック: 従来のローカルファイル方式
563
+ saved_game_data = user_id_manager.load_game_data(st.session_state.user_id)
564
+ if saved_game_data:
565
+ logger.info(f"フォールバック: ローカルファイルからゲームデータを読み込み")
566
+ else:
567
+ logger.debug("フォールバック: ローカルファイルにもゲームデータなし")
568
+ except Exception as e2:
569
+ logger.error(f"フォールバック読み込みも失敗: {e2}")
570
+ saved_game_data = None
571
 
572
  if saved_game_data and not force_reset:
573
  # 保存データから復元
 
2241
  st.session_state.chat['messages'] = []
2242
  if "affection_notifications" not in st.session_state:
2243
  st.session_state.affection_notifications = []
2244
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2245
 
2246
  # 応答処理(rerun 後にこのブロックが実行される)
2247
  if st.session_state.awaiting_response:
 
3187
 
3188
  tutorial_manager.render_tutorial_tab()
3189
 
3190
+ def main():
3191
+ """メインアプリケーション関数"""
3192
+ # 初期化の二重実行を防ぐ
3193
+ if 'app_initialized' not in st.session_state:
3194
+ st.session_state.app_initialized = True
3195
+ logger.info("アプリケーション初期化開始")
3196
+
3197
+ # 管理クラスの初期化
3198
+ managers = initialize_all_managers()
3199
+
3200
+ # セッション状態の初期化
3201
+ initialize_session_state(managers)
3202
+
3203
+ # 初期化完了をマーク
3204
+ st.session_state.managers = managers
3205
+ logger.info("初期化完了")
3206
+ else:
3207
+ # 既に初期化済みの場合はmanagersを取得
3208
+ managers = st.session_state.managers
3209
+
3210
+ # CSSの注入
3211
+ inject_custom_css()
3212
+
3213
+ # チャット入力をトップレベルで処理(最優先)
3214
+ handle_chat_input(managers)
3215
+
3216
+ # メインUI表示
3217
+ render_main_ui(managers)
3218
+
3219
+ def render_main_ui(managers):
3220
+ """メインUIの描画"""
3221
+ # 既存のUI描画コードは後で実装
3222
+ st.title("💬 麻理チャット")
3223
+ st.markdown("*捨てられたアンドロイド「麻理」との対話*")
3224
+
3225
+ # チャット履歴表示
3226
+ if 'chat' in st.session_state and 'messages' in st.session_state.chat:
3227
+ for message in st.session_state.chat['messages']:
3228
+ role = message.get("role", "user")
3229
+ content = message.get("content", "")
3230
+
3231
+ with st.chat_message(role):
3232
+ st.markdown(content)
3233
+
3234
+ def handle_chat_input(managers):
3235
+ """チャット入力をトップレベルで処理"""
3236
+ # 初期化(セッションステートに必要な変数を登録)
3237
+ if "awaiting_response" not in st.session_state:
3238
+ st.session_state.awaiting_response = False
3239
+ if "latest_prompt" not in st.session_state:
3240
+ st.session_state.latest_prompt = ""
3241
+
3242
+ # チャット入力(トップレベル)
3243
+ user_input = st.chat_input("麻理に話しかける...")
3244
+
3245
+ if user_input and not st.session_state.awaiting_response:
3246
+ st.session_state.latest_prompt = user_input
3247
+ st.session_state.awaiting_response = True
3248
+
3249
+ # rerun回数を制限(無限ループ防止)
3250
+ rerun_count = st.session_state.get('rerun_count', 0)
3251
+ if rerun_count < 5: # 最大5回まで
3252
+ st.session_state.rerun_count = rerun_count + 1
3253
+ logger.info(f"メッセージ送信によるrerun実行 (回数: {st.session_state.rerun_count})")
3254
+ st.rerun()
3255
+ else:
3256
+ logger.warning("rerun回数制限に達しました。処理を継続します。")
3257
+ st.session_state.rerun_count = 0
3258
+
3259
+ # 応答処理(rerun 後にこのブロックが実行される)
3260
+ if st.session_state.awaiting_response:
3261
+ prompt = st.session_state.latest_prompt
3262
+
3263
+ # 1. 入力チェック
3264
+ if len(prompt) > MAX_INPUT_LENGTH:
3265
+ st.error(f"⚠️ メッセージは{MAX_INPUT_LENGTH}文字以内で入力してください。")
3266
+ st.session_state.awaiting_response = False
3267
+ st.session_state.latest_prompt = ""
3268
+ else:
3269
+ # 2. ユーザーのメッセージを履歴に追加
3270
+ if 'chat' not in st.session_state:
3271
+ st.session_state.chat = {'messages': []}
3272
+ if 'messages' not in st.session_state.chat:
3273
+ st.session_state.chat['messages'] = []
3274
+
3275
+ st.session_state.chat['messages'].append({
3276
+ "role": "user",
3277
+ "content": prompt
3278
+ })
3279
+
3280
+ # 3. AI応答生成
3281
+ with st.spinner("麻理が考え中..."):
3282
+ response = process_chat_message(prompt, managers)
3283
+
3284
+ # 4. AI応答を履歴に追加
3285
+ st.session_state.chat['messages'].append({
3286
+ "role": "assistant",
3287
+ "content": response
3288
+ })
3289
+
3290
+ # 5. 応答完了状態に戻す
3291
+ st.session_state.awaiting_response = False
3292
+ st.session_state.latest_prompt = ""
3293
+ st.session_state.rerun_count = 0
3294
+
3295
+ # 再描画
3296
+ st.rerun()
3297
+
3298
+ def process_chat_message(message: str, managers):
3299
+ """チャットメッセージ処理"""
3300
+ try:
3301
+ logger.info(f"🚀 process_chat_message開始 - メッセージ: '{message}'")
3302
+
3303
+ # 簡単な応答生成(テスト用)
3304
+ return f"[HIDDEN:({message}について考えている)]そうね、{message}について話すのね。"
3305
+
3306
+ except Exception as e:
3307
+ logger.error(f"チャットメッセージ処理エラー: {e}")
3308
+ return "[HIDDEN:(システムエラーが発生した)]ごめん、何か問題が起きたみたい。"
3309
+
3310
  if __name__ == "__main__":
3311
  if not Config.validate_config():
3312
  logger.critical("手紙機能の設定にエラーがあります。アプリケーションを起動できません。")
persistent_user_manager.py CHANGED
@@ -80,32 +80,43 @@ class PersistentUserManager:
80
 
81
  def get_or_create_user_id(self) -> str:
82
  """
83
- ユーザーIDを取得または新規作成(Cookie連携)
84
 
85
  Returns:
86
  ユーザーID
87
  """
88
  try:
 
 
 
 
 
 
 
89
  # 1. CookieからユーザーIDを取得
90
  user_id = self._get_user_id_from_cookie()
91
 
92
  if user_id and self._is_valid_user_id(user_id):
93
  # 有効なユーザーIDが存在
94
  self._update_user_access_time(user_id)
95
- logger.info(f"既存ユーザーID使用: {user_id[:8]}...")
 
 
96
  return user_id
97
 
98
- # 2. セッション状態から取得を試行
99
  user_id = st.session_state.get('persistent_user_id')
100
  if user_id and self._is_valid_user_id(user_id):
101
  # セッション状態にあるIDを使用してCookieを更新
102
  self._set_user_id_cookie(user_id)
103
  self._update_user_access_time(user_id)
 
104
  logger.info(f"セッション状態からユーザーID復元: {user_id[:8]}...")
105
  return user_id
106
 
107
  # 3. 新規ユーザーIDを作成
108
  user_id = self._create_new_user()
 
109
  logger.info(f"新規ユーザーID作成: {user_id[:8]}...")
110
  return user_id
111
 
@@ -114,6 +125,7 @@ class PersistentUserManager:
114
  # フォールバック: 一時的なIDを生成
115
  fallback_id = str(uuid.uuid4())
116
  st.session_state.persistent_user_id = fallback_id
 
117
  return fallback_id
118
 
119
  def _get_user_id_from_cookie(self) -> Optional[str]:
 
80
 
81
  def get_or_create_user_id(self) -> str:
82
  """
83
+ ユーザーIDを取得または新規作成(Cookie連携・重複防止)
84
 
85
  Returns:
86
  ユーザーID
87
  """
88
  try:
89
+ # 重複チェック防止: 既にセッション状態にある場合はそれを使用
90
+ if hasattr(st.session_state, 'persistent_user_id_checked'):
91
+ existing_id = st.session_state.get('persistent_user_id')
92
+ if existing_id and self._is_valid_uuid(existing_id):
93
+ logger.debug(f"既にチェック済みのユーザーID使用: {existing_id[:8]}...")
94
+ return existing_id
95
+
96
  # 1. CookieからユーザーIDを取得
97
  user_id = self._get_user_id_from_cookie()
98
 
99
  if user_id and self._is_valid_user_id(user_id):
100
  # 有効なユーザーIDが存在
101
  self._update_user_access_time(user_id)
102
+ st.session_state.persistent_user_id = user_id
103
+ st.session_state.persistent_user_id_checked = True
104
+ logger.info(f"CookieからユーザーID取得: {user_id[:8]}...")
105
  return user_id
106
 
107
+ # 2. セッション状態から取得を試行(Cookieが無効な場合のみ)
108
  user_id = st.session_state.get('persistent_user_id')
109
  if user_id and self._is_valid_user_id(user_id):
110
  # セッション状態にあるIDを使用してCookieを更新
111
  self._set_user_id_cookie(user_id)
112
  self._update_user_access_time(user_id)
113
+ st.session_state.persistent_user_id_checked = True
114
  logger.info(f"セッション状態からユーザーID復元: {user_id[:8]}...")
115
  return user_id
116
 
117
  # 3. 新規ユーザーIDを作成
118
  user_id = self._create_new_user()
119
+ st.session_state.persistent_user_id_checked = True
120
  logger.info(f"新規ユーザーID作成: {user_id[:8]}...")
121
  return user_id
122
 
 
125
  # フォールバック: 一時的なIDを生成
126
  fallback_id = str(uuid.uuid4())
127
  st.session_state.persistent_user_id = fallback_id
128
+ st.session_state.persistent_user_id_checked = True
129
  return fallback_id
130
 
131
  def _get_user_id_from_cookie(self) -> Optional[str]: