wuhp commited on
Commit
248d55e
·
verified ·
1 Parent(s): c953990

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -109
app.py CHANGED
@@ -22,7 +22,7 @@ def list_private_models(
22
  ]
23
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
24
 
25
- # — LOG FETCHING
26
 
27
  def _get_space_jwt(repo_id: str):
28
  url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
@@ -45,10 +45,10 @@ def fetch_logs(repo_id: str, level: str):
45
  continue
46
  return "\n".join(lines)
47
 
48
- # — HANDLERS
49
 
50
  def handle_user_message(
51
- history, # list of dicts {"role","content"}
52
  sdk_choice: str,
53
  gemini_api_key: str,
54
  grounding_enabled: bool,
@@ -56,32 +56,36 @@ def handle_user_message(
56
  oauth_token: gr.OAuthToken | None
57
  ):
58
  if not (profile and oauth_token):
59
- return history + [{"role":"assistant","content":"⚠️ Please log in first."}], "", "", "<p>No Space yet.</p>", ""
60
 
61
  client = genai.Client(api_key=gemini_api_key)
62
- chat = [{
 
 
63
  "role":"system",
64
  "content":(
65
- f"You are an AI assistant writing a HuggingFace Space using the "
66
- f"{sdk_choice} SDK. After producing code, wait for logs; if errors appear, fix them."
 
 
 
 
 
67
  )
68
- }] + history
69
-
70
- # choose filenames
71
- code_fn = "app.py" if sdk_choice == "gradio" else "streamlit_app.py"
72
- readme_fn = "README.md"
73
- reqs_fn = "requirements.txt"
74
- repo_id = f"{profile.username}/{profile.username}-auto-space"
75
 
 
76
  build_logs = run_logs = ""
 
77
  for _ in range(5):
78
- # dynamic sdk_version
79
  if sdk_choice == "gradio":
80
  import gradio as _gr; sdk_version = _gr.__version__
81
  else:
82
  import streamlit as _st; sdk_version = _st.__version__
83
 
84
- # ask Gemini
85
  tools = [Tool(google_search=GoogleSearch())] if grounding_enabled else []
86
  cfg = GenerateContentConfig(tools=tools, response_modalities=["TEXT"])
87
  resp = client.models.generate_content(
@@ -89,60 +93,59 @@ def handle_user_message(
89
  contents=[m["content"] for m in chat],
90
  config=cfg
91
  )
92
- code = resp.text
93
- chat.append({"role":"assistant","content":code})
94
-
95
- # write code
96
- with open(code_fn, "w") as f:
97
- f.write(code)
98
-
99
- # write README.md
100
- with open(readme_fn, "w") as f:
101
- f.write(f"""---
102
- title: Wuhp Auto Space
103
- emoji: 🐢
104
- colorFrom: red
105
- colorTo: pink
106
- sdk: {sdk_choice}
107
- sdk_version: {sdk_version}
108
- app_file: {code_fn}
109
- pinned: false
110
- ---
111
-
112
- See config reference → https://huggingface.co/docs/hub/spaces-config-reference
113
- """)
114
-
115
- # write requirements
116
- base = "pandas\n"
117
- extra = ("streamlit\n" if sdk_choice=="streamlit" else "gradio\n")
118
- with open(reqs_fn, "w") as f:
119
- f.write(base + extra)
120
-
121
- # deploy
122
- create_repo(repo_id=repo_id,
123
- token=oauth_token.token,
124
- exist_ok=True,
125
- repo_type="space",
126
- space_sdk=sdk_choice)
127
- for fn in (code_fn, readme_fn, reqs_fn):
128
- upload_file(path_or_fileobj=fn,
129
- path_in_repo=fn,
130
- repo_id=repo_id,
131
- token=oauth_token.token,
132
- repo_type="space")
133
 
134
  # fetch logs
135
  build_logs = fetch_logs(repo_id, "build")
136
  run_logs = fetch_logs(repo_id, "run")
 
137
  if "ERROR" not in build_logs.upper() and "ERROR" not in run_logs.upper():
138
  break
139
 
 
140
  chat.append({
141
  "role":"user",
142
  "content":(
143
- f"Build logs:\n{build_logs}\n\n"
144
- f"Run logs:\n{run_logs}\n\n"
145
- "Please fix the code."
146
  )
147
  })
148
  time.sleep(2)
@@ -150,67 +153,38 @@ See config reference → https://huggingface.co/docs/hub/spaces-config-referen
150
  # prepare outputs
151
  messages = [{"role":m["role"],"content":m["content"]} for m in chat if m["role"]!="system"]
152
  iframe = f'<iframe src="https://huggingface.co/spaces/{repo_id}" width="100%" height="500px"></iframe>'
153
- return messages, build_logs, run_logs, iframe, repo_id
154
-
155
- def refresh_build_logs(repo_id: str, profile, oauth_token):
156
- if not (profile and oauth_token and repo_id):
157
- return "⚠️ Please deploy first."
158
- return fetch_logs(repo_id, "build")
159
 
160
- def refresh_run_logs(repo_id: str, profile, oauth_token):
161
- if not (profile and oauth_token and repo_id):
162
- return "⚠️ Please deploy first."
163
- return fetch_logs(repo_id, "run")
164
 
165
- # UI
 
 
 
166
 
167
- with gr.Blocks() as demo:
168
- gr.Markdown("## HF Space Auto‑Builder\n1. Sign in  2. Prompt  3. Deploy & Debug ►")
169
-
170
- # Login & model list
171
- login_btn = gr.LoginButton("huggingface", size="lg")
172
- status_md = gr.Markdown("*Not logged in.*")
173
- models_md = gr.Markdown()
174
  demo.load(show_profile, None, status_md)
175
  demo.load(list_private_models, None, models_md)
176
  login_btn.click(show_profile, None, status_md)
177
  login_btn.click(list_private_models, None, models_md)
178
 
179
- # Controls
180
- with gr.Row():
181
- sdk_choice = gr.Radio(["gradio","streamlit"], "gradio", label="SDK")
182
- api_key = gr.Textbox(label="Gemini API Key", type="password")
183
- grounding = gr.Checkbox(label="Enable grounding")
184
-
185
- # Chat + outputs
186
- chatbot = gr.Chatbot(type="messages")
187
- user_in = gr.Textbox(label="Prompt", placeholder="e.g. CSV inspector…")
188
- send_btn = gr.Button("Send")
189
- build_box = gr.Textbox(label="Build logs", lines=5)
190
- run_box = gr.Textbox(label="Run logs", lines=5)
191
- preview = gr.HTML("<p>No Space yet.</p>")
192
- state_repo = gr.Textbox(visible=False)
193
 
194
  send_btn.click(
195
  fn=handle_user_message,
196
  inputs=[chatbot, sdk_choice, api_key, grounding],
197
- outputs=[chatbot, build_box, run_box, preview, state_repo]
198
- )
199
-
200
- # Manual refresh
201
- with gr.Row():
202
- refresh_build = gr.Button("Refresh Build Logs")
203
- refresh_run = gr.Button("Refresh Run Logs")
204
-
205
- refresh_build.click(
206
- fn=refresh_build_logs,
207
- inputs=[state_repo],
208
- outputs=build_box
209
- )
210
- refresh_run.click(
211
- fn=refresh_run_logs,
212
- inputs=[state_repo],
213
- outputs=run_box
214
  )
215
 
216
  demo.launch()
 
22
  ]
23
  return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
24
 
25
+ # — HELPERS FOR HF SPACE LOGS
26
 
27
  def _get_space_jwt(repo_id: str):
28
  url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
 
45
  continue
46
  return "\n".join(lines)
47
 
48
+ # — CORE LOOP: ask LLM for JSON, write & deploy
49
 
50
  def handle_user_message(
51
+ history, # list of {"role","content"} dicts
52
  sdk_choice: str,
53
  gemini_api_key: str,
54
  grounding_enabled: bool,
 
56
  oauth_token: gr.OAuthToken | None
57
  ):
58
  if not (profile and oauth_token):
59
+ return history + [{"role":"assistant","content":"⚠️ Please log in first."}], "", "", "<p>No Space yet.</p>"
60
 
61
  client = genai.Client(api_key=gemini_api_key)
62
+
63
+ # System prompt: instruct JSON output
64
+ system_msg = {
65
  "role":"system",
66
  "content":(
67
+ "You are an AI assistant that generates all files needed for a HuggingFace Space.\n"
68
+ "Based on the user's prompt, return a **single JSON object** with keys:\n"
69
+ " • repo_name: string – the name of the new Space repo (no username).\n"
70
+ " • files: object mapping filenames to file contents (strings). \n"
71
+ " Required files: one code file (preferably app.py; if you choose a different name, update README.md),\n"
72
+ " README.md frontmatter (with title, sdk, sdk_version, app_file), and requirements.txt.\n"
73
+ "Do **NOT** return any explanatory text—only that JSON object.\n"
74
  )
75
+ }
76
+ chat = [system_msg] + history
 
 
 
 
 
77
 
78
+ repo_id = None
79
  build_logs = run_logs = ""
80
+
81
  for _ in range(5):
82
+ # dynamic version detection
83
  if sdk_choice == "gradio":
84
  import gradio as _gr; sdk_version = _gr.__version__
85
  else:
86
  import streamlit as _st; sdk_version = _st.__version__
87
 
88
+ # ask the LLM
89
  tools = [Tool(google_search=GoogleSearch())] if grounding_enabled else []
90
  cfg = GenerateContentConfig(tools=tools, response_modalities=["TEXT"])
91
  resp = client.models.generate_content(
 
93
  contents=[m["content"] for m in chat],
94
  config=cfg
95
  )
96
+ ai_text = resp.text
97
+ chat.append({"role":"assistant","content":ai_text})
98
+
99
+ # parse JSON
100
+ try:
101
+ spec = json.loads(ai_text)
102
+ repo_name = spec["repo_name"]
103
+ files = spec["files"]
104
+ except Exception as e:
105
+ # ask it to re-output valid JSON
106
+ chat.append({"role":"user","content":
107
+ "Your last response wasn't valid JSON. "
108
+ "Please reply with exactly the JSON object as specified."})
109
+ continue
110
+
111
+ repo_id = f"{profile.username}/{repo_name}"
112
+
113
+ # write & upload each file
114
+ create_repo(
115
+ repo_id=repo_id,
116
+ token=oauth_token.token,
117
+ exist_ok=True,
118
+ repo_type="space",
119
+ space_sdk=sdk_choice
120
+ )
121
+ for fn, content in files.items():
122
+ # fill in sdk_version into README if needed
123
+ if fn.lower() == "readme.md":
124
+ content = content.replace("<SDK_VERSION>", sdk_version)
125
+ with open(fn, "w") as f:
126
+ f.write(content)
127
+ upload_file(
128
+ path_or_fileobj=fn,
129
+ path_in_repo=fn,
130
+ repo_id=repo_id,
131
+ token=oauth_token.token,
132
+ repo_type="space"
133
+ )
 
 
 
134
 
135
  # fetch logs
136
  build_logs = fetch_logs(repo_id, "build")
137
  run_logs = fetch_logs(repo_id, "run")
138
+
139
  if "ERROR" not in build_logs.upper() and "ERROR" not in run_logs.upper():
140
  break
141
 
142
+ # feed errors back
143
  chat.append({
144
  "role":"user",
145
  "content":(
146
+ f"Deployment produced build logs:\n{build_logs}\n\n"
147
+ f"and run logs:\n{run_logs}\n\n"
148
+ "Please fix the code and output a new JSON spec."
149
  )
150
  })
151
  time.sleep(2)
 
153
  # prepare outputs
154
  messages = [{"role":m["role"],"content":m["content"]} for m in chat if m["role"]!="system"]
155
  iframe = f'<iframe src="https://huggingface.co/spaces/{repo_id}" width="100%" height="500px"></iframe>'
156
+ return messages, build_logs, run_logs, iframe
 
 
 
 
 
157
 
158
+ # BUILD THE UI —
 
 
 
159
 
160
+ with gr.Blocks(title="HF Space Auto‑Builder") as demo:
161
+ gr.Markdown("## Sign in + Auto‑Build Spaces\n\n"
162
+ "1. Sign in  2. Prompt  3. Deploy & Debug \n\n"
163
+ "*LLM will generate code, README, requirements, and iterate until successful.*\n\n---")
164
 
165
+ login_btn = gr.LoginButton("huggingface", size="lg")
166
+ status_md = gr.Markdown("*Not logged in.*")
167
+ models_md = gr.Markdown()
 
 
 
 
168
  demo.load(show_profile, None, status_md)
169
  demo.load(list_private_models, None, models_md)
170
  login_btn.click(show_profile, None, status_md)
171
  login_btn.click(list_private_models, None, models_md)
172
 
173
+ sdk_choice = gr.Radio(["gradio","streamlit"], "gradio", label="SDK")
174
+ api_key = gr.Textbox(label="Gemini API Key", type="password")
175
+ grounding = gr.Checkbox(label="Enable grounding")
176
+
177
+ chatbot = gr.Chatbot(type="messages")
178
+ user_in = gr.Textbox(label="Prompt", placeholder="e.g. Build a CSV inspector…")
179
+ send_btn = gr.Button("Send")
180
+ build_box = gr.Textbox(label="Build logs", lines=5)
181
+ run_box = gr.Textbox(label="Run logs", lines=5)
182
+ preview = gr.HTML("<p>No Space yet.</p>")
 
 
 
 
183
 
184
  send_btn.click(
185
  fn=handle_user_message,
186
  inputs=[chatbot, sdk_choice, api_key, grounding],
187
+ outputs=[chatbot, build_box, run_box, preview]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  )
189
 
190
  demo.launch()