wuhp commited on
Commit
91af2dc
Β·
verified Β·
1 Parent(s): 25612df

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +147 -222
app.py CHANGED
@@ -1,28 +1,19 @@
1
  import os, json
2
  import gradio as gr
3
  from huggingface_hub import (
4
- create_repo,
5
- list_models,
6
- upload_file,
7
- list_repo_files,
8
- constants,
9
  )
10
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
11
  from google import genai
12
  from google.genai import types
13
 
14
- # β€” USER INFO & MODEL LISTING (UNCHANGED) β€”
15
 
16
  def show_profile(profile: gr.OAuthProfile | None) -> str:
17
- if profile is None:
18
- return "*Not logged in.*"
19
- return f"βœ… Logged in as **{profile.username}**"
20
 
21
- def list_private_models(
22
- profile: gr.OAuthProfile | None,
23
- oauth_token: gr.OAuthToken | None
24
- ) -> str:
25
- if profile is None or oauth_token is None:
26
  return "Please log in to see your models."
27
  models = [
28
  f"{m.id} ({'private' if m.private else 'public'})"
@@ -30,121 +21,63 @@ def list_private_models(
30
  ]
31
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
32
 
33
- def enable_create(
34
- profile: gr.OAuthProfile | None,
35
- oauth_token: gr.OAuthToken | None
36
- ):
37
- return gr.update(interactive=profile is not None)
38
-
39
- def enable_repo_actions(
40
- repo_id: str,
41
- profile: gr.OAuthProfile | None,
42
- oauth_token: gr.OAuthToken | None
43
- ):
44
  return gr.update(interactive=bool(repo_id and profile and oauth_token))
45
 
46
- def create_space(
47
- repo_name: str,
48
- sdk: str,
49
- profile: gr.OAuthProfile | None,
50
- oauth_token: gr.OAuthToken | None
51
- ) -> tuple[str, str, str]:
52
- if not profile or not oauth_token:
53
- return "", "⚠️ Please log in first.", "<p>No Space created yet.</p>"
54
- repo_id = f"{profile.username}/{repo_name}"
55
- create_repo(
56
- repo_id=repo_id,
57
- token=oauth_token.token,
58
- exist_ok=True,
59
- repo_type="space",
60
- space_sdk=sdk
61
- )
62
- url = f"https://huggingface.co/spaces/{repo_id}"
63
- logmsg = f"βœ… Space ready: {url} (SDK: {sdk})"
64
- iframe = f'<iframe src="{url}" width="100%" height="500px"></iframe>'
65
- return repo_id, logmsg, iframe
66
-
67
- def upload_file_to_space(
68
- file,
69
- path_in_repo: str,
70
- repo_id: str,
71
- profile: gr.OAuthProfile | None,
72
- oauth_token: gr.OAuthToken | None
73
- ) -> str:
74
- if not profile or not oauth_token:
75
- return "⚠️ Please log in first."
76
- if not repo_id:
77
- return "⚠️ Please create a Space first."
78
- if not file:
79
- return "⚠️ No file selected."
80
- upload_file(
81
- path_or_fileobj=file.name,
82
- path_in_repo=path_in_repo,
83
- repo_id=repo_id,
84
- token=oauth_token.token,
85
- repo_type="space"
86
- )
87
- return f"βœ… Uploaded `{path_in_repo}` to `{repo_id}`"
88
-
89
- def _fetch_space_logs_level(repo_id: str, level: str) -> str:
90
- jwt_url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
91
- r = get_session().get(jwt_url, headers=build_hf_headers())
92
- hf_raise_for_status(r)
93
- jwt = r.json()["token"]
94
- logs_url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
95
  lines = []
96
- with get_session().get(logs_url, headers=build_hf_headers(token=jwt), stream=True) as resp:
97
  hf_raise_for_status(resp)
98
  for raw in resp.iter_lines():
99
- if not raw.startswith(b"data: "):
100
- continue
101
- payload = raw[len(b"data: "):]
102
- try:
103
- event = json.loads(payload.decode())
104
- except:
105
- continue
106
- ts = event.get("timestamp", "")
107
- txt = event.get("data", "")
108
- lines.append(f"[{ts}] {txt}")
109
  return "\n".join(lines)
110
 
111
- def get_build_logs(
112
- repo_id: str,
113
- profile: gr.OAuthProfile | None,
114
- oauth_token: gr.OAuthToken | None
115
- ) -> str:
116
- if not (profile and oauth_token and repo_id):
117
- return "⚠️ Please log in and create a Space first."
118
- return _fetch_space_logs_level(repo_id, "build")
119
-
120
- def get_container_logs(
121
- repo_id: str,
122
- profile: gr.OAuthProfile | None,
123
- oauth_token: gr.OAuthToken | None
124
- ) -> str:
125
  if not (profile and oauth_token and repo_id):
126
- return "⚠️ Please log in and create a Space first."
127
- return _fetch_space_logs_level(repo_id, "run")
 
128
 
129
-
130
- # β€” GEMINI FUNCTION DECLARATIONS β€”
131
 
132
  func_decls = [
133
  {
134
- "name": "create_space",
135
- "description": "Create or get a Hugging Face Space",
136
- "parameters": {
137
- "type": "object",
138
- "properties": {
139
- "repo_name": {"type":"string"},
140
- "sdk": {"type":"string","enum":["gradio","streamlit"]},
141
  },
142
- "required": ["repo_name","sdk"]
143
  }
144
  },
145
  {
146
- "name":"list_files",
147
- "description":"List files in the Space",
148
  "parameters":{
149
  "type":"object",
150
  "properties":{"repo_id":{"type":"string"}},
@@ -152,8 +85,7 @@ func_decls = [
152
  }
153
  },
154
  {
155
- "name": "get_build_logs",
156
- "description": "Fetch the build logs",
157
  "parameters":{
158
  "type":"object",
159
  "properties":{"repo_id":{"type":"string"}},
@@ -161,8 +93,7 @@ func_decls = [
161
  }
162
  },
163
  {
164
- "name": "get_run_logs",
165
- "description": "Fetch the run logs",
166
  "parameters":{
167
  "type":"object",
168
  "properties":{"repo_id":{"type":"string"}},
@@ -171,23 +102,14 @@ func_decls = [
171
  },
172
  ]
173
 
174
- # β€” CHAT HANDLER β€”
175
 
176
- def process_message(
177
- user_msg: str,
178
- profile: gr.OAuthProfile | None,
179
- oauth_token: gr.OAuthToken | None,
180
- gemini_key: str,
181
- repo_name: str,
182
- sdk: str,
183
- chat_history,
184
- session
185
- ):
186
- # init
187
  if session.get("chat") is None:
188
  client = genai.Client(api_key=gemini_key)
189
  cfg = types.GenerateContentConfig(
190
- system_instruction="You are an admin for HF Spaces: use functions to create spaces, list files, and fetch logs.",
191
  temperature=0,
192
  tools=[ types.Tool(function_declarations=func_decls) ]
193
  )
@@ -195,7 +117,7 @@ def process_message(
195
  session["repo_id"] = None
196
 
197
  chat = session["chat"]
198
- chat_history = chat_history + [(user_msg, None)]
199
  resp = chat.send_message(user_msg)
200
  part = resp.candidates[0].content.parts[0]
201
 
@@ -204,17 +126,16 @@ def process_message(
204
  args = json.loads(part.function_call.args)
205
  if name=="create_space":
206
  rid, log, iframe = create_space(args["repo_name"], args["sdk"], profile, oauth_token)
207
- session["repo_id"] = rid
208
- result = {"repo_id":rid,"log":log,"iframe":iframe}
209
  elif name=="list_files":
210
- files = list_repo_files(session["repo_id"], token=oauth_token.token, repo_type="space") if session["repo_id"] else []
211
  result = {"files":"\n".join(files)}
212
  elif name=="get_build_logs":
213
- result = {"log":get_build_logs(session["repo_id"], profile, oauth_token)}
214
  elif name=="get_run_logs":
215
- result = {"log":get_container_logs(session["repo_id"], profile, oauth_token)}
216
  else:
217
- result = {"log":f"⚠️ Unknown function {name}"}
218
 
219
  chat.send_message(
220
  types.Content(
@@ -226,98 +147,102 @@ def process_message(
226
  else:
227
  final = part.text
228
 
229
- # panels
230
- iframe = session.get("iframe", "")
231
- log = session.get("log", "")
232
- files = session.get("files", "")
233
-
234
- if part.function_call:
235
- session["iframe"] = result.get("iframe", iframe)
236
- session["log"] = result.get("log", log)
237
- session["files"] = result.get("files", files)
238
-
239
  chat_history[-1] = (user_msg, final)
240
  return chat_history, session["iframe"], session["log"], session["files"], session
241
 
242
- # β€” BUILD THE UI β€”
243
-
244
- with gr.Blocks(title="HF Spaces + Gemini Chat") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
245
  with gr.Row():
246
- # β—€ Sidebar: login + chat config
247
- with gr.Column(scale=1):
248
- gr.Markdown("## πŸ”‘ Sign in & Chat Config")
249
- login_btn = gr.LoginButton(variant="huggingface", size="sm")
250
- status_md = gr.Markdown("*Not logged in.*")
251
- models_md = gr.Markdown()
252
- demo.load(show_profile, inputs=None, outputs=status_md)
253
- login_btn.click(show_profile, inputs=None, outputs=status_md)
254
- demo.load(list_private_models, inputs=None, outputs=models_md)
255
- login_btn.click(list_private_models, inputs=None, outputs=models_md)
256
-
257
- gemini_key = gr.Textbox(label="Gemini API Key", type="password")
258
- repo_name = gr.Textbox(label="Space name", placeholder="e.g. my-space")
259
- sdk_choice = gr.Radio(["gradio","streamlit"], value="gradio", label="SDK")
260
- # β–Ά Main: chat + panels + manual controls
261
- with gr.Column(scale=3):
262
- gr.Markdown("## πŸ’¬ Chat to manage your Space")
263
- chatbox = gr.Chatbot(type="messages")
264
- user_in = gr.Textbox(show_label=False, placeholder="e.g. Create Space")
265
- send_btn = gr.Button("Send")
266
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  iframe_out = gr.HTML(label="πŸ–ΌοΈ Preview")
268
- log_out = gr.Textbox(label="πŸ“‹ Latest Log", lines=8)
269
- files_out = gr.Textbox(label="πŸ“š Files in Space", lines=4)
270
-
271
- gr.Markdown("---\n## πŸ› οΈ Manual Controls")
272
- # CREATE SPACE
273
- repo_name_m = gr.Textbox(label="New Space name", placeholder="my-space")
274
- sdk_selector = gr.Radio(["gradio","streamlit"], value="gradio", label="SDK")
275
- create_btn = gr.Button("Create Space", interactive=False)
276
- session_id = gr.Textbox(visible=False)
277
- create_logs = gr.Textbox(label="Create Logs", interactive=False, lines=3)
278
- preview_m = gr.HTML("<p>No Space created yet.</p>")
279
-
280
- demo.load(enable_create, inputs=None, outputs=[create_btn])
281
- login_btn.click(enable_create, inputs=None, outputs=[create_btn])
282
- create_btn.click(
283
- fn=create_space,
284
- inputs=[repo_name_m, sdk_selector],
285
- outputs=[session_id, create_logs, preview_m]
286
- )
287
-
288
- # UPLOAD FILE
289
- path_in_repo = gr.Textbox(label="Path in Space", value="app.py")
290
- file_uploader = gr.File(label="Select file")
291
- upload_btn = gr.Button("Upload File", interactive=False)
292
- upload_logs = gr.Textbox(label="Upload Logs", interactive=False, lines=2)
293
-
294
- demo.load(enable_repo_actions, inputs=[session_id], outputs=[upload_btn])
295
- login_btn.click(enable_repo_actions, inputs=[session_id], outputs=[upload_btn])
296
- upload_btn.click(
297
- fn=upload_file_to_space,
298
- inputs=[file_uploader, path_in_repo, session_id],
299
- outputs=[upload_logs]
300
- )
301
-
302
- # FETCH LOGS
303
- build_btn = gr.Button("Get Build Logs", interactive=False)
304
- run_btn = gr.Button("Get Container Logs", interactive=False)
305
- build_logs_md = gr.Textbox(label="Build Logs", interactive=False, lines=10)
306
- run_logs_md = gr.Textbox(label="Container Logs", interactive=False, lines=10)
307
-
308
- for b in (build_btn, run_btn):
309
- demo.load(enable_repo_actions, inputs=[session_id], outputs=[b])
310
- login_btn.click(enable_repo_actions, inputs=[session_id], outputs=[b])
311
-
312
- build_btn.click(fn=get_build_logs, inputs=[session_id], outputs=[build_logs_md])
313
- run_btn.click( fn=get_container_logs, inputs=[session_id], outputs=[run_logs_md])
314
 
315
  state = gr.State({})
316
- send_btn.click(
317
- fn=process_message,
318
- inputs=[user_in, status_md, login_btn, gemini_key, repo_name, sdk_choice, chatbox, state],
319
- outputs=[chatbox, iframe_out, log_out, files_out, state]
320
- )
321
 
322
  if __name__ == "__main__":
323
  demo.launch()
 
1
  import os, json
2
  import gradio as gr
3
  from huggingface_hub import (
4
+ create_repo, list_models, upload_file, list_repo_files, constants
 
 
 
 
5
  )
6
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
7
  from google import genai
8
  from google.genai import types
9
 
10
+ # β€” USER INFO & HF SPACE HELPERS β€”β€”
11
 
12
  def show_profile(profile: gr.OAuthProfile | None) -> str:
13
+ return f"βœ… Logged in as **{profile.username}**" if profile else "*Not logged in.*"
 
 
14
 
15
+ def list_private_models(profile, oauth_token):
16
+ if not (profile and oauth_token):
 
 
 
17
  return "Please log in to see your models."
18
  models = [
19
  f"{m.id} ({'private' if m.private else 'public'})"
 
21
  ]
22
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
23
 
24
+ def enable_create(profile, oauth_token): return gr.update(interactive=bool(profile and oauth_token))
25
+ def enable_repo_actions(repo_id, profile, oauth_token):
 
 
 
 
 
 
 
 
 
26
  return gr.update(interactive=bool(repo_id and profile and oauth_token))
27
 
28
+ def create_space(repo_name, sdk, profile, oauth_token):
29
+ if not (profile and oauth_token):
30
+ return "", "⚠️ Please log in first.", "<p>No Space.</p>"
31
+ rid = f"{profile.username}/{repo_name}"
32
+ create_repo(rid, token=oauth_token.token, exist_ok=True, repo_type="space", space_sdk=sdk)
33
+ url = f"https://huggingface.co/spaces/{rid}"
34
+ return rid, f"βœ… Space ready: {url}", f'<iframe src="{url}" width="100%" height="400px"></iframe>'
35
+
36
+ def upload_file_to_space(file, path_in_repo, repo_id, profile, oauth_token):
37
+ if not (profile and oauth_token): return "⚠️ Please log in first."
38
+ if not repo_id: return "⚠️ Create a Space first."
39
+ if not file: return "⚠️ No file selected."
40
+ upload_file(file.name, path_in_repo, repo_id, token=oauth_token.token, repo_type="space")
41
+ return f"βœ… Uploaded `{path_in_repo}`"
42
+
43
+ def fetch_logs(repo_id, level, profile, oauth_token):
44
+ if not (profile and oauth_token and repo_id):
45
+ return "⚠️ Log in & create a Space first."
46
+ # SSE JWT
47
+ r = get_session().get(f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt", headers=build_hf_headers())
48
+ hf_raise_for_status(r); jwt = r.json()["token"]
49
+ url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  lines = []
51
+ with get_session().get(url, headers=build_hf_headers(token=jwt), stream=True) as resp:
52
  hf_raise_for_status(resp)
53
  for raw in resp.iter_lines():
54
+ if raw.startswith(b"data: "):
55
+ ev = json.loads(raw[6:])
56
+ lines.append(f"[{ev.get('timestamp','')}] {ev.get('data','')}")
 
 
 
 
 
 
 
57
  return "\n".join(lines)
58
 
59
+ def list_files(repo_id, profile, oauth_token):
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  if not (profile and oauth_token and repo_id):
61
+ return "⚠️ Log in & create a Space first."
62
+ files = list_repo_files(repo_id, token=oauth_token.token, repo_type="space")
63
+ return "\n".join(files)
64
 
65
+ # β€” GEMINI FUNCTION DECLS β€”β€”
 
66
 
67
  func_decls = [
68
  {
69
+ "name":"create_space","description":"Create/get a HF Space",
70
+ "parameters":{
71
+ "type":"object",
72
+ "properties":{
73
+ "repo_name":{"type":"string"},
74
+ "sdk":{"type":"string","enum":["gradio","streamlit"]}
 
75
  },
76
+ "required":["repo_name","sdk"]
77
  }
78
  },
79
  {
80
+ "name":"list_files","description":"List files in Space",
 
81
  "parameters":{
82
  "type":"object",
83
  "properties":{"repo_id":{"type":"string"}},
 
85
  }
86
  },
87
  {
88
+ "name":"get_build_logs","description":"Fetch build logs",
 
89
  "parameters":{
90
  "type":"object",
91
  "properties":{"repo_id":{"type":"string"}},
 
93
  }
94
  },
95
  {
96
+ "name":"get_run_logs","description":"Fetch run logs",
 
97
  "parameters":{
98
  "type":"object",
99
  "properties":{"repo_id":{"type":"string"}},
 
102
  },
103
  ]
104
 
105
+ # β€” CHAT HANDLER β€”β€”
106
 
107
+ def process_message(profile, oauth_token, user_msg, gemini_key, repo_name, sdk, chat_history, session):
108
+ # init chat
 
 
 
 
 
 
 
 
 
109
  if session.get("chat") is None:
110
  client = genai.Client(api_key=gemini_key)
111
  cfg = types.GenerateContentConfig(
112
+ system_instruction="You are an admin for HF Spaces: create spaces, list files, and fetch logs.",
113
  temperature=0,
114
  tools=[ types.Tool(function_declarations=func_decls) ]
115
  )
 
117
  session["repo_id"] = None
118
 
119
  chat = session["chat"]
120
+ chat_history.append((user_msg, None))
121
  resp = chat.send_message(user_msg)
122
  part = resp.candidates[0].content.parts[0]
123
 
 
126
  args = json.loads(part.function_call.args)
127
  if name=="create_space":
128
  rid, log, iframe = create_space(args["repo_name"], args["sdk"], profile, oauth_token)
129
+ session["repo_id"], result = rid, {"log":log,"iframe":iframe}
 
130
  elif name=="list_files":
131
+ files = list_repo_files(session["repo_id"], token=oauth_token.token, repo_type="space")
132
  result = {"files":"\n".join(files)}
133
  elif name=="get_build_logs":
134
+ result = {"log":fetch_logs(session["repo_id"], "build", profile, oauth_token)}
135
  elif name=="get_run_logs":
136
+ result = {"log":fetch_logs(session["repo_id"], "run", profile, oauth_token)}
137
  else:
138
+ result = {"log":f"⚠️ Unknown fn {name}"}
139
 
140
  chat.send_message(
141
  types.Content(
 
147
  else:
148
  final = part.text
149
 
150
+ # update panels
151
+ session["iframe"] = session.get("iframe", "") if not result.get("iframe") else result["iframe"]
152
+ session["log"] = session.get("log", "") if not result.get("log") else result["log"]
153
+ session["files"] = session.get("files", "") if not result.get("files") else result["files"]
 
 
 
 
 
 
154
  chat_history[-1] = (user_msg, final)
155
  return chat_history, session["iframe"], session["log"], session["files"], session
156
 
157
+ def sync_manual(profile, oauth_token, session):
158
+ # after manual tweaks, refresh file list in panels & LLM memory
159
+ if not (profile and oauth_token and session.get("repo_id")):
160
+ return session.get("iframe",""), "⚠️ Cannot sync.", session.get("files",""), session
161
+ files = list_repo_files(session["repo_id"], token=oauth_token.token, repo_type="space")
162
+ session["files"] = "\n".join(files)
163
+ session["log"] = "πŸ”„ Manual changes synced."
164
+ return session["iframe"], session["log"], session["files"], session
165
+
166
+ # β€” BUILD UI β€”β€”
167
+
168
+ with gr.Blocks(title="HF Spaces + Gemini Chat", css="""
169
+ #sidebar {background:#f7f7f7;padding:10px;border-right:1px solid #ddd;}
170
+ #main {padding:10px;}
171
+ """) as demo:
172
  with gr.Row():
173
+ with gr.Column(elem_id="sidebar", scale=1):
174
+ gr.Markdown("### πŸ”‘ Login & Config")
175
+ login = gr.LoginButton(variant="huggingface", size="sm")
176
+ status = gr.Markdown("*Not logged in.*")
177
+ models = gr.Markdown()
178
+ demo.load(show_profile, inputs=None, outputs=status)
179
+ login.click(show_profile, inputs=None, outputs=status)
180
+ demo.load(list_private_models, inputs=None, outputs=models)
181
+ login.click(list_private_models, inputs=None, outputs=models)
182
+
183
+ gemini_key = gr.Textbox(label="Gemini API Key", type="password")
184
+ repo_name = gr.Textbox(label="Space name", placeholder="e.g. my-space")
185
+ sdk_choice = gr.Radio(["gradio","streamlit"], value="gradio", label="SDK")
186
+
187
+ gr.Markdown("---")
188
+ sync_btn = gr.Button("βœ… Confirm Manual Changes")
189
+ sync_btn.click(sync_manual, inputs=[status, login, gr.State({})],
190
+ outputs=[gr.HTML(), gr.Textbox(), gr.Textbox(), gr.State({})])
191
+
192
+ with gr.Column(elem_id="main", scale=3):
193
+ tabs = gr.Tabs()
194
+ with tabs:
195
+ with gr.TabItem("πŸ’¬ Chat"):
196
+ chatbox = gr.Chatbot(type="messages", label="Chat")
197
+ user_in = gr.Textbox(show_label=False, placeholder="Ask LLM…")
198
+ send = gr.Button("Send")
199
+ with gr.TabItem("πŸ› οΈ Manual"):
200
+ gr.Markdown("#### Create a Space")
201
+ repo_m = gr.Textbox(label="Name")
202
+ sdk_m = gr.Radio(["gradio","streamlit"], value="gradio", label="SDK")
203
+ create = gr.Button("Create", interactive=False)
204
+ sess = gr.Textbox(visible=False)
205
+ log_c = gr.Textbox(label="Log", interactive=False, lines=2)
206
+ preview = gr.HTML("<p>No Space yet</p>")
207
+
208
+ demo.load(enable_create, inputs=None, outputs=create)
209
+ login.click(enable_create, inputs=None, outputs=create)
210
+ create.click(create_space,
211
+ inputs=[repo_m, sdk_m, status, login],
212
+ outputs=[sess, log_c, preview])
213
+
214
+ gr.Markdown("#### Upload File")
215
+ path = gr.Textbox(label="Path in Repo", value="app.py")
216
+ file_u = gr.File()
217
+ up_btn = gr.Button("Upload", interactive=False)
218
+ log_u = gr.Textbox(label="Log", interactive=False, lines=2)
219
+
220
+ demo.load(enable_repo_actions, inputs=[sess, status, login], outputs=up_btn)
221
+ up_btn.click(upload_file_to_space,
222
+ inputs=[file_u, path, sess, status, login],
223
+ outputs=log_u)
224
+
225
+ gr.Markdown("#### Fetch Logs")
226
+ b_btn = gr.Button("Build Logs", interactive=False)
227
+ r_btn = gr.Button("Run Logs", interactive=False)
228
+ log_b = gr.Textbox(label="Build", interactive=False, lines=5)
229
+ log_r = gr.Textbox(label="Run", interactive=False, lines=5)
230
+
231
+ for b in (b_btn, r_btn):
232
+ demo.load(enable_repo_actions, inputs=[sess, status, login], outputs=b)
233
+ b_btn.click(fetch_logs, inputs=[sess, gr.State(), gr.State(), "build"], outputs=log_b)
234
+ r_btn.click(fetch_logs, inputs=[sess, gr.State(), gr.State(), "run"], outputs=log_r)
235
+
236
+ # always-visible panels
237
+ gr.Markdown("---")
238
  iframe_out = gr.HTML(label="πŸ–ΌοΈ Preview")
239
+ log_out = gr.Textbox(label="πŸ“‹ Latest Log", lines=4)
240
+ files_out = gr.Textbox(label="πŸ“š Files", lines=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
  state = gr.State({})
243
+ send.click(process_message,
244
+ inputs=[status, login, user_in, gemini_key, repo_name, sdk_choice, chatbox, state],
245
+ outputs=[chatbox, iframe_out, log_out, files_out, state])
 
 
246
 
247
  if __name__ == "__main__":
248
  demo.launch()