Spaces:
Sleeping
Sleeping
import streamlit as st | |
import tempfile | |
import git | |
import os | |
from pathlib import Path | |
from datetime import datetime | |
from config.settings import Settings | |
from core.file_scanner import FileScanner, FileInfo | |
from services.llm_service import LLMService | |
from typing import List, Set | |
from main import DirectoryStructureScanner, MarkdownGenerator | |
class StreamlitFileWriter: | |
def __init__(self, output_file: Path): | |
self.output_file = output_file | |
def create_markdown(self, files: List[FileInfo]) -> str: | |
content = [] | |
for file_info in files: | |
content.append(f"## {file_info.path}") | |
content.append("------------") | |
if file_info.content is not None: | |
content.append(file_info.content) | |
else: | |
content.append("# Failed to read content") | |
content.append("\n") | |
return "\n".join(content) | |
st.set_page_config( | |
page_title="Repository Code Analysis", | |
page_icon="🔍", | |
layout="wide" | |
) | |
st.markdown(""" | |
<style> | |
.stApp { | |
background-color: #0e1117; | |
color: #ffffff; | |
} | |
.chat-message { | |
padding: 1rem; | |
margin: 1rem 0; | |
border-radius: 0.5rem; | |
} | |
.assistant-message { | |
background-color: #1e2329; | |
color: #ffffff; | |
} | |
.directory-structure { | |
font-family: monospace; | |
white-space: pre; | |
background-color: #1e2329; | |
padding: 1rem; | |
border-radius: 0.5rem; | |
margin: 1rem 0; | |
} | |
.markdown-preview { | |
background-color: #1e2329; | |
padding: 1rem; | |
border-radius: 0.5rem; | |
margin: 1rem 0; | |
max-height: 500px; | |
overflow-y: auto; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# セッション状態の初期化 | |
if 'repo_content' not in st.session_state: | |
st.session_state.repo_content = None | |
if 'directory_structure' not in st.session_state: | |
st.session_state.directory_structure = None | |
if 'content_md' not in st.session_state: | |
st.session_state.content_md = None | |
if 'structure_md' not in st.session_state: | |
st.session_state.structure_md = None | |
if 'temp_dir' not in st.session_state: | |
st.session_state.temp_dir = None | |
if 'llm_service' not in st.session_state: | |
try: | |
api_key = os.getenv("ANTHROPIC_API_KEY") | |
if not api_key: | |
st.error("ANTHROPIC_API_KEY環境変数が設定されていません") | |
st.stop() | |
st.session_state.llm_service = LLMService(api_key) | |
except Exception as e: | |
st.error(str(e)) | |
st.stop() | |
st.title("🔍 リポジトリ解析・質問システム") | |
with st.sidebar: | |
st.subheader("📌 使い方") | |
st.markdown(""" | |
1. GitHubリポジトリのURLを入力 | |
2. スキャンを実行 | |
3. ディレクトリ構造と内容を確認 | |
4. Markdownファイルをダウンロード | |
5. コードについて質問 | |
""") | |
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('リポジトリを解析中...'): | |
# サイドバーで選択された拡張子を使用 | |
selected_extensions = {ext for exts in [selected_prog, selected_config, selected_doc] | |
for ext, selected in exts.items() if selected} or Settings.DEFAULT_EXTENSIONS | |
# 選択された拡張子を使用してMarkdownGeneratorを初期化 | |
generator = MarkdownGenerator(repo_url, selected_extensions) | |
content_md, structure_md, files = generator.generate_markdowns() | |
writer = StreamlitFileWriter(Path("dummy")) | |
formatted_content = writer.create_markdown(files) | |
st.session_state.content_md = formatted_content | |
st.session_state.structure_md = structure_md | |
st.session_state.repo_content = LLMService.format_code_content(files) | |
st.success(f"スキャン完了: {len(files)}個のファイルを検出") | |
st.session_state.llm_service.clear_history() | |
except Exception as e: | |
st.error(f"エラーが発生しました: {str(e)}") | |
if st.session_state.structure_md and st.session_state.content_md: | |
tab1, tab2 = st.tabs(["📁 ディレクトリ構造", "📄 ファイル内容"]) | |
with tab1: | |
st.markdown(f'<div class="markdown-preview">{st.session_state.structure_md}</div>', | |
unsafe_allow_html=True) | |
st.download_button( | |
label="ディレクトリ構造をダウンロード", | |
data=st.session_state.structure_md, | |
file_name=f"directory_structure_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md", | |
mime="text/markdown" | |
) | |
with tab2: | |
st.markdown(f'<div class="markdown-preview">{st.session_state.content_md}</div>', | |
unsafe_allow_html=True) | |
st.download_button( | |
label="ファイル内容をダウンロード", | |
data=st.session_state.content_md, | |
file_name=f"repository_content_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md", | |
mime="text/markdown" | |
) | |
if st.session_state.repo_content: | |
st.divider() | |
st.subheader("💭 コードについて質問する") | |
for message in st.session_state.llm_service.conversation_history: | |
if message.role == "assistant": | |
st.markdown(f'<div class="chat-message assistant-message">{message.content}</div>', | |
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() | |