Spaces:
Sleeping
Sleeping
LPX55
commited on
Commit
·
4cc700d
1
Parent(s):
4478d67
Refactor app.py to utilize shared functions for greeting, calculation, and image processing, enhancing modularity and code reuse. Introduce space loading tabs for dynamic integration of popular Hugging Face Spaces.
Browse files- .gitignore +2 -1
- README.md +55 -1
- app.py +97 -179
- calculator_tab.py +1 -1
- greeting_tab.py +1 -1
- sepia_tab.py +1 -1
- shared_functions.py +48 -0
- space_loader_tab.py +65 -0
.gitignore
CHANGED
@@ -1,2 +1,3 @@
|
|
1 |
env/
|
2 |
-
__pycache__
|
|
|
|
1 |
env/
|
2 |
+
__pycache__
|
3 |
+
__pycache__/*
|
README.md
CHANGED
@@ -10,4 +10,58 @@ pinned: false
|
|
10 |
license: openrail
|
11 |
---
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
license: openrail
|
11 |
---
|
12 |
|
13 |
+
# Dynamic Space Loading
|
14 |
+
---
|
15 |
+
|
16 |
+
## 1. **Sending Data To/From IFrames**
|
17 |
+
|
18 |
+
### **A. Standard Web (HTML/JS) Context**
|
19 |
+
- **IFrames are sandboxed:** By default, an iframe is isolated from the parent page for security reasons.
|
20 |
+
- **postMessage API:**
|
21 |
+
- The standard way to communicate between a parent page and an iframe (and vice versa) is using the [window.postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) API.
|
22 |
+
- This requires both the parent and the iframe to have JavaScript code that listens for and sends messages.
|
23 |
+
- Example:
|
24 |
+
- Parent: `iframeEl.contentWindow.postMessage({data: "hello"}, "https://iframe-domain.com")`
|
25 |
+
- IFrame: `window.parent.postMessage({data: "hi back"}, "https://parent-domain.com")`
|
26 |
+
- **Limitations in Gradio:**
|
27 |
+
- Gradio does not expose a built-in way to inject custom JS for postMessage into the iframe or parent.
|
28 |
+
- If you control both the parent and the iframe (i.e., both are your own apps), you could add custom JS to both and use postMessage.
|
29 |
+
- If the iframe is a third-party app (like a Hugging Face Space you don’t control), you cannot inject JS into it, so you cannot send/receive data programmatically.
|
30 |
+
|
31 |
+
### **B. Gradio Context**
|
32 |
+
- **No built-in Gradio API for iframe communication.**
|
33 |
+
- **You can use gr.HTML to inject a script into the parent,** but you cannot inject into the iframe if you don’t control its code.
|
34 |
+
|
35 |
+
---
|
36 |
+
|
37 |
+
## 2. **Sending Data Between Tabs in Gradio**
|
38 |
+
|
39 |
+
- **Tabs in Gradio are just layout elements:** All components in all tabs exist in the same Python process and can share state.
|
40 |
+
- **You can use gr.State or any shared variable:**
|
41 |
+
- For example, you can have a gr.State object that is updated in one tab and read in another.
|
42 |
+
- You can also use hidden components or callbacks to pass data between tabs.
|
43 |
+
---
|
44 |
+
|
45 |
+
## 3. **Summary Table**
|
46 |
+
|
47 |
+
| Method | Parent ↔ IFrame | Tab ↔ Tab (Gradio) |
|
48 |
+
|-----------------------|:--------------:|:------------------:|
|
49 |
+
| postMessage (JS) | Yes (if you control both) | N/A |
|
50 |
+
| gr.State | No | Yes |
|
51 |
+
| Hidden Components | No | Yes |
|
52 |
+
| gradio API | No | Yes |
|
53 |
+
|
54 |
+
---
|
55 |
+
|
56 |
+
## 4. **Practical Recommendations**
|
57 |
+
|
58 |
+
- **For arbitrary Hugging Face Spaces in iframes:**
|
59 |
+
- You cannot send/receive data programmatically unless the Space itself is designed to listen for postMessage.
|
60 |
+
- **For your own Spaces:**
|
61 |
+
- You can add JS to both parent and iframe to use postMessage.
|
62 |
+
- **For Gradio tabs:**
|
63 |
+
- Use gr.State or shared components for seamless data transfer.
|
64 |
+
|
65 |
+
---
|
66 |
+
|
67 |
+
**If you want a code example for tab-to-tab data sharing, or want to explore advanced iframe communication (with custom JS), let me know!**
|
app.py
CHANGED
@@ -4,58 +4,40 @@ import numpy as np
|
|
4 |
from style import js_func, css_func
|
5 |
import tempfile
|
6 |
import pandas as pd
|
|
|
|
|
7 |
from greeting_tab import greeting_tab
|
8 |
from calculator_tab import calculator_tab
|
9 |
from sepia_tab import sepia_tab
|
|
|
10 |
|
11 |
-
|
12 |
-
greeting = f"Hello, {name}{'!' * int(intensity)}"
|
13 |
-
if exclaim:
|
14 |
-
greeting = greeting.upper()
|
15 |
-
return greeting
|
16 |
-
|
17 |
-
def calculator(num1, operation, num2):
|
18 |
-
if operation == "add":
|
19 |
-
result = num1 + num2
|
20 |
-
elif operation == "subtract":
|
21 |
-
result = num1 - num2
|
22 |
-
elif operation == "multiply":
|
23 |
-
result = num1 * num2
|
24 |
-
elif operation == "divide":
|
25 |
-
if num2 == 0:
|
26 |
-
raise gr.Error("Cannot divide by zero!")
|
27 |
-
result = num1 / num2
|
28 |
-
return result
|
29 |
-
|
30 |
-
def sepia(input_img):
|
31 |
-
sepia_filter = np.array([
|
32 |
-
[0.393, 0.769, 0.189],
|
33 |
-
[0.349, 0.686, 0.168],
|
34 |
-
[0.272, 0.534, 0.131]
|
35 |
-
])
|
36 |
-
sepia_img = input_img @ sepia_filter.T
|
37 |
-
sepia_img = np.clip(sepia_img, 0, 255).astype(np.uint8)
|
38 |
-
return sepia_img
|
39 |
-
|
40 |
-
def download_text(text):
|
41 |
-
if not text:
|
42 |
-
text = ""
|
43 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8") as f:
|
44 |
-
f.write(text)
|
45 |
-
return f.name
|
46 |
-
|
47 |
-
def download_csv(result):
|
48 |
-
if result is None:
|
49 |
-
result = ""
|
50 |
-
df = pd.DataFrame({"Result": [result]})
|
51 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode="w", encoding="utf-8") as f:
|
52 |
-
df.to_csv(f, index=False)
|
53 |
-
return f.name
|
54 |
|
55 |
theme = gr.Theme.from_hub("LPX55/modal_ai")
|
56 |
|
57 |
with gr.Blocks(theme=theme, js=js_func, css=css_func) as demo:
|
58 |
show_space_tab = gr.State(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
with gr.Sidebar(width="25vw"):
|
60 |
gr.Markdown("""
|
61 |
# 🤖 API + MCP Demo
|
@@ -73,14 +55,13 @@ with gr.Blocks(theme=theme, js=js_func, css=css_func) as demo:
|
|
73 |
- [Calculator](#calculator)
|
74 |
- [Sepia Image](#sepia-image)
|
75 |
- [Custom IFrame Loader](#custom-iframe-loader)
|
|
|
76 |
---
|
77 |
### [GitHub Repo](https://github.com/yourrepo) | [Docs](https://yourdocs)
|
78 |
---
|
79 |
**Tips:**
|
80 |
- Try the examples in each tab!
|
81 |
- Download your results with the button on the right.
|
82 |
-
|
83 |
-
|
84 |
""")
|
85 |
gr.Code(
|
86 |
"""from gradio_client import Client
|
@@ -95,15 +76,83 @@ print(client.predict("Alex", 5, False, api_name="/greet"))
|
|
95 |
load_sam_iframe_btn = gr.Button("Load SAM2.1 Masking Tool (iframe)", elem_id="load-sam-iframe-btn")
|
96 |
load_sam_api_btn = gr.Button("Load SAM2.1 Masking Tool (API Proxy)", elem_id="load-sam-api-btn")
|
97 |
open_sam_tab_btn = gr.Button("Open SAM2.1 Masking Tool in New Tab", elem_id="open-sam-tab-btn")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
with gr.Tab("Greeting"):
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
with gr.Tab("Calculator"):
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
with gr.Tab("Sepia Image"):
|
106 |
sepia_tab()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
# Add state variables for each dynamic tab
|
109 |
extra_space_open = gr.State(True)
|
@@ -112,151 +161,20 @@ print(client.predict("Alex", 5, False, api_name="/greet"))
|
|
112 |
sam_api_tab_open = gr.State(True)
|
113 |
custom_iframe_tab_open = gr.State(True)
|
114 |
|
115 |
-
with gr.Tab("Extra Space", visible=False) as extra_space_tab:
|
116 |
-
@gr.render(inputs=extra_space_open)
|
117 |
-
def render_extra_space(is_open):
|
118 |
-
if is_open:
|
119 |
-
gr.Markdown("## External Gradio Space")
|
120 |
-
gr.HTML('<iframe src="https://huggingface.co/spaces/gradio/calculator" width="100%" height="600" style="border:none;"></iframe>')
|
121 |
-
close_btn = gr.Button("Close Tab")
|
122 |
-
def close_tab():
|
123 |
-
return gr.Tab(visible=False), False
|
124 |
-
close_btn.click(fn=close_tab, outputs=[extra_space_tab, extra_space_open])
|
125 |
-
|
126 |
-
with gr.Tab("SAM2.1 Masking Tool (gr.load)", visible=False) as sam_tab:
|
127 |
-
@gr.render(inputs=sam_tab_open)
|
128 |
-
def render_sam_tab(is_open):
|
129 |
-
if is_open:
|
130 |
-
gr.Markdown("## LPX55/SAM2_1-Image-Predictor-Masking-Tool-CPU (gr.load)")
|
131 |
-
sam_interface = gr.load("LPX55/SAM2_1-Image-Predictor-Masking-Tool-CPU", src="spaces")
|
132 |
-
close_btn = gr.Button("Close Tab")
|
133 |
-
def close_tab():
|
134 |
-
return gr.Tab(visible=False), False
|
135 |
-
close_btn.click(fn=close_tab, outputs=[sam_tab, sam_tab_open])
|
136 |
-
|
137 |
-
with gr.Tab("SAM2.1 Masking Tool (iframe)", visible=False) as sam_iframe_tab:
|
138 |
-
@gr.render(inputs=sam_iframe_tab_open)
|
139 |
-
def render_sam_iframe_tab(is_open):
|
140 |
-
if is_open:
|
141 |
-
gr.Markdown("## LPX55/SAM2_1-Image-Predictor-Masking-Tool-CPU (iframe)")
|
142 |
-
gr.HTML('<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>')
|
143 |
-
close_btn = gr.Button("Close Tab")
|
144 |
-
def close_tab():
|
145 |
-
return gr.Tab(visible=False), False
|
146 |
-
close_btn.click(fn=close_tab, outputs=[sam_iframe_tab, sam_iframe_tab_open])
|
147 |
-
|
148 |
-
with gr.Tab("SAM2.1 Masking Tool (API Proxy)", visible=False) as sam_api_tab:
|
149 |
-
@gr.render(inputs=sam_api_tab_open)
|
150 |
-
def render_sam_api_tab(is_open):
|
151 |
-
if is_open:
|
152 |
-
gr.Markdown("## LPX55/SAM2_1-Image-Predictor-Masking-Tool-CPU (API Proxy)")
|
153 |
-
api_image = gr.Image(label="Input Image")
|
154 |
-
api_btn = gr.Button("Run Remote Masking")
|
155 |
-
api_output = gr.Textbox(label="API Response (raw)")
|
156 |
-
def call_sam_api(image):
|
157 |
-
import requests
|
158 |
-
import base64
|
159 |
-
import json
|
160 |
-
if image is None:
|
161 |
-
return "No image uploaded."
|
162 |
-
with open(image, "rb") as f:
|
163 |
-
img_b64 = base64.b64encode(f.read()).decode()
|
164 |
-
payload = {"data": [img_b64]}
|
165 |
-
try:
|
166 |
-
resp = requests.post(
|
167 |
-
"https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space/run/predict",
|
168 |
-
json=payload,
|
169 |
-
timeout=60
|
170 |
-
)
|
171 |
-
if resp.status_code == 200:
|
172 |
-
return json.dumps(resp.json(), indent=2)
|
173 |
-
else:
|
174 |
-
return f"Error: {resp.status_code} {resp.text}"
|
175 |
-
except Exception as e:
|
176 |
-
return f"Exception: {str(e)}"
|
177 |
-
api_btn.click(fn=call_sam_api, inputs=api_image, outputs=api_output)
|
178 |
-
close_btn = gr.Button("Close Tab")
|
179 |
-
def close_tab():
|
180 |
-
return gr.Tab(visible=False), False
|
181 |
-
close_btn.click(fn=close_tab, outputs=[sam_api_tab, sam_api_tab_open])
|
182 |
-
|
183 |
-
with gr.Tab("Custom IFrame Loader") as custom_iframe_tab:
|
184 |
-
@gr.render(inputs=custom_iframe_tab_open)
|
185 |
-
def render_custom_iframe_tab(is_open):
|
186 |
-
if is_open:
|
187 |
-
gr.Markdown("## Load Any IFrame URL")
|
188 |
-
custom_url = gr.Textbox(label="IFrame URL", placeholder="https://example.com")
|
189 |
-
load_custom_iframe_btn = gr.Button("Load IFrame")
|
190 |
-
custom_iframe = gr.HTML(visible=True)
|
191 |
-
def load_custom_iframe(url):
|
192 |
-
if not url:
|
193 |
-
return "<div style='color:red'>Please enter a URL.</div>"
|
194 |
-
return f'<iframe src="{url}" width="100%" height="800" style="border:none;"></iframe>'
|
195 |
-
load_custom_iframe_btn.click(fn=load_custom_iframe, inputs=custom_url, outputs=custom_iframe)
|
196 |
-
close_btn = gr.Button("Close Tab")
|
197 |
-
def close_tab():
|
198 |
-
return gr.Tab(visible=False), False
|
199 |
-
close_btn.click(fn=close_tab, outputs=[custom_iframe_tab, custom_iframe_tab_open])
|
200 |
-
|
201 |
-
# Iframe lazy load pattern
|
202 |
-
heavy_iframe_src = gr.State("")
|
203 |
-
with gr.Tab("Heavy Space (iframe - lazy load)", visible=False) as heavy_iframe_tab:
|
204 |
-
iframe_html = gr.HTML("")
|
205 |
-
close_btn = gr.Button("Close Tab")
|
206 |
-
def close_heavy_iframe_tab():
|
207 |
-
return gr.Tab(visible=False), ""
|
208 |
-
close_btn.click(fn=close_heavy_iframe_tab, outputs=[heavy_iframe_tab, iframe_html])
|
209 |
-
def open_heavy_iframe_tab():
|
210 |
-
src = '<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>'
|
211 |
-
return gr.Tab(visible=True), src
|
212 |
-
open_heavy_iframe_btn = gr.Button("Open Heavy Space (iframe - lazy load)")
|
213 |
-
open_heavy_iframe_btn.click(fn=open_heavy_iframe_tab, outputs=[heavy_iframe_tab, iframe_html])
|
214 |
-
|
215 |
-
# Iframe always loaded pattern
|
216 |
-
with gr.Tab("Heavy Space (iframe - always loaded)", visible=True) as heavy_iframe_always_tab:
|
217 |
-
gr.HTML('<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>')
|
218 |
-
close_btn2 = gr.Button("Close Tab")
|
219 |
-
def close_heavy_iframe_always_tab():
|
220 |
-
return gr.Tab(visible=False)
|
221 |
-
close_btn2.click(fn=close_heavy_iframe_always_tab, outputs=heavy_iframe_always_tab)
|
222 |
-
open_heavy_iframe_always_btn = gr.Button("Open Heavy Space (iframe - always loaded)")
|
223 |
-
def open_heavy_iframe_always_tab():
|
224 |
-
return gr.Tab(visible=True)
|
225 |
-
open_heavy_iframe_always_btn.click(fn=open_heavy_iframe_always_tab, outputs=heavy_iframe_always_tab)
|
226 |
-
|
227 |
def show_tab():
|
228 |
return gr.Tab(visible=True)
|
229 |
|
230 |
load_space_btn.click(fn=show_tab, outputs=[extra_space_tab])
|
231 |
|
232 |
-
def show_sam_tab():
|
233 |
-
return gr.Tab(visible=True)
|
234 |
-
|
235 |
-
load_sam_btn.click(fn=show_sam_tab, outputs=[sam_tab])
|
236 |
-
|
237 |
-
def show_sam_iframe_tab():
|
238 |
-
iframe_html = '<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>'
|
239 |
-
return gr.Tab(visible=True), iframe_html
|
240 |
-
|
241 |
-
load_sam_iframe_btn.click(fn=show_sam_iframe_tab, outputs=[sam_iframe_tab, sam_iframe])
|
242 |
-
|
243 |
def show_sam_api_tab():
|
244 |
return gr.Tab(visible=True)
|
245 |
|
246 |
-
load_sam_api_btn.click(fn=show_sam_api_tab, outputs=[sam_api_tab])
|
247 |
-
|
248 |
def open_in_new_tab():
|
249 |
# This function does nothing server-side, but the button will have a link
|
250 |
pass
|
251 |
|
252 |
open_sam_tab_btn.click(fn=open_in_new_tab, inputs=None, outputs=None, js="window.open('https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space', '_blank')")
|
253 |
|
254 |
-
|
255 |
-
---
|
256 |
-
## 📡 API Usage
|
257 |
-
- Every function in this demo is automatically available as a REST API!
|
258 |
-
- View the [OpenAPI schema](./openapi.json) or click "Use via API" in the footer.
|
259 |
-
- Try the [gradio_client](https://www.gradio.app/guides/getting-started-with-the-python-client) or [@gradio/client](https://www.gradio.app/guides/getting-started-with-the-js-client) to call these endpoints programmatically.
|
260 |
-
""")
|
261 |
|
262 |
demo.launch(mcp_server=True)
|
|
|
4 |
from style import js_func, css_func
|
5 |
import tempfile
|
6 |
import pandas as pd
|
7 |
+
from shared_functions import greet, calculator, sepia, download_text, download_csv
|
8 |
+
|
9 |
from greeting_tab import greeting_tab
|
10 |
from calculator_tab import calculator_tab
|
11 |
from sepia_tab import sepia_tab
|
12 |
+
from space_loader_tab import gr_load_tab, iframe_loader_tab
|
13 |
|
14 |
+
import json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
theme = gr.Theme.from_hub("LPX55/modal_ai")
|
17 |
|
18 |
with gr.Blocks(theme=theme, js=js_func, css=css_func) as demo:
|
19 |
show_space_tab = gr.State(False)
|
20 |
+
# Iframe lazy load pattern
|
21 |
+
heavy_iframe_src = gr.State("")
|
22 |
+
with gr.Tab("Heavy Space (iframe - lazy load)", visible=False) as heavy_iframe_tab:
|
23 |
+
iframe_html = gr.HTML("")
|
24 |
+
close_btn = gr.Button("Close Tab")
|
25 |
+
def close_heavy_iframe_tab():
|
26 |
+
return gr.Tab(visible=False), ""
|
27 |
+
close_btn.click(fn=close_heavy_iframe_tab, outputs=[heavy_iframe_tab, iframe_html])
|
28 |
+
def open_heavy_iframe_tab():
|
29 |
+
src = '<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>'
|
30 |
+
return gr.Tab(visible=True), src
|
31 |
+
# Iframe always loaded pattern
|
32 |
+
with gr.Tab("Heavy Space (iframe - always loaded)", visible=False) as heavy_iframe_always_tab:
|
33 |
+
gr.HTML('<iframe src="https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space" width="100%" height="800" style="border:none;"></iframe>')
|
34 |
+
close_btn2 = gr.Button("Close Tab")
|
35 |
+
def close_heavy_iframe_always_tab():
|
36 |
+
return gr.Tab(visible=False)
|
37 |
+
close_btn2.click(fn=close_heavy_iframe_always_tab, outputs=heavy_iframe_always_tab)
|
38 |
+
def open_heavy_iframe_always_tab():
|
39 |
+
return gr.Tab(visible=True)
|
40 |
+
|
41 |
with gr.Sidebar(width="25vw"):
|
42 |
gr.Markdown("""
|
43 |
# 🤖 API + MCP Demo
|
|
|
55 |
- [Calculator](#calculator)
|
56 |
- [Sepia Image](#sepia-image)
|
57 |
- [Custom IFrame Loader](#custom-iframe-loader)
|
58 |
+
- [Space Loader](#space-loader)
|
59 |
---
|
60 |
### [GitHub Repo](https://github.com/yourrepo) | [Docs](https://yourdocs)
|
61 |
---
|
62 |
**Tips:**
|
63 |
- Try the examples in each tab!
|
64 |
- Download your results with the button on the right.
|
|
|
|
|
65 |
""")
|
66 |
gr.Code(
|
67 |
"""from gradio_client import Client
|
|
|
76 |
load_sam_iframe_btn = gr.Button("Load SAM2.1 Masking Tool (iframe)", elem_id="load-sam-iframe-btn")
|
77 |
load_sam_api_btn = gr.Button("Load SAM2.1 Masking Tool (API Proxy)", elem_id="load-sam-api-btn")
|
78 |
open_sam_tab_btn = gr.Button("Open SAM2.1 Masking Tool in New Tab", elem_id="open-sam-tab-btn")
|
79 |
+
open_heavy_iframe_btn = gr.Button("Open Heavy Space (iframe - lazy load)")
|
80 |
+
open_heavy_iframe_btn.click(fn=open_heavy_iframe_tab, outputs=[heavy_iframe_tab, iframe_html])
|
81 |
+
open_heavy_iframe_always_btn = gr.Button("Open Heavy Space (iframe - always loaded)")
|
82 |
+
open_heavy_iframe_always_btn.click(fn=open_heavy_iframe_always_tab, outputs=heavy_iframe_always_tab)
|
83 |
+
|
84 |
+
# All tabs grouped together for a unified tab bar
|
85 |
+
shared_state = gr.State({"greeting": None, "calculation": None})
|
86 |
+
shared_state_box = gr.JSON(label="Shared Data Between Tabs")
|
87 |
+
def pretty_json(state):
|
88 |
+
return json.dumps(state, indent=2, ensure_ascii=False)
|
89 |
|
90 |
with gr.Tab("Greeting"):
|
91 |
+
name = gr.Textbox(label="Name", info="Enter your name", placeholder="e.g. Alex")
|
92 |
+
intensity = gr.Slider(1, 20, value=3, step=1, label="Intensity", info="How excited should the greeting be?")
|
93 |
+
with gr.Accordion("Advanced Options", open=False):
|
94 |
+
exclaim = gr.Checkbox(label="Shout (all caps)", info="Make the greeting all uppercase and add exclamations")
|
95 |
+
greet_btn = gr.Button("Greet")
|
96 |
+
greet_output = gr.Textbox(label="Greeting", lines=2)
|
97 |
+
download_greet_btn = gr.DownloadButton(label="Download Greeting", value=download_text, inputs=greet_output)
|
98 |
+
gr.Examples(
|
99 |
+
[["Jill", 1, False], ["Sam", 3, True], ["Alex", 5, False]],
|
100 |
+
inputs=[name, intensity, exclaim],
|
101 |
+
outputs=greet_output,
|
102 |
+
fn=greet
|
103 |
+
)
|
104 |
+
def update_greeting_state(greeting, state):
|
105 |
+
state = dict(state)
|
106 |
+
state["greeting"] = greeting
|
107 |
+
return state
|
108 |
+
greet_btn.click(greet, [name, intensity, exclaim], greet_output).then(update_greeting_state, [greet_output, shared_state], shared_state)
|
109 |
|
110 |
with gr.Tab("Calculator"):
|
111 |
+
num1 = gr.Number(label="Number 1", info="First number")
|
112 |
+
operation = gr.Radio(["add", "subtract", "multiply", "divide"], label="Operation", info="Choose the operation")
|
113 |
+
num2 = gr.Number(label="Number 2", info="Second number")
|
114 |
+
calc_btn = gr.Button("Calculate")
|
115 |
+
calc_output = gr.Number(label="Result")
|
116 |
+
download_calc_btn = gr.DownloadButton(label="Download Result", value=download_csv, inputs=calc_output)
|
117 |
+
gr.Examples(
|
118 |
+
[[45, "add", 3], [3.14, "divide", 2], [144, "multiply", 2.5], [0, "subtract", 1.2]],
|
119 |
+
inputs=[num1, operation, num2],
|
120 |
+
outputs=calc_output,
|
121 |
+
fn=calculator
|
122 |
+
)
|
123 |
+
def update_calc_state(result, state):
|
124 |
+
state = dict(state)
|
125 |
+
state["calculation"] = result
|
126 |
+
return state
|
127 |
+
calc_btn.click(calculator, [num1, operation, num2], calc_output).then(update_calc_state, [calc_output, shared_state], shared_state)
|
128 |
|
129 |
with gr.Tab("Sepia Image"):
|
130 |
sepia_tab()
|
131 |
+
with gr.Tab("Space Loader (gr.load)"):
|
132 |
+
gr_load_tab()
|
133 |
+
with gr.Tab("Space Loader (iframe)"):
|
134 |
+
iframe_loader_tab()
|
135 |
+
with gr.Tab("Extra Space", visible=False) as extra_space_tab:
|
136 |
+
gr.Markdown("## External Gradio Space")
|
137 |
+
gr.HTML('<iframe src="https://huggingface.co/spaces/gradio/calculator" width="100%" height="600" style="border:none;"></iframe>')
|
138 |
+
close_btn = gr.Button("Close Tab")
|
139 |
+
def close_tab():
|
140 |
+
return gr.Tab(visible=False)
|
141 |
+
close_btn.click(fn=close_tab, outputs=extra_space_tab)
|
142 |
+
with gr.Tab("Custom IFrame Loader") as custom_iframe_tab:
|
143 |
+
gr.Markdown("## Load Any IFrame URL")
|
144 |
+
custom_url = gr.Textbox(label="IFrame URL", placeholder="https://example.com")
|
145 |
+
load_custom_iframe_btn = gr.Button("Load IFrame")
|
146 |
+
custom_iframe = gr.HTML(visible=True)
|
147 |
+
def load_custom_iframe(url):
|
148 |
+
if not url:
|
149 |
+
return "<div style='color:red'>Please enter a URL.</div>"
|
150 |
+
return f'<iframe src="{url}" width="100%" height="800" style="border:none;"></iframe>'
|
151 |
+
load_custom_iframe_btn.click(fn=load_custom_iframe, inputs=custom_url, outputs=custom_iframe)
|
152 |
+
close_btn = gr.Button("Close Tab")
|
153 |
+
def close_tab_custom():
|
154 |
+
return gr.Tab(visible=False)
|
155 |
+
close_btn.click(fn=close_tab_custom, outputs=custom_iframe_tab)
|
156 |
|
157 |
# Add state variables for each dynamic tab
|
158 |
extra_space_open = gr.State(True)
|
|
|
161 |
sam_api_tab_open = gr.State(True)
|
162 |
custom_iframe_tab_open = gr.State(True)
|
163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
def show_tab():
|
165 |
return gr.Tab(visible=True)
|
166 |
|
167 |
load_space_btn.click(fn=show_tab, outputs=[extra_space_tab])
|
168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
def show_sam_api_tab():
|
170 |
return gr.Tab(visible=True)
|
171 |
|
|
|
|
|
172 |
def open_in_new_tab():
|
173 |
# This function does nothing server-side, but the button will have a link
|
174 |
pass
|
175 |
|
176 |
open_sam_tab_btn.click(fn=open_in_new_tab, inputs=None, outputs=None, js="window.open('https://lpx55-sam2-1-image-predictor-masking-tool-cpu.hf.space', '_blank')")
|
177 |
|
178 |
+
shared_state.change(pretty_json, shared_state, shared_state_box)
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
|
180 |
demo.launch(mcp_server=True)
|
calculator_tab.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import gradio as gr
|
2 |
-
from
|
3 |
|
4 |
def calculator_tab():
|
5 |
gr.Markdown("## Toy Calculator")
|
|
|
1 |
import gradio as gr
|
2 |
+
from shared_functions import calculator, download_csv
|
3 |
|
4 |
def calculator_tab():
|
5 |
gr.Markdown("## Toy Calculator")
|
greeting_tab.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import gradio as gr
|
2 |
-
from
|
3 |
|
4 |
def greeting_tab():
|
5 |
gr.Markdown("## Greeting Generator")
|
|
|
1 |
import gradio as gr
|
2 |
+
from shared_functions import greet, download_text
|
3 |
|
4 |
def greeting_tab():
|
5 |
gr.Markdown("## Greeting Generator")
|
sepia_tab.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import gradio as gr
|
2 |
-
from
|
3 |
|
4 |
def sepia_tab():
|
5 |
gr.Markdown("## Sepia Image Filter")
|
|
|
1 |
import gradio as gr
|
2 |
+
from shared_functions import sepia
|
3 |
|
4 |
def sepia_tab():
|
5 |
gr.Markdown("## Sepia Image Filter")
|
shared_functions.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import tempfile
|
2 |
+
import pandas as pd
|
3 |
+
import numpy as np
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
def greet(name="Stranger", intensity=1, exclaim=False):
|
7 |
+
greeting = f"Hello, {name}{'!' * int(intensity)}"
|
8 |
+
if exclaim:
|
9 |
+
greeting = greeting.upper()
|
10 |
+
return greeting
|
11 |
+
|
12 |
+
def calculator(num1, operation, num2):
|
13 |
+
if operation == "add":
|
14 |
+
result = num1 + num2
|
15 |
+
elif operation == "subtract":
|
16 |
+
result = num1 - num2
|
17 |
+
elif operation == "multiply":
|
18 |
+
result = num1 * num2
|
19 |
+
elif operation == "divide":
|
20 |
+
if num2 == 0:
|
21 |
+
raise gr.Error("Cannot divide by zero!")
|
22 |
+
result = num1 / num2
|
23 |
+
return result
|
24 |
+
|
25 |
+
def sepia(input_img):
|
26 |
+
sepia_filter = np.array([
|
27 |
+
[0.393, 0.769, 0.189],
|
28 |
+
[0.349, 0.686, 0.168],
|
29 |
+
[0.272, 0.534, 0.131]
|
30 |
+
])
|
31 |
+
sepia_img = input_img @ sepia_filter.T
|
32 |
+
sepia_img = np.clip(sepia_img, 0, 255).astype(np.uint8)
|
33 |
+
return sepia_img
|
34 |
+
|
35 |
+
def download_text(text):
|
36 |
+
if not text:
|
37 |
+
text = ""
|
38 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".txt", mode="w", encoding="utf-8") as f:
|
39 |
+
f.write(text)
|
40 |
+
return f.name
|
41 |
+
|
42 |
+
def download_csv(result):
|
43 |
+
if result is None:
|
44 |
+
result = ""
|
45 |
+
df = pd.DataFrame({"Result": [result]})
|
46 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".csv", mode="w", encoding="utf-8") as f:
|
47 |
+
df.to_csv(f, index=False)
|
48 |
+
return f.name
|
space_loader_tab.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
|
3 |
+
POPULAR_SPACES = [
|
4 |
+
"gradio/calculator",
|
5 |
+
"gradio/image-classification",
|
6 |
+
"huggingface-projects/llama-2-7b-chat",
|
7 |
+
"gradio/englishtranslator",
|
8 |
+
"gradio/blocks-gallery"
|
9 |
+
]
|
10 |
+
|
11 |
+
def gr_load_tab():
|
12 |
+
gr.Markdown("## Load a Popular Hugging Face Space (gr.load)")
|
13 |
+
space_dropdown = gr.Dropdown(POPULAR_SPACES, label="Popular Spaces", interactive=True)
|
14 |
+
load_btn = gr.Button("Load Space")
|
15 |
+
error_box = gr.Markdown(visible=False)
|
16 |
+
with gr.Column():
|
17 |
+
gr.Markdown("### gr.load() Interface")
|
18 |
+
loaded_interface = gr.Blocks()
|
19 |
+
|
20 |
+
def load_space(space):
|
21 |
+
if not space or "/" not in space:
|
22 |
+
return gr.update(visible=True, value="**Error:** Please select a valid space name."), None
|
23 |
+
try:
|
24 |
+
interface = gr.load(space, src="spaces")
|
25 |
+
except Exception as e:
|
26 |
+
return gr.update(visible=True, value=f"**Error loading space:** {e}"), None
|
27 |
+
return gr.update(visible=False), interface
|
28 |
+
|
29 |
+
load_btn.click(
|
30 |
+
fn=load_space,
|
31 |
+
inputs=space_dropdown,
|
32 |
+
outputs=[error_box, loaded_interface]
|
33 |
+
)
|
34 |
+
|
35 |
+
def iframe_loader_tab():
|
36 |
+
gr.Markdown("## Load Any Hugging Face Space (iframe)")
|
37 |
+
with gr.Row():
|
38 |
+
space_name = gr.Textbox(label="Space Name", placeholder="e.g. gradio/calculator")
|
39 |
+
space_dropdown = gr.Dropdown(POPULAR_SPACES, label="Popular Spaces", interactive=True)
|
40 |
+
load_btn = gr.Button("Load Space")
|
41 |
+
error_box = gr.Markdown(visible=False)
|
42 |
+
with gr.Column():
|
43 |
+
gr.Markdown("### Space IFrame")
|
44 |
+
iframe_html = gr.HTML("")
|
45 |
+
|
46 |
+
def get_space_name(text, dropdown):
|
47 |
+
return text if text else dropdown
|
48 |
+
|
49 |
+
def load_space(space):
|
50 |
+
if not space or "/" not in space:
|
51 |
+
return gr.update(visible=True, value="**Error:** Please enter a valid space name (e.g. gradio/calculator)."), ""
|
52 |
+
space_id = space.replace("/", "-")
|
53 |
+
iframe_url = f"https://{space_id}.hf.space?__theme=dark"
|
54 |
+
iframe = f'<iframe src="{iframe_url}" width="100%" height="600" style="border:none;"></iframe>'
|
55 |
+
return gr.update(visible=False), iframe
|
56 |
+
|
57 |
+
load_btn.click(
|
58 |
+
fn=get_space_name,
|
59 |
+
inputs=[space_name, space_dropdown],
|
60 |
+
outputs=space_name
|
61 |
+
).then(
|
62 |
+
fn=load_space,
|
63 |
+
inputs=space_name,
|
64 |
+
outputs=[error_box, iframe_html]
|
65 |
+
)
|