wuhp commited on
Commit
8e720f5
·
verified ·
1 Parent(s): 17e2ef6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -163
app.py CHANGED
@@ -1,180 +1,54 @@
1
- import os
2
- import json
3
  import uuid
4
- from typing import Any, Dict, Tuple
5
-
6
  import gradio as gr
7
- from huggingface_hub import create_repo, HfApi
8
- from google import genai
9
- from google.genai import types
10
- from google.genai.types import Tool, GoogleSearch
11
-
12
- # -----------------------------------------------------------------------------
13
- # Configuration
14
- # -----------------------------------------------------------------------------
15
- MODEL_ID = "gemini-2.5-flash-preview-04-17"
16
- WORKSPACE_DIR = "workspace"
17
- SYSTEM_INSTRUCTION = (
18
- "You are a helpful coding assistant that scaffolds a complete Hugging Face Space app. "
19
- "Based on the user's request, decide between Gradio or Streamlit (whichever fits best), "
20
- "and respond with exactly one JSON object with keys:\n"
21
- " • \"framework\": either \"gradio\" or \"streamlit\"\n"
22
- " • \"files\": a map of relative file paths to file contents\n"
23
- " • \"message\": a human‑readable summary\n"
24
- "Do not include extra text or markdown."
25
- )
26
-
27
- state_store: Dict[str, Dict[str, Any]] = {}
28
-
29
- def start_app(
30
- gemini_key: str,
31
- hf_token: str,
32
- hf_username: str,
33
- repo_name: str
34
- ) -> Dict[str, Any]:
35
- os.makedirs(WORKSPACE_DIR, exist_ok=True)
36
- client = genai.Client(api_key=gemini_key)
37
- config = types.GenerateContentConfig(system_instruction=SYSTEM_INSTRUCTION)
38
- tools = [Tool(google_search=GoogleSearch())]
39
- chat = client.chats.create(model=MODEL_ID, config=config, tools=tools)
40
- local_path = os.path.join(WORKSPACE_DIR, repo_name)
41
- os.makedirs(local_path, exist_ok=True)
42
- return {
43
- "chat": chat,
44
- "hf_token": hf_token,
45
- "hf_username": hf_username,
46
- "repo_name": repo_name,
47
- "created": False,
48
- "repo_id": None,
49
- "local_path": local_path,
50
- "embed_url": None,
51
- "logs": [f"Initialized workspace at {WORKSPACE_DIR}/{repo_name}."]
52
- }
53
-
54
- def handle_message(user_msg: str, state: Dict[str, Any]) -> Tuple[str, Dict[str, Any]]:
55
- chat = state["chat"]
56
- logs = state.setdefault("logs", [])
57
- logs.append(f"> **User**: {user_msg}")
58
- resp = chat.send_message(user_msg)
59
- logs.append("Received response from Gemini.")
60
-
61
- try:
62
- data = json.loads(resp.text)
63
- framework = data["framework"]
64
- files = data.get("files", {})
65
- reply = data.get("message", "")
66
- except Exception:
67
- logs.append("⚠️ Failed to parse assistant JSON.\n" + resp.text)
68
- return "⚠️ Parsing error. Check logs.", state
69
 
70
- if not state["created"]:
71
- full_repo = f"{state['hf_username']}/{state['repo_name']}"
72
- create_repo(
73
- repo_id=full_repo,
74
- token=state["hf_token"],
75
- exist_ok=True,
76
- repo_type="space",
77
- space_sdk=framework,
78
- )
79
- state.update({
80
- "created": True,
81
- "repo_id": full_repo,
82
- "embed_url": f"https://huggingface.co/spaces/{full_repo}",
83
- })
84
-
85
- if files:
86
- logs.append(f"Writing {len(files)} file(s): {list(files)}")
87
- for relpath, content in files.items():
88
- dest = os.path.join(state["local_path"], relpath)
89
- os.makedirs(os.path.dirname(dest), exist_ok=True)
90
- with open(dest, "w", encoding="utf‑8") as fp:
91
- fp.write(content)
92
-
93
- HfApi(token=state["hf_token"]).upload_folder(
94
- folder_path=state["local_path"],
95
- repo_id=state["repo_id"],
96
- repo_type="space",
97
- )
98
- logs.append("Snapshot upload complete.")
99
- return reply, state
100
 
101
- with gr.Blocks(title="Gemini → HF Space scaffolder") as demo:
102
- # 1) OAuth button + status
103
- login_btn = gr.LoginButton(variant="huggingface", size="lg") # displays "Sign in with Hugging Face"
104
  status_md = gr.Markdown("*Not logged in.*")
105
 
106
- # 2) show_profile called on load & login/logout
107
  def show_profile(profile: gr.OAuthProfile | None) -> str:
108
  return "*Not logged in.*" if profile is None else f"Logged in as **{profile.username}**"
109
 
110
- # Trigger on page load and when login button is clicked
111
  demo.load(fn=show_profile, inputs=None, outputs=[status_md])
112
  login_btn.click(fn=show_profile, inputs=None, outputs=[status_md])
113
 
114
- with gr.Row():
115
- with gr.Column(scale=1):
116
- gemini_key = gr.Textbox(label="Gemini API Key", type="password")
117
- repo_name = gr.Textbox(label="New App (repo) name")
118
- session_id = gr.Textbox(value="", visible=False)
119
- start_btn = gr.Button("Start a new app")
120
- with gr.Column(scale=3):
121
- chatbot = gr.Chatbot(type="messages", value=[])
122
- logs_display = gr.Textbox(label="Operation Logs", interactive=False, lines=8)
123
- preview_iframe = gr.HTML("<p>No deployed app yet.</p>")
124
- user_msg = gr.Textbox(label="Your message")
125
- send_btn = gr.Button("Send", interactive=False)
126
 
127
- # 3) on_start: triggered by "Start a new app"
128
- def on_start(
129
- evt,
130
- gemini_key: str,
131
- repo_name: str,
132
- oauth_token: gr.OAuthToken | None
133
- ):
134
- if oauth_token is None:
135
- return gr.Error("Please *Sign in with Hugging Face* first."), "", "", gr.update(interactive=False)
136
- hf_username = oauth_token.user_info["username"]
137
- new_id = str(uuid.uuid4())
138
- state_store[new_id] = start_app(gemini_key, oauth_token.token, hf_username, repo_name)
139
- logs = "\n".join(state_store[new_id]["logs"])
140
- return new_id, logs, "<p>Awaiting first instruction…</p>", gr.update(interactive=True)
141
-
142
- start_btn.click(
143
- on_start,
144
- inputs=[gemini_key, repo_name, login_btn], # pass login_btn to provide OAuthToken
145
- outputs=[session_id, logs_display, preview_iframe, send_btn],
146
- )
147
-
148
- # 4) Handle user messages
149
- def on_send(
150
- msg: str,
151
- chat_history: list[dict],
152
- sess_id: str
153
- ) -> Tuple[list[dict], str, str, str]:
154
- if not sess_id or sess_id not in state_store:
155
- return [], sess_id, "", ""
156
- reply, new_state = handle_message(msg, state_store[sess_id])
157
- state_store[sess_id] = new_state
158
-
159
- history = chat_history or []
160
- history.append({"role": "user", "content": msg})
161
- history.append({"role": "assistant", "content": reply})
162
-
163
- logs = "\n".join(new_state["logs"])
164
- embed = ""
165
- if new_state.get("embed_url"):
166
- embed = f'<iframe src="{new_state["embed_url"]}" width="100%" height="500px"></iframe>'
167
- return history, sess_id, logs, embed
168
 
169
- send_btn.click(
170
- on_send,
171
- inputs=[user_msg, chatbot, session_id],
172
- outputs=[chatbot, session_id, logs_display, preview_iframe],
173
- )
174
- user_msg.submit(
175
- on_send,
176
- inputs=[user_msg, chatbot, session_id],
177
- outputs=[chatbot, session_id, logs_display, preview_iframe],
 
 
 
 
 
 
 
 
 
 
 
178
  )
179
 
180
  if __name__ == "__main__":
 
 
 
1
  import uuid
 
 
2
  import gradio as gr
3
+ from huggingface_hub import create_repo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
+ # Store created spaces' info
6
+ state_store = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
+ with gr.Blocks(title="HF Space Creator") as demo:
9
+ # 1) OAuth button + login status
10
+ login_btn = gr.LoginButton(variant="huggingface", size="lg")
11
  status_md = gr.Markdown("*Not logged in.*")
12
 
 
13
  def show_profile(profile: gr.OAuthProfile | None) -> str:
14
  return "*Not logged in.*" if profile is None else f"Logged in as **{profile.username}**"
15
 
16
+ # Update status on page load and after click
17
  demo.load(fn=show_profile, inputs=None, outputs=[status_md])
18
  login_btn.click(fn=show_profile, inputs=None, outputs=[status_md])
19
 
20
+ # 2) Repo creation UI
21
+ repo_name = gr.Textbox(label="New Space name", placeholder="your-repo-name")
22
+ create_btn = gr.Button("Create Space", interactive=False)
23
+ session_id = gr.Textbox(value="", visible=False)
24
+ logs = gr.Textbox(label="Logs", interactive=False, lines=5)
25
+ preview_iframe = gr.HTML("<p>No Space created yet.</p>")
 
 
 
 
 
 
26
 
27
+ # Enable create button only after login
28
+ def enable_create(profile: gr.OAuthProfile | None):
29
+ return gr.update(interactive=(profile is not None))
30
+ login_btn.click(fn=enable_create, inputs=None, outputs=[create_btn])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ def create_space(name: str, oauth_token: gr.OAuthToken | None):
33
+ if oauth_token is None:
34
+ return "", "Please sign in first.", "<p>No Space created yet.</p>"
35
+ username = oauth_token.user_info["username"]
36
+ repo_id = f"{username}/{name}"
37
+ create_repo(
38
+ repo_id=repo_id,
39
+ token=oauth_token.token,
40
+ exist_ok=True,
41
+ repo_type="space"
42
+ )
43
+ url = f"https://huggingface.co/spaces/{repo_id}"
44
+ logs = f"Created or found Space: {url}"
45
+ iframe = f'<iframe src="{url}" width="100%" height="500px"></iframe>'
46
+ return repo_id, logs, iframe
47
+
48
+ create_btn.click(
49
+ fn=create_space,
50
+ inputs=[repo_name, login_btn],
51
+ outputs=[session_id, logs, preview_iframe]
52
  )
53
 
54
  if __name__ == "__main__":