DeL-TaiseiOzaki commited on
Commit
396927c
1 Parent(s): e32a461

app.pyの更新

Browse files
Files changed (1) hide show
  1. app.py +138 -147
app.py CHANGED
@@ -1,189 +1,180 @@
1
  import streamlit as st
2
  import tempfile
3
  import git
4
- from core.file_scanner import FileScanner
5
  from pathlib import Path
6
- from datetime import datetime
7
  from services.llm_service import LLMService
8
- from core.file_scanner import FileInfo
9
  from typing import List
10
 
 
11
  # ページ設定
12
  st.set_page_config(
13
- page_title="Repository Code Analysis",
14
- page_icon="🔍",
15
- layout="wide"
16
  )
17
 
18
  # ダークテーマの設定
19
  st.markdown("""
20
  <style>
21
- .stApp {
22
- background-color: #0e1117;
23
- color: #ffffff;
24
- }
25
- .chat-message {
26
- padding: 1rem;
27
- margin: 1rem 0;
28
- border-radius: 0.5rem;
29
- }
30
- .assistant-message {
31
- background-color: #1e2329;
32
- color: #ffffff;
33
- }
34
- .stButton button {
35
- background-color: #2ea44f;
36
- color: #ffffff;
37
- }
38
- .stTextArea textarea {
39
- background-color: #1e2329;
40
- color: #ffffff;
41
- }
42
  </style>
43
  """, unsafe_allow_html=True)
44
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
  def clone_repository(repo_url: str) -> Path:
47
- """リポジトリをクローンして一時ディレクトリに保存"""
48
- temp_dir = Path(tempfile.mkdtemp())
49
- git.Repo.clone_from(repo_url, temp_dir)
50
- return temp_dir
51
-
52
- def create_download_content(files: List[FileInfo]) -> str:
53
- content = "# スキャン結果\n\n"
54
- for file in files:
55
- content += f"## {file.path}\n"
56
- content += f"サイズ: {file.formatted_size}\n"
57
- content += f"エンコーディング: {file.encoding or '不明'}\n\n"
58
- if file.content:
59
- content += f"```{file.extension[1:] if file.extension else ''}\n"
60
- content += file.content
61
- content += "\n```\n\n"
62
- return content
63
 
64
  # セッション状態の初期化
65
  if 'repo_content' not in st.session_state:
66
- st.session_state.repo_content = None
67
  if 'temp_dir' not in st.session_state:
68
- st.session_state.temp_dir = None
69
  if 'llm_service' not in st.session_state:
70
- try:
71
- st.session_state.llm_service = LLMService()
72
- except ValueError as e:
73
- st.error(str(e))
74
- st.stop()
75
 
76
  # メインのUIレイアウト
77
  st.title("🔍 リポジトリ解析・質問システム")
78
 
79
  # サイドバーでモデル選択
80
- available_models = st.session_state.llm_service.settings.get_available_models()
81
- if len(available_models) > 1:
82
- selected_model = st.sidebar.selectbox(
83
- "使用するモデル",
84
- available_models,
85
- index=available_models.index(st.session_state.llm_service.current_model)
86
- )
87
- st.session_state.llm_service.switch_model(selected_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
  # URLの入力
90
  repo_url = st.text_input(
91
- "GitHubリポジトリのURLを入力",
92
- placeholder="https://github.com/username/repository.git"
93
  )
94
 
95
  # スキャン実行ボタン
96
  if st.button("スキャン開始", disabled=not repo_url):
97
- try:
98
- with st.spinner('リポジトリをクローン中...'):
99
- temp_dir = clone_repository(repo_url)
100
- st.session_state.temp_dir = temp_dir
101
-
102
- with st.spinner('ファイルをスキャン中...'):
103
- scanner = FileScanner(temp_dir)
104
- files = scanner.scan_files() # List[FileInfo] を取得
105
- st.session_state.repo_content = LLMService.format_code_content(files)
106
-
107
- st.success(f"スキャン完了: {len(files)}個のファイルを検出")
108
- # 新しいスキャン時に会話履歴をクリア
109
- st.session_state.llm_service.clear_history()
110
-
111
- except Exception as e:
112
- st.error(f"エラーが発生しました: {str(e)}")
 
 
 
 
 
 
 
 
 
 
113
 
114
  # スキャン完了後の質問セクション
115
  if st.session_state.repo_content:
116
- st.divider()
117
- st.subheader("💭 コードについて質問する")
118
-
119
- # スキャン結果のダウンロードボタン
120
- scan_result = create_download_content(files) # filesはスキャン結果
121
- st.download_button(
122
- label="スキャン結果をダウンロード",
123
- data=scan_result,
124
- file_name=f"scan_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
125
- mime="text/markdown"
126
- )
127
-
128
- # 会話履歴の表示(アシスタントの回答のみ)
129
- for message in st.session_state.llm_service.conversation_history:
130
- if message.role == "assistant": # アシスタントの回答のみを表示
131
- st.markdown(f'<div class="chat-message assistant-message">{message.content}</div>',
132
- unsafe_allow_html=True)
133
-
134
- query = st.text_area(
135
- "質問を入力してください",
136
- placeholder="例: このコードの主な機能は何ですか?"
137
- )
138
-
139
- col1, col2 = st.columns([1, 5])
140
- with col1:
141
- if st.button("履歴クリア"):
142
- st.session_state.llm_service.clear_history()
143
- st.rerun()
144
-
145
- with col2:
146
- if st.button("質問する", disabled=not query):
147
- with st.spinner('回答を生成中...'):
148
- response, error = st.session_state.llm_service.get_response(
149
- st.session_state.repo_content,
150
- query
151
- )
152
-
153
- if error:
154
- st.error(error)
155
- else:
156
- st.rerun() # 会話履歴を更新するために再表示
157
 
158
  # セッション終了時のクリーンアップ
159
  if st.session_state.temp_dir and Path(st.session_state.temp_dir).exists():
160
- try:
161
- import shutil
162
- shutil.rmtree(st.session_state.temp_dir)
163
- except:
164
- pass
165
-
166
- # サイドバー情報
167
- with st.sidebar:
168
- model = st.radio(
169
- "���用するモデル",
170
- ["Claude", "OpenAI"],
171
- key="model_selection"
172
- )
173
- st.session_state.llm_service.switch_model(model.lower())
174
- st.divider()
175
- st.subheader("📌 使い方")
176
- st.markdown("""
177
- 1. GitHubリポジトリのURLを入力
178
- 2. スキャンを実行
179
- 3. コードについて質問(最大5ターンの会話が可能)
180
- """)
181
-
182
- st.subheader("🔍 スキャン対象")
183
- st.markdown("""
184
- - Python (.py)
185
- - JavaScript (.js)
186
- - Java (.java)
187
- - C/C++ (.c, .h, .cpp, .hpp)
188
- - その他の主要なプログラミング言語
189
- """)
 
1
  import streamlit as st
2
  import tempfile
3
  import git
 
4
  from pathlib import Path
5
+ from datetime import datetime
6
  from services.llm_service import LLMService
7
+ from core.file_scanner import FileScanner, FileInfo
8
  from typing import List
9
 
10
+
11
  # ページ設定
12
  st.set_page_config(
13
+ page_title="Repository Code Analysis",
14
+ page_icon="🔍",
15
+ layout="wide"
16
  )
17
 
18
  # ダークテーマの設定
19
  st.markdown("""
20
  <style>
21
+ .stApp {
22
+ background-color: #0e1117;
23
+ color: #ffffff;
24
+ }
25
+ .chat-message {
26
+ padding: 1rem;
27
+ margin: 1rem 0;
28
+ border-radius: 0.5rem;
29
+ }
30
+ .assistant-message {
31
+ background-color: #1e2329;
32
+ color: #ffffff;
33
+ }
34
+ .stButton button {
35
+ background-color: #2ea44f;
36
+ color: #ffffff;
37
+ }
38
+ .stTextArea textarea {
39
+ background-color: #1e2329;
40
+ color: #ffffff;
41
+ }
42
  </style>
43
  """, unsafe_allow_html=True)
44
 
45
+ def create_download_content(files: List[FileInfo]) -> str:
46
+ content = "# スキャン結果\n\n"
47
+ for file in files:
48
+ content += f"## {file.path}\n"
49
+ content += f"サイズ: {file.formatted_size}\n"
50
+ content += f"エンコーディング: {file.encoding or '不明'}\n\n"
51
+ if file.content:
52
+ content += f"```{file.extension[1:] if file.extension else ''}\n"
53
+ content += file.content
54
+ content += "\n```\n\n"
55
+ return content
56
 
57
  def clone_repository(repo_url: str) -> Path:
58
+ """リポジトリをクローンして一時ディレクトリに保存"""
59
+ temp_dir = Path(tempfile.mkdtemp())
60
+ git.Repo.clone_from(repo_url, temp_dir)
61
+ return temp_dir
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  # セッション状態の初期化
64
  if 'repo_content' not in st.session_state:
65
+ st.session_state.repo_content = None
66
  if 'temp_dir' not in st.session_state:
67
+ st.session_state.temp_dir = None
68
  if 'llm_service' not in st.session_state:
69
+ try:
70
+ st.session_state.llm_service = LLMService()
71
+ except ValueError as e:
72
+ st.error(str(e))
73
+ st.stop()
74
 
75
  # メインのUIレイアウト
76
  st.title("🔍 リポジトリ解析・質問システム")
77
 
78
  # サイドバーでモデル選択
79
+ with st.sidebar:
80
+ model = st.radio(
81
+ "使用するモデル",
82
+ ["Claude", "OpenAI"],
83
+ key="model_selection"
84
+ )
85
+ st.session_state.llm_service.switch_model(model.lower())
86
+
87
+ st.divider()
88
+ st.subheader("📌 使い方")
89
+ st.markdown("""
90
+ 1. GitHubリポジトリのURLを入力
91
+ 2. スキャンを実行
92
+ 3. コードについて質問(最大5ターンの会話が可能)
93
+ """)
94
+
95
+ st.subheader("🔍 スキャン対象")
96
+ st.markdown("""
97
+ - Python (.py)
98
+ - JavaScript (.js)
99
+ - Java (.java)
100
+ - C/C++ (.c, .h, .cpp, .hpp)
101
+ - その他の主要なプログラミング言語
102
+ """)
103
 
104
  # URLの入力
105
  repo_url = st.text_input(
106
+ "GitHubリポジトリのURLを入力",
107
+ placeholder="https://github.com/username/repository.git"
108
  )
109
 
110
  # スキャン実行ボタン
111
  if st.button("スキャン開始", disabled=not repo_url):
112
+ try:
113
+ with st.spinner('リポジトリをクローン中...'):
114
+ temp_dir = clone_repository(repo_url)
115
+ st.session_state.temp_dir = temp_dir
116
+
117
+ with st.spinner('ファイルをスキャン中...'):
118
+ scanner = FileScanner(temp_dir)
119
+ files = scanner.scan_files()
120
+ st.session_state.repo_content = LLMService.format_code_content(files)
121
+
122
+ st.success(f"スキャン完了: {len(files)}個のファイルを検出")
123
+
124
+ # スキャン結果のダウンロードボタン
125
+ scan_result = create_download_content(files)
126
+ st.download_button(
127
+ label="スキャン結果をダウンロード",
128
+ data=scan_result,
129
+ file_name=f"scan_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
130
+ mime="text/markdown"
131
+ )
132
+
133
+ # 新しいスキャン時に会話履歴をクリア
134
+ st.session_state.llm_service.clear_history()
135
+
136
+ except Exception as e:
137
+ st.error(f"エラーが発生しました: {str(e)}")
138
 
139
  # スキャン完了後の質問セクション
140
  if st.session_state.repo_content:
141
+ st.divider()
142
+ st.subheader("💭 コードについて質問する")
143
+
144
+ # 会話履歴の表示(アシスタントの回答のみ)
145
+ for message in st.session_state.llm_service.conversation_history:
146
+ if message.role == "assistant":
147
+ st.markdown(f'<div class="chat-message assistant-message">{message.content}</div>',
148
+ unsafe_allow_html=True)
149
+
150
+ query = st.text_area(
151
+ "質問を入力してください",
152
+ placeholder="例: このコードの主な機能は何ですか?"
153
+ )
154
+
155
+ col1, col2 = st.columns([1, 5])
156
+ with col1:
157
+ if st.button("履歴クリア"):
158
+ st.session_state.llm_service.clear_history()
159
+ st.rerun()
160
+
161
+ with col2:
162
+ if st.button("質問する", disabled=not query):
163
+ with st.spinner('回答を生成中...'):
164
+ response, error = st.session_state.llm_service.get_response(
165
+ st.session_state.repo_content,
166
+ query
167
+ )
168
+
169
+ if error:
170
+ st.error(error)
171
+ else:
172
+ st.rerun()
 
 
 
 
 
 
 
 
 
173
 
174
  # セッション終了時のクリーンアップ
175
  if st.session_state.temp_dir and Path(st.session_state.temp_dir).exists():
176
+ try:
177
+ import shutil
178
+ shutil.rmtree(st.session_state.temp_dir)
179
+ except:
180
+ pass