flashstudio 0.1.8__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flashstudio might be problematic. Click here for more details.

Files changed (110) hide show
  1. {flashstudio-0.1.8 → flashstudio-0.2.0}/PKG-INFO +4 -6
  2. {flashstudio-0.1.8 → flashstudio-0.2.0}/README.md +50 -54
  3. flashstudio-0.2.0/flashstudio/launcher.py +183 -0
  4. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/PKG-INFO +4 -6
  5. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/requires.txt +4 -6
  6. {flashstudio-0.1.8 → flashstudio-0.2.0}/pyproject.toml +3 -5
  7. flashstudio-0.1.8/flashstudio/launcher.py +0 -104
  8. {flashstudio-0.1.8 → flashstudio-0.2.0}/README_PYPI.md +0 -0
  9. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/__init__.py +0 -0
  10. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/app.py +0 -0
  11. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/cli.py +0 -0
  12. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/__init__.py +0 -0
  13. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/project_manager.py +0 -0
  14. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/sidebar.py +0 -0
  15. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/styles.py +0 -0
  16. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/wizard.py +0 -0
  17. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/components/zone_drawer/__init__.py +0 -0
  18. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/constants.py +0 -0
  19. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/core/__init__.py +0 -0
  20. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/core/constants.py +0 -0
  21. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/__init__.py +0 -0
  22. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/__init__.py +0 -0
  23. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/_common.py +0 -0
  24. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/__init__.py +0 -0
  25. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/metrics.py +0 -0
  26. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/pipeline_status.py +0 -0
  27. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/project_banner.py +0 -0
  28. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/quick_actions.py +0 -0
  29. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/recent_runs.py +0 -0
  30. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/overview/tab.py +0 -0
  31. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/dashboard/page.py +0 -0
  32. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/__init__.py +0 -0
  33. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/_common.py +0 -0
  34. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/download/__init__.py +0 -0
  35. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/download/tab.py +0 -0
  36. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/helpers.py +0 -0
  37. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/page.py +0 -0
  38. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/preview/__init__.py +0 -0
  39. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/preview/tab.py +0 -0
  40. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/upload/__init__.py +0 -0
  41. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/upload/tab.py +0 -0
  42. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/verify/__init__.py +0 -0
  43. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/data/verify/tab.py +0 -0
  44. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/export/__init__.py +0 -0
  45. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/export/page.py +0 -0
  46. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/export/weights/__init__.py +0 -0
  47. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/export/weights/exporter.py +0 -0
  48. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/export/weights/settings.py +0 -0
  49. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/__init__.py +0 -0
  50. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/_common.py +0 -0
  51. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/data/__init__.py +0 -0
  52. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/data/tab.py +0 -0
  53. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/model/__init__.py +0 -0
  54. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/model/tab.py +0 -0
  55. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/page.py +0 -0
  56. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/run/__init__.py +0 -0
  57. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/run/detection.py +0 -0
  58. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/run/tab.py +0 -0
  59. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/run/video.py +0 -0
  60. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/solution/__init__.py +0 -0
  61. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/inference/solution/tab.py +0 -0
  62. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/__init__.py +0 -0
  63. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/_common.py +0 -0
  64. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/advanced/__init__.py +0 -0
  65. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/advanced/tab.py +0 -0
  66. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/architecture/__init__.py +0 -0
  67. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/architecture/tab.py +0 -0
  68. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/augment/__init__.py +0 -0
  69. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/augment/tab.py +0 -0
  70. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/hyperparams/__init__.py +0 -0
  71. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/hyperparams/tab.py +0 -0
  72. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/page.py +0 -0
  73. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/utils/__init__.py +0 -0
  74. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/model/utils/config.py +0 -0
  75. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/__init__.py +0 -0
  76. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/_common.py +0 -0
  77. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/__init__.py +0 -0
  78. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/controls.py +0 -0
  79. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/dialogs.py +0 -0
  80. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/preflight.py +0 -0
  81. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/runner.py +0 -0
  82. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/launch/tab.py +0 -0
  83. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/__init__.py +0 -0
  84. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/checkpoints.py +0 -0
  85. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/curves.py +0 -0
  86. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/dashboard.py +0 -0
  87. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/gt_verification.py +0 -0
  88. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/log_viewer.py +0 -0
  89. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/parsers.py +0 -0
  90. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/run_meta.py +0 -0
  91. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/tab.py +0 -0
  92. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/monitor/visualizations.py +0 -0
  93. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/pages/training/page.py +0 -0
  94. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/__init__.py +0 -0
  95. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/config.py +0 -0
  96. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/device.py +0 -0
  97. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/filesystem.py +0 -0
  98. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/jobs.py +0 -0
  99. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio/utils/training_hooks.py +0 -0
  100. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/SOURCES.txt +0 -0
  101. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/dependency_links.txt +0 -0
  102. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/entry_points.txt +0 -0
  103. {flashstudio-0.1.8 → flashstudio-0.2.0}/flashstudio.egg-info/top_level.txt +0 -0
  104. {flashstudio-0.1.8 → flashstudio-0.2.0}/setup.cfg +0 -0
  105. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_app.py +0 -0
  106. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_cli.py +0 -0
  107. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_constants.py +0 -0
  108. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_launcher.py +0 -0
  109. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_pipeline_flow.py +0 -0
  110. {flashstudio-0.1.8 → flashstudio-0.2.0}/tests/test_save_dir_compat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flashstudio
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: Interactive Training & Inference UI for FlashDet — runs on Google Colab
5
5
  Author: FlashVision
6
6
  License: Apache-2.0
@@ -19,17 +19,15 @@ Requires-Dist: plotly>=5.0
19
19
  Requires-Dist: pandas>=1.5
20
20
  Requires-Dist: pillow>=9.0
21
21
  Requires-Dist: numpy>=1.21
22
- Requires-Dist: pyngrok>=6.0
23
22
  Requires-Dist: opencv-python>=4.5
24
23
  Requires-Dist: pyyaml>=6.0
25
24
  Requires-Dist: flashdet
26
25
  Provides-Extra: full
27
- Requires-Dist: pyngrok>=6.0; extra == "full"
28
26
  Requires-Dist: torch>=2.0; extra == "full"
29
- Requires-Dist: opencv-python>=4.5; extra == "full"
30
27
  Requires-Dist: flashdet[export]; extra == "full"
31
- Provides-Extra: colab
32
- Requires-Dist: pyngrok>=6.0; extra == "colab"
28
+ Requires-Dist: pyngrok>=6.0; extra == "full"
29
+ Provides-Extra: ngrok
30
+ Requires-Dist: pyngrok>=6.0; extra == "ngrok"
33
31
  Provides-Extra: dev
34
32
  Requires-Dist: ruff; extra == "dev"
35
33
  Requires-Dist: pytest; extra == "dev"
@@ -28,7 +28,7 @@
28
28
  - 📤 **Export** — ONNX export with FP16 auto-generated weights
29
29
  - 📦 **Data** — Native `flashdet download` datasets + custom upload (COCO/VOC/YOLO formats)
30
30
  - 📊 **Dashboard** — Overview with recent training runs from workspace
31
- - 🚀 **Colab Support** — ngrok tunneling for remote access
31
+ - 🚀 **Colab Support** — Works out-of-the-box, no token or signup needed
32
32
 
33
33
  ---
34
34
 
@@ -80,19 +80,14 @@ Full inference pipeline with 17 built-in solutions (object counting, speed estim
80
80
 
81
81
  ## Installation
82
82
 
83
- ### Step 1: Install FlashStudio
84
-
85
83
  ```bash
86
84
  pip install flashstudio
87
85
  ```
88
86
 
89
- ### Step 2: Install FlashDet (required for training/inference)
90
-
91
- ```bash
92
- pip install git+https://github.com/FlashVision/FlashDet.git
93
- ```
87
+ This automatically installs FlashDet and all other dependencies.
94
88
 
95
- ### Development install (from source)
89
+ <details>
90
+ <summary><b>Development install (from source)</b></summary>
96
91
 
97
92
  ```bash
98
93
  git clone https://github.com/FlashVision/FlashStudio.git
@@ -100,6 +95,8 @@ cd FlashStudio
100
95
  pip install -e .
101
96
  ```
102
97
 
98
+ </details>
99
+
103
100
  ---
104
101
 
105
102
  ## Usage — Local Machine
@@ -123,53 +120,46 @@ Then open **http://localhost:8501** in your browser.
123
120
 
124
121
  ## Usage — Google Colab
125
122
 
126
- ### Step 1: Install packages
123
+ No signup or token needed. Just 2 steps:
124
+
125
+ ### Step 1: Install
126
+
127
+ ```python
128
+ !pip install -q flashstudio
129
+ ```
130
+
131
+ ### Step 2: Launch
127
132
 
128
133
  ```python
129
- !pip install flashstudio
130
- !pip install git+https://github.com/FlashVision/FlashDet.git
134
+ from flashstudio import launch
135
+ launch()
131
136
  ```
132
137
 
133
- ### Step 2: Get ngrok token (free, one-time setup)
138
+ A clickable **"Open FlashStudio"** button appears in the cell output. Click it to open the UI.
134
139
 
135
- FlashStudio uses [ngrok](https://ngrok.com) to create a public URL for the Streamlit UI in Colab.
140
+ FlashStudio auto-detects Colab and uses the built-in proxy to create a working URL — no `localhost`, no ngrok, no token.
136
141
 
137
- 1. **Sign up** (free): https://dashboard.ngrok.com/signup
138
- 2. **Get your auth token**: https://dashboard.ngrok.com/get-started/your-authtoken
139
- 3. Copy the token (looks like `2xAbC1234_something...`)
142
+ <details>
143
+ <summary><b>Optional: ngrok for a stable public URL</b></summary>
140
144
 
141
- ### Step 3: Launch
145
+ If the built-in proxy doesn't work for your setup, you can use ngrok as a fallback:
142
146
 
143
- ```python
144
- from flashstudio import launch
147
+ 1. Get a free token at https://dashboard.ngrok.com/get-started/your-authtoken
148
+ 2. Pass it when launching:
145
149
 
146
- # Pass your ngrok token
147
- launch(ngrok_token="YOUR_NGROK_TOKEN_HERE")
150
+ ```python
151
+ launch(ngrok_token="YOUR_TOKEN")
148
152
  ```
149
153
 
150
154
  Or set it as an environment variable:
151
155
 
152
156
  ```python
153
157
  import os
154
- os.environ["NGROK_TOKEN"] = "YOUR_NGROK_TOKEN_HERE"
155
-
156
- from flashstudio import launch
158
+ os.environ["NGROK_TOKEN"] = "YOUR_TOKEN"
157
159
  launch()
158
160
  ```
159
161
 
160
- ### Step 4: Open the URL
161
-
162
- After launching, you'll see output like:
163
-
164
- ```
165
- ============================================================
166
- FlashStudio is running!
167
- Local: http://localhost:8501
168
- Public: https://abc123.ngrok-free.app
169
- ============================================================
170
- ```
171
-
172
- Click the **Public URL** to open FlashStudio in a new tab.
162
+ </details>
173
163
 
174
164
  ---
175
165
 
@@ -203,7 +193,7 @@ FlashStudio/
203
193
  ├── flashstudio/
204
194
  │ ├── __init__.py # Package init + launch() export
205
195
  │ ├── app.py # Main Streamlit app (wizard flow)
206
- │ ├── launcher.py # Colab/local launcher with ngrok
196
+ │ ├── launcher.py # Colab/local launcher (auto-tunnel)
207
197
  │ ├── cli.py # CLI entrypoint
208
198
  │ ├── constants.py # Centralized constants (paths, defaults, models)
209
199
  │ │
@@ -297,26 +287,32 @@ FlashStudio/
297
287
 
298
288
  ## Troubleshooting
299
289
 
300
- ### `ModuleNotFoundError: No module named 'pyngrok'`
301
-
302
- ```bash
303
- pip install --upgrade flashstudio
304
- ```
290
+ ### Colab: "localhost can't be reached" or ngrok error
305
291
 
306
- ### ngrok authentication error (`ERR_NGROK_4018`)
292
+ `launch()` uses Colab's built-in proxy automatically. If it doesn't work, run this in a **new cell**:
307
293
 
308
- You need an ngrok auth token. Get one free at:
309
- https://dashboard.ngrok.com/get-started/your-authtoken
294
+ ```python
295
+ import subprocess, sys, time
296
+
297
+ proc = subprocess.Popen(
298
+ [sys.executable, "-m", "streamlit", "run",
299
+ __import__('flashstudio.launcher', fromlist=['_get_app_path'])._get_app_path(),
300
+ "--server.port", "8501", "--server.headless", "true",
301
+ "--server.enableCORS", "false", "--server.enableXsrfProtection", "false"],
302
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE
303
+ )
304
+ time.sleep(5)
305
+
306
+ from google.colab.output import eval_js
307
+ print(eval_js("google.colab.kernel.proxyPort(8501)"))
308
+ ```
310
309
 
311
- Then pass it to `launch(ngrok_token="your_token")`.
310
+ Open the printed URL in a new tab. No token or signup needed.
312
311
 
313
312
  ### Streamlit port already in use
314
313
 
315
314
  ```bash
316
- # Kill existing Streamlit processes
317
315
  pkill -f "streamlit run"
318
-
319
- # Then restart
320
316
  flashstudio --port 8501
321
317
  ```
322
318
 
@@ -324,10 +320,10 @@ flashstudio --port 8501
324
320
 
325
321
  ## Requirements
326
322
 
327
- - Python >= 3.9
328
- - FlashDet (`pip install git+https://github.com/FlashVision/FlashDet.git`)
329
- - ngrok account (free) for Google Colab usage
323
+ - Python >= 3.10
330
324
  - GPU recommended for training (T4 or better)
325
+ - Google Colab works out-of-the-box (no extra accounts needed)
326
+ - FlashDet installs automatically with `pip install flashstudio`
331
327
 
332
328
  ## License
333
329
 
@@ -0,0 +1,183 @@
1
+ """Launch FlashStudio UI — works locally and inside Google Colab."""
2
+
3
+ import subprocess
4
+ import sys
5
+ import os
6
+ from pathlib import Path
7
+
8
+ from flashstudio.utils.device import is_colab
9
+
10
+ _STREAMLIT_CONFIG = """\
11
+ [theme]
12
+ primaryColor = "#7C3AED"
13
+ backgroundColor = "#FFFFFF"
14
+ secondaryBackgroundColor = "#F8F9FB"
15
+ textColor = "#1A1A2E"
16
+ font = "sans serif"
17
+
18
+ [server]
19
+ headless = true
20
+ port = 8501
21
+ enableCORS = false
22
+ enableXsrfProtection = false
23
+
24
+ [client]
25
+ showSidebarNavigation = false
26
+
27
+ [browser]
28
+ gatherUsageStats = false
29
+ """
30
+
31
+
32
+ def _get_app_path() -> str:
33
+ return str(Path(__file__).parent / "app.py")
34
+
35
+
36
+ def _ensure_streamlit_config():
37
+ """Write the default Streamlit config if one doesn't already exist."""
38
+ config_dir = Path.home() / ".streamlit"
39
+ config_file = config_dir / "config.toml"
40
+ if config_file.exists():
41
+ return
42
+ config_dir.mkdir(parents=True, exist_ok=True)
43
+ config_file.write_text(_STREAMLIT_CONFIG)
44
+
45
+
46
+ def launch(port: int = 8501, share: bool = True, ngrok_token: str | None = None):
47
+ """Launch FlashStudio Streamlit app.
48
+
49
+ Args:
50
+ port: Port to run the Streamlit server on.
51
+ share: If True and running in Colab, creates a public ngrok tunnel.
52
+ ngrok_token: Optional ngrok auth token. If not provided, uses NGROK_TOKEN env var.
53
+ """
54
+ _ensure_streamlit_config()
55
+ app_path = _get_app_path()
56
+
57
+ if is_colab():
58
+ return _launch_colab(app_path, port, share, ngrok_token)
59
+ else:
60
+ _launch_local(app_path, port)
61
+ return None
62
+
63
+
64
+ def _launch_colab(app_path: str, port: int, share: bool, ngrok_token: str | None):
65
+ """Launch in Google Colab with automatic tunnel detection."""
66
+ import time as _time
67
+ import urllib.request
68
+ import urllib.error
69
+
70
+ print(" Starting FlashStudio...", end="", flush=True)
71
+
72
+ proc = subprocess.Popen(
73
+ [sys.executable, "-m", "streamlit", "run", app_path,
74
+ "--server.port", str(port),
75
+ "--server.headless", "true",
76
+ "--server.enableCORS", "false",
77
+ "--server.enableXsrfProtection", "false"],
78
+ stdout=subprocess.PIPE,
79
+ stderr=subprocess.PIPE,
80
+ )
81
+
82
+ # Wait until Streamlit is actually responding (up to 30s)
83
+ ready = False
84
+ for i in range(30):
85
+ _time.sleep(1)
86
+ if proc.poll() is not None:
87
+ _, stderr = proc.communicate()
88
+ err_msg = stderr.decode("utf-8", errors="replace")[-500:] if stderr else "Unknown error"
89
+ print(f"\n\n FlashStudio failed to start:\n {err_msg}")
90
+ return proc
91
+ try:
92
+ urllib.request.urlopen(f"http://localhost:{port}/_stcore/health", timeout=2)
93
+ ready = True
94
+ break
95
+ except Exception:
96
+ print(".", end="", flush=True)
97
+
98
+ if ready:
99
+ print(" Ready!")
100
+ else:
101
+ print(" (still loading, URL may take a moment)")
102
+
103
+ public_url = None
104
+
105
+ # Method 1: Colab's built-in proxy (simplest, no install needed)
106
+ try:
107
+ from google.colab.output import eval_js
108
+ result = eval_js(f"google.colab.kernel.proxyPort({port})")
109
+ if result and str(result).startswith("http"):
110
+ public_url = str(result)
111
+ except Exception:
112
+ pass
113
+
114
+ # Method 2: ngrok (only if token is provided)
115
+ if not public_url:
116
+ token = ngrok_token or os.environ.get("NGROK_TOKEN", "")
117
+ if token:
118
+ try:
119
+ from pyngrok import ngrok, conf
120
+ conf.get_default().auth_token = token
121
+ public_url = str(ngrok.connect(port, "http"))
122
+ except ImportError:
123
+ try:
124
+ subprocess.check_call(
125
+ [sys.executable, "-m", "pip", "install", "-q", "pyngrok"],
126
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
127
+ )
128
+ from pyngrok import ngrok, conf
129
+ conf.get_default().auth_token = token
130
+ public_url = str(ngrok.connect(port, "http"))
131
+ except Exception:
132
+ pass
133
+ except Exception:
134
+ pass
135
+
136
+ print(f"\n{'=' * 60}")
137
+ print(" FlashStudio is running!")
138
+ if public_url:
139
+ print(f" Open: {public_url}")
140
+ else:
141
+ print(f" Port: {port}")
142
+ print("")
143
+ print(" Run this in a new cell to get the URL:")
144
+ print(f" from google.colab.output import eval_js")
145
+ print(f" print(eval_js('google.colab.kernel.proxyPort({port})'))")
146
+ print(f"{'=' * 60}\n")
147
+
148
+ if public_url:
149
+ try:
150
+ from IPython.display import display, HTML
151
+ display(HTML(
152
+ f'<a href="{public_url}" target="_blank" '
153
+ f'style="display:inline-block;font-size:16px;padding:10px 24px;'
154
+ f'background:#7C3AED;color:white;border-radius:8px;'
155
+ f'text-decoration:none;font-weight:600;margin:8px 0;">'
156
+ f'Open FlashStudio</a>'
157
+ ))
158
+ except Exception:
159
+ pass
160
+ else:
161
+ try:
162
+ from IPython.display import display, HTML
163
+ display(HTML(
164
+ f'<div style="padding:12px;background:#FEF3C7;border-radius:8px;'
165
+ f'margin:8px 0;font-size:14px;">'
166
+ f'Run in a <b>new cell</b>:<br>'
167
+ f'<code style="background:#F3F4F6;padding:4px 8px;border-radius:4px;">'
168
+ f'from google.colab.output import eval_js; '
169
+ f'print(eval_js("google.colab.kernel.proxyPort({port})"))</code>'
170
+ f'</div>'
171
+ ))
172
+ except Exception:
173
+ pass
174
+
175
+ return proc
176
+
177
+
178
+ def _launch_local(app_path: str, port: int):
179
+ """Launch locally with streamlit."""
180
+ subprocess.run(
181
+ [sys.executable, "-m", "streamlit", "run", app_path,
182
+ "--server.port", str(port)],
183
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flashstudio
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: Interactive Training & Inference UI for FlashDet — runs on Google Colab
5
5
  Author: FlashVision
6
6
  License: Apache-2.0
@@ -19,17 +19,15 @@ Requires-Dist: plotly>=5.0
19
19
  Requires-Dist: pandas>=1.5
20
20
  Requires-Dist: pillow>=9.0
21
21
  Requires-Dist: numpy>=1.21
22
- Requires-Dist: pyngrok>=6.0
23
22
  Requires-Dist: opencv-python>=4.5
24
23
  Requires-Dist: pyyaml>=6.0
25
24
  Requires-Dist: flashdet
26
25
  Provides-Extra: full
27
- Requires-Dist: pyngrok>=6.0; extra == "full"
28
26
  Requires-Dist: torch>=2.0; extra == "full"
29
- Requires-Dist: opencv-python>=4.5; extra == "full"
30
27
  Requires-Dist: flashdet[export]; extra == "full"
31
- Provides-Extra: colab
32
- Requires-Dist: pyngrok>=6.0; extra == "colab"
28
+ Requires-Dist: pyngrok>=6.0; extra == "full"
29
+ Provides-Extra: ngrok
30
+ Requires-Dist: pyngrok>=6.0; extra == "ngrok"
33
31
  Provides-Extra: dev
34
32
  Requires-Dist: ruff; extra == "dev"
35
33
  Requires-Dist: pytest; extra == "dev"
@@ -3,21 +3,19 @@ plotly>=5.0
3
3
  pandas>=1.5
4
4
  pillow>=9.0
5
5
  numpy>=1.21
6
- pyngrok>=6.0
7
6
  opencv-python>=4.5
8
7
  pyyaml>=6.0
9
8
  flashdet
10
9
 
11
- [colab]
12
- pyngrok>=6.0
13
-
14
10
  [dev]
15
11
  ruff
16
12
  pytest
17
13
  pytest-cov
18
14
 
19
15
  [full]
20
- pyngrok>=6.0
21
16
  torch>=2.0
22
- opencv-python>=4.5
23
17
  flashdet[export]
18
+ pyngrok>=6.0
19
+
20
+ [ngrok]
21
+ pyngrok>=6.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "flashstudio"
7
- version = "0.1.8"
7
+ version = "0.2.0"
8
8
  description = "Interactive Training & Inference UI for FlashDet — runs on Google Colab"
9
9
  readme = "README_PYPI.md"
10
10
  license = {text = "Apache-2.0"}
@@ -25,7 +25,6 @@ dependencies = [
25
25
  "pandas>=1.5",
26
26
  "pillow>=9.0",
27
27
  "numpy>=1.21",
28
- "pyngrok>=6.0",
29
28
  "opencv-python>=4.5",
30
29
  "pyyaml>=6.0",
31
30
  "flashdet",
@@ -33,12 +32,11 @@ dependencies = [
33
32
 
34
33
  [project.optional-dependencies]
35
34
  full = [
36
- "pyngrok>=6.0",
37
35
  "torch>=2.0",
38
- "opencv-python>=4.5",
39
36
  "flashdet[export]",
37
+ "pyngrok>=6.0",
40
38
  ]
41
- colab = ["pyngrok>=6.0"]
39
+ ngrok = ["pyngrok>=6.0"]
42
40
  dev = ["ruff", "pytest", "pytest-cov"]
43
41
 
44
42
  [project.scripts]
@@ -1,104 +0,0 @@
1
- """Launch FlashStudio UI — works locally and inside Google Colab."""
2
-
3
- import subprocess
4
- import sys
5
- import os
6
- from pathlib import Path
7
-
8
- from flashstudio.utils.device import is_colab
9
-
10
- _STREAMLIT_CONFIG = """\
11
- [theme]
12
- primaryColor = "#7C3AED"
13
- backgroundColor = "#FFFFFF"
14
- secondaryBackgroundColor = "#F8F9FB"
15
- textColor = "#1A1A2E"
16
- font = "sans serif"
17
-
18
- [server]
19
- headless = true
20
- port = 8501
21
- enableCORS = false
22
- enableXsrfProtection = false
23
-
24
- [client]
25
- showSidebarNavigation = false
26
-
27
- [browser]
28
- gatherUsageStats = false
29
- """
30
-
31
-
32
- def _get_app_path() -> str:
33
- return str(Path(__file__).parent / "app.py")
34
-
35
-
36
- def _ensure_streamlit_config():
37
- """Write the default Streamlit config if one doesn't already exist."""
38
- config_dir = Path.home() / ".streamlit"
39
- config_file = config_dir / "config.toml"
40
- if config_file.exists():
41
- return
42
- config_dir.mkdir(parents=True, exist_ok=True)
43
- config_file.write_text(_STREAMLIT_CONFIG)
44
-
45
-
46
- def launch(port: int = 8501, share: bool = True, ngrok_token: str | None = None):
47
- """Launch FlashStudio Streamlit app.
48
-
49
- Args:
50
- port: Port to run the Streamlit server on.
51
- share: If True and running in Colab, creates a public ngrok tunnel.
52
- ngrok_token: Optional ngrok auth token. If not provided, uses NGROK_TOKEN env var.
53
- """
54
- _ensure_streamlit_config()
55
- app_path = _get_app_path()
56
-
57
- if is_colab():
58
- _launch_colab(app_path, port, share, ngrok_token)
59
- else:
60
- _launch_local(app_path, port)
61
-
62
-
63
- def _launch_colab(app_path: str, port: int, share: bool, ngrok_token: str | None):
64
- """Launch in Google Colab with ngrok tunnel."""
65
- try:
66
- from pyngrok import ngrok, conf
67
- except ImportError:
68
- print("Installing pyngrok...")
69
- subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "pyngrok"])
70
- from pyngrok import ngrok, conf
71
-
72
- token = ngrok_token or os.environ.get("NGROK_TOKEN", "")
73
- if token:
74
- conf.get_default().auth_token = token
75
-
76
- proc = subprocess.Popen(
77
- [sys.executable, "-m", "streamlit", "run", app_path,
78
- "--server.port", str(port),
79
- "--server.headless", "true",
80
- "--server.enableCORS", "false",
81
- "--server.enableXsrfProtection", "false"],
82
- stdout=subprocess.PIPE,
83
- stderr=subprocess.PIPE,
84
- )
85
-
86
- if share:
87
- public_url = ngrok.connect(port, "http")
88
- print(f"\n{'=' * 60}")
89
- print(" FlashStudio is running!")
90
- print(f" Local: http://localhost:{port}")
91
- print(f" Public: {public_url}")
92
- print(f"{'=' * 60}\n")
93
- else:
94
- print(f"\n FlashStudio running at http://localhost:{port}\n")
95
-
96
- return proc
97
-
98
-
99
- def _launch_local(app_path: str, port: int):
100
- """Launch locally with streamlit."""
101
- subprocess.run(
102
- [sys.executable, "-m", "streamlit", "run", app_path,
103
- "--server.port", str(port)],
104
- )
File without changes
File without changes