wuhp commited on
Commit
246858a
·
verified ·
1 Parent(s): 52ae72e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -64
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
- 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,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
- 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,9 +80,8 @@ def get_container_logs(repo_id, profile, token):
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,27 +91,24 @@ func_decls = [
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"]
@@ -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"] = 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
166
  )
167
  session["repo_id"] = rid
168
- result = {"log": log, "iframe": iframe}
 
169
  elif name == "list_files":
170
  fl = list_repo_files(session["repo_id"], token=token.token, repo_type="space")
171
- result = {"files": "\n".join(fl)}
 
172
  elif name == "get_build_logs":
173
- result = {"log": get_build_logs(session["repo_id"], profile, token)}
 
174
  elif name == "get_run_logs":
175
- result = {"log": get_container_logs(session["repo_id"], 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(
184
  function_call=part.function_call,
185
- function_response=json.dumps(result)
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"]
@@ -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
- 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."
@@ -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
- # 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.*")
@@ -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
- 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],
@@ -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],