groxy / app.py
Yasu777's picture
Update app.py
c189735 verified
# app.py を修正して会話履歴引き継ぎに対応
import streamlit as st
import os
import asyncio
import re
from groq import Groq
from prompts import (
INSIGHT_CHAIN_SYSTEM_PROMPT,
INSIGHT_CHAIN_USER_PROMPT,
RESPONSE_SYSTEM_PROMPT
)
from validators.factory import ValidatorFactory
from ai_coder_app import AICoderApp
from utils import run_async
# Groq APIクライアントの設定
client = Groq(
api_key=os.environ.get("GROQ_API_KEY")
)
# AICoderAppのインスタンス作成
ai_coder_app = AICoderApp(client)
# アプリのタイトルと説明
st.title("気づきの連鎖AIチャット(モード分離版)")
st.markdown("質問や問題を入力すると、AIが気づきの連鎖プロセスで深く考察し、選択したモードに応じた回答を提供します。")
# セッション状態の初期化
if "messages" not in st.session_state:
st.session_state.messages = []
if "last_prompt" not in st.session_state:
st.session_state.last_prompt = None
if "feedback_count" not in st.session_state:
st.session_state.feedback_count = 0
if "app_mode" not in st.session_state:
st.session_state.app_mode = "normal"
if "context_preserved" not in st.session_state:
st.session_state.context_preserved = False
# セッションからアプリモード取得(最初のロード時のみ)
if hasattr(ai_coder_app, "current_mode"):
ai_coder_app.current_mode = st.session_state.app_mode
# 過去のメッセージを表示
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
# サイドバーの設定
with st.sidebar:
st.title("モード設定")
# 動作モードの選択
mode_options = {
"normal": "通常モード(一般的な質問応答)",
"implementation": "実装モード(アイデア→設計→実装)",
"verification": "検証修正モード(コード検証と修正)",
"error_resolution": "エラー解決モード(エラー診断と修正)"
}
selected_mode = st.selectbox(
"動作モード",
options=list(mode_options.keys()),
format_func=lambda x: mode_options[x],
index=list(mode_options.keys()).index(st.session_state.app_mode)
)
# モード変更時の処理
if selected_mode != st.session_state.app_mode:
# 前回のモードからコンテキストを保存
if not st.session_state.context_preserved and len(st.session_state.messages) > 0:
st.session_state.context_preserved = True
print(f"DEBUG: モード変更時のコンテキスト保存: {st.session_state.app_mode} -> {selected_mode}")
st.session_state.app_mode = selected_mode
ai_coder_app.current_mode = selected_mode
# モード変更メッセージをチャット履歴に追加
mode_change_message = f"モードを「{mode_options[selected_mode]}」に変更しました。"
# モード説明を追加
mode_descriptions = {
"normal": "通常の質問応答モードです。一般的な質問や議論に適しています。",
"implementation": "アイデアから設計と実装を生成するモードです。新しい機能の開発に適しています。",
"verification": "コードを検証して問題点を修正するモードです。既存コードの品質向上に適しています。",
"error_resolution": "エラーメッセージから問題を診断・修正するモードです。デバッグに適しています。"
}
mode_change_message += f"\n\n{mode_descriptions[selected_mode]}"
# 前のモードからの情報引き継ぎについての案内
context_info = ""
if st.session_state.app_mode == "verification" and len(st.session_state.messages) > 0:
# 直前のメッセージを取得
last_assistant_message = next((msg["content"] for msg in reversed(st.session_state.messages)
if msg["role"] == "assistant"), None)
# メッセージ内にコードブロックが含まれるか確認
if last_assistant_message and "```" in last_assistant_message:
context_info = "\n\n前回の実装結果を検証する場合は、「前回のコードを検証してください」と入力してください。"
mode_change_message += context_info
# チャット履歴に追加
st.session_state.messages.append({"role": "assistant", "content": mode_change_message})
# モード別の設定
st.markdown(f"### {mode_options[selected_mode]}の設定")
# 思考の深さパラメータを通常モードと実装モードの両方に追加
if selected_mode == "normal" or selected_mode == "implementation":
thought_depth_help = "値が大きいほど、より深い考察が行われます" if selected_mode == "normal" else "値が大きいほど、実装前の分析の深さが増します"
thought_depth = st.slider("思考の深さ", min_value=1, max_value=5, value=3,
help=thought_depth_help)
if selected_mode == "implementation":
physics_validation = st.checkbox("物理シミュレーション検証", value=False,
help="物理シミュレーションの正確性と安定性を検証します")
elif selected_mode == "verification":
physics_validation = st.checkbox("物理シミュレーション検証", value=False,
help="物理シミュレーションの正確性と安定性を検証します")
dependency_resolution = st.checkbox("依存性解決", value=True,
help="暗黙的な依存関係を検出し、必要なインポートを追加します")
test_generation = st.checkbox("テスト生成", value=False,
help="包括的なテストケースを自動生成します")
edge_case_validation = st.checkbox("エッジケース検証", value=True,
help="境界条件とエッジケースを特定し対処します")
elif selected_mode == "error_resolution":
# エラー解決モード用の設定(今後追加)
pass
# 共通設定
with st.expander("詳細設定", expanded=False):
max_retries = st.slider("修正ループ最大回数", min_value=1, max_value=3, value=2,
help="コード生成のフィードバックと改善ループの最大回数")
focus_area = st.selectbox("重点検証項目",
options=["全般", "コードの完全性", "エラーハンドリング", "物理的正確性", "エッジケース処理"],
help="検証時に特に重視する項目")
# 会話履歴の引き継ぎ設定
preserve_context = st.checkbox("会話履歴を引き継ぐ", value=True,
help="モード切替時に会話履歴を引き継ぎます")
if not preserve_context and st.button("会話履歴をクリア", help="現在の会話履歴をすべて削除します"):
st.session_state.messages = []
st.session_state.context_preserved = False
st.rerun()
# デバッグモード
debug_mode = st.checkbox("デバッグモード", value=False)
if debug_mode:
if hasattr(ai_coder_app, "last_insight_chain_result") and ai_coder_app.last_insight_chain_result:
st.markdown("### 気づきの連鎖AIの生成結果")
st.markdown(ai_coder_app.last_insight_chain_result)
if hasattr(ai_coder_app, "last_design_doc") and ai_coder_app.last_design_doc:
st.markdown("### 設計書")
st.markdown(ai_coder_app.last_design_doc)
if hasattr(ai_coder_app, "last_verification_result") and ai_coder_app.last_verification_result:
st.markdown("### コード検証結果")
st.markdown(ai_coder_app.last_verification_result.get("verification_summary", ""))
if hasattr(ai_coder_app, "context") and ai_coder_app.context:
st.markdown("### モード別コンテキスト")
st.write(f"保存されているモード: {list(ai_coder_app.context.keys())}")
for mode, ctx in ai_coder_app.context.items():
if ctx:
st.markdown(f"**{mode}モード**:")
st.write(f"- 保存データ: {list(ctx.keys())}")
if st.session_state.last_prompt:
st.markdown("### 最終プロンプト")
st.markdown(st.session_state.last_prompt)
# モード別のプレースホルダーテキスト
mode_placeholders = {
"normal": "質問や議論したいトピックを入力してください",
"implementation": "実装したい機能やアイデアを入力してください",
"verification": "検証・修正したいコードを入力してください",
"error_resolution": "発生したエラーメッセージとコードを入力してください"
}
# 前回のコード検証キーワード
previous_code_keywords = [
"前回のコード", "前の実装結果", "前のコード", "先ほどのコード", "さっきのコード",
"previous code", "generated code", "above code"
]
# ユーザー入力の処理
if prompt := st.chat_input(mode_placeholders.get(selected_mode, "質問や問題を入力してください")):
# 前回のコード検証リクエストの場合、前回の会話から実装結果を取得
if selected_mode == "verification" and any(keyword in prompt.lower() for keyword in previous_code_keywords) and not "```" in prompt:
# 直前のアシスタントメッセージからコードブロックを抽出
last_assistant_message = next((msg["content"] for msg in reversed(st.session_state.messages)
if msg["role"] == "assistant"), None)
if last_assistant_message:
# コードブロックのパターン
code_blocks = re.findall(r"```(\w*)\n([\s\S]*?)\n```", last_assistant_message)
if code_blocks:
# プロンプトにコードブロックを追加
enhanced_prompt = prompt + "\n\n"
for lang, code in code_blocks:
lang = lang or "python" # 言語指定がない場合はPythonと仮定
enhanced_prompt += f"```{lang}\n{code}\n```\n\n"
prompt = enhanced_prompt
print("DEBUG: 前回のコードブロックを検証用に追加しました")
# ユーザーの入力をチャット履歴に追加
st.session_state.messages.append({"role": "user", "content": prompt})
# 新しい質問の場合はフィードバックカウントをリセット
if st.session_state.last_prompt != prompt:
st.session_state.feedback_count = 0
ai_coder_app.feedback_count = 0
st.session_state.last_prompt = prompt
# ユーザーの入力を表示
with st.chat_message("user"):
st.markdown(prompt)
# 処理中のプレースホルダーを作成
with st.chat_message("assistant"):
message_placeholder = st.empty()
message_placeholder.markdown("考え中...")
try:
# 設定パラメータの準備
settings = {
"app_mode": selected_mode,
# 通常モード用設定
"thought_depth": thought_depth if 'thought_depth' in locals() else 3,
# 実装モード用設定
"physics_validation": physics_validation if 'physics_validation' in locals() else False,
# 検証修正モード用設定
"dependency_resolution": dependency_resolution if 'dependency_resolution' in locals() else True,
"test_generation": test_generation if 'test_generation' in locals() else False,
"edge_case_validation": edge_case_validation if 'edge_case_validation' in locals() else True,
# 共通設定
"max_retries": max_retries if 'max_retries' in locals() else 2,
"focus_area": focus_area if 'focus_area' in locals() else "全般",
"preserve_context": preserve_context if 'preserve_context' in locals() else True
}
# AICoderAppにユーザー入力を処理させる
with st.spinner("AIが応答を生成中..."):
final_result = run_async(ai_coder_app.process_user_input(prompt, settings))
# プレースホルダーを最終応答で更新
message_placeholder.markdown(final_result)
# アシスタントの応答をチャット履歴に追加
st.session_state.messages.append({"role": "assistant", "content": final_result})
except Exception as e:
message_placeholder.markdown(f"エラーが発生しました: {str(e)}")
st.error(f"API呼び出し中にエラーが発生しました: {str(e)}")
# サイドバーにコード再検証ボタンを追加(検証修正モードのみ)
with st.sidebar:
if selected_mode == "verification":
if st.button("コード再検証", help="現在表示されているコードを再度検証し、さらなる改善を行います"):
if st.session_state.messages and len(st.session_state.messages) > 0:
# 最後のアシスタント応答からコードを抽出して検証
last_assistant_message = next((msg["content"] for msg in reversed(st.session_state.messages)
if msg["role"] == "assistant"), None)
if last_assistant_message:
# 新しいユーザーメッセージを追加(コードの再検証)
st.session_state.messages.append({
"role": "user",
"content": "このコードをさらに検証して改善してください。"
})
# メッセージを表示(自動リロードでUIに反映)
st.rerun()