import streamlit as st import tempfile import git from pathlib import Path from datetime import datetime from services.llm_service import LLMService from core.file_scanner import FileScanner, FileInfo from typing import List st.set_page_config( page_title="Repository Code Analysis", page_icon="🔍", layout="wide" ) st.markdown(""" """, unsafe_allow_html=True) def create_download_content(files: List[FileInfo]) -> str: content = "# スキャン結果\n\n" for file in files: content += f"## {file.path}\n" content += f"サイズ: {file.formatted_size}\n" content += f"エンコーディング: {file.encoding or '不明'}\n\n" if file.content: content += f"```{file.extension[1:] if file.extension else ''}\n" content += file.content content += "\n```\n\n" return content def clone_repository(repo_url: str) -> Path: temp_dir = Path(tempfile.mkdtemp()) git.Repo.clone_from(repo_url, temp_dir) return temp_dir if 'repo_content' not in st.session_state: st.session_state.repo_content = None if 'temp_dir' not in st.session_state: st.session_state.temp_dir = None if 'llm_service' not in st.session_state: try: st.session_state.llm_service = LLMService() except ValueError as e: st.error(str(e)) st.stop() st.title("🔍 リポジトリ解析・質問システム") with st.sidebar: if not st.session_state.llm_service.settings.anthropic_api_key: st.error("Anthropic API key is required") st.stop() st.write("Using Claude model") # LLM機能の切り替え use_llm = st.toggle("LLMによるコード解説を有効にする", value=True, key="use_llm") st.divider() st.subheader("📌 使い方") if use_llm: st.markdown(""" 1. GitHubリポジトリのURLを入力 2. スキャンを実行 3. コードについて質問(最大5ターンの会話が可能) """) else: st.markdown(""" 1. GitHubリポジトリのURLを入力 2. スキャンを実行してコードを解析 """) repo_url = st.text_input( "GitHubリポジトリのURLを入力", placeholder="https://github.com/username/repository.git" ) if st.button("スキャン開始", disabled=not repo_url): try: with st.spinner('リポジトリをクローン中...'): temp_dir = clone_repository(repo_url) st.session_state.temp_dir = temp_dir with st.spinner('ファイルをスキャン中...'): scanner = FileScanner(temp_dir) files = scanner.scan_files() st.session_state.repo_content = LLMService.format_code_content(files) st.success(f"スキャン完了: {len(files)}個のファイルを検出") scan_result = create_download_content(files) st.download_button( label="スキャン結果をダウンロード", data=scan_result, file_name=f"scan_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md", mime="text/markdown" ) st.session_state.llm_service.clear_history() except Exception as e: st.error(f"エラーが発生しました: {str(e)}") if st.session_state.repo_content and st.session_state.use_llm: st.divider() st.subheader("💭 コードについて質問する") for message in st.session_state.llm_service.conversation_history: if message.role == "assistant": st.markdown(f'
{message.content}
', unsafe_allow_html=True) query = st.text_area( "質問を入力してください", placeholder="例: このコードの主な機能は何ですか?" ) col1, col2 = st.columns([1, 5]) with col1: if st.button("履歴クリア"): st.session_state.llm_service.clear_history() st.rerun() with col2: if st.button("質問する", disabled=not query): with st.spinner('回答を生成中...'): response, error = st.session_state.llm_service.get_response( st.session_state.repo_content, query ) if error: st.error(error) else: st.rerun() if st.session_state.temp_dir and Path(st.session_state.temp_dir).exists(): try: import shutil shutil.rmtree(st.session_state.temp_dir) except: pass