Spaces:
Sleeping
Sleeping
File size: 8,395 Bytes
cafc4a3 36c9099 cafc4a3 36c9099 cafc4a3 | 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 | import streamlit as st
import tempfile
import subprocess
import os
from streamlit_ace import st_ace
from utils import save_generated_code_to_new_file # chatではなくutilsからインポート
def setup_editor(api_key, mobile=False):
"""コードエディタとその関連機能をセットアップする"""
# ヘッダー
st.header("コードエディタ" if not mobile else "エディタ")
if st.session_state.current_file:
# ファイルの拡張子に基づいて言語を設定
file_ext = os.path.splitext(st.session_state.current_file)[1].lower()
lang_map = {
".py": "python",
".js": "javascript",
".html": "html",
".css": "css",
".json": "json",
".txt": "text"
}
language = lang_map.get(file_ext, "python")
# エディタの表示
st.subheader(f"編集中: {st.session_state.current_file}")
# モバイル向けの調整
editor_height = 300 if mobile else 500
# AIに編集を任せるモード
if st.session_state.ai_edit_mode and st.button("AIに編集を依頼", key="ai_edit_btn"):
current_code = st.session_state.files[st.session_state.current_file]
instructions = st.session_state.edit_instructions or "コードを改善してください"
with st.spinner("AIによるコード編集中..."):
# request_ai_editを直接インポートせず、関数を通して呼び出す
from chat import request_ai_edit # 関数を使う直前でインポート(循環を避ける)
edited_code = request_ai_edit(
api_key,
current_code,
instructions,
language
)
if edited_code:
st.session_state.files[st.session_state.current_file] = edited_code
st.success("AIによるコード編集が完了しました")
st.session_state.active_tab = "エディタ" # モバイルの場合はエディタタブに戻る
st.rerun()
# エディタを表示
code = st_ace(
value=st.session_state.files[st.session_state.current_file],
language=language,
theme="monokai",
keybinding="vscode",
font_size=14 if not mobile else 16, # モバイルでは少し大きく
min_lines=10,
max_lines=50,
height=editor_height,
key=f"ace_editor_{st.session_state.current_file}"
)
# コードを保存
st.session_state.files[st.session_state.current_file] = code
# アクション関連のボタン
col1, col2 = st.columns(2)
# Python codeの場合、実行ボタンを表示
if language == "python":
with col1:
if st.button("コードを実行", key="run_code_btn", use_container_width=True):
run_python_code(code)
# ファイルダウンロード機能
with col2:
st.download_button(
label="ファイルをダウンロード",
data=code,
file_name=st.session_state.current_file,
key="download_file",
use_container_width=True
)
else:
st.info("サイドバーから既存のファイルを選択するか、新しいファイルを作成してください。")
# 簡易ファイル作成ボタン(特にモバイル向け)
if st.button("新しいPythonファイルを作成", key="quick_file_create", use_container_width=True):
import time
filename = f"script_{int(time.time())}.py"
st.session_state.files[filename] = "# 新しいPythonスクリプト\n\n# コードを入力してください\n"
st.session_state.current_file = filename
st.rerun()
def run_python_code(code):
"""Pythonコードを実行して結果を表示する"""
with st.spinner("コードを実行中..."):
# 一時ファイルを作成してコードを実行
with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as tmp:
tmp.write(code.encode())
tmp_name = tmp.name
try:
# サブプロセスでPythonコードを実行
result = subprocess.run(
["python", tmp_name],
capture_output=True,
text=True,
timeout=10 # 10秒のタイムアウト
)
# 実行結果を表示
if result.stdout:
st.code(result.stdout, language="text")
if result.stderr:
st.error(result.stderr)
# エラーが発生した場合、自動的にエラー修正モードに切り替える
if st.button("エラー修正AIに相談", key="ask_error_fix"):
st.session_state.current_mode = "エラー修正モード"
error_query = f"次のPythonコードにエラーがあります。修正方法を教えてください。\n\n```python\n{code}\n```\n\nエラーメッセージ:\n```\n{result.stderr}\n```"
# チャットにエラー修正用のメッセージを追加
if "messages" not in st.session_state:
st.session_state.messages = []
st.session_state.messages.append({"role": "user", "content": error_query})
st.session_state.active_tab = "チャット" # モバイルモードではチャットタブに切り替え
st.rerun()
except subprocess.TimeoutExpired:
st.error("実行がタイムアウトしました(10秒以上かかりました)")
except Exception as e:
st.error(f"実行中にエラーが発生しました: {str(e)}")
finally:
# 一時ファイルを削除
if os.path.exists(tmp_name):
os.unlink(tmp_name)
def save_generated_code_to_new_file(code_text, suggested_name=None):
"""AIが生成したコードを新しいファイルに保存する"""
import re
# コードブロックのマークアップを削除
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 |