""" ステータス表示コンポーネント 好感度ゲージと関係ステージの表示を担当する """ import streamlit as st import logging from typing import Dict, Tuple logger = logging.getLogger(__name__) class StatusDisplay: """ステータス表示を管理するクラス""" def __init__(self): """ステータス表示の初期化""" self.stage_colors = { "敵対": {"color": "#ff4757", "emoji": "🔴", "bg_color": "rgba(255, 71, 87, 0.1)"}, "警戒": {"color": "#ff6348", "emoji": "🟠", "bg_color": "rgba(255, 99, 72, 0.1)"}, "中立": {"color": "#ffa502", "emoji": "🟡", "bg_color": "rgba(255, 165, 2, 0.1)"}, "好意": {"color": "#2ed573", "emoji": "🟢", "bg_color": "rgba(46, 213, 115, 0.1)"}, "親密": {"color": "#a55eea", "emoji": "💜", "bg_color": "rgba(165, 94, 234, 0.1)"} } def get_affection_color(self, affection: int) -> str: """ 好感度に基づいて色を取得する Args: affection: 好感度値 (0-100) Returns: 色のHEXコード """ if affection < 20: return "#ff4757" # 赤 elif affection < 40: return "#ff6348" # オレンジ elif affection < 60: return "#ffa502" # 黄色 elif affection < 80: return "#2ed573" # 緑 else: return "#a55eea" # 紫 def get_relationship_stage_info(self, affection: int) -> Dict[str, str]: """ 好感度から関係性ステージの情報を取得する Args: affection: 好感度値 (0-100) Returns: ステージ情報の辞書 """ if affection < 20: stage = "敵対" elif affection < 40: stage = "警戒" elif affection < 60: stage = "中立" elif affection < 80: stage = "好意" else: stage = "親密" # 古いキー形式との互換性を保つため、新しいキーで検索し、見つからない場合は中立を返す stage_info = None for key, value in self.stage_colors.items(): if stage in key: stage_info = value break return stage_info or self.stage_colors.get("中立", {"color": "#ffa502", "emoji": "🟡", "bg_color": "rgba(255, 165, 2, 0.1)"}) def render_affection_gauge(self, affection: int) -> None: """ 好感度ゲージを表示する Args: affection: 好感度値 (0-100) """ try: # 好感度の値を0-100の範囲に制限 affection = max(0, min(100, affection)) # 好感度メトリック表示 col1, col2 = st.columns([2, 1]) with col1: st.metric("好感度", f"{affection}/100") with col2: # 好感度の変化を表示(前回の値と比較) prev_affection = st.session_state.get('prev_affection', affection) delta = affection - prev_affection if delta != 0: st.metric("変化", f"{delta:+d}") st.session_state.prev_affection = affection # プログレスバー progress_value = affection / 100.0 affection_color = self.get_affection_color(affection) # カスタムプログレスバーのCSS progress_css = f""" """ st.markdown(progress_css, unsafe_allow_html=True) # プログレスバーのHTML progress_html = f"""
{affection}%
""" st.markdown(progress_html, unsafe_allow_html=True) # Streamlitの標準プログレスバーも表示(フォールバック) st.progress(progress_value) except Exception as e: logger.error(f"好感度ゲージ表示エラー: {e}") # フォールバック表示 st.metric("好感度", f"{affection}/100") st.progress(affection / 100.0) def render_relationship_stage(self, affection: int) -> None: """ 関係性ステージを表示する Args: affection: 好感度値 (0-100) """ try: stage_info = self.get_relationship_stage_info(affection) # ステージ名を取得 if affection < 20: stage_name = "ステージ1:敵対" stage_description = "麻理はあなたを敵視している" elif affection < 40: stage_name = "ステージ2:警戒" stage_description = "麻理はあなたを警戒している" elif affection < 60: stage_name = "ステージ3:中立" stage_description = "麻理はあなたに対して中立的" elif affection < 80: stage_name = "ステージ4:好意" stage_description = "麻理はあなたに好意を持っている" else: stage_name = "ステージ5:親密" stage_description = "麻理はあなたと親密な関係" # ステージ表示のCSS stage_css = f""" """ st.markdown(stage_css, unsafe_allow_html=True) # ステージ表示のHTML stage_html = f"""
{stage_info['emoji']}
{stage_name}
{stage_description}
""" st.markdown(stage_html, unsafe_allow_html=True) # フォールバック表示 st.write(f"{stage_info['emoji']} **関係性**: {stage_name}") except Exception as e: logger.error(f"関係性ステージ表示エラー: {e}") # フォールバック表示 if affection < 20: st.write("🔴 **関係性**: ステージ1:敵対") elif affection < 40: st.write("🟠 **関係性**: ステージ2:中立") elif affection < 60: st.write("🟡 **関係性**: ステージ3:好意") elif affection < 80: st.write("🟢 **関係性**: ステージ4:親密") else: st.write("💜 **関係性**: ステージ5:最接近") def render_affection_history(self, max_history: int = 10) -> None: """ 好感度の履歴を表示する(デバッグモード用) Args: max_history: 表示する履歴の最大数 """ try: if not st.session_state.get('debug_mode', False): return # 好感度履歴を取得 affection_history = st.session_state.get('affection_history', []) if not affection_history: st.write("好感度の履歴がありません") return # 最新の履歴を表示 recent_history = affection_history[-max_history:] st.subheader("📈 好感度履歴") for i, entry in enumerate(reversed(recent_history)): timestamp = entry.get('timestamp', 'Unknown') affection = entry.get('affection', 0) change = entry.get('change', 0) message = entry.get('message', '') change_str = f"({change:+d})" if change != 0 else "" st.write(f"{i+1}. {affection}/100 {change_str} - {timestamp[:19]}") if message: st.caption(f"メッセージ: {message[:50]}...") except Exception as e: logger.error(f"好感度履歴表示エラー: {e}") def update_affection_history(self, old_affection: int, new_affection: int, message: str = "") -> None: """ 好感度履歴を更新する Args: old_affection: 変更前の好感度 new_affection: 変更後の好感度 message: 関連するメッセージ """ try: if 'affection_history' not in st.session_state: st.session_state.affection_history = [] # 履歴エントリを作成 history_entry = { 'timestamp': st.session_state.get('current_timestamp', ''), 'affection': new_affection, 'change': new_affection - old_affection, 'message': message[:100] if message else '' # メッセージを100文字に制限 } st.session_state.affection_history.append(history_entry) # 履歴の長さを制限(最大50エントリ) if len(st.session_state.affection_history) > 50: st.session_state.affection_history = st.session_state.affection_history[-50:] except Exception as e: logger.error(f"好感度履歴更新エラー: {e}") def get_affection_statistics(self) -> Dict[str, float]: """ 好感度の統計情報を取得する Returns: 統計情報の辞書 """ try: affection_history = st.session_state.get('affection_history', []) if not affection_history: return { 'current': st.session_state.get('affection', 30), 'average': 30.0, 'max': 30, 'min': 30, 'total_changes': 0 } affections = [entry['affection'] for entry in affection_history] changes = [entry['change'] for entry in affection_history if entry['change'] != 0] return { 'current': st.session_state.get('affection', 30), 'average': sum(affections) / len(affections), 'max': max(affections), 'min': min(affections), 'total_changes': len(changes), 'positive_changes': len([c for c in changes if c > 0]), 'negative_changes': len([c for c in changes if c < 0]) } except Exception as e: logger.error(f"好感度統計取得エラー: {e}") return { 'current': st.session_state.get('affection', 30), 'average': 30.0, 'max': 30, 'min': 30, 'total_changes': 0 } def apply_status_styles(self) -> None: """ ステータス表示用のカスタムスタイルを適用する """ try: status_css = """ """ st.markdown(status_css, unsafe_allow_html=True) logger.debug("ステータス表示用スタイルを適用しました") except Exception as e: logger.error(f"ステータススタイル適用エラー: {e}") def render_enhanced_status_display(self, affection: int) -> None: """ 拡張されたステータス表示を描画する Args: affection: 現在の好感度 """ try: # カスタムスタイルを適用 self.apply_status_styles() # ステータスコンテナの開始 st.markdown('
', unsafe_allow_html=True) # 好感度ゲージ self.render_affection_gauge(affection) # 関係性ステージ self.render_relationship_stage(affection) # ステータスコンテナの終了 st.markdown('
', unsafe_allow_html=True) except Exception as e: logger.error(f"拡張ステータス表示エラー: {e}") # フォールバック:通常の表示 self.render_affection_gauge(affection) self.render_relationship_stage(affection) def show_affection_change_notification(self, old_affection: int, new_affection: int, reason: str = "") -> None: """ 好感度変化の通知を表示する Args: old_affection: 変更前の好感度 new_affection: 変更後の好感度 reason: 変化の理由 """ try: change = new_affection - old_affection if change == 0: return # 変化の方向に応じてスタイルを決定 if change > 0: icon = "📈" color = "#2ed573" change_text = f"+{change}" css_class = "affection-change-positive" else: icon = "📉" color = "#ff4757" change_text = str(change) css_class = "affection-change-negative" # 通知メッセージを作成 notification_html = f"""
{icon} 好感度が変化しました: {change_text} {f'
{reason}' if reason else ''}
""" st.markdown(notification_html, unsafe_allow_html=True) # 自動で消える通知(JavaScript) auto_hide_js = """ """ st.markdown(auto_hide_js, unsafe_allow_html=True) except Exception as e: logger.error(f"好感度変化通知エラー: {e}") def get_status_display_config(self) -> Dict[str, any]: """ ステータス表示の設定情報を取得する Returns: 設定情報の辞書 """ try: current_affection = st.session_state.get('affection', 30) stage_info = self.get_relationship_stage_info(current_affection) return { "current_affection": current_affection, "affection_color": self.get_affection_color(current_affection), "stage_info": stage_info, "history_count": len(st.session_state.get('affection_history', [])), "statistics": self.get_affection_statistics(), "styles_applied": True } except Exception as e: logger.error(f"ステータス表示設定取得エラー: {e}") return { "current_affection": 30, "affection_color": "#ffa502", "stage_info": self.stage_colors["中立"], "history_count": 0, "statistics": {}, "styles_applied": False }