Spaces:
Sleeping
Sleeping
# app.py | |
import streamlit as st | |
from pathlib import Path | |
from core.file_scanner import FileScanner, FileInfo | |
# セッション状態を初期化 | |
if 'scanned_files' not in st.session_state: | |
st.session_state.scanned_files = [] # List[FileInfo] | |
if 'selected_files' not in st.session_state: | |
st.session_state.selected_files = set() # {Path} 相対パス or 絶対パス | |
st.title("指定拡張子のみディレクトリスキャン & 選択ダウンロード") | |
# --- 1) ユーザー入力: スキャンしたいローカルディレクトリパス --- | |
dir_path_str = st.text_input("ローカルディレクトリパス", value=".") | |
# --- 2) ユーザー入力: スキャン対象拡張子選択 --- | |
st.subheader("スキャン対象拡張子") | |
available_exts = [".py", ".js", ".ts", ".md", ".txt", ".java", ".cpp"] | |
chosen_exts = [] | |
for ext in available_exts: | |
if st.checkbox(ext, key=f"ext_{ext}", value=(ext in [".py", ".md"])): | |
chosen_exts.append(ext) | |
# --- 3) 「スキャン実行」ボタン --- | |
if st.button("スキャン開始"): | |
base_path = Path(dir_path_str).resolve() | |
if not base_path.is_dir(): | |
st.error("有効なディレクトリを指定してください") | |
else: | |
scanner = FileScanner(base_path, set(chosen_exts)) | |
found_files = scanner.scan_files() | |
st.session_state.scanned_files = found_files | |
st.session_state.selected_files = set() # スキャン毎に選択リセット | |
st.success(f"スキャン完了: {len(found_files)}個のファイル") | |
# --- 4) ファイルを表示するUI(ディレクトリ構造 or リスト) + 全選択 / 全解除 --- | |
if st.session_state.scanned_files: | |
# 全選択 / 全解除ボタン | |
col1, col2 = st.columns(2) | |
with col1: | |
if st.button("すべて選択"): | |
# すべてのファイルを選択 | |
base_path = Path(dir_path_str).resolve() | |
# relative_to で相対パスを使うか、絶対パスを使うかは好みでOK | |
st.session_state.selected_files = { | |
f.path.relative_to(base_path) for f in st.session_state.scanned_files | |
} | |
with col2: | |
if st.button("すべて解除"): | |
st.session_state.selected_files = set() | |
st.write("### ファイル一覧 (指定拡張子のみ)") | |
base_path = Path(dir_path_str).resolve() | |
for file_info in st.session_state.scanned_files: | |
# 相対パスで扱う例 | |
rel_path = file_info.path.relative_to(base_path) | |
checked = (rel_path in st.session_state.selected_files) | |
# チェックボックス + ファイル名表示 | |
new_checked = st.checkbox( | |
f"{rel_path} ({file_info.formatted_size})", | |
value=checked, | |
key=str(rel_path) # keyは重複しないように文字列にしておく | |
) | |
# 選択状態を更新 | |
if new_checked: | |
st.session_state.selected_files.add(rel_path) | |
else: | |
st.session_state.selected_files.discard(rel_path) | |
# --- 5) 選択ファイルをまとめてMarkdown化 & ダウンロード --- | |
def create_markdown_for_selected(files, selected_paths, base_dir: Path) -> str: | |
""" | |
選択されたファイルだけをMarkdownテキストとして返す | |
""" | |
output = [] | |
for f in files: | |
rel_path = f.path.relative_to(base_dir) | |
if rel_path in selected_paths: | |
output.append(f"## {rel_path}") | |
output.append("------------") | |
if f.content is not None: | |
output.append(f.content) | |
else: | |
output.append("# Failed to read content") | |
output.append("") # 空行 | |
return "\n".join(output) | |
if st.session_state.scanned_files: | |
st.write("### 選択ファイルをMarkdownダウンロード") | |
if st.button("選択ファイルをまとめてダウンロード"): | |
base_path = Path(dir_path_str).resolve() | |
markdown_text = create_markdown_for_selected( | |
st.session_state.scanned_files, | |
st.session_state.selected_files, | |
base_path | |
) | |
st.download_button( | |
label="ダウンロード", | |
data=markdown_text, | |
file_name="selected_files.md", | |
mime="text/markdown" | |
) | |