wuhp commited on
Commit
03a7726
·
verified ·
1 Parent(s): 4e09d57

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -45
app.py CHANGED
@@ -82,7 +82,7 @@ def check_iframe(url: str, timeout: int = 5) -> bool:
82
  except:
83
  return False
84
 
85
- # — CORE LOOP —
86
 
87
  def handle_user_message(
88
  history,
@@ -97,21 +97,33 @@ def handle_user_message(
97
  if not profile or not oauth_token:
98
  return history + [{"role":"assistant","content":"⚠️ Please log in first."}], "", "", "<p>No Space yet.</p>"
99
 
100
- client = genai.Client(api_key=gemini_api_key)
101
- code_fn = "app.py" if sdk_choice=="gradio" else "streamlit_app.py"
102
- repo_id = f"{profile.username}/{profile.username}-auto-space"
103
  iframe_url = f"https://huggingface.co/spaces/{repo_id}"
104
 
105
- system_msg = {
 
106
  "role":"system",
107
  "content":(
108
- f"You are an AI assistant that scaffolds a complete HuggingFace Space using the "
109
- f"{sdk_choice} SDK. **Respond with exactly one markdown code block** containing the "
110
- f"entire contents of `{code_fn}`—no extra commentary or version hints. After that, "
111
- "wait for logs; if errors appear, fix the code and re-output the full code block."
112
  )
113
  }
114
- chat = [system_msg] + history
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  build_logs = run_logs = ""
117
  backoff = 1
@@ -125,28 +137,28 @@ def handle_user_message(
125
  max_output_tokens=max_output_tokens,
126
  )
127
 
128
- # generate code
129
- resp = client.models.generate_content(
130
  model="gemini-2.5-flash-preview-04-17",
131
- contents=[m["content"] for m in chat],
132
  config=cfg
133
  )
134
- code = extract_code(resp.text)
135
- chat.append({"role":"assistant","content":code})
 
136
 
137
- # local syntax check
138
  try:
139
  compile(code, code_fn, "exec")
140
  except SyntaxError as e:
141
- chat.append({
142
  "role":"user",
143
- "content": f"SyntaxError caught: {e}. Please output the corrected `{code_fn}` code block only."
144
  })
145
- time.sleep(backoff)
146
- backoff = min(backoff*2, 30)
147
  continue
148
 
149
- # write files
150
  sdk_version = get_sdk_version(sdk_choice)
151
  files = {
152
  code_fn: code,
@@ -158,8 +170,6 @@ sdk_version: {sdk_version}
158
  app_file: {code_fn}
159
  pinned: false
160
  ---
161
-
162
- See https://huggingface.co/docs/hub/spaces-config-reference
163
  """,
164
  "requirements.txt": "pandas\n" + ("streamlit\n" if sdk_choice=="streamlit" else "gradio\n")
165
  }
@@ -167,46 +177,59 @@ See https://huggingface.co/docs/hub/spaces-config-reference
167
  with open(fn, "w") as f:
168
  f.write(content)
169
 
170
- # push to HF
171
  create_repo(repo_id=repo_id, token=oauth_token.token,
172
  exist_ok=True, repo_type="space", space_sdk=sdk_choice)
173
  for fn in files:
174
  upload_file(
175
- path_or_fileobj=fn,
176
- path_in_repo=fn,
177
- repo_id=repo_id,
178
- token=oauth_token.token,
179
  repo_type="space"
180
  )
181
 
182
  # fetch logs
183
  build_logs = fetch_logs(repo_id, "build")
184
  run_logs = fetch_logs(repo_id, "run")
185
- errors = classify_errors(build_logs + "\n" + run_logs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
 
187
  if "ERROR" not in build_logs.upper() and \
188
  "ERROR" not in run_logs.upper() and \
189
  check_iframe(iframe_url):
190
  break
191
 
192
- chat.append({
 
193
  "role":"user",
194
- "content":(
195
- f"Attempt {attempt} had {errors} errors.\n"
196
- f"Build logs:\n{build_logs}\n\n"
197
- f"Run logs:\n{run_logs}\n\n"
198
- f"Please output the full corrected `{code_fn}` code block only, "
199
- f"and ensure the iframe at {iframe_url} returns HTTP 200."
200
- )
201
  })
202
- time.sleep(backoff)
203
- backoff = min(backoff*2, 30)
204
 
205
- messages = [{"role":m["role"],"content":m["content"]} for m in chat if m["role"]!="system"]
 
 
 
 
206
  iframe_html = (
207
  f'<iframe src="{iframe_url}" width="100%" height="500px"></iframe>'
208
- + ("" if check_iframe(iframe_url) else
209
- "<p style='color:red;'>⚠️ iframe not responding.</p>")
210
  )
211
  return messages, build_logs, run_logs, iframe_html
212
 
@@ -249,9 +272,9 @@ with gr.Blocks(title="HF Space Auto‑Builder") as demo:
249
 
250
  refresh_btn = gr.Button("Refresh Logs")
251
  refresh_btn.click(
252
- fn=lambda profile,token: (
253
- fetch_logs(f"{profile.username}/{profile.username}-auto-space","build"),
254
- fetch_logs(f"{profile.username}/{profile.username}-auto-space","run")
255
  ),
256
  outputs=[build_box, run_box]
257
  )
 
82
  except:
83
  return False
84
 
85
+ # — CORE LOOP WITH TWO AGENTS
86
 
87
  def handle_user_message(
88
  history,
 
97
  if not profile or not oauth_token:
98
  return history + [{"role":"assistant","content":"⚠️ Please log in first."}], "", "", "<p>No Space yet.</p>"
99
 
100
+ client = genai.Client(api_key=gemini_api_key)
101
+ code_fn = "app.py" if sdk_choice=="gradio" else "streamlit_app.py"
102
+ repo_id = f"{profile.username}/{profile.username}-auto-space"
103
  iframe_url = f"https://huggingface.co/spaces/{repo_id}"
104
 
105
+ # SYSTEM PROMPTS —
106
+ system_code = {
107
  "role":"system",
108
  "content":(
109
+ "You are **Code‑Gen Agent**, a proactive AI developer. Your sole responsibility is to author "
110
+ f"and correct the entire `{code_fn}` file in a single markdown code block—no extra commentary. "
111
+ "You have permission to edit files, push updates to the HF Space, and optimize code. "
112
+ "After each push, await build & run logs before making further changes."
113
  )
114
  }
115
+ system_debug = {
116
+ "role":"system",
117
+ "content":(
118
+ "You are **Debug Agent**, a meticulous code reviewer. You can read all files, logs, and the app "
119
+ "preview, but you **cannot** modify or push code. Your task is to analyze the latest code + logs "
120
+ "and return concise, actionable feedback or “All clear.”"
121
+ )
122
+ }
123
+
124
+ # initialize each agent’s conversation
125
+ code_chat = [system_code] + history[:]
126
+ debug_chat = [system_debug] + history[:]
127
 
128
  build_logs = run_logs = ""
129
  backoff = 1
 
137
  max_output_tokens=max_output_tokens,
138
  )
139
 
140
+ # --- 1) Code‑Gen generates or updates code ---
141
+ resp_code = client.models.generate_content(
142
  model="gemini-2.5-flash-preview-04-17",
143
+ contents=[m["content"] for m in code_chat],
144
  config=cfg
145
  )
146
+ code = extract_code(resp_code.text)
147
+ code_chat.append({"role":"assistant","content":code})
148
+ debug_chat.append({"role":"assistant","content":code})
149
 
150
+ # quick syntax check
151
  try:
152
  compile(code, code_fn, "exec")
153
  except SyntaxError as e:
154
+ code_chat.append({
155
  "role":"user",
156
+ "content": f"SyntaxError caught: {e}. Please correct `{code_fn}` only."
157
  })
158
+ time.sleep(backoff); backoff = min(backoff*2, 30)
 
159
  continue
160
 
161
+ # write & push to HF Space
162
  sdk_version = get_sdk_version(sdk_choice)
163
  files = {
164
  code_fn: code,
 
170
  app_file: {code_fn}
171
  pinned: false
172
  ---
 
 
173
  """,
174
  "requirements.txt": "pandas\n" + ("streamlit\n" if sdk_choice=="streamlit" else "gradio\n")
175
  }
 
177
  with open(fn, "w") as f:
178
  f.write(content)
179
 
 
180
  create_repo(repo_id=repo_id, token=oauth_token.token,
181
  exist_ok=True, repo_type="space", space_sdk=sdk_choice)
182
  for fn in files:
183
  upload_file(
184
+ path_or_fileobj=fn, path_in_repo=fn,
185
+ repo_id=repo_id, token=oauth_token.token,
 
 
186
  repo_type="space"
187
  )
188
 
189
  # fetch logs
190
  build_logs = fetch_logs(repo_id, "build")
191
  run_logs = fetch_logs(repo_id, "run")
192
+ err_types = classify_errors(build_logs + "\n" + run_logs)
193
+
194
+ # --- 2) Debug‑Agent reviews code & logs ---
195
+ debug_input = (
196
+ f"🏷 **Attempt {attempt}**\n"
197
+ f"Error types: {err_types}\n\n"
198
+ f"**Build logs:**\n{build_logs}\n\n"
199
+ f"**Run logs:**\n{run_logs}\n\n"
200
+ "If there are no errors, reply “All clear.” Otherwise, list your recommended changes."
201
+ )
202
+ debug_chat.append({"role":"user","content":debug_input})
203
+ resp_debug = client.models.generate_content(
204
+ model="gemini-2.5-flash-preview-04-17",
205
+ contents=[m["content"] for m in debug_chat],
206
+ config=cfg
207
+ )
208
+ feedback = resp_debug.text.strip()
209
+ debug_chat.append({"role":"assistant","content":feedback})
210
 
211
+ # check for success
212
  if "ERROR" not in build_logs.upper() and \
213
  "ERROR" not in run_logs.upper() and \
214
  check_iframe(iframe_url):
215
  break
216
 
217
+ # feed debug feedback back to Code‑Gen
218
+ code_chat.append({
219
  "role":"user",
220
+ "content": f"🔧 Debug feedback:\n{feedback}\nPlease output the full corrected `{code_fn}` code block only."
 
 
 
 
 
 
221
  })
222
+ time.sleep(backoff); backoff = min(backoff*2, 30)
 
223
 
224
+ # prepare UI outputs
225
+ messages = [
226
+ {"role": m["role"], "content": m["content"]}
227
+ for m in code_chat if m["role"] != "system"
228
+ ]
229
  iframe_html = (
230
  f'<iframe src="{iframe_url}" width="100%" height="500px"></iframe>'
231
+ + ("" if check_iframe(iframe_url)
232
+ else "<p style='color:red;'>⚠️ iframe not responding.</p>")
233
  )
234
  return messages, build_logs, run_logs, iframe_html
235
 
 
272
 
273
  refresh_btn = gr.Button("Refresh Logs")
274
  refresh_btn.click(
275
+ fn=lambda profile, token: (
276
+ fetch_logs(f"{profile.username}/{profile.username}-auto-space", "build"),
277
+ fetch_logs(f"{profile.username}/{profile.username}-auto-space", "run")
278
  ),
279
  outputs=[build_box, run_box]
280
  )