Spaces:
Sleeping
Sleeping
Update chat.py
Browse files
chat.py
CHANGED
|
@@ -2,7 +2,7 @@ import streamlit as st
|
|
| 2 |
import re
|
| 3 |
import os
|
| 4 |
from groq import Groq
|
| 5 |
-
from utils import load_system_prompt, extract_all_code_blocks, is_physics_related, save_generated_code_to_new_file #
|
| 6 |
|
| 7 |
def setup_chat(api_key, mobile=False):
|
| 8 |
"""チャット機能とその関連機能をセットアップする"""
|
|
@@ -67,6 +67,11 @@ def process_chat_input(prompt, api_key):
|
|
| 67 |
process_mode_command(prompt)
|
| 68 |
return
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
# 通常の質問処理
|
| 71 |
process_normal_query(prompt, api_key)
|
| 72 |
|
|
@@ -165,6 +170,95 @@ def process_mode_command(prompt):
|
|
| 165 |
# アシスタントメッセージをセッション状態に追加
|
| 166 |
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
def process_normal_query(prompt, api_key):
|
| 169 |
"""通常の質問を処理し、AIからの応答を生成する"""
|
| 170 |
# APIキーがある場合のみ実行
|
|
@@ -298,6 +392,31 @@ def generate_chain_response(user_input, api_key):
|
|
| 298 |
editor_code = st.session_state.files[st.session_state.current_file]
|
| 299 |
editor_reference = f"現在エディタで開かれているファイル '{st.session_state.current_file}':\n```\n{editor_code}\n```"
|
| 300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 301 |
# 通常モード用のシステムプロンプトをロード
|
| 302 |
system_prompt = load_system_prompt(MODELS["qwen_coder"], "通常モード")
|
| 303 |
|
|
@@ -320,6 +439,10 @@ def generate_chain_response(user_input, api_key):
|
|
| 320 |
if editor_code:
|
| 321 |
qwen_prompt += f"\n\n{editor_reference}\n\nエディタで開かれているコードに関して、ユーザーの質問に答えるか、必要に応じてコードの改善を提案してください。"
|
| 322 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
qwen_response = client.chat.completions.create(
|
| 324 |
model=MODELS["qwen_coder"],
|
| 325 |
messages=[
|
|
@@ -341,6 +464,26 @@ def generate_chain_response(user_input, api_key):
|
|
| 341 |
deepseek_section = f"DeepSeekの物理学的知見:\n{deepseek_knowledge}"
|
| 342 |
physics_note = "この実装には物理シミュレーションが含まれているため、物理法則の正確性と数値的安定性を特に重視してください。"
|
| 343 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 344 |
# Step 2a: 設計フェーズ - 専用のプロンプトを使用
|
| 345 |
design_system_prompt = load_system_prompt(MODELS["qwen_coder"], "実装モード_設計")
|
| 346 |
|
|
@@ -357,6 +500,10 @@ def generate_chain_response(user_input, api_key):
|
|
| 357 |
if is_physics:
|
| 358 |
design_prompt += f"\n\n{deepseek_section}"
|
| 359 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
design_response = client.chat.completions.create(
|
| 361 |
model=MODELS["qwen_coder"],
|
| 362 |
messages=[
|
|
@@ -389,6 +536,10 @@ def generate_chain_response(user_input, api_key):
|
|
| 389 |
{user_input}
|
| 390 |
"""
|
| 391 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
implementation_response = client.chat.completions.create(
|
| 393 |
model=MODELS["qwen_coder"],
|
| 394 |
messages=[
|
|
@@ -426,6 +577,26 @@ def generate_chain_response(user_input, api_key):
|
|
| 426 |
if is_physics:
|
| 427 |
deepseek_section = f"DeepSeekの物理学的知見:\n{deepseek_knowledge}"
|
| 428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 429 |
# エラー修正モード用のシステムプロンプトをロード
|
| 430 |
error_system_prompt = load_system_prompt(MODELS["qwen_coder"], "エラー修正モード")
|
| 431 |
|
|
@@ -454,6 +625,10 @@ def generate_chain_response(user_input, api_key):
|
|
| 454 |
if is_physics:
|
| 455 |
error_prompt += f"\n\n{deepseek_section}"
|
| 456 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 457 |
error_response = client.chat.completions.create(
|
| 458 |
model=MODELS["qwen_coder"],
|
| 459 |
messages=[
|
|
@@ -504,6 +679,26 @@ def generate_direct_response(user_input, api_key):
|
|
| 504 |
editor_code = st.session_state.files[st.session_state.current_file]
|
| 505 |
editor_reference = f"\n\n現在エディタで開かれているファイル '{st.session_state.current_file}':\n```\n{editor_code}\n```\n\nエディタで開かれているコードに関して、ユーザーの質問に答えるか、必要に応じてコードの改善を提案してください。"
|
| 506 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
qwen_prompt = f"""
|
| 508 |
あなたはユーザーと継続的な会話を行っているアシスタントです。
|
| 509 |
これまでの会話の流れを踏まえて、最新のユーザー入力に適切に応答してください。
|
|
@@ -521,6 +716,10 @@ def generate_direct_response(user_input, api_key):
|
|
| 521 |
if editor_code:
|
| 522 |
qwen_prompt += editor_reference
|
| 523 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
qwen_response = client.chat.completions.create(
|
| 525 |
model=MODELS["qwen_coder"],
|
| 526 |
messages=[
|
|
|
|
| 2 |
import re
|
| 3 |
import os
|
| 4 |
from groq import Groq
|
| 5 |
+
from utils import load_system_prompt, extract_all_code_blocks, is_physics_related, save_generated_code_to_new_file, get_file_dependencies # get_file_dependenciesをインポート
|
| 6 |
|
| 7 |
def setup_chat(api_key, mobile=False):
|
| 8 |
"""チャット機能とその関連機能をセットアップする"""
|
|
|
|
| 67 |
process_mode_command(prompt)
|
| 68 |
return
|
| 69 |
|
| 70 |
+
# ファイル解析コマンドを検出
|
| 71 |
+
if prompt.strip().startswith("/analyse") or prompt.strip().startswith("/analyze"):
|
| 72 |
+
process_analyze_command(api_key)
|
| 73 |
+
return
|
| 74 |
+
|
| 75 |
# 通常の質問処理
|
| 76 |
process_normal_query(prompt, api_key)
|
| 77 |
|
|
|
|
| 170 |
# アシスタントメッセージをセッション状態に追加
|
| 171 |
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 172 |
|
| 173 |
+
def process_analyze_command(api_key):
|
| 174 |
+
"""アップロードされたファイル群を解析するコマンドを処理する"""
|
| 175 |
+
# ファイルが存在するか確認
|
| 176 |
+
if not st.session_state.files:
|
| 177 |
+
response = "解析するファイルがありません。まずはファイルをアップロードするか作成してください。"
|
| 178 |
+
st.chat_message("assistant").markdown(response)
|
| 179 |
+
st.session_state.messages.append({"role": "assistant", "content": response})
|
| 180 |
+
return
|
| 181 |
+
|
| 182 |
+
with st.spinner("ファイル群を解析中..."):
|
| 183 |
+
# 依存関係の分析を実行
|
| 184 |
+
dependencies, file_summary = get_file_dependencies(st.session_state.files)
|
| 185 |
+
|
| 186 |
+
# 解析結果を生成
|
| 187 |
+
all_files_content = ""
|
| 188 |
+
for filename, content in st.session_state.files.items():
|
| 189 |
+
# ファイルサイズが大きい場合は先頭部分のみ
|
| 190 |
+
if len(content) > 1000:
|
| 191 |
+
all_files_content += f"\n\nファイル '{filename}'(先頭部分):\n```\n{content[:1000]}...\n```"
|
| 192 |
+
else:
|
| 193 |
+
all_files_content += f"\n\nファイル '{filename}':\n```\n{content}\n```"
|
| 194 |
+
|
| 195 |
+
# AIに解析を依頼
|
| 196 |
+
client = Groq(api_key=api_key)
|
| 197 |
+
|
| 198 |
+
# モデル名のマッピング
|
| 199 |
+
from config import MODELS
|
| 200 |
+
|
| 201 |
+
system_prompt = load_system_prompt(MODELS["qwen_coder"], "通常モード")
|
| 202 |
+
system_prompt += """
|
| 203 |
+
複数のファイルからなるプロジェクトを解析する際は、以下の点に注目してください:
|
| 204 |
+
1. ファイル間の依存関係と呼び出し構造
|
| 205 |
+
2. 主要なクラスやモジュールの責任範囲
|
| 206 |
+
3. データの流れと状態管理の方法
|
| 207 |
+
4. アプリケーションのアーキテクチャパターン
|
| 208 |
+
5. コードの再利用性と保守性
|
| 209 |
+
|
| 210 |
+
解析結果は以下の構造で提供してください:
|
| 211 |
+
1. プロジェクト概要 - 全体の目的と機能
|
| 212 |
+
2. 主要コンポーネント - 各ファイルの役割と責任
|
| 213 |
+
3. 依存関係図 - ファイル間の関係性
|
| 214 |
+
4. アーキテクチャ評価 - 設計パターンと原則の適用状況
|
| 215 |
+
5. 改善提案 - リファクタリングや拡張のための提案
|
| 216 |
+
"""
|
| 217 |
+
|
| 218 |
+
analyze_prompt = f"""
|
| 219 |
+
以下のファイル群からなるプロジェクトの構造と依存関係を分析してください。
|
| 220 |
+
各ファイルの役割、相互関係、データフローを明確にし、システム全体の理解を深めるための
|
| 221 |
+
包括的な分析を提供してください。
|
| 222 |
+
|
| 223 |
+
ファイル依存関係の分析結果:
|
| 224 |
+
{dependencies}
|
| 225 |
+
|
| 226 |
+
ファイル概要:
|
| 227 |
+
{file_summary}
|
| 228 |
+
|
| 229 |
+
アップロードされたファイル群の内容(一部省略あり):
|
| 230 |
+
{all_files_content}
|
| 231 |
+
"""
|
| 232 |
+
|
| 233 |
+
# 回答の生成
|
| 234 |
+
response = client.chat.completions.create(
|
| 235 |
+
model=MODELS["qwen_coder"],
|
| 236 |
+
messages=[
|
| 237 |
+
{"role": "system", "content": system_prompt},
|
| 238 |
+
{"role": "user", "content": analyze_prompt}
|
| 239 |
+
],
|
| 240 |
+
temperature=0.5,
|
| 241 |
+
max_tokens=4000
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
analysis_result = response.choices[0].message.content
|
| 245 |
+
|
| 246 |
+
# 分析結果を思考プロセスに追加
|
| 247 |
+
st.session_state.thinking_process.append({
|
| 248 |
+
"title": "プロジェクト構造解析",
|
| 249 |
+
"content": f"依存関係:\n{dependencies}\n\nファイル概要:\n{file_summary}"
|
| 250 |
+
})
|
| 251 |
+
|
| 252 |
+
# レスポンスを表示
|
| 253 |
+
st.chat_message("assistant").markdown(analysis_result)
|
| 254 |
+
|
| 255 |
+
# アシスタントメッセージをセッション状態に追加
|
| 256 |
+
st.session_state.messages.append({"role": "assistant", "content": analysis_result})
|
| 257 |
+
|
| 258 |
+
# 明示的に表示を更新するために変数を設定
|
| 259 |
+
st.session_state.ui_needs_update = True
|
| 260 |
+
st.rerun()
|
| 261 |
+
|
| 262 |
def process_normal_query(prompt, api_key):
|
| 263 |
"""通常の質問を処理し、AIからの応答を生成する"""
|
| 264 |
# APIキーがある場合のみ実行
|
|
|
|
| 392 |
editor_code = st.session_state.files[st.session_state.current_file]
|
| 393 |
editor_reference = f"現在エディタで開かれているファイル '{st.session_state.current_file}':\n```\n{editor_code}\n```"
|
| 394 |
|
| 395 |
+
# アップロードされた全ファイルのリストを作成
|
| 396 |
+
all_files_context = ""
|
| 397 |
+
mentioned_files = []
|
| 398 |
+
|
| 399 |
+
# ユーザー入力で言及されたファイル名を抽出
|
| 400 |
+
for filename in st.session_state.files.keys():
|
| 401 |
+
if filename in user_input and filename != st.session_state.current_file:
|
| 402 |
+
mentioned_files.append(filename)
|
| 403 |
+
|
| 404 |
+
# ファイルコンテキストの生成
|
| 405 |
+
if mentioned_files:
|
| 406 |
+
all_files_context = "ユーザーが言及したファイル:\n"
|
| 407 |
+
for filename in mentioned_files:
|
| 408 |
+
file_content = st.session_state.files[filename]
|
| 409 |
+
# ファイルサイズが大きい場合は先頭部分のみ含める
|
| 410 |
+
if len(file_content) > 1500:
|
| 411 |
+
all_files_context += f"\nファイル '{filename}'(先頭部分):\n```\n{file_content[:1500]}...\n```"
|
| 412 |
+
else:
|
| 413 |
+
all_files_context += f"\nファイル '{filename}':\n```\n{file_content}\n```"
|
| 414 |
+
elif len(st.session_state.files) > 1: # 複数ファイルがある場合
|
| 415 |
+
all_files_context = "アップロードされたファイル一覧:\n"
|
| 416 |
+
for filename in st.session_state.files.keys():
|
| 417 |
+
if filename != st.session_state.current_file: # 現在開いているファイル以外
|
| 418 |
+
all_files_context += f"- {filename}\n"
|
| 419 |
+
|
| 420 |
# 通常モード用のシステムプロンプトをロード
|
| 421 |
system_prompt = load_system_prompt(MODELS["qwen_coder"], "通常モード")
|
| 422 |
|
|
|
|
| 439 |
if editor_code:
|
| 440 |
qwen_prompt += f"\n\n{editor_reference}\n\nエディタで開かれているコードに関して、ユーザーの質問に答えるか、必要に応じてコードの改善を提案してください。"
|
| 441 |
|
| 442 |
+
# アップロードされたファイル情報を追加
|
| 443 |
+
if all_files_context:
|
| 444 |
+
qwen_prompt += f"\n\n{all_files_context}"
|
| 445 |
+
|
| 446 |
qwen_response = client.chat.completions.create(
|
| 447 |
model=MODELS["qwen_coder"],
|
| 448 |
messages=[
|
|
|
|
| 464 |
deepseek_section = f"DeepSeekの物理学的知見:\n{deepseek_knowledge}"
|
| 465 |
physics_note = "この実装には物理シミュレーションが含まれているため、物理法則の正確性と数値的安定性を特に重視してください。"
|
| 466 |
|
| 467 |
+
# アップロードされたファイル情報を取得
|
| 468 |
+
all_files_context = ""
|
| 469 |
+
mentioned_files = []
|
| 470 |
+
|
| 471 |
+
# ユーザー入力で言及されたファイル名を抽出
|
| 472 |
+
for filename in st.session_state.files.keys():
|
| 473 |
+
if filename in user_input:
|
| 474 |
+
mentioned_files.append(filename)
|
| 475 |
+
|
| 476 |
+
# ファイルコンテキストの生成
|
| 477 |
+
if mentioned_files:
|
| 478 |
+
all_files_context = "参照すべきファイル:\n"
|
| 479 |
+
for filename in mentioned_files:
|
| 480 |
+
file_content = st.session_state.files[filename]
|
| 481 |
+
# ファイルサイズが大きい場合は先頭部分のみ含める
|
| 482 |
+
if len(file_content) > 1000:
|
| 483 |
+
all_files_context += f"\nファイル '{filename}'(先頭部分):\n```\n{file_content[:1000]}...\n```"
|
| 484 |
+
else:
|
| 485 |
+
all_files_context += f"\nファイル '{filename}':\n```\n{file_content}\n```"
|
| 486 |
+
|
| 487 |
# Step 2a: 設計フェーズ - 専用のプロンプトを使用
|
| 488 |
design_system_prompt = load_system_prompt(MODELS["qwen_coder"], "実装モード_設計")
|
| 489 |
|
|
|
|
| 500 |
if is_physics:
|
| 501 |
design_prompt += f"\n\n{deepseek_section}"
|
| 502 |
|
| 503 |
+
# アップロードされたファイル情報を追加
|
| 504 |
+
if all_files_context:
|
| 505 |
+
design_prompt += f"\n\n{all_files_context}\n\n上記ファイルの構造や機能を考慮して設計を行ってください。"
|
| 506 |
+
|
| 507 |
design_response = client.chat.completions.create(
|
| 508 |
model=MODELS["qwen_coder"],
|
| 509 |
messages=[
|
|
|
|
| 536 |
{user_input}
|
| 537 |
"""
|
| 538 |
|
| 539 |
+
# アップロードされたファイル情報を追加(実装フェーズでも必要)
|
| 540 |
+
if all_files_context:
|
| 541 |
+
implementation_prompt += f"\n\n{all_files_context}\n\n上記の既存ファイルと互換性のあるコードを生成してください。"
|
| 542 |
+
|
| 543 |
implementation_response = client.chat.completions.create(
|
| 544 |
model=MODELS["qwen_coder"],
|
| 545 |
messages=[
|
|
|
|
| 577 |
if is_physics:
|
| 578 |
deepseek_section = f"DeepSeekの物理学的知見:\n{deepseek_knowledge}"
|
| 579 |
|
| 580 |
+
# アップロードされたファイル情報を取得
|
| 581 |
+
all_files_context = ""
|
| 582 |
+
mentioned_files = []
|
| 583 |
+
|
| 584 |
+
# ユーザー入力で言及されたファイル名を抽出
|
| 585 |
+
for filename in st.session_state.files.keys():
|
| 586 |
+
if filename in user_input and filename != st.session_state.current_file:
|
| 587 |
+
mentioned_files.append(filename)
|
| 588 |
+
|
| 589 |
+
# ファイルコンテキストの生成
|
| 590 |
+
if mentioned_files:
|
| 591 |
+
all_files_context = "関連するファイル:\n"
|
| 592 |
+
for filename in mentioned_files:
|
| 593 |
+
file_content = st.session_state.files[filename]
|
| 594 |
+
# ファイルサイズが大きい場合は先頭部分のみ含める
|
| 595 |
+
if len(file_content) > 1000:
|
| 596 |
+
all_files_context += f"\nファイル '{filename}'(先頭部分):\n```\n{file_content[:1000]}...\n```"
|
| 597 |
+
else:
|
| 598 |
+
all_files_context += f"\nファイル '{filename}':\n```\n{file_content}\n```"
|
| 599 |
+
|
| 600 |
# エラー修正モード用のシステムプロンプトをロード
|
| 601 |
error_system_prompt = load_system_prompt(MODELS["qwen_coder"], "エラー修正モード")
|
| 602 |
|
|
|
|
| 625 |
if is_physics:
|
| 626 |
error_prompt += f"\n\n{deepseek_section}"
|
| 627 |
|
| 628 |
+
# 関連ファイル情報を追加
|
| 629 |
+
if all_files_context:
|
| 630 |
+
error_prompt += f"\n\n{all_files_context}"
|
| 631 |
+
|
| 632 |
error_response = client.chat.completions.create(
|
| 633 |
model=MODELS["qwen_coder"],
|
| 634 |
messages=[
|
|
|
|
| 679 |
editor_code = st.session_state.files[st.session_state.current_file]
|
| 680 |
editor_reference = f"\n\n現在エディタで開かれているファイル '{st.session_state.current_file}':\n```\n{editor_code}\n```\n\nエディタで開かれているコードに関して、ユーザーの質問に答えるか、必要に応じてコードの改善を提案してください。"
|
| 681 |
|
| 682 |
+
# ユーザー入力で言及されたファイルに関する情報を追加
|
| 683 |
+
all_files_context = ""
|
| 684 |
+
mentioned_files = []
|
| 685 |
+
|
| 686 |
+
# ユーザー入力で言及されたファイル名を抽出
|
| 687 |
+
for filename in st.session_state.files.keys():
|
| 688 |
+
if filename in user_input and filename != st.session_state.current_file:
|
| 689 |
+
mentioned_files.append(filename)
|
| 690 |
+
|
| 691 |
+
# ファイルコンテキストの生成
|
| 692 |
+
if mentioned_files:
|
| 693 |
+
all_files_context = "\n\nユーザーが言及したファイル:\n"
|
| 694 |
+
for filename in mentioned_files:
|
| 695 |
+
file_content = st.session_state.files[filename]
|
| 696 |
+
# ファイルサイズが大きい場合は先頭部分のみ含める
|
| 697 |
+
if len(file_content) > 1000:
|
| 698 |
+
all_files_context += f"\nファイル '{filename}'(先頭部分):\n```\n{file_content[:1000]}...\n```"
|
| 699 |
+
else:
|
| 700 |
+
all_files_context += f"\nファイル '{filename}':\n```\n{file_content}\n```"
|
| 701 |
+
|
| 702 |
qwen_prompt = f"""
|
| 703 |
あなたはユーザーと継続的な会話を行っているアシスタントです。
|
| 704 |
これまでの会話の流れを踏まえて、最新のユーザー入力に適切に応答してください。
|
|
|
|
| 716 |
if editor_code:
|
| 717 |
qwen_prompt += editor_reference
|
| 718 |
|
| 719 |
+
# 言及されたファイルがある場合はコンテキストに追加
|
| 720 |
+
if all_files_context:
|
| 721 |
+
qwen_prompt += all_files_context
|
| 722 |
+
|
| 723 |
qwen_response = client.chat.completions.create(
|
| 724 |
model=MODELS["qwen_coder"],
|
| 725 |
messages=[
|