Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -35,9 +35,14 @@ 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 |
url = f"https://huggingface.co/spaces/{rid}"
|
40 |
-
return
|
|
|
|
|
|
|
|
|
41 |
|
42 |
def upload_file_to_space(file, path, repo_id, profile, token):
|
43 |
if not (profile and token):
|
@@ -50,7 +55,10 @@ def upload_file_to_space(file, path, repo_id, profile, token):
|
|
50 |
return f"✅ Uploaded `{path}` to `{repo_id}`"
|
51 |
|
52 |
def _fetch_space_logs_level(repo_id, level):
|
53 |
-
r = get_session().get(
|
|
|
|
|
|
|
54 |
hf_raise_for_status(r)
|
55 |
jwt = r.json()["token"]
|
56 |
url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
|
@@ -77,8 +85,9 @@ def get_container_logs(repo_id, profile, token):
|
|
77 |
|
78 |
func_decls = [
|
79 |
{
|
80 |
-
"name":"create_space",
|
81 |
-
"
|
|
|
82 |
"type":"object",
|
83 |
"properties":{
|
84 |
"repo_name":{"type":"string"},
|
@@ -88,24 +97,27 @@ func_decls = [
|
|
88 |
}
|
89 |
},
|
90 |
{
|
91 |
-
"name":"list_files",
|
92 |
-
"
|
|
|
93 |
"type":"object",
|
94 |
"properties":{"repo_id":{"type":"string"}},
|
95 |
"required":["repo_id"]
|
96 |
}
|
97 |
},
|
98 |
{
|
99 |
-
"name":"get_build_logs",
|
100 |
-
"
|
|
|
101 |
"type":"object",
|
102 |
"properties":{"repo_id":{"type":"string"}},
|
103 |
"required":["repo_id"]
|
104 |
}
|
105 |
},
|
106 |
{
|
107 |
-
"name":"get_run_logs",
|
108 |
-
"
|
|
|
109 |
"type":"object",
|
110 |
"properties":{"repo_id":{"type":"string"}},
|
111 |
"required":["repo_id"]
|
@@ -118,6 +130,7 @@ func_decls = [
|
|
118 |
def process_message(profile, token, user_msg,
|
119 |
gemini_key, sidebar_repo, sidebar_sdk,
|
120 |
chat_history, session):
|
|
|
121 |
if session.get("chat") is None:
|
122 |
client = genai.Client(api_key=gemini_key)
|
123 |
cfg = types.GenerateContentConfig(
|
@@ -130,16 +143,23 @@ def process_message(profile, token, user_msg,
|
|
130 |
)
|
131 |
session["chat"] = client.chats.create(model="gemini-2.0-flash", config=cfg)
|
132 |
session["repo_id"] = None
|
|
|
133 |
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
137 |
part = resp.candidates[0].content.parts[0]
|
138 |
|
139 |
result = {}
|
|
|
140 |
if part.function_call:
|
|
|
|
|
|
|
|
|
|
|
141 |
name = part.function_call.name
|
142 |
-
args = json.loads(part.function_call.args)
|
143 |
if name == "create_space":
|
144 |
rid, log, iframe = create_space(
|
145 |
args["repo_name"], args["sdk"], profile, token
|
@@ -156,7 +176,8 @@ def process_message(profile, token, user_msg,
|
|
156 |
else:
|
157 |
result = {"log": f"⚠️ Unknown function {name}"}
|
158 |
|
159 |
-
chat
|
|
|
160 |
types.Content(
|
161 |
role="function",
|
162 |
parts=[ types.Part(
|
@@ -165,40 +186,50 @@ def process_message(profile, token, user_msg,
|
|
165 |
)]
|
166 |
)
|
167 |
)
|
168 |
-
final
|
|
|
169 |
else:
|
170 |
-
|
171 |
|
|
|
|
|
|
|
|
|
172 |
if "iframe" in result: session["iframe"] = result["iframe"]
|
173 |
if "log" in result: session["log"] = result["log"]
|
174 |
if "files" in result: session["files"] = result["files"]
|
175 |
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
182 |
|
183 |
def sync_manual(profile, token, session):
|
184 |
if not (profile and token and session.get("repo_id")):
|
185 |
-
return (
|
186 |
-
|
187 |
-
|
188 |
-
|
|
|
|
|
189 |
fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
|
190 |
session["files"] = "\n".join(fl)
|
191 |
session["log"] = "🔄 Manual changes synced."
|
192 |
-
return (
|
193 |
-
|
194 |
-
|
195 |
-
|
|
|
|
|
196 |
|
197 |
# — BUILD UI —
|
198 |
|
199 |
with gr.Blocks(css="""
|
200 |
-
#sidebar { background
|
201 |
-
#main { padding:
|
202 |
""") as demo:
|
203 |
|
204 |
with gr.Row():
|
@@ -209,11 +240,13 @@ with gr.Blocks(css="""
|
|
209 |
profile_state = gr.State(None)
|
210 |
token_state = gr.State(None)
|
211 |
|
212 |
-
#
|
213 |
login_btn.click(None, [], [profile_state, token_state])
|
214 |
|
215 |
status_md = gr.Markdown("*Not logged in.*")
|
216 |
-
profile_state.change(show_profile,
|
|
|
|
|
217 |
|
218 |
models_md = gr.Markdown()
|
219 |
profile_state.change(list_private_models,
|
@@ -222,7 +255,8 @@ with gr.Blocks(css="""
|
|
222 |
|
223 |
gemini_key = gr.Textbox(label="Gemini API Key", type="password")
|
224 |
sidebar_repo = gr.Textbox(label="Space name", placeholder="my-space")
|
225 |
-
sidebar_sdk = gr.Radio(["gradio","streamlit"],
|
|
|
226 |
|
227 |
gr.Markdown("---")
|
228 |
confirm_btn = gr.Button("🔄 Confirm Manual Changes")
|
@@ -232,16 +266,18 @@ with gr.Blocks(css="""
|
|
232 |
tabs = gr.Tabs()
|
233 |
with tabs:
|
234 |
with gr.TabItem("💬 Chat"):
|
235 |
-
chatbox = gr.Chatbot(type="
|
236 |
user_input = gr.Textbox(show_label=False, placeholder="Ask the LLM…")
|
237 |
send_btn = gr.Button("Send")
|
238 |
with gr.TabItem("🛠️ Manual"):
|
239 |
gr.Markdown("#### Create a Space")
|
240 |
repo_m = gr.Textbox(label="Name")
|
241 |
-
sdk_m = gr.Radio(["gradio","streamlit"],
|
|
|
242 |
create_btn = gr.Button("Create Space")
|
243 |
sess_id = gr.Textbox(visible=False)
|
244 |
-
log_c = gr.Textbox(label="Log",
|
|
|
245 |
preview = gr.HTML("<p>No Space yet.</p>")
|
246 |
|
247 |
create_btn.click(create_space,
|
@@ -253,7 +289,8 @@ with gr.Blocks(css="""
|
|
253 |
path = gr.Textbox(label="Path", value="app.py")
|
254 |
file_u = gr.File()
|
255 |
upload_btn = gr.Button("Upload File")
|
256 |
-
log_u = gr.Textbox(label="Log",
|
|
|
257 |
|
258 |
upload_btn.click(upload_file_to_space,
|
259 |
inputs=[file_u, path, sess_id,
|
@@ -263,8 +300,10 @@ with gr.Blocks(css="""
|
|
263 |
gr.Markdown("#### Fetch Logs")
|
264 |
b_btn = gr.Button("Build Logs")
|
265 |
r_btn = gr.Button("Run Logs")
|
266 |
-
log_b = gr.Textbox(label="Build",
|
267 |
-
|
|
|
|
|
268 |
|
269 |
b_btn.click(get_build_logs,
|
270 |
inputs=[sess_id, profile_state, token_state],
|
@@ -273,7 +312,7 @@ with gr.Blocks(css="""
|
|
273 |
inputs=[sess_id, profile_state, token_state],
|
274 |
outputs=[log_r])
|
275 |
|
276 |
-
#
|
277 |
gr.Markdown("---")
|
278 |
iframe_out = gr.HTML(label="🖼️ Preview")
|
279 |
log_out = gr.Textbox(label="📋 Latest Log", lines=4)
|
|
|
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 |
+
return (
|
42 |
+
rid,
|
43 |
+
f"✅ Space ready: {url} (SDK: {sdk})",
|
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 |
return f"✅ Uploaded `{path}` to `{repo_id}`"
|
56 |
|
57 |
def _fetch_space_logs_level(repo_id, level):
|
58 |
+
r = get_session().get(
|
59 |
+
f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt",
|
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 |
|
86 |
func_decls = [
|
87 |
{
|
88 |
+
"name": "create_space",
|
89 |
+
"description": "Create/get a HF Space",
|
90 |
+
"parameters": {
|
91 |
"type":"object",
|
92 |
"properties":{
|
93 |
"repo_name":{"type":"string"},
|
|
|
97 |
}
|
98 |
},
|
99 |
{
|
100 |
+
"name": "list_files",
|
101 |
+
"description": "List files in Space",
|
102 |
+
"parameters": {
|
103 |
"type":"object",
|
104 |
"properties":{"repo_id":{"type":"string"}},
|
105 |
"required":["repo_id"]
|
106 |
}
|
107 |
},
|
108 |
{
|
109 |
+
"name": "get_build_logs",
|
110 |
+
"description": "Fetch build logs",
|
111 |
+
"parameters": {
|
112 |
"type":"object",
|
113 |
"properties":{"repo_id":{"type":"string"}},
|
114 |
"required":["repo_id"]
|
115 |
}
|
116 |
},
|
117 |
{
|
118 |
+
"name": "get_run_logs",
|
119 |
+
"description": "Fetch run logs",
|
120 |
+
"parameters": {
|
121 |
"type":"object",
|
122 |
"properties":{"repo_id":{"type":"string"}},
|
123 |
"required":["repo_id"]
|
|
|
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(
|
|
|
143 |
)
|
144 |
session["chat"] = client.chats.create(model="gemini-2.0-flash", config=cfg)
|
145 |
session["repo_id"] = None
|
146 |
+
session["messages"] = []
|
147 |
|
148 |
+
# Record user message
|
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 may already be dict
|
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
|
|
|
176 |
else:
|
177 |
result = {"log": f"⚠️ Unknown function {name}"}
|
178 |
|
179 |
+
# Send the function result back into the chat
|
180 |
+
session["chat"].send_message(
|
181 |
types.Content(
|
182 |
role="function",
|
183 |
parts=[ types.Part(
|
|
|
186 |
)]
|
187 |
)
|
188 |
)
|
189 |
+
# The assistant’s final message
|
190 |
+
assistant_text = session["chat"].get_history()[-1].parts[0].text
|
191 |
else:
|
192 |
+
assistant_text = part.text
|
193 |
|
194 |
+
# Record assistant message
|
195 |
+
session["messages"].append({"role":"assistant","content":assistant_text})
|
196 |
+
|
197 |
+
# Update the panels
|
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"]
|
201 |
|
202 |
+
return (
|
203 |
+
session["messages"],
|
204 |
+
session.get("iframe",""),
|
205 |
+
session.get("log",""),
|
206 |
+
session.get("files",""),
|
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 |
+
session.get("iframe",""),
|
214 |
+
"⚠️ Cannot sync manual changes.",
|
215 |
+
session.get("files",""),
|
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."
|
221 |
+
return (
|
222 |
+
session.get("iframe",""),
|
223 |
+
session["log"],
|
224 |
+
session["files"],
|
225 |
+
session
|
226 |
+
)
|
227 |
|
228 |
# — BUILD UI —
|
229 |
|
230 |
with gr.Blocks(css="""
|
231 |
+
#sidebar { background:#f2f2f2; padding:1rem; border-right:1px solid #ccc; }
|
232 |
+
#main { padding:1rem; }
|
233 |
""") as demo:
|
234 |
|
235 |
with gr.Row():
|
|
|
240 |
profile_state = gr.State(None)
|
241 |
token_state = gr.State(None)
|
242 |
|
243 |
+
# Capture both profile and token from the login button
|
244 |
login_btn.click(None, [], [profile_state, token_state])
|
245 |
|
246 |
status_md = gr.Markdown("*Not logged in.*")
|
247 |
+
profile_state.change(show_profile,
|
248 |
+
inputs=[profile_state],
|
249 |
+
outputs=[status_md])
|
250 |
|
251 |
models_md = gr.Markdown()
|
252 |
profile_state.change(list_private_models,
|
|
|
255 |
|
256 |
gemini_key = gr.Textbox(label="Gemini API Key", type="password")
|
257 |
sidebar_repo = gr.Textbox(label="Space name", placeholder="my-space")
|
258 |
+
sidebar_sdk = gr.Radio(["gradio","streamlit"],
|
259 |
+
value="gradio", label="SDK")
|
260 |
|
261 |
gr.Markdown("---")
|
262 |
confirm_btn = gr.Button("🔄 Confirm Manual Changes")
|
|
|
266 |
tabs = gr.Tabs()
|
267 |
with tabs:
|
268 |
with gr.TabItem("💬 Chat"):
|
269 |
+
chatbox = gr.Chatbot(type="messages")
|
270 |
user_input = gr.Textbox(show_label=False, placeholder="Ask the LLM…")
|
271 |
send_btn = gr.Button("Send")
|
272 |
with gr.TabItem("🛠️ Manual"):
|
273 |
gr.Markdown("#### Create a Space")
|
274 |
repo_m = gr.Textbox(label="Name")
|
275 |
+
sdk_m = gr.Radio(["gradio","streamlit"],
|
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 |
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 |
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 |
+
interactive=False, lines=5)
|
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],
|
|
|
312 |
inputs=[sess_id, profile_state, token_state],
|
313 |
outputs=[log_r])
|
314 |
|
315 |
+
# Persistent panels
|
316 |
gr.Markdown("---")
|
317 |
iframe_out = gr.HTML(label="🖼️ Preview")
|
318 |
log_out = gr.Textbox(label="📋 Latest Log", lines=4)
|