"""Gradio UI for Hugging Face Spaces — same behavior as index.html.""" import html from pathlib import Path import gradio as gr from fastapi import HTTPException from main import ( _extensions_in_tree, fetch_repo_data_github, fetch_repo_data_lcoaldisk, llm_structure_from_tree, llm_summary_from_code, llm_technologies_from_requirements, parse_github_url, ) def _error_message(detail: str | list | dict) -> str: if isinstance(detail, str): return detail if isinstance(detail, list): parts = [] for item in detail: if isinstance(item, dict) and "msg" in item: loc = item.get("loc", []) parts.append(f"{'.'.join(str(x) for x in loc)}: {item['msg']}") else: parts.append(str(item)) return "; ".join(parts) if parts else str(detail) return str(detail) def _technologies_html(technologies: list[str]) -> str: if not technologies: return "" tags = "".join( f'' f"{html.escape(str(t))}" for t in technologies ) return f'
{tags}
' def _error_html(message: str) -> str: return f'

{html.escape(message)}

' async def summarize(repo_source: str) -> tuple[str, str, str, str]: """Run /summarize logic. Returns (summary, technologies_html, structure, error_html).""" repo_source = (repo_source or "").strip() if not repo_source: return "", "", "", _error_html("repo_source is required") try: if "github.com" in repo_source: owner, repo = parse_github_url(repo_source) code_context, requirements_content, directory_tree, files_included = ( await fetch_repo_data_github(owner, repo) ) else: path = Path(repo_source).expanduser().resolve() if not path.exists() or not path.is_dir(): return ( "", "", "", _error_html( "repo_source must be either a valid GitHub URL " "or an existing local directory path" ), ) code_context, requirements_content, directory_tree, files_included = ( await fetch_repo_data_lcoaldisk(str(path)) ) if files_included == 0: return ( "", "", "", _error_html("No readable text files found in the repository."), ) extensions_in_project = _extensions_in_tree(directory_tree) summary_text = await llm_summary_from_code(code_context) technologies_list = await llm_technologies_from_requirements( requirements_content, extensions_in_project ) structure_text = await llm_structure_from_tree(directory_tree) return summary_text, _technologies_html(technologies_list), structure_text, "" except HTTPException as exc: return "", "", "", _error_html(_error_message(exc.detail)) except ValueError as exc: return "", "", "", _error_html(str(exc)) except Exception as exc: return "", "", "", _error_html(str(exc) or "Internal server error") with gr.Blocks(title="Repo Summarizer") as demo: gr.Markdown("# Repo Summarizer") repo_input = gr.Textbox( label="GitHub URL/Local Path Repository", placeholder="https://github.com/owner/repo or /path/to/repo", ) submit_btn = gr.Button("Summarize", variant="primary") with gr.Column(): error_out = gr.HTML("") gr.Markdown("### Summary") summary_out = gr.Markdown("") gr.Markdown("### Technologies") technologies_out = gr.HTML("") gr.Markdown("### Structure") structure_out = gr.Markdown("") async def run_and_show(repo_source: str): summary, tech_html, structure, err_html = await summarize(repo_source) return err_html, summary, tech_html, structure outputs = [error_out, summary_out, technologies_out, structure_out] submit_btn.click( fn=run_and_show, inputs=[repo_input], outputs=outputs, show_progress=True, ) repo_input.submit( fn=run_and_show, inputs=[repo_input], outputs=outputs, show_progress=True, ) demo.queue() if __name__ == "__main__": demo.launch( server_name="0.0.0.0", ssr_mode=False, share=False, )