wuhp commited on
Commit
5d26448
·
verified ·
1 Parent(s): 599725a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +136 -168
app.py CHANGED
@@ -1,4 +1,4 @@
1
- import os, json, requests
2
  import gradio as gr
3
  from huggingface_hub import (
4
  create_repo, list_models, upload_file, constants
@@ -7,57 +7,46 @@ from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_st
7
  from google import genai
8
  from google.genai import types
9
 
10
- # — USER INFO & MODEL LISTING — (unchanged)
11
- def show_profile(profile: gr.OAuthProfile | None) -> str:
12
- if profile is None:
13
- return "*Not logged in.*"
14
- return f"✅ Logged in as **{profile.username}**"
15
 
16
- def list_private_models(profile: gr.OAuthProfile | None,
17
- oauth_token: gr.OAuthToken | None) -> str:
18
- if profile is None or oauth_token is None:
 
 
19
  return "Please log in to see your models."
20
  models = [
21
  f"{m.id} ({'private' if m.private else 'public'})"
22
- for m in list_models(author=profile.username, token=oauth_token.token)
23
  ]
24
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
25
 
26
- # — BUTTON‑ENABLING HELPERS — (unchanged)
27
- def enable_create(profile: gr.OAuthProfile | None,
28
- oauth_token: gr.OAuthToken | None):
29
- return gr.update(interactive=profile is not None)
30
-
31
- def enable_repo_actions(repo_id: str,
32
- profile: gr.OAuthProfile | None,
33
- oauth_token: gr.OAuthToken | None):
34
- return gr.update(interactive=bool(repo_id and profile and oauth_token))
35
-
36
- # CORE ACTIONS — (unchanged)
37
- def create_space(repo_name: str, sdk: str,
38
- profile: gr.OAuthProfile | None,
39
- oauth_token: gr.OAuthToken | None
40
- ) -> tuple[str, str, str]:
41
- if not profile or not oauth_token:
42
  return "", "⚠️ Please log in first.", "<p>No Space created yet.</p>"
43
- repo_id = f"{profile.username}/{repo_name}"
44
  create_repo(
45
- repo_id=repo_id,
46
- token=oauth_token.token,
47
  exist_ok=True,
48
  repo_type="space",
49
  space_sdk=sdk
50
  )
51
- url = f"https://huggingface.co/spaces/{repo_id}"
52
- logmsg = f"✅ Space ready: {url} (SDK: {sdk})"
53
- iframe = f'<iframe src="{url}" width="100%" height="400px"></iframe>'
54
- return repo_id, logmsg, iframe
55
-
56
- def upload_file_to_space(file, path_in_repo: str, repo_id: str,
57
- profile: gr.OAuthProfile | None,
58
- oauth_token: gr.OAuthToken | None
59
- ) -> str:
60
- if not profile or not oauth_token:
61
  return "⚠️ Please log in first."
62
  if not repo_id:
63
  return "⚠️ Please create a Space first."
@@ -65,52 +54,45 @@ def upload_file_to_space(file, path_in_repo: str, repo_id: str,
65
  return "⚠️ No file selected."
66
  upload_file(
67
  path_or_fileobj=file.name,
68
- path_in_repo=path_in_repo,
69
  repo_id=repo_id,
70
- token=oauth_token.token,
71
  repo_type="space"
72
  )
73
- return f"✅ Uploaded `{path_in_repo}` to `{repo_id}`"
74
 
75
- def _fetch_space_logs_level(repo_id: str, level: str) -> str:
76
  jwt_url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
77
  r = get_session().get(jwt_url, headers=build_hf_headers())
78
  hf_raise_for_status(r)
79
  jwt = r.json()["token"]
80
- logs_url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
81
  lines = []
82
- with get_session().get(logs_url, headers=build_hf_headers(token=jwt), stream=True) as resp:
83
  hf_raise_for_status(resp)
84
  for raw in resp.iter_lines():
85
  if raw.startswith(b"data: "):
86
- ev = json.loads(raw[len(b"data: "):].decode())
87
- ts, txt = ev.get("timestamp", ""), ev.get("data", "")
88
- lines.append(f"[{ts}] {txt}")
89
  return "\n".join(lines)
90
 
91
- def get_build_logs(repo_id: str,
92
- profile: gr.OAuthProfile | None,
93
- oauth_token: gr.OAuthToken | None
94
- ) -> str:
95
- if not (profile and oauth_token and repo_id):
96
  return "⚠️ Please log in and create a Space first."
97
  return _fetch_space_logs_level(repo_id, "build")
98
 
99
- def get_container_logs(repo_id: str,
100
- profile: gr.OAuthProfile | None,
101
- oauth_token: gr.OAuthToken | None
102
- ) -> str:
103
- if not (profile and oauth_token and repo_id):
104
  return "⚠️ Please log in and create a Space first."
105
  return _fetch_space_logs_level(repo_id, "run")
106
 
107
 
108
- # — GEMINI FUNCTION DECLARATIONS —
 
109
  func_decls = [
110
  {
111
- "name": "create_space",
112
- "description": "Create or get a Hugging Face Space",
113
- "parameters": {
114
  "type":"object",
115
  "properties":{
116
  "repo_name":{"type":"string"},
@@ -120,8 +102,7 @@ func_decls = [
120
  }
121
  },
122
  {
123
- "name":"list_files",
124
- "description":"List files in the Space",
125
  "parameters":{
126
  "type":"object",
127
  "properties":{"repo_id":{"type":"string"}},
@@ -129,8 +110,7 @@ func_decls = [
129
  }
130
  },
131
  {
132
- "name":"get_build_logs",
133
- "description":"Fetch the build logs",
134
  "parameters":{
135
  "type":"object",
136
  "properties":{"repo_id":{"type":"string"}},
@@ -138,8 +118,7 @@ func_decls = [
138
  }
139
  },
140
  {
141
- "name":"get_run_logs",
142
- "description":"Fetch the run logs",
143
  "parameters":{
144
  "type":"object",
145
  "properties":{"repo_id":{"type":"string"}},
@@ -148,17 +127,17 @@ func_decls = [
148
  },
149
  ]
150
 
151
- # — CHAT HANDLER —
152
- def process_message(profile, oauth_token, user_msg,
153
- gemini_key, repo_name, sdk,
 
154
  chat_history, session):
155
- # initialize chat on first call
156
  if session.get("chat") is None:
157
  client = genai.Client(api_key=gemini_key)
158
  cfg = types.GenerateContentConfig(
159
  system_instruction=(
160
  "You are a HF Spaces admin. "
161
- "Use functions to create spaces, list files, or fetch logs."
162
  ),
163
  temperature=0,
164
  tools=[ types.Tool(function_declarations=func_decls) ]
@@ -175,29 +154,24 @@ def process_message(profile, oauth_token, user_msg,
175
  if part.function_call:
176
  name = part.function_call.name
177
  args = json.loads(part.function_call.args)
178
- if name == "create_space":
179
  rid, log, iframe = create_space(
180
- args["repo_name"], args["sdk"], profile, oauth_token
181
  )
182
  session["repo_id"] = rid
183
  result = {"log": log, "iframe": iframe}
184
- elif name == "list_files":
185
  files = list_repo_files(
186
- session["repo_id"], token=oauth_token.token, repo_type="space"
187
  )
188
  result = {"files": "\n".join(files)}
189
- elif name == "get_build_logs":
190
- result = {
191
- "log": get_build_logs(session["repo_id"], profile, oauth_token)
192
- }
193
- elif name == "get_run_logs":
194
- result = {
195
- "log": get_container_logs(session["repo_id"], profile, oauth_token)
196
- }
197
  else:
198
  result = {"log": f"⚠️ Unknown function {name}"}
199
 
200
- # feed function result back into the chat
201
  chat.send_message(
202
  types.Content(
203
  role="function",
@@ -223,15 +197,14 @@ def process_message(profile, oauth_token, user_msg,
223
  session.get("files",""),
224
  session)
225
 
226
- # SYNC MANUAL CHANGES —
227
- def sync_manual(profile, oauth_token, session):
228
- if not (profile and oauth_token and session.get("repo_id")):
229
  return (session.get("iframe",""),
230
  "⚠️ Cannot sync manual changes.",
231
  session.get("files",""),
232
  session)
233
  files = list_repo_files(
234
- session["repo_id"], token=oauth_token.token, repo_type="space"
235
  )
236
  session["files"] = "\n".join(files)
237
  session["log"] = "🔄 Manual changes synced."
@@ -240,116 +213,112 @@ def sync_manual(profile, oauth_token, session):
240
  session["files"],
241
  session)
242
 
 
 
 
 
 
243
 
244
- # — BUILD THE UI —
245
  with gr.Blocks(css="""
246
- #sidebar { background:#fafafa; padding:1em; border-right:1px solid #ddd; }
247
- #main { padding:1em; }
248
  """) as demo:
249
 
250
  with gr.Row():
251
- # Sidebar
252
  with gr.Column(elem_id="sidebar", scale=1):
253
  gr.Markdown("### 🔑 HF Login & Config")
254
- hf_login = gr.LoginButton(variant="huggingface", size="sm")
255
- status_md = gr.Markdown("*Not logged in.*")
256
- models_md = gr.Markdown()
257
-
258
- # login callbacks
259
- hf_login.click(show_profile,
260
- inputs=[hf_login], outputs=[status_md])
261
- hf_login.click(list_private_models,
262
- inputs=[hf_login, hf_login], outputs=[models_md])
263
-
264
- gemini_key = gr.Textbox(label="Gemini API Key",
265
- type="password")
266
- sidebar_repo = gr.Textbox(label="Space name",
267
- placeholder="e.g. my-space")
 
 
 
 
 
 
268
  sidebar_sdk = gr.Radio(["gradio","streamlit"],
269
  value="gradio", label="SDK")
270
 
271
  gr.Markdown("---")
272
- confirm_btn = gr.Button("🔄 Confirm Manual Changes")
273
 
274
- # Main area: Chat & Manual Controls
275
  with gr.Column(elem_id="main", scale=3):
276
  tabs = gr.Tabs()
277
  with tabs:
278
  with gr.TabItem("💬 Chat"):
279
- chatbox = gr.Chatbot(type="messages")
280
- user_input= gr.Textbox(show_label=False,
281
- placeholder="Ask the LLM…")
282
- send_btn = gr.Button("Send")
283
  with gr.TabItem("🛠️ Manual"):
284
  gr.Markdown("#### Create a Space")
285
- repo_m = gr.Textbox(label="Name")
286
- sdk_m = gr.Radio(["gradio","streamlit"],
287
- value="gradio", label="SDK")
288
- create_btn = gr.Button("Create Space",
289
- interactive=False)
290
  sess_id = gr.Textbox(visible=False)
291
  log_c = gr.Textbox(label="Log",
292
- interactive=False, lines=2)
293
- iframe_m = gr.HTML("<p>No Space yet.</p>")
294
 
295
- hf_login.click(enable_create,
296
- inputs=[hf_login, hf_login],
297
- outputs=[create_btn])
298
  create_btn.click(create_space,
299
  inputs=[repo_m, sdk_m,
300
- hf_login, hf_login],
301
- outputs=[sess_id, log_c,
302
- iframe_m])
303
 
304
  gr.Markdown("#### Upload File")
305
- path = gr.Textbox(label="Path in Repo",
306
- value="app.py")
307
- file_u = gr.File()
308
- up_btn = gr.Button("Upload File",
309
- interactive=False)
310
- log_u = gr.Textbox(label="Log",
311
- interactive=False, lines=2)
312
-
313
- hf_login.click(enable_repo_actions,
314
- inputs=[sess_id, hf_login, hf_login],
315
- outputs=[up_btn])
316
  up_btn.click(upload_file_to_space,
317
- inputs=[file_u, path, sess_id,
318
- hf_login, hf_login],
 
319
  outputs=[log_u])
320
 
321
  gr.Markdown("#### Fetch Logs")
322
- build_btn = gr.Button("Build Logs",
323
- interactive=False)
324
- run_btn = gr.Button("Run Logs",
325
- interactive=False)
326
- log_b = gr.Textbox(label="Build",
327
- interactive=False, lines=5)
328
- log_r = gr.Textbox(label="Run",
329
- interactive=False, lines=5)
330
-
331
- hf_login.click(enable_repo_actions,
332
- inputs=[sess_id, hf_login, hf_login],
333
- outputs=[build_btn, run_btn])
334
- build_btn.click(get_build_logs,
335
- inputs=[sess_id,
336
- hf_login, hf_login],
337
- outputs=[log_b])
338
- run_btn.click(get_container_logs,
339
- inputs=[sess_id,
340
- hf_login, hf_login],
341
- outputs=[log_r])
342
-
343
- # persistent bottom panels
344
  gr.Markdown("---")
345
  iframe_out = gr.HTML(label="🖼️ Preview")
346
- log_out = gr.Textbox(label="📋 Latest Log",
347
- lines=4)
348
  files_out = gr.Textbox(label="📚 Files", lines=4)
349
 
350
  state = gr.State({})
351
  send_btn.click(process_message,
352
- inputs=[hf_login, hf_login,
353
  user_input, gemini_key,
354
  sidebar_repo, sidebar_sdk,
355
  chatbox, state],
@@ -357,9 +326,8 @@ with gr.Blocks(css="""
357
  log_out, files_out, state])
358
 
359
  confirm_btn.click(sync_manual,
360
- inputs=[hf_login, hf_login, state],
361
- outputs=[iframe_out, log_out,
362
- files_out, state])
363
 
364
  if __name__ == "__main__":
365
  demo.launch()
 
1
+ import os, json
2
  import gradio as gr
3
  from huggingface_hub import (
4
  create_repo, list_models, upload_file, constants
 
7
  from google import genai
8
  from google.genai import types
9
 
10
+ # — USER INFO & MODEL LISTING —
 
 
 
 
11
 
12
+ def show_profile(profile):
13
+ return f"✅ Logged in as **{profile.username}**" if profile else "*Not logged in.*"
14
+
15
+ def list_private_models(profile, token):
16
+ if not (profile and token):
17
  return "Please log in to see your models."
18
  models = [
19
  f"{m.id} ({'private' if m.private else 'public'})"
20
+ for m in list_models(author=profile.username, token=token.token)
21
  ]
22
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
23
 
24
+ # — BUTTON‑ENABLING HELPERS —
25
+
26
+ def enable_create(profile, token):
27
+ return gr.update(interactive=bool(profile and token))
28
+
29
+ def enable_repo_actions(repo_id, profile, token):
30
+ return gr.update(interactive=bool(repo_id and profile and token))
31
+
32
+ # CORE ACTIONS
33
+
34
+ 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(
39
+ repo_id=rid,
40
+ token=token.token,
41
  exist_ok=True,
42
  repo_type="space",
43
  space_sdk=sdk
44
  )
45
+ url = f"https://huggingface.co/spaces/{rid}"
46
+ return rid, f"✅ Space ready: {url}", f'<iframe src="{url}" width="100%" height="400px"></iframe>'
47
+
48
+ def upload_file_to_space(file, path, repo_id, profile, token):
49
+ if not (profile and token):
 
 
 
 
 
50
  return "⚠️ Please log in first."
51
  if not repo_id:
52
  return "⚠️ Please create a Space first."
 
54
  return "⚠️ No file selected."
55
  upload_file(
56
  path_or_fileobj=file.name,
57
+ path_in_repo=path,
58
  repo_id=repo_id,
59
+ token=token.token,
60
  repo_type="space"
61
  )
62
+ return f"✅ Uploaded `{path}` to `{repo_id}`"
63
 
64
+ def _fetch_space_logs_level(repo_id, level):
65
  jwt_url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
66
  r = get_session().get(jwt_url, headers=build_hf_headers())
67
  hf_raise_for_status(r)
68
  jwt = r.json()["token"]
69
+ url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
70
  lines = []
71
+ with get_session().get(url, headers=build_hf_headers(token=jwt), stream=True) as resp:
72
  hf_raise_for_status(resp)
73
  for raw in resp.iter_lines():
74
  if raw.startswith(b"data: "):
75
+ ev = json.loads(raw[6:].decode())
76
+ lines.append(f"[{ev.get('timestamp','')}] {ev.get('data','')}")
 
77
  return "\n".join(lines)
78
 
79
+ def get_build_logs(repo_id, profile, token):
80
+ if not (profile and token and repo_id):
 
 
 
81
  return "⚠️ Please log in and create a Space first."
82
  return _fetch_space_logs_level(repo_id, "build")
83
 
84
+ def get_container_logs(repo_id, profile, token):
85
+ if not (profile and token and repo_id):
 
 
 
86
  return "⚠️ Please log in and create a Space first."
87
  return _fetch_space_logs_level(repo_id, "run")
88
 
89
 
90
+ # — GEMINI FUNCTION DECLARATIONS —
91
+
92
  func_decls = [
93
  {
94
+ "name":"create_space","description":"Create or get a Hugging Face Space",
95
+ "parameters":{
 
96
  "type":"object",
97
  "properties":{
98
  "repo_name":{"type":"string"},
 
102
  }
103
  },
104
  {
105
+ "name":"list_files","description":"List files in the Space",
 
106
  "parameters":{
107
  "type":"object",
108
  "properties":{"repo_id":{"type":"string"}},
 
110
  }
111
  },
112
  {
113
+ "name":"get_build_logs","description":"Fetch build logs",
 
114
  "parameters":{
115
  "type":"object",
116
  "properties":{"repo_id":{"type":"string"}},
 
118
  }
119
  },
120
  {
121
+ "name":"get_run_logs","description":"Fetch run logs",
 
122
  "parameters":{
123
  "type":"object",
124
  "properties":{"repo_id":{"type":"string"}},
 
127
  },
128
  ]
129
 
130
+ # — CHAT HANDLER —
131
+
132
+ def process_message(profile, token, user_msg,
133
+ gemini_key, sidebar_repo, sidebar_sdk,
134
  chat_history, session):
 
135
  if session.get("chat") is None:
136
  client = genai.Client(api_key=gemini_key)
137
  cfg = types.GenerateContentConfig(
138
  system_instruction=(
139
  "You are a HF Spaces admin. "
140
+ "Use functions to create spaces, list files, and fetch logs."
141
  ),
142
  temperature=0,
143
  tools=[ types.Tool(function_declarations=func_decls) ]
 
154
  if part.function_call:
155
  name = part.function_call.name
156
  args = json.loads(part.function_call.args)
157
+ if name=="create_space":
158
  rid, log, iframe = create_space(
159
+ args["repo_name"], args["sdk"], profile, token
160
  )
161
  session["repo_id"] = rid
162
  result = {"log": log, "iframe": iframe}
163
+ elif name=="list_files":
164
  files = list_repo_files(
165
+ session["repo_id"], token=token.token, repo_type="space"
166
  )
167
  result = {"files": "\n".join(files)}
168
+ elif name=="get_build_logs":
169
+ result = {"log": get_build_logs(session["repo_id"], profile, token)}
170
+ elif name=="get_run_logs":
171
+ result = {"log": get_container_logs(session["repo_id"], profile, token)}
 
 
 
 
172
  else:
173
  result = {"log": f"⚠️ Unknown function {name}"}
174
 
 
175
  chat.send_message(
176
  types.Content(
177
  role="function",
 
197
  session.get("files",""),
198
  session)
199
 
200
+ def sync_manual(profile, token, session):
201
+ if not (profile and token and session.get("repo_id")):
 
202
  return (session.get("iframe",""),
203
  "⚠️ Cannot sync manual changes.",
204
  session.get("files",""),
205
  session)
206
  files = list_repo_files(
207
+ session["repo_id"], token=token.token, repo_type="space"
208
  )
209
  session["files"] = "\n".join(files)
210
  session["log"] = "🔄 Manual changes synced."
 
213
  session["files"],
214
  session)
215
 
216
+ def capture_login(profile, oauth_token):
217
+ return profile, oauth_token
218
+
219
+
220
+ # — BUILD THE UI —
221
 
 
222
  with gr.Blocks(css="""
223
+ #sidebar {background:#f0f0f0;padding:1rem;border-right:1px solid #ccc;}
224
+ #main {padding:1rem;}
225
  """) as demo:
226
 
227
  with gr.Row():
228
+ # Sidebar
229
  with gr.Column(elem_id="sidebar", scale=1):
230
  gr.Markdown("### 🔑 HF Login & Config")
231
+ login_btn = gr.LoginButton(variant="huggingface", size="sm")
232
+ profile_state = gr.State()
233
+ token_state = gr.State()
234
+
235
+ login_btn.click(capture_login,
236
+ inputs=[login_btn],
237
+ outputs=[profile_state, token_state])
238
+
239
+ status_md = gr.Markdown("*Not logged in.*")
240
+ profile_state.change(show_profile,
241
+ inputs=[profile_state],
242
+ outputs=[status_md])
243
+
244
+ models_md = gr.Markdown()
245
+ profile_state.change(list_private_models,
246
+ inputs=[profile_state, token_state],
247
+ outputs=[models_md])
248
+
249
+ gemini_key = gr.Textbox(label="Gemini API Key", type="password")
250
+ sidebar_repo = gr.Textbox(label="Space name", placeholder="my-space")
251
  sidebar_sdk = gr.Radio(["gradio","streamlit"],
252
  value="gradio", label="SDK")
253
 
254
  gr.Markdown("---")
255
+ confirm_btn = gr.Button("🔄 Confirm Manual Changes")
256
 
257
+ # Main area
258
  with gr.Column(elem_id="main", scale=3):
259
  tabs = gr.Tabs()
260
  with tabs:
261
  with gr.TabItem("💬 Chat"):
262
+ chatbox = gr.Chatbot(type="pairs")
263
+ user_input = gr.Textbox(show_label=False,
264
+ placeholder="Ask the LLM…")
265
+ send_btn = gr.Button("Send")
266
  with gr.TabItem("🛠️ Manual"):
267
  gr.Markdown("#### Create a Space")
268
+ repo_m = gr.Textbox(label="Name")
269
+ sdk_m = gr.Radio(["gradio","streamlit"],
270
+ value="gradio", label="SDK")
271
+ create_btn = gr.Button("Create Space")
 
272
  sess_id = gr.Textbox(visible=False)
273
  log_c = gr.Textbox(label="Log",
274
+ interactive=False, lines=2)
275
+ preview = gr.HTML("<p>No Space yet.</p>")
276
 
 
 
 
277
  create_btn.click(create_space,
278
  inputs=[repo_m, sdk_m,
279
+ profile_state, token_state],
280
+ outputs=[sess_id, log_c, preview])
 
281
 
282
  gr.Markdown("#### Upload File")
283
+ path_in_repo = gr.Textbox(label="Path in Repo",
284
+ value="app.py")
285
+ file_uploader = gr.File()
286
+ up_btn = gr.Button("Upload File")
287
+ log_u = gr.Textbox(label="Log",
288
+ interactive=False, lines=2)
289
+
 
 
 
 
290
  up_btn.click(upload_file_to_space,
291
+ inputs=[file_uploader, path_in_repo,
292
+ sess_id,
293
+ profile_state, token_state],
294
  outputs=[log_u])
295
 
296
  gr.Markdown("#### Fetch Logs")
297
+ b_btn = gr.Button("Build Logs")
298
+ r_btn = gr.Button("Run Logs")
299
+ log_b = gr.Textbox(label="Build",
300
+ interactive=False, lines=5)
301
+ log_r = gr.Textbox(label="Run",
302
+ interactive=False, lines=5)
303
+
304
+ b_btn.click(get_build_logs,
305
+ inputs=[sess_id,
306
+ profile_state, token_state],
307
+ outputs=[log_b])
308
+ r_btn.click(get_container_logs,
309
+ inputs=[sess_id,
310
+ profile_state, token_state],
311
+ outputs=[log_r])
312
+
313
+ # Persistent panels
 
 
 
 
 
314
  gr.Markdown("---")
315
  iframe_out = gr.HTML(label="🖼️ Preview")
316
+ log_out = gr.Textbox(label="📋 Latest Log", lines=4)
 
317
  files_out = gr.Textbox(label="📚 Files", lines=4)
318
 
319
  state = gr.State({})
320
  send_btn.click(process_message,
321
+ inputs=[profile_state, token_state,
322
  user_input, gemini_key,
323
  sidebar_repo, sidebar_sdk,
324
  chatbox, state],
 
326
  log_out, files_out, state])
327
 
328
  confirm_btn.click(sync_manual,
329
+ inputs=[profile_state, token_state, state],
330
+ outputs=[iframe_out, log_out, files_out, state])
 
331
 
332
  if __name__ == "__main__":
333
  demo.launch()