Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
| 1 |
##############################################################################
|
| 2 |
# Sozo Business Studio · 10-Jul-2025
|
| 3 |
-
# • FIXED:
|
| 4 |
-
# • FIXED:
|
| 5 |
-
# • FIXED: FFmpeg failures with a robust media concatenation function.
|
| 6 |
# • NOTE: The user's prompts, classes, and AI calls are preserved exactly.
|
| 7 |
##############################################################################
|
| 8 |
|
| 9 |
-
import os, re, json, hashlib, uuid, base64, io, tempfile, requests, subprocess
|
| 10 |
from pathlib import Path
|
| 11 |
from typing import Tuple, Dict, List
|
| 12 |
|
|
@@ -182,7 +181,6 @@ class ChartGenerator:
|
|
| 182 |
if response.startswith("```json"): response = response[7:-3]
|
| 183 |
elif response.startswith("```"): response = response[3:-3]
|
| 184 |
spec_dict = json.loads(response)
|
| 185 |
-
# Filter to only include keys expected by the ChartSpecification constructor
|
| 186 |
valid_keys = [p.name for p in inspect.signature(ChartSpecification).parameters.values()]
|
| 187 |
filtered_dict = {k: v for k, v in spec_dict.items() if k in valid_keys}
|
| 188 |
return ChartSpecification(**filtered_dict)
|
|
@@ -194,7 +192,7 @@ class ChartGenerator:
|
|
| 194 |
numeric_cols = self.enhanced_ctx['numeric_columns']; categorical_cols = self.enhanced_ctx['categorical_columns']
|
| 195 |
if "bar" in description.lower() and categorical_cols and numeric_cols: return ChartSpecification("bar", description, categorical_cols[0], numeric_cols[0])
|
| 196 |
elif "pie" in description.lower() and categorical_cols and numeric_cols: return ChartSpecification("pie", description, categorical_cols[0], numeric_cols[0])
|
| 197 |
-
elif "line" in description.lower() and len(numeric_cols) >= 1: return ChartSpecification("line",
|
| 198 |
elif "scatter" in description.lower() and len(numeric_cols) >= 2: return ChartSpecification("scatter", description, numeric_cols[0], numeric_cols[1])
|
| 199 |
elif "hist" in description.lower() and numeric_cols: return ChartSpecification("hist", description, numeric_cols[0], None)
|
| 200 |
else: return ChartSpecification("bar", description, self.df.columns[0], self.df.columns[1] if len(self.df.columns) > 1 else None)
|
|
@@ -229,14 +227,14 @@ def animate_chart(spec: ChartSpecification, df: pd.DataFrame, dur: float, out: P
|
|
| 229 |
"""FIXED: Renders a reliable animated chart using proven patterns, compatible with ChartSpecification."""
|
| 230 |
plot_data = prepare_plot_data(spec, df)
|
| 231 |
title = spec.title
|
| 232 |
-
frames = max(10, int(dur * fps))
|
| 233 |
fig, ax = plt.subplots(figsize=(WIDTH / 100, HEIGHT / 100), dpi=100)
|
| 234 |
plt.tight_layout(pad=2.5)
|
| 235 |
ctype = spec.chart_type
|
| 236 |
|
| 237 |
-
# This robust animation logic is adapted from the working example
|
| 238 |
if ctype == "pie":
|
| 239 |
-
|
|
|
|
| 240 |
ax.set_title(title); ax.axis('equal')
|
| 241 |
def init(): [w.set_alpha(0) for w in wedges]; return wedges
|
| 242 |
def update(i): [w.set_alpha(i / (frames - 1)) for w in wedges]; return wedges
|
|
@@ -249,7 +247,7 @@ def animate_chart(spec: ChartSpecification, df: pd.DataFrame, dur: float, out: P
|
|
| 249 |
progress = i / (frames - 1)
|
| 250 |
for b, h in zip(bars, plot_data.values): b.set_height(h * progress)
|
| 251 |
return bars
|
| 252 |
-
else:
|
| 253 |
line, = ax.plot([], [], lw=2)
|
| 254 |
if ctype == 'scatter':
|
| 255 |
x_full, y_full = plot_data.iloc[:, 0], plot_data.iloc[:, 1]
|
|
@@ -287,7 +285,6 @@ def safe_chart(desc: str, df: pd.DataFrame, dur: float, out: Path) -> str:
|
|
| 287 |
return animate_chart(chart_spec, df, dur, out)
|
| 288 |
except Exception as e:
|
| 289 |
print(f"Chart animation failed for '{desc}': {e}. Falling back to static image.")
|
| 290 |
-
# Fallback: create a static version of the chart and fade it in
|
| 291 |
temp_png = out.with_suffix(".png")
|
| 292 |
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", google_api_key=API_KEY, temperature=0.1)
|
| 293 |
chart_generator = create_chart_generator(llm, df)
|
|
@@ -296,7 +293,7 @@ def safe_chart(desc: str, df: pd.DataFrame, dur: float, out: Path) -> str:
|
|
| 296 |
img = cv2.imread(str(temp_png))
|
| 297 |
img_resized = cv2.resize(img, (WIDTH, HEIGHT))
|
| 298 |
return animate_image_fade(img_resized, dur, out)
|
| 299 |
-
else:
|
| 300 |
img = generate_image_from_prompt(f"A professional business chart showing {desc}")
|
| 301 |
img_cv = cv2.cvtColor(np.array(img.resize((WIDTH, HEIGHT))), cv2.COLOR_RGB2BGR)
|
| 302 |
return animate_image_fade(img_cv, dur, out)
|
|
|
|
| 1 |
##############################################################################
|
| 2 |
# Sozo Business Studio · 10-Jul-2025
|
| 3 |
+
# • FIXED: Added missing 'inspect' import to resolve NameError in ChartGenerator.
|
| 4 |
+
# • FIXED: Corrected tuple unpacking for pie charts in the animation function.
|
|
|
|
| 5 |
# • NOTE: The user's prompts, classes, and AI calls are preserved exactly.
|
| 6 |
##############################################################################
|
| 7 |
|
| 8 |
+
import os, re, json, hashlib, uuid, base64, io, tempfile, requests, subprocess, inspect # FIXED: Added missing import
|
| 9 |
from pathlib import Path
|
| 10 |
from typing import Tuple, Dict, List
|
| 11 |
|
|
|
|
| 181 |
if response.startswith("```json"): response = response[7:-3]
|
| 182 |
elif response.startswith("```"): response = response[3:-3]
|
| 183 |
spec_dict = json.loads(response)
|
|
|
|
| 184 |
valid_keys = [p.name for p in inspect.signature(ChartSpecification).parameters.values()]
|
| 185 |
filtered_dict = {k: v for k, v in spec_dict.items() if k in valid_keys}
|
| 186 |
return ChartSpecification(**filtered_dict)
|
|
|
|
| 192 |
numeric_cols = self.enhanced_ctx['numeric_columns']; categorical_cols = self.enhanced_ctx['categorical_columns']
|
| 193 |
if "bar" in description.lower() and categorical_cols and numeric_cols: return ChartSpecification("bar", description, categorical_cols[0], numeric_cols[0])
|
| 194 |
elif "pie" in description.lower() and categorical_cols and numeric_cols: return ChartSpecification("pie", description, categorical_cols[0], numeric_cols[0])
|
| 195 |
+
elif "line" in description.lower() and len(numeric_cols) >= 1: return ChartSpecification("line", self.df.columns[0], numeric_cols[0])
|
| 196 |
elif "scatter" in description.lower() and len(numeric_cols) >= 2: return ChartSpecification("scatter", description, numeric_cols[0], numeric_cols[1])
|
| 197 |
elif "hist" in description.lower() and numeric_cols: return ChartSpecification("hist", description, numeric_cols[0], None)
|
| 198 |
else: return ChartSpecification("bar", description, self.df.columns[0], self.df.columns[1] if len(self.df.columns) > 1 else None)
|
|
|
|
| 227 |
"""FIXED: Renders a reliable animated chart using proven patterns, compatible with ChartSpecification."""
|
| 228 |
plot_data = prepare_plot_data(spec, df)
|
| 229 |
title = spec.title
|
| 230 |
+
frames = max(10, int(dur * fps))
|
| 231 |
fig, ax = plt.subplots(figsize=(WIDTH / 100, HEIGHT / 100), dpi=100)
|
| 232 |
plt.tight_layout(pad=2.5)
|
| 233 |
ctype = spec.chart_type
|
| 234 |
|
|
|
|
| 235 |
if ctype == "pie":
|
| 236 |
+
# FIXED: Correctly unpack the three return values from ax.pie when autopct is used
|
| 237 |
+
wedges, _, _ = ax.pie(plot_data, labels=plot_data.index, startangle=90, autopct='%1.1f%%')
|
| 238 |
ax.set_title(title); ax.axis('equal')
|
| 239 |
def init(): [w.set_alpha(0) for w in wedges]; return wedges
|
| 240 |
def update(i): [w.set_alpha(i / (frames - 1)) for w in wedges]; return wedges
|
|
|
|
| 247 |
progress = i / (frames - 1)
|
| 248 |
for b, h in zip(bars, plot_data.values): b.set_height(h * progress)
|
| 249 |
return bars
|
| 250 |
+
else:
|
| 251 |
line, = ax.plot([], [], lw=2)
|
| 252 |
if ctype == 'scatter':
|
| 253 |
x_full, y_full = plot_data.iloc[:, 0], plot_data.iloc[:, 1]
|
|
|
|
| 285 |
return animate_chart(chart_spec, df, dur, out)
|
| 286 |
except Exception as e:
|
| 287 |
print(f"Chart animation failed for '{desc}': {e}. Falling back to static image.")
|
|
|
|
| 288 |
temp_png = out.with_suffix(".png")
|
| 289 |
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", google_api_key=API_KEY, temperature=0.1)
|
| 290 |
chart_generator = create_chart_generator(llm, df)
|
|
|
|
| 293 |
img = cv2.imread(str(temp_png))
|
| 294 |
img_resized = cv2.resize(img, (WIDTH, HEIGHT))
|
| 295 |
return animate_image_fade(img_resized, dur, out)
|
| 296 |
+
else:
|
| 297 |
img = generate_image_from_prompt(f"A professional business chart showing {desc}")
|
| 298 |
img_cv = cv2.cvtColor(np.array(img.resize((WIDTH, HEIGHT))), cv2.COLOR_RGB2BGR)
|
| 299 |
return animate_image_fade(img_cv, dur, out)
|