fffiloni commited on
Commit
1804627
·
verified ·
1 Parent(s): 18c2ef3

Improve Gradio UI and add small-town friendly presets

Browse files
Files changed (1) hide show
  1. app.py +82 -43
app.py CHANGED
@@ -1,4 +1,3 @@
1
- import os
2
  import subprocess
3
  from pathlib import Path
4
  import gradio as gr
@@ -7,26 +6,56 @@ ROOT = Path(__file__).resolve().parent
7
  THEMES_DIR = ROOT / "themes"
8
  POSTERS_DIR = ROOT / "posters"
9
 
 
10
  def list_themes():
11
  if THEMES_DIR.exists():
12
  return sorted([p.stem for p in THEMES_DIR.glob("*.json")])
13
  return []
14
 
 
15
  THEMES = list_themes()
16
 
17
- def _latest_png():
18
- pngs = sorted(POSTERS_DIR.glob("*.png"), key=lambda p: p.stat().st_mtime)
19
- return str(pngs[-1]) if pngs else None
20
 
21
- def generate(city, country, theme, distance_m, fast_mode):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  """
23
- Génération avec logs streamés dans l'UI.
24
- Note: la barre tqdm du script peut rester à 0% jusqu’à la fin de l’étape,
25
- puis sauter à 33% / 66% / 100%. (normal) [oai_citation:2‡Hacker News](https://news.ycombinator.com/item?id=46656834&utm_source=chatgpt.com)
26
  """
27
  POSTERS_DIR.mkdir(parents=True, exist_ok=True)
28
 
29
- # Mode rapide = distance réduite (gros impact)
 
 
 
 
 
30
  if fast_mode:
31
  distance_m = min(int(distance_m), 12000)
32
 
@@ -38,13 +67,14 @@ def generate(city, country, theme, distance_m, fast_mode):
38
  "--distance", str(int(distance_m)),
39
  ]
40
 
 
 
41
  status_lines = []
42
- status_lines.append("🚀 Lancement… (le téléchargement OSM peut être lent sur Spaces)")
43
- status_lines.append(f"Commande: {' '.join(cmd)}")
44
- status_lines.append("Astuce: si tu vois '0%|0/3' longtemps, ça peut sauter à 33% d’un coup.")
45
  yield "\n".join(status_lines), None
46
 
47
- # Stream stdout/stderr
48
  proc = subprocess.Popen(
49
  cmd,
50
  stdout=subprocess.PIPE,
@@ -53,65 +83,74 @@ def generate(city, country, theme, distance_m, fast_mode):
53
  bufsize=1,
54
  )
55
 
56
- for line in proc.stdout:
57
- line = line.rstrip()
58
- if not line:
59
- continue
60
- status_lines.append(line)
 
61
 
62
- # garde le texte lisible (évite un textbox infini)
63
- if len(status_lines) > 200:
64
- status_lines = status_lines[-200:]
65
 
66
- yield "\n".join(status_lines), None
 
 
67
 
68
- rc = proc.wait()
69
  if rc != 0:
70
- status_lines.append(f"\n❌ Erreur (code {rc}). Regarde les logs ci-dessus.")
71
  yield "\n".join(status_lines), None
72
  return
73
 
74
- out_png = _latest_png()
75
  if not out_png:
76
- status_lines.append("\n❌ Aucun PNG trouvé dans /posters.")
77
  yield "\n".join(status_lines), None
78
  return
79
 
80
- status_lines.append("\n✅ Terminé.")
81
  yield "\n".join(status_lines), out_png
82
 
83
 
84
  with gr.Blocks() as demo:
85
- gr.Markdown("# MapToPoster – Test sur Hugging Face")
86
 
87
  with gr.Row():
88
- city = gr.Textbox(label="Ville", value="Paris")
89
- country = gr.Textbox(label="Pays", value="France")
90
 
91
  with gr.Row():
92
  theme = gr.Dropdown(
93
- label="Thème",
94
  choices=THEMES,
95
  value=(THEMES[0] if THEMES else None),
96
  )
97
- # valeurs adaptées aux Spaces (le repo dit que >20km devient lourd) [oai_citation:3‡GitHub](https://github.com/originalankur/maptoposter?utm_source=chatgpt.com)
98
- distance = gr.Slider(
99
- label="Distance (m)",
100
- minimum=4000,
101
- maximum=20000,
102
- step=500,
103
- value=10000,
104
  )
105
 
106
- fast_mode = gr.Checkbox(label="Mode rapide (cap à ~12 km)", value=True)
 
 
 
 
 
 
 
 
 
107
 
108
- btn = gr.Button("Générer")
109
- status = gr.Textbox(label="Logs / Statut", lines=18)
110
- out = gr.Image(label="Poster généré", type="filepath")
111
 
112
  btn.click(
113
  generate,
114
- inputs=[city, country, theme, distance, fast_mode],
115
  outputs=[status, out],
116
  )
117
 
 
 
1
  import subprocess
2
  from pathlib import Path
3
  import gradio as gr
 
6
  THEMES_DIR = ROOT / "themes"
7
  POSTERS_DIR = ROOT / "posters"
8
 
9
+
10
  def list_themes():
11
  if THEMES_DIR.exists():
12
  return sorted([p.stem for p in THEMES_DIR.glob("*.json")])
13
  return []
14
 
15
+
16
  THEMES = list_themes()
17
 
 
 
 
18
 
19
+ def list_pngs():
20
+ if not POSTERS_DIR.exists():
21
+ return []
22
+ return sorted(POSTERS_DIR.glob("*.png"), key=lambda p: p.stat().st_mtime)
23
+
24
+
25
+ def latest_new_png(before_paths):
26
+ """Return the newest PNG created after starting the generation."""
27
+ after = list_pngs()
28
+ before_set = set(before_paths)
29
+ new_files = [p for p in after if str(p) not in before_set]
30
+ if new_files:
31
+ return str(sorted(new_files, key=lambda p: p.stat().st_mtime)[-1])
32
+ return str(after[-1]) if after else None
33
+
34
+
35
+ def preset_to_distance(preset):
36
+ """Map presets to a distance value (meters). Custom returns None."""
37
+ return {
38
+ "Village / Small town": 4000,
39
+ "City / Downtown": 10000,
40
+ "Metro / Large area": 16000,
41
+ "Custom": None,
42
+ }.get(preset, None)
43
+
44
+
45
+ def generate(city, country, theme, preset, distance_m, fast_mode):
46
  """
47
+ Run the poster script and stream logs into the UI.
48
+
49
+ Note: tqdm progress can sit at 0% for a while, then jump to 33%/66%/100% (normal).
50
  """
51
  POSTERS_DIR.mkdir(parents=True, exist_ok=True)
52
 
53
+ # Apply preset if selected (except Custom)
54
+ preset_dist = preset_to_distance(preset)
55
+ if preset_dist is not None:
56
+ distance_m = preset_dist
57
+
58
+ # Fast mode: cap distance (biggest perf win on shared Spaces)
59
  if fast_mode:
60
  distance_m = min(int(distance_m), 12000)
61
 
 
67
  "--distance", str(int(distance_m)),
68
  ]
69
 
70
+ before = [str(p) for p in list_pngs()]
71
+
72
  status_lines = []
73
+ status_lines.append("🚀 Starting… (OSM downloads can be slow on shared Spaces)")
74
+ status_lines.append(f"Command: {' '.join(cmd)}")
75
+ status_lines.append("Tip: if you see '0%|0/3' for a while, it may jump to 33% all at once.")
76
  yield "\n".join(status_lines), None
77
 
 
78
  proc = subprocess.Popen(
79
  cmd,
80
  stdout=subprocess.PIPE,
 
83
  bufsize=1,
84
  )
85
 
86
+ try:
87
+ for line in proc.stdout:
88
+ line = line.rstrip()
89
+ if not line:
90
+ continue
91
+ status_lines.append(line)
92
 
93
+ # Keep the log box readable
94
+ if len(status_lines) > 250:
95
+ status_lines = status_lines[-250:]
96
 
97
+ yield "\n".join(status_lines), None
98
+ finally:
99
+ rc = proc.wait()
100
 
 
101
  if rc != 0:
102
+ status_lines.append(f"\n❌ Generation failed (exit code {rc}). See logs above.")
103
  yield "\n".join(status_lines), None
104
  return
105
 
106
+ out_png = latest_new_png(before)
107
  if not out_png:
108
+ status_lines.append("\n❌ No PNG found in /posters.")
109
  yield "\n".join(status_lines), None
110
  return
111
 
112
+ status_lines.append("\n✅ Done.")
113
  yield "\n".join(status_lines), out_png
114
 
115
 
116
  with gr.Blocks() as demo:
117
+ gr.Markdown("# MapToPoster – Hugging Face Demo")
118
 
119
  with gr.Row():
120
+ city = gr.Textbox(label="City", value="Paris")
121
+ country = gr.Textbox(label="Country", value="France")
122
 
123
  with gr.Row():
124
  theme = gr.Dropdown(
125
+ label="Theme",
126
  choices=THEMES,
127
  value=(THEMES[0] if THEMES else None),
128
  )
129
+
130
+ preset = gr.Dropdown(
131
+ label="Preset",
132
+ choices=["Village / Small town", "City / Downtown", "Metro / Large area", "Custom"],
133
+ value="City / Downtown",
 
 
134
  )
135
 
136
+ # Allow < 4000m for small towns/villages
137
+ distance = gr.Slider(
138
+ label="Distance (m) (used when Preset=Custom)",
139
+ minimum=1000,
140
+ maximum=20000,
141
+ step=250,
142
+ value=4000,
143
+ )
144
+
145
+ fast_mode = gr.Checkbox(label="Fast mode (cap ~12km)", value=True)
146
 
147
+ btn = gr.Button("Generate")
148
+ status = gr.Textbox(label="Logs / Status", lines=18)
149
+ out = gr.Image(label="Poster", type="filepath")
150
 
151
  btn.click(
152
  generate,
153
+ inputs=[city, country, theme, preset, distance, fast_mode],
154
  outputs=[status, out],
155
  )
156