broadfield-dev commited on
Commit
0729d19
·
verified ·
1 Parent(s): e2897a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1 -215
app.py CHANGED
@@ -15,221 +15,7 @@ if not HF_TOKEN:
15
  hf_api = HfApi()
16
 
17
  # Documentation as a string
18
- DOCUMENTATION = """# Assembler Space API Documentation
19
-
20
- ## Overview
21
- The **Assembler Space** is a Hugging Face Space that acts as a factory for creating new Hugging Face Spaces dynamically. It exposes a Flask-based API that accepts JSON input containing code, files, parameters, and configuration details. Upon receiving a valid request, it creates a new Space repository on Hugging Face, populates it with the provided files, and triggers its deployment. The API supports multiple Space types (e.g., `gradio`, `static`, `docker`, `streamlit`) and multi-file submissions, making it versatile for generating a wide range of applications.
22
-
23
- The Assembler Space itself runs as a Docker-based Space on Hugging Face, accessible via a public URL: `https://broadfield-dev-assembler.hf.space`.
24
-
25
- ## Base URL
26
- The API is hosted at:
27
- https://broadfield-dev-assembler.hf.space/create-space
28
-
29
- ## Endpoints
30
-
31
- ### `POST /create-space`
32
- Creates a new Hugging Face Space based on the provided JSON payload.
33
-
34
- #### Request Format
35
- - **Method**: `POST`
36
- - **Content-Type**: `application/json`
37
- - **Body**: A JSON object with the following fields:
38
-
39
- | Field | Type | Required | Description |
40
- |--------------|----------|----------|-----------------------------------------------------------------------------|
41
- | `space_type` | String | No | The type of Space to create. Options: `gradio`, `static`, `docker`, `streamlit`. Defaults to `gradio` if omitted. |
42
- | `files` | Object | Yes | A dictionary where keys are filenames (e.g., `app.py`, `index.html`) and values are file contents as strings. |
43
- | `parameters` | Object | No | A dictionary of key-value pairs to be injected into Python files as `PARAMS` or used by the generated Space’s code. |
44
-
45
- #### Request Constraints
46
- - At least one file must be provided in `files`.
47
- - Filenames in `files` should include extensions (e.g., `.py`, `.html`, `.css`, `.txt`) to ensure correct handling.
48
- - `space_type` must match one of the supported values, or the request will fail.
49
- - File contents should be valid for the intended `space_type` (e.g., Python code for `gradio` or `docker`, HTML for `static`).
50
-
51
- #### Response Format
52
- - **Content-Type**: `application/json`
53
- - **Status Codes**:
54
- - `200 OK`: Space creation succeeded.
55
- - `400 Bad Request`: Invalid JSON or missing/invalid fields.
56
- - `500 Internal Server Error`: Unexpected error during Space creation.
57
- - **Body**: A JSON object with the following fields:
58
-
59
- | Field | Type | Description |
60
- |-----------|--------|-----------------------------------------------------------------------------|
61
- | `message` | String | A brief status message (e.g., `"New Space created"`). |
62
- | `url` | String | The URL of the newly created Space (e.g., `https://huggingface.co/spaces/<username>/<space-name>`). |
63
- | `note` | String | Additional information (e.g., deployment time warning). |
64
- | `error` | String | (Only in error responses) Description of what went wrong. |
65
-
66
- ### `GET /docs`
67
- Returns this documentation as plain text in Markdown format.
68
-
69
- #### Request Format
70
- - **Method**: `GET`
71
- - **Content-Type**: None required
72
-
73
- #### Response Format
74
- - **Content-Type**: `text/plain`
75
- - **Status Codes**:
76
- - `200 OK`: Documentation returned successfully.
77
- - **Body**: The full Markdown documentation as a string.
78
-
79
- #### Example Requests and Responses
80
-
81
- ##### Example 1: Static Space
82
- **Request (`POST /create-space`):**
83
- ~~~json
84
- {
85
- "space_type": "static",
86
- "files": {
87
- "index.html": "<html><body><h1>Hello World</h1><p>Message: {{params['message']}}</p></body></html>",
88
- "style.css": "h1 { color: green; }"
89
- },
90
- "parameters": {
91
- "message": "Static Space Test"
92
- }
93
- }
94
- ~~~
95
-
96
- **Response (200 OK):**
97
- ~~~json
98
- {
99
- "message": "New Space created",
100
- "url": "https://huggingface.co/spaces/broadfield-dev/GeneratedSpace-abc123",
101
- "note": "It may take a few minutes to build and deploy."
102
- }
103
- ~~~
104
-
105
- **Notes:**
106
- - Static Spaces don’t automatically process `parameters`. The new Space’s code must handle them (e.g., via JavaScript or server-side templating if added).
107
-
108
- ##### Example 2: Docker Space with Flask
109
- **Request (`POST /create-space`):**
110
- ~~~json
111
- {
112
- "space_type": "docker",
113
- "files": {
114
- "app.py": "from flask import Flask\\napp = Flask(__name__)\\[email protected]('/')\\ndef home():\\n return f'Hello, {PARAMS['name']}'\\nif __name__ == '__main__':\\n app.run(host='0.0.0.0', port=7860)",
115
- "requirements.txt": "flask",
116
- "Dockerfile": "FROM python:3.10-slim\\nWORKDIR /app\\nCOPY . .\\nRUN pip install -r requirements.txt\\nEXPOSE 7860\\nCMD [\\"python\\", \\"app.py\\"]"
117
- },
118
- "parameters": {
119
- "name": "Docker User"
120
- }
121
- }
122
- ~~~
123
-
124
- **Response (200 OK):**
125
- ~~~json
126
- {
127
- "message": "New Space created",
128
- "url": "https://huggingface.co/spaces/broadfield-dev/GeneratedSpace-xyz789",
129
- "note": "It may take a few minutes to build and deploy."
130
- }
131
- ~~~
132
-
133
- **Notes:**
134
- - The `parameters` are injected into `app.py` as `PARAMS`. The port is set to 7860 to match Hugging Face’s default.
135
-
136
- ##### Example 3: Gradio Space
137
- **Request (`POST /create-space`):**
138
- ~~~json
139
- {
140
- "space_type": "gradio",
141
- "files": {
142
- "app.py": "import gradio as gr\\ndef greet():\\n return f'Hi, {PARAMS['user']}'\\ninterface = gr.Interface(fn=greet, inputs=None, outputs='text')\\ninterface.launch()"
143
- },
144
- "parameters": {
145
- "user": "Gradio Fan"
146
- }
147
- }
148
- ~~~
149
-
150
- **Response (200 OK):**
151
- ~~~json
152
- {
153
- "message": "New Space created",
154
- "url": "https://huggingface.co/spaces/broadfield-dev/GeneratedSpace-def456",
155
- "note": "It may take a few minutes to build and deploy."
156
- }
157
- ~~~
158
-
159
- ##### Example 4: Invalid Request
160
- **Request (`POST /create-space`):**
161
- ~~~json
162
- {
163
- "space_type": "invalid",
164
- "files": {}
165
- }
166
- ~~~
167
-
168
- **Response (400 Bad Request):**
169
- ~~~json
170
- {
171
- "error": "Invalid space_type. Must be one of ['gradio', 'static', 'docker', 'streamlit']"
172
- }
173
- ~~~
174
-
175
- ##### Example 5: Get Documentation
176
- **Request (`GET /docs`):**
177
- GET https://broadfield-dev-assembler.hf.space/docs
178
-
179
- **Response (200 OK):**
180
- <The full Markdown text of this documentation>
181
- ```
182
-
183
- Usage Example (Python)
184
- Here’s how to call the API using Python’s requests library:
185
- python
186
- import requests
187
-
188
- # Create a new Space
189
- url = "https://broadfield-dev-assembler.hf.space/create-space"
190
- payload = {
191
- "space_type": "static",
192
- "files": {
193
- "index.html": "<html><body><h1>Test Page</h1></body></html>"
194
- },
195
- "parameters": {
196
- "key": "value"
197
- }
198
- }
199
- headers = {"Content-Type": "application/json"}
200
-
201
- response = requests.post(url, json=payload)
202
- if response.status_code == 200:
203
- print("Success:", response.json())
204
- else:
205
- print("Error:", response.status_code, response.json())
206
-
207
- # Fetch documentation
208
- docs_url = "https://broadfield-dev-assembler.hf.space/docs"
209
- docs_response = requests.get(docs_url)
210
- if docs_response.status_code == 200:
211
- print("Documentation:", docs_response.text)
212
- Additional Details
213
- Supported Space Types
214
- gradio: For interactive Python apps using the Gradio framework. Requires an app.py with Gradio code.
215
- static: For static websites. Requires at least an index.html file; supports additional files like style.css.
216
- docker: For custom apps (e.g., Flask, FastAPI). Requires a Dockerfile or uses a default one if omitted.
217
- streamlit: For Streamlit apps. Requires an app.py with Streamlit code.
218
- File Handling
219
- Python Files (.py): The parameters object is injected as a global PARAMS variable at the top of the file.
220
- Other Files: Contents are uploaded as-is; no automatic parameter injection (e.g., HTML files need custom logic to use parameters).
221
- Requirements: If requirements.txt isn’t provided, a default is generated based on space_type (e.g., gradio for Gradio, flask for Docker).
222
- Deployment Notes
223
- Build Time: New Spaces take 1-5 minutes to build and deploy on Hugging Face. The API returns immediately with a URL, but the Space won’t be live until the build completes.
224
- Port for Docker: Hugging Face expects Docker Spaces to listen on port 7860. Ensure your Dockerfile and app code align with this (see Example 2).
225
- Security Considerations
226
- The Assembler doesn’t execute the provided code; it only creates a new Space. However, ensure the generated Space’s code is safe if deploying publicly.
227
- Avoid sending sensitive data in parameters unless the new Space is private (not implemented here but can be adjusted).
228
- Limitations
229
- Rate Limits: Hugging Face may restrict frequent Space creation. Check their API documentation for quotas.
230
- File Size: Large files may fail to upload; keep contents reasonable (e.g., <1MB per file).
231
- Error Handling: Basic validation is included, but complex syntax checking isn’t performed.
232
- """
233
  def generate_space_name():
234
  """Generate a unique Space name."""
235
  random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))
 
15
  hf_api = HfApi()
16
 
17
  # Documentation as a string
18
+ DOCUMENTATION = docs.DOCUMENTATION
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  def generate_space_name():
20
  """Generate a unique Space name."""
21
  random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=6))