Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import json, os
|
2 |
import gradio as gr
|
3 |
from huggingface_hub import (
|
4 |
create_repo, list_models, upload_file, list_repo_files, constants
|
@@ -35,14 +35,11 @@ def create_space(repo_name, sdk, profile, token):
|
|
35 |
if not (profile and token):
|
36 |
return "", "⚠️ Please log in first.", "<p>No Space created yet.</p>"
|
37 |
rid = f"{profile.username}/{repo_name}"
|
38 |
-
create_repo(rid, token=token.token, exist_ok=True,
|
39 |
-
repo_type="space", space_sdk=sdk)
|
40 |
url = f"https://huggingface.co/spaces/{rid}"
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
f'<iframe src="{url}" width="100%" height="400px"></iframe>'
|
45 |
-
)
|
46 |
|
47 |
def upload_file_to_space(file, path, repo_id, profile, token):
|
48 |
if not (profile and token):
|
@@ -55,10 +52,8 @@ def upload_file_to_space(file, path, repo_id, profile, token):
|
|
55 |
return f"✅ Uploaded `{path}` to `{repo_id}`"
|
56 |
|
57 |
def _fetch_space_logs_level(repo_id, level):
|
58 |
-
r = get_session().get(
|
59 |
-
|
60 |
-
headers=build_hf_headers()
|
61 |
-
)
|
62 |
hf_raise_for_status(r)
|
63 |
jwt = r.json()["token"]
|
64 |
url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
|
@@ -85,9 +80,8 @@ def get_container_logs(repo_id, profile, token):
|
|
85 |
|
86 |
func_decls = [
|
87 |
{
|
88 |
-
"name":
|
89 |
-
"
|
90 |
-
"parameters": {
|
91 |
"type":"object",
|
92 |
"properties":{
|
93 |
"repo_name":{"type":"string"},
|
@@ -97,27 +91,24 @@ func_decls = [
|
|
97 |
}
|
98 |
},
|
99 |
{
|
100 |
-
"name":
|
101 |
-
"
|
102 |
-
"parameters": {
|
103 |
"type":"object",
|
104 |
"properties":{"repo_id":{"type":"string"}},
|
105 |
"required":["repo_id"]
|
106 |
}
|
107 |
},
|
108 |
{
|
109 |
-
"name":
|
110 |
-
"
|
111 |
-
"parameters": {
|
112 |
"type":"object",
|
113 |
"properties":{"repo_id":{"type":"string"}},
|
114 |
"required":["repo_id"]
|
115 |
}
|
116 |
},
|
117 |
{
|
118 |
-
"name":
|
119 |
-
"
|
120 |
-
"parameters": {
|
121 |
"type":"object",
|
122 |
"properties":{"repo_id":{"type":"string"}},
|
123 |
"required":["repo_id"]
|
@@ -125,12 +116,12 @@ func_decls = [
|
|
125 |
},
|
126 |
]
|
127 |
|
128 |
-
# — CHAT HANDLER —
|
129 |
|
130 |
def process_message(profile, token, user_msg,
|
131 |
gemini_key, sidebar_repo, sidebar_sdk,
|
132 |
chat_history, session):
|
133 |
-
# Initialize on first call
|
134 |
if session.get("chat") is None:
|
135 |
client = genai.Client(api_key=gemini_key)
|
136 |
cfg = types.GenerateContentConfig(
|
@@ -141,60 +132,79 @@ def process_message(profile, token, user_msg,
|
|
141 |
temperature=0,
|
142 |
tools=[ types.Tool(function_declarations=func_decls) ]
|
143 |
)
|
144 |
-
session["chat"]
|
145 |
-
session["repo_id"]
|
146 |
session["messages"] = []
|
147 |
-
|
148 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
session["messages"].append({"role":"user","content":user_msg})
|
150 |
|
|
|
151 |
resp = session["chat"].send_message(user_msg)
|
152 |
part = resp.candidates[0].content.parts[0]
|
153 |
|
154 |
result = {}
|
155 |
-
# If the model wants to call a function
|
156 |
if part.function_call:
|
157 |
-
# args
|
158 |
args = part.function_call.args
|
159 |
if isinstance(args, str):
|
160 |
args = json.loads(args)
|
161 |
-
|
162 |
name = part.function_call.name
|
|
|
163 |
if name == "create_space":
|
164 |
rid, log, iframe = create_space(
|
165 |
args["repo_name"], args["sdk"], profile, token
|
166 |
)
|
167 |
session["repo_id"] = rid
|
168 |
-
result = {"log":
|
|
|
169 |
elif name == "list_files":
|
170 |
fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
|
171 |
-
result = {"files":
|
|
|
172 |
elif name == "get_build_logs":
|
173 |
-
result = {"log":
|
|
|
174 |
elif name == "get_run_logs":
|
175 |
-
result = {"log":
|
|
|
176 |
else:
|
177 |
-
result = {"log":
|
178 |
|
179 |
-
#
|
180 |
session["chat"].send_message(
|
181 |
types.Content(
|
182 |
role="function",
|
183 |
parts=[ types.Part(
|
184 |
function_call=part.function_call,
|
185 |
-
function_response=json.dumps
|
186 |
)]
|
187 |
)
|
188 |
)
|
189 |
-
#
|
190 |
-
|
191 |
else:
|
192 |
-
|
193 |
|
194 |
-
# Record assistant
|
195 |
-
session["messages"].append({"role":"assistant","content":
|
196 |
|
197 |
-
# Update
|
198 |
if "iframe" in result: session["iframe"] = result["iframe"]
|
199 |
if "log" in result: session["log"] = result["log"]
|
200 |
if "files" in result: session["files"] = result["files"]
|
@@ -207,14 +217,14 @@ def process_message(profile, token, user_msg,
|
|
207 |
session
|
208 |
)
|
209 |
|
|
|
|
|
210 |
def sync_manual(profile, token, session):
|
211 |
if not (profile and token and session.get("repo_id")):
|
212 |
-
return (
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
session
|
217 |
-
)
|
218 |
fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
|
219 |
session["files"] = "\n".join(fl)
|
220 |
session["log"] = "🔄 Manual changes synced."
|
@@ -225,7 +235,7 @@ def sync_manual(profile, token, session):
|
|
225 |
session
|
226 |
)
|
227 |
|
228 |
-
# — BUILD UI —
|
229 |
|
230 |
with gr.Blocks(css="""
|
231 |
#sidebar { background:#f2f2f2; padding:1rem; border-right:1px solid #ccc; }
|
@@ -240,7 +250,7 @@ with gr.Blocks(css="""
|
|
240 |
profile_state = gr.State(None)
|
241 |
token_state = gr.State(None)
|
242 |
|
243 |
-
#
|
244 |
login_btn.click(None, [], [profile_state, token_state])
|
245 |
|
246 |
status_md = gr.Markdown("*Not logged in.*")
|
@@ -276,8 +286,7 @@ with gr.Blocks(css="""
|
|
276 |
value="gradio", label="SDK")
|
277 |
create_btn = gr.Button("Create Space")
|
278 |
sess_id = gr.Textbox(visible=False)
|
279 |
-
log_c = gr.Textbox(label="Log",
|
280 |
-
interactive=False, lines=2)
|
281 |
preview = gr.HTML("<p>No Space yet.</p>")
|
282 |
|
283 |
create_btn.click(create_space,
|
@@ -289,8 +298,7 @@ with gr.Blocks(css="""
|
|
289 |
path = gr.Textbox(label="Path", value="app.py")
|
290 |
file_u = gr.File()
|
291 |
upload_btn = gr.Button("Upload File")
|
292 |
-
log_u = gr.Textbox(label="Log",
|
293 |
-
interactive=False, lines=2)
|
294 |
|
295 |
upload_btn.click(upload_file_to_space,
|
296 |
inputs=[file_u, path, sess_id,
|
@@ -300,10 +308,8 @@ with gr.Blocks(css="""
|
|
300 |
gr.Markdown("#### Fetch Logs")
|
301 |
b_btn = gr.Button("Build Logs")
|
302 |
r_btn = gr.Button("Run Logs")
|
303 |
-
log_b = gr.Textbox(label="Build",
|
304 |
-
|
305 |
-
log_r = gr.Textbox(label="Run",
|
306 |
-
interactive=False, lines=5)
|
307 |
|
308 |
b_btn.click(get_build_logs,
|
309 |
inputs=[sess_id, profile_state, token_state],
|
@@ -324,8 +330,7 @@ with gr.Blocks(css="""
|
|
324 |
user_input, gemini_key,
|
325 |
sidebar_repo, sidebar_sdk,
|
326 |
chatbox, state],
|
327 |
-
outputs=[chatbox, iframe_out,
|
328 |
-
log_out, files_out, state])
|
329 |
|
330 |
confirm_btn.click(sync_manual,
|
331 |
inputs=[profile_state, token_state, state],
|
|
|
1 |
+
import re, json, os
|
2 |
import gradio as gr
|
3 |
from huggingface_hub import (
|
4 |
create_repo, list_models, upload_file, list_repo_files, constants
|
|
|
35 |
if not (profile and token):
|
36 |
return "", "⚠️ Please log in first.", "<p>No Space created yet.</p>"
|
37 |
rid = f"{profile.username}/{repo_name}"
|
38 |
+
create_repo(rid, token=token.token, exist_ok=True, repo_type="space", space_sdk=sdk)
|
|
|
39 |
url = f"https://huggingface.co/spaces/{rid}"
|
40 |
+
log = f"✅ Space ready: {url} (SDK: {sdk})"
|
41 |
+
iframe = f'<iframe src="{url}" width="100%" height="400px"></iframe>'
|
42 |
+
return rid, log, iframe
|
|
|
|
|
43 |
|
44 |
def upload_file_to_space(file, path, repo_id, profile, token):
|
45 |
if not (profile and token):
|
|
|
52 |
return f"✅ Uploaded `{path}` to `{repo_id}`"
|
53 |
|
54 |
def _fetch_space_logs_level(repo_id, level):
|
55 |
+
r = get_session().get(f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt",
|
56 |
+
headers=build_hf_headers())
|
|
|
|
|
57 |
hf_raise_for_status(r)
|
58 |
jwt = r.json()["token"]
|
59 |
url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
|
|
|
80 |
|
81 |
func_decls = [
|
82 |
{
|
83 |
+
"name":"create_space","description":"Create/get a HF Space",
|
84 |
+
"parameters":{
|
|
|
85 |
"type":"object",
|
86 |
"properties":{
|
87 |
"repo_name":{"type":"string"},
|
|
|
91 |
}
|
92 |
},
|
93 |
{
|
94 |
+
"name":"list_files","description":"List files in Space",
|
95 |
+
"parameters":{
|
|
|
96 |
"type":"object",
|
97 |
"properties":{"repo_id":{"type":"string"}},
|
98 |
"required":["repo_id"]
|
99 |
}
|
100 |
},
|
101 |
{
|
102 |
+
"name":"get_build_logs","description":"Fetch build logs",
|
103 |
+
"parameters":{
|
|
|
104 |
"type":"object",
|
105 |
"properties":{"repo_id":{"type":"string"}},
|
106 |
"required":["repo_id"]
|
107 |
}
|
108 |
},
|
109 |
{
|
110 |
+
"name":"get_run_logs","description":"Fetch run logs",
|
111 |
+
"parameters":{
|
|
|
112 |
"type":"object",
|
113 |
"properties":{"repo_id":{"type":"string"}},
|
114 |
"required":["repo_id"]
|
|
|
116 |
},
|
117 |
]
|
118 |
|
119 |
+
# — CHAT HANDLER —
|
120 |
|
121 |
def process_message(profile, token, user_msg,
|
122 |
gemini_key, sidebar_repo, sidebar_sdk,
|
123 |
chat_history, session):
|
124 |
+
# 1) Initialize chat on first call
|
125 |
if session.get("chat") is None:
|
126 |
client = genai.Client(api_key=gemini_key)
|
127 |
cfg = types.GenerateContentConfig(
|
|
|
132 |
temperature=0,
|
133 |
tools=[ types.Tool(function_declarations=func_decls) ]
|
134 |
)
|
135 |
+
session["chat"] = client.chats.create(model="gemini-2.0-flash", config=cfg)
|
136 |
+
session["repo_id"] = None
|
137 |
session["messages"] = []
|
138 |
+
|
139 |
+
# 1.5) Auto‐create from “call it X” in free chat if no space yet:
|
140 |
+
if session["repo_id"] is None:
|
141 |
+
m = re.search(r"call it ([A-Za-z0-9_-]+)", user_msg, re.IGNORECASE)
|
142 |
+
if m:
|
143 |
+
name = m.group(1)
|
144 |
+
rid, log, iframe = create_space(name, sidebar_sdk, profile, token)
|
145 |
+
session["repo_id"] = rid
|
146 |
+
# update panels & messages
|
147 |
+
session["iframe"] = iframe
|
148 |
+
session["log"] = log
|
149 |
+
session["files"] = ""
|
150 |
+
session["messages"].append({"role":"assistant",
|
151 |
+
"content":f"Created Space `{name}` with SDK `{sidebar_sdk}`. {log}"})
|
152 |
+
return (session["messages"], iframe, log, "", session)
|
153 |
+
|
154 |
+
# Record user turn
|
155 |
session["messages"].append({"role":"user","content":user_msg})
|
156 |
|
157 |
+
# 2) Send to Gemini
|
158 |
resp = session["chat"].send_message(user_msg)
|
159 |
part = resp.candidates[0].content.parts[0]
|
160 |
|
161 |
result = {}
|
|
|
162 |
if part.function_call:
|
163 |
+
# parse args
|
164 |
args = part.function_call.args
|
165 |
if isinstance(args, str):
|
166 |
args = json.loads(args)
|
|
|
167 |
name = part.function_call.name
|
168 |
+
|
169 |
if name == "create_space":
|
170 |
rid, log, iframe = create_space(
|
171 |
args["repo_name"], args["sdk"], profile, token
|
172 |
)
|
173 |
session["repo_id"] = rid
|
174 |
+
result = {"log":log,"iframe":iframe}
|
175 |
+
|
176 |
elif name == "list_files":
|
177 |
fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
|
178 |
+
result = {"files":"\n".join(fl)}
|
179 |
+
|
180 |
elif name == "get_build_logs":
|
181 |
+
result = {"log":get_build_logs(session["repo_id"], profile, token)}
|
182 |
+
|
183 |
elif name == "get_run_logs":
|
184 |
+
result = {"log":get_container_logs(session["repo_id"], profile, token)}
|
185 |
+
|
186 |
else:
|
187 |
+
result = {"log":f"⚠️ Unknown function {name}"}
|
188 |
|
189 |
+
# feed the function result back as a dict
|
190 |
session["chat"].send_message(
|
191 |
types.Content(
|
192 |
role="function",
|
193 |
parts=[ types.Part(
|
194 |
function_call=part.function_call,
|
195 |
+
function_response=result # <-- dict, not json.dumps
|
196 |
)]
|
197 |
)
|
198 |
)
|
199 |
+
# assistant’s final turn
|
200 |
+
assistant_content = session["chat"].get_history()[-1].parts[0].text
|
201 |
else:
|
202 |
+
assistant_content = part.text
|
203 |
|
204 |
+
# Record assistant turn
|
205 |
+
session["messages"].append({"role":"assistant","content":assistant_content})
|
206 |
|
207 |
+
# Update panels
|
208 |
if "iframe" in result: session["iframe"] = result["iframe"]
|
209 |
if "log" in result: session["log"] = result["log"]
|
210 |
if "files" in result: session["files"] = result["files"]
|
|
|
217 |
session
|
218 |
)
|
219 |
|
220 |
+
# — SYNC MANUAL CHANGES —
|
221 |
+
|
222 |
def sync_manual(profile, token, session):
|
223 |
if not (profile and token and session.get("repo_id")):
|
224 |
+
return (session.get("iframe",""),
|
225 |
+
"⚠️ Cannot sync manual changes.",
|
226 |
+
session.get("files",""),
|
227 |
+
session)
|
|
|
|
|
228 |
fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
|
229 |
session["files"] = "\n".join(fl)
|
230 |
session["log"] = "🔄 Manual changes synced."
|
|
|
235 |
session
|
236 |
)
|
237 |
|
238 |
+
# — BUILD THE UI —
|
239 |
|
240 |
with gr.Blocks(css="""
|
241 |
#sidebar { background:#f2f2f2; padding:1rem; border-right:1px solid #ccc; }
|
|
|
250 |
profile_state = gr.State(None)
|
251 |
token_state = gr.State(None)
|
252 |
|
253 |
+
# capture both
|
254 |
login_btn.click(None, [], [profile_state, token_state])
|
255 |
|
256 |
status_md = gr.Markdown("*Not logged in.*")
|
|
|
286 |
value="gradio", label="SDK")
|
287 |
create_btn = gr.Button("Create Space")
|
288 |
sess_id = gr.Textbox(visible=False)
|
289 |
+
log_c = gr.Textbox(label="Log", interactive=False, lines=2)
|
|
|
290 |
preview = gr.HTML("<p>No Space yet.</p>")
|
291 |
|
292 |
create_btn.click(create_space,
|
|
|
298 |
path = gr.Textbox(label="Path", value="app.py")
|
299 |
file_u = gr.File()
|
300 |
upload_btn = gr.Button("Upload File")
|
301 |
+
log_u = gr.Textbox(label="Log", interactive=False, lines=2)
|
|
|
302 |
|
303 |
upload_btn.click(upload_file_to_space,
|
304 |
inputs=[file_u, path, sess_id,
|
|
|
308 |
gr.Markdown("#### Fetch Logs")
|
309 |
b_btn = gr.Button("Build Logs")
|
310 |
r_btn = gr.Button("Run Logs")
|
311 |
+
log_b = gr.Textbox(label="Build", interactive=False, lines=5)
|
312 |
+
log_r = gr.Textbox(label="Run", interactive=False, lines=5)
|
|
|
|
|
313 |
|
314 |
b_btn.click(get_build_logs,
|
315 |
inputs=[sess_id, profile_state, token_state],
|
|
|
330 |
user_input, gemini_key,
|
331 |
sidebar_repo, sidebar_sdk,
|
332 |
chatbox, state],
|
333 |
+
outputs=[chatbox, iframe_out, log_out, files_out, state])
|
|
|
334 |
|
335 |
confirm_btn.click(sync_manual,
|
336 |
inputs=[profile_state, token_state, state],
|