wuhp commited on
Commit
5a807ae
·
verified ·
1 Parent(s): 2157587

Update hfmaker.py

Browse files
Files changed (1) hide show
  1. hfmaker.py +137 -192
hfmaker.py CHANGED
@@ -1,228 +1,173 @@
1
  import gradio as gr
2
- import requests
3
- import json
4
- from huggingface_hub import (
5
- create_repo,
6
- list_models,
7
- upload_file,
8
- constants,
9
- )
10
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
 
 
11
 
12
- # — USER INFO & MODEL LISTING —
13
 
14
  def show_profile(profile: gr.OAuthProfile | None) -> str:
15
  if profile is None:
16
  return "*Not logged in.*"
17
  return f"✅ Logged in as **{profile.username}**"
18
 
19
- def list_private_models(
20
- profile: gr.OAuthProfile | None,
21
- oauth_token: gr.OAuthToken | None
22
- ) -> str:
23
- if profile is None or oauth_token is None:
24
- return "Please log in to see your models."
25
- models = [
26
- f"{m.id} ({'private' if m.private else 'public'})"
27
- for m in list_models(author=profile.username, token=oauth_token.token)
28
- ]
29
- return "No models found." if not models else "Models:\n\n" + "\n - ".join(models)
30
-
31
- # — BUTTON‑ENABLING HELPERS —
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
- # — CORE ACTIONS —
47
-
48
- def create_space(
49
- repo_name: str,
50
- sdk: str,
51
- profile: gr.OAuthProfile | None,
52
- oauth_token: gr.OAuthToken | None
53
- ) -> tuple[str, str, str]:
54
- if not profile or not oauth_token:
55
- return "", "⚠️ Please log in first.", "<p>No Space created yet.</p>"
56
- repo_id = f"{profile.username}/{repo_name}"
57
- create_repo(
58
- repo_id=repo_id,
59
- token=oauth_token.token,
60
- exist_ok=True,
61
- repo_type="space",
62
- space_sdk=sdk
63
- )
64
- url = f"https://huggingface.co/spaces/{repo_id}"
65
- logmsg = f"✅ Space ready: {url} (SDK: {sdk})"
66
- iframe = f'<iframe src="{url}" width="100%" height="500px"></iframe>'
67
- return repo_id, logmsg, iframe
68
-
69
- def upload_file_to_space(
70
- file,
71
- path_in_repo: str,
72
- repo_id: str,
73
- profile: gr.OAuthProfile | None,
74
- oauth_token: gr.OAuthToken | None
75
- ) -> str:
76
- if not profile or not oauth_token:
77
- return "⚠️ Please log in first."
78
- if not repo_id:
79
- return "⚠️ Please create a Space first."
80
- if not file:
81
- return "⚠️ No file selected."
82
- upload_file(
83
- path_or_fileobj=file.name,
84
- path_in_repo=path_in_repo,
85
- repo_id=repo_id,
86
- token=oauth_token.token,
87
- repo_type="space"
88
- )
89
- return f"✅ Uploaded `{path_in_repo}` to `{repo_id}`"
90
-
91
- def _fetch_space_logs_level(repo_id: str, level: str) -> str:
92
- # 1) Get SSE JWT
93
- jwt_url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
94
- r = get_session().get(jwt_url, headers=build_hf_headers())
95
  hf_raise_for_status(r)
96
- jwt = r.json()["token"]
97
- # 2) Stream logs
 
 
98
  logs_url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
99
  lines = []
100
  with get_session().get(logs_url, headers=build_hf_headers(token=jwt), stream=True) as resp:
101
  hf_raise_for_status(resp)
102
  for raw in resp.iter_lines():
103
- if not raw.startswith(b"data: "):
104
- continue
105
- payload = raw[len(b"data: "):]
106
- try:
107
- event = json.loads(payload.decode())
108
- except json.JSONDecodeError:
109
- continue
110
- ts = event.get("timestamp", "")
111
- txt = event.get("data", "")
112
- lines.append(f"[{ts}] {txt}")
113
  return "\n".join(lines)
114
 
115
- def get_build_logs(
116
- repo_id: str,
117
- profile: gr.OAuthProfile | None,
118
- oauth_token: gr.OAuthToken | None
119
- ) -> str:
120
- if not (profile and oauth_token and repo_id):
121
- return "⚠️ Please log in and create a Space first."
122
- return _fetch_space_logs_level(repo_id, "build")
123
 
124
- def get_container_logs(
125
- repo_id: str,
 
 
 
126
  profile: gr.OAuthProfile | None,
127
  oauth_token: gr.OAuthToken | None
128
- ) -> str:
129
- if not (profile and oauth_token and repo_id):
130
- return "⚠️ Please log in and create a Space first."
131
- return _fetch_space_logs_level(repo_id, "run")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
  # — BUILD THE UI —
134
 
135
- with gr.Blocks(title="HF OAuth + Space Manager with Logs") as demo:
136
- gr.Markdown(
137
- "## Sign in with Hugging Face + Manage Your Space\n\n"
138
- "1. Sign in\n"
139
- "2. Create a Space (Gradio/Streamlit)\n"
140
- "3. Upload files to it\n"
141
- "4. Fetch build and container logs\n\n"
142
- "---"
143
- )
144
 
145
- # — LOGIN & MODEL LIST
146
  login_btn = gr.LoginButton(variant="huggingface", size="lg")
147
  status_md = gr.Markdown("*Not logged in.*")
148
- models_md = gr.Markdown()
149
  demo.load(show_profile, inputs=None, outputs=status_md)
150
  login_btn.click(show_profile, inputs=None, outputs=status_md)
151
- demo.load(list_private_models, inputs=None, outputs=models_md)
152
- login_btn.click(list_private_models,
153
- inputs=None, outputs=models_md)
154
 
155
- # — CREATE SPACE
156
- repo_name = gr.Textbox(label="New Space name", placeholder="my-space")
157
- sdk_selector = gr.Radio(
158
  choices=["gradio","streamlit"],
159
  value="gradio",
160
- label="Space template (SDK)"
161
- )
162
- create_btn = gr.Button("Create Space", interactive=False)
163
- session_id = gr.Textbox(visible=False)
164
- create_logs = gr.Textbox(label="Create Logs", interactive=False, lines=3)
165
- preview = gr.HTML("<p>No Space created yet.</p>")
166
-
167
- demo.load(enable_create, inputs=None, outputs=[create_btn])
168
- login_btn.click(enable_create, inputs=None, outputs=[create_btn])
169
-
170
- create_btn.click(
171
- fn=create_space,
172
- inputs=[repo_name, sdk_selector],
173
- outputs=[session_id, create_logs, preview]
174
- )
175
-
176
- # — UPLOAD FILES —
177
- path_in_repo = gr.Textbox(label="Path in Space", value="app.py")
178
- file_uploader = gr.File(label="Select file")
179
- upload_btn = gr.Button("Upload File", interactive=False)
180
- upload_logs = gr.Textbox(label="Upload Logs", interactive=False, lines=2)
181
-
182
- demo.load(enable_repo_actions,
183
- inputs=[session_id],
184
- outputs=[upload_btn])
185
- login_btn.click(enable_repo_actions,
186
- inputs=[session_id],
187
- outputs=[upload_btn])
188
- session_id.change(enable_repo_actions,
189
- inputs=[session_id],
190
- outputs=[upload_btn])
191
-
192
- upload_btn.click(
193
- fn=upload_file_to_space,
194
- inputs=[file_uploader, path_in_repo, session_id],
195
- outputs=[upload_logs]
196
- )
197
-
198
- # — FETCH BUILD & CONTAINER LOGS —
199
- build_logs_btn = gr.Button("Get Build Logs", interactive=False)
200
- container_logs_btn = gr.Button("Get Container Logs", interactive=False)
201
- build_logs_md = gr.Textbox(label="Build Logs", interactive=False, lines=10)
202
- container_logs_md = gr.Textbox(label="Container Logs", interactive=False, lines=10)
203
-
204
- # enable both log buttons
205
- for btn in (build_logs_btn, container_logs_btn):
206
- demo.load(enable_repo_actions,
207
- inputs=[session_id],
208
- outputs=[btn])
209
- login_btn.click(enable_repo_actions,
210
- inputs=[session_id],
211
- outputs=[btn])
212
- session_id.change(enable_repo_actions,
213
- inputs=[session_id],
214
- outputs=[btn])
215
-
216
- build_logs_btn.click(
217
- fn=get_build_logs,
218
- inputs=[session_id],
219
- outputs=[build_logs_md]
220
  )
221
- container_logs_btn.click(
222
- fn=get_container_logs,
223
- inputs=[session_id],
224
- outputs=[container_logs_md]
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  )
226
 
227
- if __name__ == "__main__":
228
  demo.launch()
 
1
  import gradio as gr
2
+ import json, time
3
+ from huggingface_hub import create_repo, upload_file, constants
 
 
 
 
 
 
4
  from huggingface_hub.utils import build_hf_headers, get_session, hf_raise_for_status
5
+ from google import genai # Gemini Python SDK
6
+ from google.genai.types import Tool, GenerateContentConfig, GoogleSearch
7
 
8
+ # — USER INFO & MODEL LISTING (from your reference)
9
 
10
  def show_profile(profile: gr.OAuthProfile | None) -> str:
11
  if profile is None:
12
  return "*Not logged in.*"
13
  return f"✅ Logged in as **{profile.username}**"
14
 
15
+ # — HELPERS FOR HF SPACE LOGS —
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ def _get_space_jwt(repo_id: str):
18
+ url = f"{constants.ENDPOINT}/api/spaces/{repo_id}/jwt"
19
+ r = get_session().get(url, headers=build_hf_headers())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  hf_raise_for_status(r)
21
+ return r.json()["token"]
22
+
23
+ def fetch_logs(repo_id: str, level: str):
24
+ jwt = _get_space_jwt(repo_id)
25
  logs_url = f"https://api.hf.space/v1/{repo_id}/logs/{level}"
26
  lines = []
27
  with get_session().get(logs_url, headers=build_hf_headers(token=jwt), stream=True) as resp:
28
  hf_raise_for_status(resp)
29
  for raw in resp.iter_lines():
30
+ if raw.startswith(b"data: "):
31
+ try:
32
+ ev = json.loads(raw[len(b"data: "):].decode())
33
+ ts = ev.get("timestamp","")
34
+ txt = ev.get("data","")
35
+ lines.append(f"[{ts}] {txt}")
36
+ except:
37
+ continue
 
 
38
  return "\n".join(lines)
39
 
40
+ # — CORE LOOP: send prompt & (iteratively) deploy —
 
 
 
 
 
 
 
41
 
42
+ def handle_user_message(
43
+ history, # list of {"role","content"} dicts
44
+ sdk_choice: str,
45
+ gemini_api_key: str,
46
+ grounding_enabled: bool,
47
  profile: gr.OAuthProfile | None,
48
  oauth_token: gr.OAuthToken | None
49
+ ):
50
+ # require login
51
+ if profile is None or oauth_token is None:
52
+ return history + [{"role":"assistant","content":"⚠️ Please log in first."}], "", "", "<p>No Space yet.</p>"
53
+
54
+ # initialize Gemini
55
+ genai_client = genai.Client(api_key=gemini_api_key)
56
+
57
+ # build the prompt history (including a system instruction)
58
+ chat = [{
59
+ "role":"system",
60
+ "content":(
61
+ f"You are an AI assistant that writes a HuggingFace Space using the "
62
+ f"{sdk_choice} SDK. After producing code, wait for logs. "
63
+ "If errors appear, fix them and return the full updated code."
64
+ )
65
+ }] + history
66
+
67
+ filename = "app.py" if sdk_choice=="gradio" else "streamlit_app.py"
68
+ build_logs = run_logs = ""
69
+
70
+ for _ in range(5):
71
+ # assemble tools
72
+ tools = []
73
+ if grounding_enabled:
74
+ tools.append(Tool(google_search=GoogleSearch()))
75
+
76
+ config = GenerateContentConfig(
77
+ tools=tools,
78
+ response_modalities=["TEXT"],
79
+ )
80
+
81
+ # call Gemini
82
+ response = genai_client.models.generate_content(
83
+ model="gemini-2.5-flash-preview-04-17",
84
+ contents=[m["content"] for m in chat],
85
+ config=config
86
+ )
87
+ ai_code = response.text
88
+ chat.append({"role":"assistant", "content": ai_code})
89
+
90
+ # write & deploy
91
+ with open(filename, "w") as f:
92
+ f.write(ai_code)
93
+
94
+ repo_id = f"{profile.username}/{profile.username}-auto-space"
95
+ create_repo(
96
+ repo_id=repo_id,
97
+ token=oauth_token.token,
98
+ exist_ok=True,
99
+ repo_type="space",
100
+ space_sdk=sdk_choice
101
+ )
102
+ upload_file(
103
+ path_or_fileobj=filename,
104
+ path_in_repo=filename,
105
+ repo_id=repo_id,
106
+ token=oauth_token.token,
107
+ repo_type="space"
108
+ )
109
+
110
+ # fetch build & run logs
111
+ build_logs = fetch_logs(repo_id, "build")
112
+ run_logs = fetch_logs(repo_id, "run")
113
+
114
+ # if no errors, stop looping
115
+ if "ERROR" not in build_logs.upper() and "ERROR" not in run_logs.upper():
116
+ break
117
+
118
+ # otherwise feed logs back to Gemini
119
+ chat.append({
120
+ "role":"user",
121
+ "content":(
122
+ f"Build logs:\n{build_logs}\n\n"
123
+ f"Run logs:\n{run_logs}\n\n"
124
+ "Please fix the code."
125
+ )
126
+ })
127
+ time.sleep(2)
128
+
129
+ # prepare outputs for gr.Chatbot(type="messages")
130
+ messages = [{"role":m["role"], "content":m["content"]} for m in chat if m["role"]!="system"]
131
+ iframe = f'<iframe src="https://huggingface.co/spaces/{repo_id}" width="100%" height="500px"></iframe>'
132
+ return messages, build_logs, run_logs, iframe
133
 
134
  # — BUILD THE UI —
135
 
136
+ with gr.Blocks(title="HF Space Auto‑Builder (Gradio & Streamlit)") as demo:
137
+ gr.Markdown("## Sign in with Hugging Face + Auto‑Build Spaces\n\n"
138
+ "1. Sign in\n2. Enter your prompt\n3. Watch the code deploy & debug itself\n\n---")
 
 
 
 
 
 
139
 
140
+ # — LOGIN —
141
  login_btn = gr.LoginButton(variant="huggingface", size="lg")
142
  status_md = gr.Markdown("*Not logged in.*")
143
+ # automatically show profile on load & login
144
  demo.load(show_profile, inputs=None, outputs=status_md)
145
  login_btn.click(show_profile, inputs=None, outputs=status_md)
 
 
 
146
 
147
+ # — SIDEBAR CONTROLS
148
+ sdk_choice = gr.Radio(
 
149
  choices=["gradio","streamlit"],
150
  value="gradio",
151
+ label="SDK template"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  )
153
+ api_key = gr.Textbox(label="Gemini API Key", type="password")
154
+ grounding = gr.Checkbox(label="Enable grounding", value=False)
155
+
156
+ # — CHAT INTERFACE & OUTPUTS —
157
+ chatbot = gr.Chatbot(type="messages")
158
+ user_in = gr.Textbox(placeholder="e.g. Generate me a blurtest app…", label="Prompt")
159
+ send_btn = gr.Button("Send")
160
+
161
+ build_box = gr.Textbox(label="Build logs", lines=5, interactive=False)
162
+ run_box = gr.Textbox(label="Run logs", lines=5, interactive=False)
163
+ preview = gr.HTML("<p>No Space yet.</p>")
164
+
165
+ # wire up the Send button
166
+ send_btn.click(
167
+ fn=handle_user_message,
168
+ inputs=[chatbot, sdk_choice, api_key, grounding],
169
+ outputs=[chatbot, build_box, run_box, preview]
170
  )
171
 
172
+ if __name__=="__main__":
173
  demo.launch()