Spaces:
Sleeping
Sleeping
File size: 13,545 Bytes
b070b4a 4943545 93329be | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | import os
import re
import streamlit as st
# プロンプトディレクトリのパス
PROMPTS_DIR = "prompts"
# プロンプトディレクトリが存在しない場合は作成
def ensure_prompts_directory():
if not os.path.exists(PROMPTS_DIR):
os.makedirs(PROMPTS_DIR)
# モデル名とモードからプロンプトファイルのパスを取得
def get_prompt_path(model_name, mode=None):
if mode:
# モードが指定されている場合はモード別のプロンプトを返す
return os.path.join(PROMPTS_DIR, f"{model_name}_{mode}.txt")
else:
# モードが指定されていない場合は基本プロンプトを返す
return os.path.join(PROMPTS_DIR, f"{model_name}.txt")
# デフォルトのプロンプト内容 - モデル別(簡易版)
DEFAULT_MODEL_PROMPTS = {
"mistral-saba-24b": """あなたは入力分析に特化したAIアシスタントです。ユーザーの質問や要求を深く分析し、重要な要素や課題を抽出してください。""",
"qwen-2.5-coder-32b": """あなたはコーディングに特化した高性能AIアシスタントです。
プログラミング問題に対する効率的なソリューションを提供し、多様な言語に対応してください。""",
"deepseek-r1-distill-llama-70b": """あなたは知識豊富なAIアシスタントです。
特に物理シミュレーションや複雑なアルゴリズムについての深い理解を持っています。"""
}
# デフォルトのプロンプト内容 - モード別(簡易版)
DEFAULT_MODE_PROMPTS = {
"qwen-2.5-coder-32b_通常モード": """あなたはコーディングアシスタントとして、ユーザーの質問や課題に対して明確で実用的な回答を提供してください。""",
"qwen-2.5-coder-32b_実装モード_設計": """ユーザーの要件に基づいて詳細な設計書を作成してください。
システム構造、コンポーネント責任、技術的仕様を明確に定義してください。""",
"qwen-2.5-coder-32b_実装モード_実装": """提供された設計書に基づいて、高品質な実装コードを生成してください。
コードは実行可能で、適切なエラー処理とコメントを含むものにしてください。""",
"qwen-2.5-coder-32b_エラー修正モード": """ユーザーが提示したコードのエラーを診断し修正してください。
エラーの根本原因を特定し、修正方法と再発防止策を提案してください。"""
}
# すべてのデフォルトプロンプトを含む辞書
ALL_DEFAULT_PROMPTS = {**DEFAULT_MODEL_PROMPTS, **DEFAULT_MODE_PROMPTS}
# プロンプトファイルが存在しない場合にデフォルトのプロンプトを作成
def create_default_prompt_files():
ensure_prompts_directory()
for prompt_key, prompt_text in ALL_DEFAULT_PROMPTS.items():
prompt_path = os.path.join(PROMPTS_DIR, f"{prompt_key}.txt")
if not os.path.exists(prompt_path):
with open(prompt_path, "w", encoding="utf-8") as f:
f.write(prompt_text)
# プロンプトをロード(ファイルが存在しない場合はデフォルトを使用)
def load_system_prompt(model_name, mode=None):
ensure_prompts_directory()
if mode:
# モード指定がある場合、モード別プロンプトをロード
prompt_key = f"{model_name}_{mode}"
prompt_path = get_prompt_path(model_name, mode)
# モード別プロンプトが存在しなければデフォルトを作成
if not os.path.exists(prompt_path) and prompt_key in DEFAULT_MODE_PROMPTS:
with open(prompt_path, "w", encoding="utf-8") as f:
f.write(DEFAULT_MODE_PROMPTS[prompt_key])
# ファイルが存在すればロード
if os.path.exists(prompt_path):
with open(prompt_path, "r", encoding="utf-8") as f:
return f.read()
# モード別プロンプトがない場合は基本プロンプトを使用
# 基本プロンプトをロード
base_prompt_path = os.path.join(PROMPTS_DIR, f"{model_name}.txt")
if os.path.exists(base_prompt_path):
with open(base_prompt_path, "r", encoding="utf-8") as f:
return f.read()
# どのファイルも存在しない場合、デフォルトを返す
return DEFAULT_MODEL_PROMPTS.get(model_name, "あなたはコーディングの専門家です。ユーザーのプログラミングに関する質問に詳細かつ正確に回答してください。")
# テキストが物理学に関連しているかチェックする関数
def is_physics_related(text):
"""テキストが物理学に関連しているか判定する"""
lower_text = text.lower()
# 明確な物理関連キーワード
explicit_physics_keywords = [
"物理法則", "物理シミュレーション", "ニュートン力学", "電磁気学", "熱力学", "量子力学", "相対性理論",
"physics simulation", "newton's laws", "electromagnetism", "thermodynamics",
"quantum mechanics", "relativity theory"
]
# 単語境界を考慮すべきキーワード
word_boundary_keywords = [
r"\b力学\b", r"\b重力\b", r"\b摩擦\b", r"\b衝突\b", r"\b運動方程式\b", r"\b加速度\b", r"\b速度\b", r"\b質量\b",
r"\bgravity\b", r"\bfriction\b", r"\bcollision\b", r"\bvelocity\b", r"\bacceleration\b", r"\bmass\b"
]
# 明確な物理用語が含まれているか
explicit_match = any(keyword.lower() in lower_text for keyword in explicit_physics_keywords)
# 境界を考慮すべき単語が含まれているか
boundary_match = any(re.search(pattern, lower_text) for pattern in word_boundary_keywords)
# 物理シミュレーション関連のフレーズパターン
physics_phrases = [
r"物理.*シミュレ(ーション|ート)",
r"physics.*simulation",
r"ボールの.*衝突",
r"ball.*collision",
r"重力.*計算",
r"gravity.*calculation",
r"運動方程式",
r"equation.*motion",
r"力学.*モデル",
r"mechanics.*model"
]
phrase_match = any(re.search(pattern, lower_text) for pattern in physics_phrases)
# 誤検出しやすいコンテキスト
non_physics_contexts = [
"アプリの動作", "システムの動作", "プログラムの動作", "ソフトウェアの動作",
"app behavior", "system behavior", "program behavior", "software behavior",
"UIの動き", "インターフェースの動き", "ボタンの動き",
"UI movement", "interface movement", "button movement"
]
negative_context = any(context.lower() in lower_text for context in non_physics_contexts)
return explicit_match or (boundary_match and not negative_context) or phrase_match
# テキストからコードブロックを抽出する関数
def extract_all_code_blocks(text):
"""テキストから全てのコードブロックを抽出する"""
code_block_pattern = r"```(\w+)?\n([\s\S]*?)\n```"
matches = re.findall(code_block_pattern, text)
if not matches:
return []
code_blocks = []
for lang, code in matches:
lang = lang or "python" # 言語指定がない場合はPythonと仮定
code_blocks.append(f"```{lang}\n{code}\n```")
return code_blocks
# AIが生成したコードを新しいファイルに保存する関数
def save_generated_code_to_new_file(code_text, suggested_name=None):
"""AIが生成したコードを新しいファイルに保存する"""
# コードブロックのマークアップを削除
code_pattern = r"```(?:\w+)?\n([\s\S]*?)\n```"
match = re.search(code_pattern, code_text)
clean_code = match.group(1) if match else code_text
# 言語の推測
language = "py" # デフォルトはPython
lang_pattern = r"```(\w+)\n"
lang_match = re.search(lang_pattern, code_text)
if lang_match:
detected_lang = lang_match.group(1).lower()
lang_mapping = {
"python": "py",
"javascript": "js",
"html": "html",
"css": "css",
"json": "json",
"java": "java",
"cpp": "cpp",
"c++": "cpp",
"c": "c",
"go": "go",
"rust": "rs",
"typescript": "ts"
}
language = lang_mapping.get(detected_lang, detected_lang)
# ファイル名の生成
if not suggested_name:
import hashlib
import time
# タイムスタンプとコードの一部からハッシュを生成
timestamp = str(int(time.time()))
code_hash = hashlib.md5(clean_code[:100].encode()).hexdigest()[:6]
suggested_name = f"generated_{timestamp}_{code_hash}"
# 拡張子が含まれていなければ追加
if "." not in suggested_name:
suggested_name = f"{suggested_name}.{language}"
# 同名ファイルが存在する場合は連番を付ける
base_name, ext = os.path.splitext(suggested_name)
counter = 1
file_name = suggested_name
while file_name in st.session_state.files:
file_name = f"{base_name}_{counter}{ext}"
counter += 1
# ファイルを保存
st.session_state.files[file_name] = clean_code
st.session_state.current_file = file_name
return file_name
# ファイル間の依存関係を分析する関数
def get_file_dependencies(files):
"""アップロードされたファイル群の依存関係を分析する"""
dependencies = {}
file_summary = {}
# ファイル間の依存関係を検出
for filename, content in files.items():
dependencies[filename] = []
file_summary[filename] = []
# 主要な機能や役割を特定するためのキーワードパターン
keyword_patterns = {
"import": r"import\s+(\w+)", # Pythonのimport文
"from": r"from\s+(\w+(?:\.\w+)*)\s+import", # fromを使ったimport文
"require": r"require\(['\"](.+?)['\"]\)", # Node.jsのrequire
"include": r"include\(['\"](.+?)['\"]\)", # PHPやC/C++のinclude
"class": r"class\s+(\w+)", # クラス定義
"function": r"def\s+(\w+)|function\s+(\w+)", # 関数定義
"streamlit": r"st\.(\w+)", # Streamlit関数
"variable": r"(\w+)\s*=\s*" # 変数定義
}
# 他のファイル名への参照を検索
for other_filename in files.keys():
if other_filename != filename and other_filename in content:
# ファイル名への直接参照パターン
direct_ref_patterns = [
rf"import\s+{os.path.splitext(other_filename)[0]}", # Pythonのimport
rf"from\s+{os.path.splitext(other_filename)[0]}", # Pythonのfrom import
rf"require\(['\"]\./{other_filename}['\"]\)", # Node.jsのrequire
rf"include\(['\"]\./{other_filename}['\"]\)", # includeでの参照
rf"open\(['\"]\./{other_filename}['\"]\)", # ファイルを開く操作
rf"['\"]\./{other_filename}['\"]" # ファイルパスの文字列
]
# いずれかのパターンにマッチする場合、依存関係を追加
if any(re.search(pattern, content) for pattern in direct_ref_patterns):
dependencies[filename].append(other_filename)
# ファイルの主要なコンポーネントを抽出
for keyword, pattern in keyword_patterns.items():
matches = re.findall(pattern, content)
if matches:
flat_matches = []
for match in matches:
if isinstance(match, tuple):
# タプルの場合(複数のキャプチャグループがある場合)
flat_matches.extend([m for m in match if m])
else:
flat_matches.append(match)
# 重複を除去して最大10個までの項目を記録
unique_matches = list(set(flat_matches))[:10]
if unique_matches:
summary_item = f"{keyword}: {', '.join(unique_matches)}"
file_summary[filename].append(summary_item)
# 依存関係を文字列として整形
dependencies_str = "ファイル間の依存関係:\n"
for filename, deps in dependencies.items():
if deps:
dependencies_str += f"- {filename} -> {', '.join(deps)}\n"
else:
dependencies_str += f"- {filename}: 依存ファイルなし\n"
# ファイル概要を文字列として整形
summary_str = "各ファイルの概要:\n"
for filename, summary_items in file_summary.items():
summary_str += f"## {filename}\n"
if summary_items:
for item in summary_items:
summary_str += f"- {item}\n"
else:
summary_str += "- 主要コンポーネントを検出できませんでした\n"
summary_str += "\n"
return dependencies_str, summary_str |