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())