import gradio as gr from huggingface_hub import InferenceClient, HfApi import os import requests from typing import List, Dict, Union import traceback from PIL import Image from io import BytesIO import asyncio from gradio_client import Client import time import threading import json HF_TOKEN = os.getenv("HF_TOKEN") hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus-08-2024", token=HF_TOKEN) hf_api = HfApi(token=HF_TOKEN) def get_headers(): if not HF_TOKEN: raise ValueError("Hugging Face token not found in environment variables") return {"Authorization": f"Bearer {HF_TOKEN}"} def get_file_content(space_id: str, file_path: str) -> str: file_url = f"https://huggingface.co/spaces/{space_id}/raw/main/{file_path}" try: response = requests.get(file_url, headers=get_headers()) if response.status_code == 200: return response.text else: return f"File not found or inaccessible: {file_path}" except requests.RequestException: return f"Error fetching content for file: {file_path}" def get_space_structure(space_id: str) -> Dict: try: files = hf_api.list_repo_files(repo_id=space_id, repo_type="space") tree = {"type": "directory", "path": "", "name": space_id, "children": []} for file in files: path_parts = file.split('/') current = tree for i, part in enumerate(path_parts): if i == len(path_parts) - 1: # 파일 current["children"].append({"type": "file", "path": file, "name": part}) else: # 디렉토리 found = False for child in current["children"]: if child["type"] == "directory" and child["name"] == part: current = child found = True break if not found: new_dir = {"type": "directory", "path": '/'.join(path_parts[:i+1]), "name": part, "children": []} current["children"].append(new_dir) current = new_dir return tree except Exception as e: print(f"Error in get_space_structure: {str(e)}") return {"error": f"API request error: {str(e)}"} def format_tree_structure(tree_data: Dict, indent: str = "") -> str: formatted = f"{indent}{tree_data['name']}\n" if tree_data["type"] == "directory": for child in sorted(tree_data.get("children", []), key=lambda x: (x["type"] != "directory", x["name"])): formatted += format_tree_structure(child, indent + " ") return formatted def summarize_code(app_content: str) -> str: system_message = "당신은 Python 코드를 분석하고 요약하는 AI 조수입니다. 주어진 코드를 3줄 이내로 간결하게 요약해주세요." user_message = f"다음 Python 코드를 3줄 이내로 요약해주세요:\n\n{app_content}" messages = [ {"role": "system", "content": system_message}, {"role": "user", "content": user_message} ] try: response = hf_client.chat_completion(messages, max_tokens=200, temperature=0.7) return response.choices[0].message.content except Exception as e: return f"요약 생성 중 오류 발생: {str(e)}" def analyze_code(app_content: str) -> str: system_message = """당신은 Python 코드를 분석하는 AI 조수입니다. 주어진 코드를 분석하여 다음 항목에 대해 설명해주세요: A. 배경 및 필요성 B. 기능적 효용성 및 가치 C. 특장점 D. 적용 대상 및 타겟 E. 기대효과 기존 및 유사 프로젝트와 비교하여 분석해주세요. Markdown 형식으로 출력하세요.""" user_message = f"다음 Python 코드를 분석해주세요:\n\n{app_content}" messages = [ {"role": "system", "content": system_message}, {"role": "user", "content": user_message} ] try: response = hf_client.chat_completion(messages, max_tokens=1000, temperature=0.7) return response.choices[0].message.content except Exception as e: return f"분석 생성 중 오류 발생: {str(e)}" def explain_usage(app_content: str) -> str: system_message = "당신은 Python 코드를 분석하여 사용법을 설명하는 AI 조수입니다. 주어진 코드를 바탕으로 마치 화면을 보는 것처럼 사용법을 상세히 설명해주세요. Markdown 형식으로 출력하세요." user_message = f"다음 Python 코드의 사용법을 설명해주세요:\n\n{app_content}" messages = [ {"role": "system", "content": system_message}, {"role": "user", "content": user_message} ] try: response = hf_client.chat_completion(messages, max_tokens=800, temperature=0.7) return response.choices[0].message.content except Exception as e: return f"사용법 설명 생성 중 오류 발생: {str(e)}" def analyze_space(url: str, progress=gr.Progress()): try: space_id = url.split('spaces/')[-1] progress(0.1, desc="파일 구조 분석 중...") tree_structure = get_space_structure(space_id) tree_view = format_tree_structure(tree_structure) progress(0.3, desc="app.py 내용 가져오는 중...") app_content = get_file_content(space_id, "app.py") progress(0.4, desc="코드 요약 중...") summary = summarize_code(app_content) progress(0.6, desc="코드 분석 중...") analysis = analyze_code(app_content) progress(0.8, desc="사용법 설명 생성 중...") usage = explain_usage(app_content) progress(1.0, desc="완료") return summary, analysis, usage, app_content, tree_view, tree_structure, space_id except Exception as e: print(f"Error in analyze_space: {str(e)}") print(traceback.format_exc()) return f"오류가 발생했습니다: {str(e)}", "", "", "", "", None, "" def create_ui(): try: css = """ footer {visibility: hidden;} .output-group { border: 1px solid #ddd; border-radius: 5px; padding: 10px; margin-bottom: 20px; } .scroll-lock { overflow-y: auto !important; max-height: calc((100vh - 200px) / 5) !important; } .full-height { height: calc(100vh - 200px) !important; overflow-y: auto !important; } """ js = """ function openFile(path, spaceId) { const filePathInput = document.querySelector('input[data-testid="file_path_input"]'); const spaceIdInput = document.querySelector('input[data-testid="space_id_input"]'); if (filePathInput && spaceIdInput) { filePathInput.value = path; spaceIdInput.value = spaceId; filePathInput.dispatchEvent(new Event('change')); } } """ with gr.Blocks(css=css, theme="Nymbo/Nymbo_Theme") as demo: gr.Markdown("# HuggingFace Space Analyzer") with gr.Row(): with gr.Column(scale=6): # 왼쪽 60% url_input = gr.Textbox(label="HuggingFace Space URL") analyze_button = gr.Button("분석") with gr.Group(elem_classes="output-group scroll-lock"): summary_output = gr.Markdown(label="요약 (3줄 이내)") with gr.Group(elem_classes="output-group scroll-lock"): analysis_output = gr.Markdown(label="분석") with gr.Group(elem_classes="output-group scroll-lock"): usage_output = gr.Markdown(label="사용법") with gr.Group(elem_classes="output-group scroll-lock"): tree_view_output = gr.Textbox(label="파일 구조 (Tree View)", lines=20) with gr.Group(elem_classes="output-group scroll-lock"): file_buttons = gr.Dataframe( headers=["파일 이름", "열기"], datatype=["str", "html"], col_count=(2, "fixed"), label="파일 리스트" ) with gr.Column(scale=4): # 오른쪽 40% with gr.Group(elem_classes="output-group full-height"): code_tabs = gr.Tabs() with code_tabs: app_py_tab = gr.TabItem("app.py") with app_py_tab: app_py_content = gr.Code(language="python", label="app.py", lines=30) space_id_state = gr.State() tree_structure_state = gr.State() def update_file_buttons(tree_structure, space_id): if tree_structure is None: return [] def get_files(node): files = [] if node["type"] == "file": files.append(node) elif node["type"] == "directory": for child in node.get("children", []): files.extend(get_files(child)) return files files = get_files(tree_structure) return [[file["path"], f''] for file in files] def open_file(file_path: str, space_id: str): content = get_file_content(space_id, file_path) return gr.Tabs.update(selected=file_path), gr.Code(value=content, language="python", label=file_path, lines=30) analyze_button.click( analyze_space, inputs=[url_input], outputs=[summary_output, analysis_output, usage_output, app_py_content, tree_view_output, tree_structure_state, space_id_state] ).then( update_file_buttons, inputs=[tree_structure_state, space_id_state], outputs=[file_buttons] ) file_path_input = gr.Textbox(visible=False) space_id_input = gr.Textbox(visible=False) def handle_file_open(file_path, space_id): return file_path, space_id file_path_input.change( open_file, inputs=[file_path_input, space_id_input], outputs=[code_tabs, code_tabs] ) # JavaScript 코드를 HTML에 직접 삽입 gr.HTML(f"") return demo except Exception as e: print(f"Error in create_ui: {str(e)}") print(traceback.format_exc()) raise if __name__ == "__main__": try: demo = create_ui() demo.queue() demo.launch() except Exception as e: print(f"Error in main: {str(e)}") print(traceback.format_exc())