Spaces:
Running
Running
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,271 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from huggingface_hub import InferenceClient, HfApi
|
3 |
+
import os
|
4 |
+
import requests
|
5 |
+
from typing import List, Dict, Union
|
6 |
+
import traceback
|
7 |
+
from PIL import Image
|
8 |
+
from io import BytesIO
|
9 |
+
import asyncio
|
10 |
+
from gradio_client import Client
|
11 |
+
import time
|
12 |
+
import threading
|
13 |
+
import json
|
14 |
+
|
15 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
16 |
+
hf_client = InferenceClient("CohereForAI/c4ai-command-r-plus-08-2024", token=HF_TOKEN)
|
17 |
+
hf_api = HfApi(token=HF_TOKEN)
|
18 |
+
|
19 |
+
def get_headers():
|
20 |
+
if not HF_TOKEN:
|
21 |
+
raise ValueError("Hugging Face token not found in environment variables")
|
22 |
+
return {"Authorization": f"Bearer {HF_TOKEN}"}
|
23 |
+
|
24 |
+
def get_file_content(space_id: str, file_path: str) -> str:
|
25 |
+
file_url = f"https://huggingface.co/spaces/{space_id}/raw/main/{file_path}"
|
26 |
+
try:
|
27 |
+
response = requests.get(file_url, headers=get_headers())
|
28 |
+
if response.status_code == 200:
|
29 |
+
return response.text
|
30 |
+
else:
|
31 |
+
return f"File not found or inaccessible: {file_path}"
|
32 |
+
except requests.RequestException:
|
33 |
+
return f"Error fetching content for file: {file_path}"
|
34 |
+
|
35 |
+
def get_space_structure(space_id: str) -> Dict:
|
36 |
+
try:
|
37 |
+
files = hf_api.list_repo_files(repo_id=space_id, repo_type="space")
|
38 |
+
|
39 |
+
tree = {"type": "directory", "path": "", "name": space_id, "children": []}
|
40 |
+
for file in files:
|
41 |
+
path_parts = file.split('/')
|
42 |
+
current = tree
|
43 |
+
for i, part in enumerate(path_parts):
|
44 |
+
if i == len(path_parts) - 1: # ํ์ผ
|
45 |
+
current["children"].append({"type": "file", "path": file, "name": part})
|
46 |
+
else: # ๋๋ ํ ๋ฆฌ
|
47 |
+
found = False
|
48 |
+
for child in current["children"]:
|
49 |
+
if child["type"] == "directory" and child["name"] == part:
|
50 |
+
current = child
|
51 |
+
found = True
|
52 |
+
break
|
53 |
+
if not found:
|
54 |
+
new_dir = {"type": "directory", "path": '/'.join(path_parts[:i+1]), "name": part, "children": []}
|
55 |
+
current["children"].append(new_dir)
|
56 |
+
current = new_dir
|
57 |
+
|
58 |
+
return tree
|
59 |
+
except Exception as e:
|
60 |
+
print(f"Error in get_space_structure: {str(e)}")
|
61 |
+
return {"error": f"API request error: {str(e)}"}
|
62 |
+
|
63 |
+
def format_tree_structure(tree_data: Dict, indent: str = "") -> str:
|
64 |
+
formatted = f"{indent}{tree_data['name']}\n"
|
65 |
+
if tree_data["type"] == "directory":
|
66 |
+
for child in sorted(tree_data.get("children", []), key=lambda x: (x["type"] != "directory", x["name"])):
|
67 |
+
formatted += format_tree_structure(child, indent + " ")
|
68 |
+
return formatted
|
69 |
+
|
70 |
+
def summarize_code(app_content: str) -> str:
|
71 |
+
system_message = "๋น์ ์ Python ์ฝ๋๋ฅผ ๋ถ์ํ๊ณ ์์ฝํ๋ AI ์กฐ์์
๋๋ค. ์ฃผ์ด์ง ์ฝ๋๋ฅผ 3์ค ์ด๋ด๋ก ๊ฐ๊ฒฐํ๊ฒ ์์ฝํด์ฃผ์ธ์."
|
72 |
+
user_message = f"๋ค์ Python ์ฝ๋๋ฅผ 3์ค ์ด๋ด๋ก ์์ฝํด์ฃผ์ธ์:\n\n{app_content}"
|
73 |
+
|
74 |
+
messages = [
|
75 |
+
{"role": "system", "content": system_message},
|
76 |
+
{"role": "user", "content": user_message}
|
77 |
+
]
|
78 |
+
|
79 |
+
try:
|
80 |
+
response = hf_client.chat_completion(messages, max_tokens=200, temperature=0.7)
|
81 |
+
return response.choices[0].message.content
|
82 |
+
except Exception as e:
|
83 |
+
return f"์์ฝ ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}"
|
84 |
+
|
85 |
+
def analyze_code(app_content: str) -> str:
|
86 |
+
system_message = """๋น์ ์ Python ์ฝ๋๋ฅผ ๋ถ์ํ๋ AI ์กฐ์์
๋๋ค. ์ฃผ์ด์ง ์ฝ๋๋ฅผ ๋ถ์ํ์ฌ ๋ค์ ํญ๋ชฉ์ ๋ํด ์ค๋ช
ํด์ฃผ์ธ์:
|
87 |
+
A. ๋ฐฐ๊ฒฝ ๋ฐ ํ์์ฑ
|
88 |
+
B. ๊ธฐ๋ฅ์ ํจ์ฉ์ฑ ๋ฐ ๊ฐ์น
|
89 |
+
C. ํน์ฅ์
|
90 |
+
D. ์ ์ฉ ๋์ ๋ฐ ํ๊ฒ
|
91 |
+
E. ๊ธฐ๋ํจ๊ณผ
|
92 |
+
๊ธฐ์กด ๋ฐ ์ ์ฌ ํ๋ก์ ํธ์ ๋น๊ตํ์ฌ ๋ถ์ํด์ฃผ์ธ์."""
|
93 |
+
user_message = f"๋ค์ Python ์ฝ๋๋ฅผ ๋ถ์ํด์ฃผ์ธ์:\n\n{app_content}"
|
94 |
+
|
95 |
+
messages = [
|
96 |
+
{"role": "system", "content": system_message},
|
97 |
+
{"role": "user", "content": user_message}
|
98 |
+
]
|
99 |
+
|
100 |
+
try:
|
101 |
+
response = hf_client.chat_completion(messages, max_tokens=1000, temperature=0.7)
|
102 |
+
return response.choices[0].message.content
|
103 |
+
except Exception as e:
|
104 |
+
return f"๋ถ์ ์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}"
|
105 |
+
|
106 |
+
def explain_usage(app_content: str) -> str:
|
107 |
+
system_message = "๋น์ ์ Python ์ฝ๋๋ฅผ ๋ถ์ํ์ฌ ์ฌ์ฉ๋ฒ์ ์ค๋ช
ํ๋ AI ์กฐ์์
๋๋ค. ์ฃผ์ด์ง ์ฝ๋๋ฅผ ๋ฐํ์ผ๋ก ๋ง์น ํ๋ฉด์ ๋ณด๋ ๊ฒ์ฒ๋ผ ์ฌ์ฉ๋ฒ์ ์์ธํ ์ค๋ช
ํด์ฃผ์ธ์."
|
108 |
+
user_message = f"๋ค์ Python ์ฝ๋์ ์ฌ์ฉ๋ฒ์ ์ค๋ช
ํด์ฃผ์ธ์:\n\n{app_content}"
|
109 |
+
|
110 |
+
messages = [
|
111 |
+
{"role": "system", "content": system_message},
|
112 |
+
{"role": "user", "content": user_message}
|
113 |
+
]
|
114 |
+
|
115 |
+
try:
|
116 |
+
response = hf_client.chat_completion(messages, max_tokens=800, temperature=0.7)
|
117 |
+
return response.choices[0].message.content
|
118 |
+
except Exception as e:
|
119 |
+
return f"์ฌ์ฉ๋ฒ ์ค๋ช
์์ฑ ์ค ์ค๋ฅ ๋ฐ์: {str(e)}"
|
120 |
+
|
121 |
+
def analyze_space(url: str):
|
122 |
+
try:
|
123 |
+
space_id = url.split('spaces/')[-1]
|
124 |
+
|
125 |
+
app_content = get_file_content(space_id, "app.py")
|
126 |
+
summary = summarize_code(app_content)
|
127 |
+
analysis = analyze_code(app_content)
|
128 |
+
usage = explain_usage(app_content)
|
129 |
+
|
130 |
+
tree_structure = get_space_structure(space_id)
|
131 |
+
tree_view = format_tree_structure(tree_structure)
|
132 |
+
|
133 |
+
return summary, analysis, usage, app_content, tree_view, tree_structure, space_id
|
134 |
+
except Exception as e:
|
135 |
+
print(f"Error in analyze_space: {str(e)}")
|
136 |
+
print(traceback.format_exc())
|
137 |
+
return f"์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}", "", "", "", "", None, ""
|
138 |
+
|
139 |
+
def create_ui():
|
140 |
+
try:
|
141 |
+
css = """
|
142 |
+
footer {visibility: hidden;}
|
143 |
+
.output-group {
|
144 |
+
border: 1px solid #ddd;
|
145 |
+
border-radius: 5px;
|
146 |
+
padding: 10px;
|
147 |
+
margin-bottom: 20px;
|
148 |
+
}
|
149 |
+
.scroll-lock {
|
150 |
+
overflow: auto !important;
|
151 |
+
max-height: 400px !important;
|
152 |
+
}
|
153 |
+
"""
|
154 |
+
|
155 |
+
with gr.Blocks(css=css, theme="Nymbo/Nymbo_Theme") as demo:
|
156 |
+
gr.Markdown("# HuggingFace Space Analyzer")
|
157 |
+
|
158 |
+
with gr.Row():
|
159 |
+
with gr.Column(scale=6): # ์ผ์ชฝ 60%
|
160 |
+
url_input = gr.Textbox(label="HuggingFace Space URL")
|
161 |
+
analyze_button = gr.Button("๋ถ์")
|
162 |
+
|
163 |
+
with gr.Group(elem_classes="output-group scroll-lock"):
|
164 |
+
summary_output = gr.Textbox(label="์์ฝ (3์ค ์ด๋ด)", lines=3)
|
165 |
+
|
166 |
+
with gr.Group(elem_classes="output-group scroll-lock"):
|
167 |
+
analysis_output = gr.Textbox(label="๋ถ์", lines=15)
|
168 |
+
|
169 |
+
with gr.Group(elem_classes="output-group scroll-lock"):
|
170 |
+
usage_output = gr.Textbox(label="์ฌ์ฉ๋ฒ", lines=10)
|
171 |
+
|
172 |
+
with gr.Group(elem_classes="output-group scroll-lock"):
|
173 |
+
tree_view_output = gr.Textbox(label="ํ์ผ ๊ตฌ์กฐ (Tree View)", lines=20)
|
174 |
+
|
175 |
+
file_buttons = gr.Dataframe(
|
176 |
+
headers=["ํ์ผ ์ด๋ฆ", "์ด๊ธฐ"],
|
177 |
+
datatype=["str", "html"],
|
178 |
+
col_count=(2, "fixed"),
|
179 |
+
label="ํ์ผ ๋ฆฌ์คํธ"
|
180 |
+
)
|
181 |
+
|
182 |
+
with gr.Column(scale=4): # ์ค๋ฅธ์ชฝ 40%
|
183 |
+
with gr.Group(elem_classes="output-group scroll-lock"):
|
184 |
+
code_tabs = gr.Tabs()
|
185 |
+
with code_tabs:
|
186 |
+
app_py_tab = gr.TabItem("app.py")
|
187 |
+
with app_py_tab:
|
188 |
+
app_py_content = gr.Code(language="python", label="app.py", lines=30)
|
189 |
+
|
190 |
+
space_id_state = gr.State()
|
191 |
+
tree_structure_state = gr.State()
|
192 |
+
|
193 |
+
def update_file_buttons(tree_structure, space_id):
|
194 |
+
if tree_structure is None:
|
195 |
+
return []
|
196 |
+
|
197 |
+
def get_files(node):
|
198 |
+
files = []
|
199 |
+
if node["type"] == "file":
|
200 |
+
files.append(node)
|
201 |
+
elif node["type"] == "directory":
|
202 |
+
for child in node.get("children", []):
|
203 |
+
files.extend(get_files(child))
|
204 |
+
return files
|
205 |
+
|
206 |
+
files = get_files(tree_structure)
|
207 |
+
return [[file["path"], f'<button onclick="openFile(\'{file["path"]}\', \'{space_id}\')">์ด๊ธฐ</button>'] for file in files]
|
208 |
+
|
209 |
+
def open_file(file_path: str, space_id: str):
|
210 |
+
content = get_file_content(space_id, file_path)
|
211 |
+
return gr.Tabs.update(selected=file_path), gr.Code(value=content, language="python", label=file_path, lines=30)
|
212 |
+
|
213 |
+
analyze_button.click(
|
214 |
+
analyze_space,
|
215 |
+
inputs=[url_input],
|
216 |
+
outputs=[summary_output, analysis_output, usage_output, app_py_content, tree_view_output, tree_structure_state, space_id_state]
|
217 |
+
).then(
|
218 |
+
update_file_buttons,
|
219 |
+
inputs=[tree_structure_state, space_id_state],
|
220 |
+
outputs=[file_buttons]
|
221 |
+
)
|
222 |
+
|
223 |
+
demo.load(None, None, None, _js="""
|
224 |
+
function openFile(path, spaceId) {
|
225 |
+
const event = new CustomEvent('open-file', { detail: { path, spaceId } });
|
226 |
+
window.dispatchEvent(event);
|
227 |
+
}
|
228 |
+
""")
|
229 |
+
|
230 |
+
file_path_input = gr.Textbox(visible=False)
|
231 |
+
space_id_input = gr.Textbox(visible=False)
|
232 |
+
|
233 |
+
def handle_file_open(file_path, space_id):
|
234 |
+
return file_path, space_id
|
235 |
+
|
236 |
+
demo.load(handle_file_open, [file_path_input, space_id_input], [file_path_input, space_id_input], _js="""
|
237 |
+
function(file_path_input, space_id_input) {
|
238 |
+
function handleOpenFile(event) {
|
239 |
+
const { path, spaceId } = event.detail;
|
240 |
+
file_path_input.value = path;
|
241 |
+
space_id_input.value = spaceId;
|
242 |
+
file_path_input.dispatchEvent(new Event('change'));
|
243 |
+
space_id_input.dispatchEvent(new Event('change'));
|
244 |
+
}
|
245 |
+
window.addEventListener('open-file', handleOpenFile);
|
246 |
+
return [file_path_input, space_id_input];
|
247 |
+
}
|
248 |
+
""")
|
249 |
+
|
250 |
+
file_path_input.change(
|
251 |
+
open_file,
|
252 |
+
inputs=[file_path_input, space_id_input],
|
253 |
+
outputs=[code_tabs, code_tabs],
|
254 |
+
_js="(path, spaceId) => [path, spaceId]"
|
255 |
+
)
|
256 |
+
|
257 |
+
return demo
|
258 |
+
|
259 |
+
except Exception as e:
|
260 |
+
print(f"Error in create_ui: {str(e)}")
|
261 |
+
print(traceback.format_exc())
|
262 |
+
raise
|
263 |
+
|
264 |
+
if __name__ == "__main__":
|
265 |
+
try:
|
266 |
+
demo = create_ui()
|
267 |
+
demo.launch()
|
268 |
+
except Exception as e:
|
269 |
+
print(f"Error in main: {str(e)}")
|
270 |
+
print(traceback.format_exc())
|
271 |
+
|