Skip to content

Commit 5e9efd6

Browse files
Update app.py
1 parent 77b34e8 commit 5e9efd6

File tree

1 file changed

+49
-24
lines changed

1 file changed

+49
-24
lines changed

backend/app.py

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
from datetime import datetime
1515
import tempfile
1616
import atexit
17+
from reportlab.lib.pagesizes import letter
18+
from reportlab.pdfgen import canvas
19+
from reportlab.lib.units import inch
1720

1821
# === CONFIG ===
1922
BACKEND_BASE_URL = "https://ai-dslab-backend-cpf2feachnetbbck.westus-01.azurewebsites.net"
@@ -25,24 +28,60 @@
2528
UPLOAD_FOLDER = TEMP_DIR.name
2629
PLOT_PATH = os.path.join(UPLOAD_FOLDER, "plot.png")
2730
FORECAST_PLOT_PATH = os.path.join(UPLOAD_FOLDER, "forecast_plot.png")
28-
REPORT_PATH = os.path.join(UPLOAD_FOLDER, "summary_report.txt")
31+
REPORT_PATH = os.path.join(UPLOAD_FOLDER, "summary_report.pdf")
2932

3033
@atexit.register
3134
def cleanup_temp_dir():
3235
TEMP_DIR.cleanup()
3336

3437
log_stream = io.StringIO()
38+
cached_summary = "" # Global cache for OpenAI summary
3539

3640
def log_print(*args):
3741
print(*args, file=log_stream)
3842
sys.stdout.flush()
3943

44+
def generate_pdf_report(summary, r2, mse, forecast_dict):
45+
c = canvas.Canvas(REPORT_PATH, pagesize=letter)
46+
width, height = letter
47+
text = c.beginText(1 * inch, height - 1 * inch)
48+
49+
text.setFont("Helvetica-Bold", 14)
50+
text.textLine("AI Forecast Report")
51+
text.setFont("Helvetica", 10)
52+
text.textLine(f"Model: Linear Regression")
53+
text.textLine(f"R² Score: {r2:.4f}")
54+
text.textLine(f"MSE: {mse:.4f}")
55+
text.textLine("")
56+
57+
text.setFont("Helvetica-Bold", 12)
58+
text.textLine("OpenAI Data Summary:")
59+
text.setFont("Helvetica", 9)
60+
for line in summary.splitlines():
61+
text.textLine(line)
62+
63+
text.textLine("")
64+
text.setFont("Helvetica-Bold", 12)
65+
text.textLine("Forecast Results:")
66+
text.setFont("Helvetica", 10)
67+
for k, v in forecast_dict.items():
68+
text.textLine(f"{k}: {v}")
69+
70+
c.drawText(text)
71+
72+
if os.path.exists(FORECAST_PLOT_PATH):
73+
c.drawImage(FORECAST_PLOT_PATH, 1 * inch, 1 * inch, width=5.5 * inch, preserveAspectRatio=True)
74+
75+
c.save()
76+
4077
@app.route("/")
4178
def index():
4279
return jsonify({"message": "AI DataScience Backend is running on Azure."})
4380

4481
@app.route("/upload", methods=["POST"])
4582
def upload_file():
83+
global cached_summary
84+
4685
log_stream.truncate(0)
4786
log_stream.seek(0)
4887

@@ -63,9 +102,8 @@ def upload_file():
63102

64103
df = df[[x_col, y_col]].dropna()
65104
df.columns = ['X', 'Y']
66-
log_print("Cleaned Data:\n", df.head())
105+
log_print("Cleaned Data:\n\n", df.head())
67106

68-
# Scatter plot
69107
plt.figure()
70108
plt.scatter(df['X'], df['Y'])
71109
plt.xlabel('X')
@@ -74,7 +112,6 @@ def upload_file():
74112
plt.savefig(PLOT_PATH)
75113
plt.close()
76114

77-
# Try parsing X as datetime
78115
df['X_date'] = pd.to_datetime(df['X'], errors='coerce')
79116
use_dates = df['X_date'].notna().sum() >= len(df) // 2
80117
try:
@@ -87,18 +124,13 @@ def upload_file():
87124
except:
88125
return jsonify({"error": "Failed to parse X or Y as numeric or date."}), 400
89126

90-
if model_choice == "linear":
91-
model = LinearRegression()
92-
else:
93-
return jsonify({"error": "Only linear regression supported for now."}), 400
94-
127+
model = LinearRegression()
95128
model.fit(X, y)
96129
y_pred = model.predict(X)
97130
r2 = r2_score(y, y_pred)
98131
mse = mean_squared_error(y, y_pred)
99132
log_print(f"Model Trained. R² = {r2:.4f}, MSE = {mse:.4f}")
100133

101-
# OpenAI Summary
102134
try:
103135
openai.api_key = os.getenv("OPENAI_API_KEY")
104136
client = openai.OpenAI(api_key=openai.api_key)
@@ -111,9 +143,11 @@ def upload_file():
111143
)
112144
summary = response.choices[0].message.content
113145
log_print("Summary generated by OpenAI.")
146+
cached_summary = summary # cache for report
114147
except Exception as e:
115148
summary = "OpenAI summarization failed."
116149
log_print("OpenAI error:", str(e))
150+
cached_summary = summary
117151

118152
return jsonify({
119153
"summary": summary,
@@ -167,11 +201,10 @@ def predict():
167201

168202
y_future = model.predict(values_parsed)
169203
result = {
170-
(datetime.fromordinal(int(x)) if use_dates else float(x)): round(p, 2)
204+
datetime.fromordinal(int(x)).strftime("%Y-%m-%d") if use_dates else float(x): round(p, 2)
171205
for x, p in zip(values_parsed.flatten(), y_future)
172206
}
173207

174-
# Generate second plot
175208
X_all = np.concatenate((X, values_parsed))
176209
x_min, x_max = X_all.min(), X_all.max()
177210
x_plot = np.linspace(x_min, x_max, 200).reshape(-1, 1)
@@ -188,19 +221,11 @@ def predict():
188221
plt.savefig(FORECAST_PLOT_PATH)
189222
plt.close()
190223

191-
# Write report
192-
with open(REPORT_PATH, 'w') as f:
193-
f.write("AI Forecast Report\\n")
194-
f.write("=================\\n\\n")
195-
f.write("Model: Linear Regression\\n")
196-
f.write(f"R² Score: {r2_score(y, model.predict(X)):.4f}\\n")
197-
f.write(f"MSE: {mean_squared_error(y, model.predict(X)):.4f}\\n")
198-
f.write("\\nForecast Results:\\n")
199-
for k, v in result.items():
200-
f.write(f"{k}: {v}\\n")
224+
# PDF report generation
225+
generate_pdf_report(cached_summary, r2_score(y, model.predict(X)), mean_squared_error(y, model.predict(X)), result)
201226

202227
return jsonify({
203-
"forecast": {str(k): v for k, v in result.items()},
228+
"forecast": result,
204229
"log": log_stream.getvalue(),
205230
"plot_url": f"{BACKEND_BASE_URL}/plot.png",
206231
"forecast_plot_url": f"{BACKEND_BASE_URL}/forecast_plot.png"
@@ -224,4 +249,4 @@ def serve_forecast_plot():
224249

225250
@app.route("/download-report", methods=["GET"])
226251
def download_report():
227-
return send_file(REPORT_PATH, as_attachment=True, download_name="report.txt")
252+
return send_file(REPORT_PATH, as_attachment=True, download_name="report.pdf")

0 commit comments

Comments
 (0)