Skip to content

Commit c34054f

Browse files
committed
fix dto, render markdown, rearreange report content
1 parent 767869b commit c34054f

3 files changed

Lines changed: 116 additions & 50 deletions

File tree

src/main/java/com/example/weatherapp/weather/WeatherService.java

Lines changed: 107 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ public WeatherReport fetchHourlyReport(double lat, double lon) {
3232
"temperature_2m",
3333
"precipitation",
3434
"wind_speed_10m",
35-
"relative_humidity_2m"
36-
))
35+
"relative_humidity_2m"))
3736
.queryParam("forecast_days", 3)
3837
.queryParam("timezone", "auto")
3938
.toUriString();
4039

4140
ResponseEntity<Map> resp = restTemplate.getForEntity(url, Map.class);
4241
Map body = resp.getBody();
43-
if (body == null) throw new IllegalStateException("Empty response from weather API");
42+
if (body == null)
43+
throw new IllegalStateException("Empty response from weather API");
4444

4545
// Map response into our DTO
4646
WeatherReport report = new WeatherReport();
@@ -52,11 +52,13 @@ public WeatherReport fetchHourlyReport(double lat, double lon) {
5252
if (!(hourlyObj instanceof Map<?, ?> hourly)) {
5353
throw new IllegalStateException("Unexpected response: missing hourly");
5454
}
55-
report.setTimes(asStringList(hourly.get("time")));
56-
report.setTemperature2m(asDoubleList(hourly.get("temperature_2m")));
57-
report.setPrecipitation(asDoubleList(hourly.get("precipitation")));
58-
report.setWindSpeed10m(asDoubleList(hourly.get("wind_speed_10m")));
59-
report.setRelativeHumidity2m(asDoubleList(hourly.get("relative_humidity_2m")));
55+
WeatherReport.Hourly hourlyData = new WeatherReport.Hourly();
56+
hourlyData.setTime(asStringList(hourly.get("time")));
57+
hourlyData.setTemperature2m(asDoubleList(hourly.get("temperature_2m")));
58+
hourlyData.setPrecipitation(asDoubleList(hourly.get("precipitation")));
59+
hourlyData.setWindSpeed10m(asDoubleList(hourly.get("wind_speed_10m")));
60+
hourlyData.setRelativeHumidity2m(asDoubleList(hourly.get("relative_humidity_2m")));
61+
report.setHourly(hourlyData);
6062

6163
return report;
6264
}
@@ -72,45 +74,113 @@ private static List<String> asStringList(Object o) {
7274

7375
@SuppressWarnings("unchecked")
7476
private static List<Double> asDoubleList(Object o) {
75-
if (o == null) return null;
77+
if (o == null)
78+
return null;
7679
return ((List<?>) o).stream().map(WeatherService::asDouble).toList();
7780
}
7881

7982
private static Double asDouble(Object o) {
80-
if (o == null) return null;
81-
if (o instanceof Number n) return n.doubleValue();
82-
try { return Double.parseDouble(String.valueOf(o)); } catch (Exception e) { return null; }
83+
if (o == null)
84+
return null;
85+
if (o instanceof Number n)
86+
return n.doubleValue();
87+
try {
88+
return Double.parseDouble(String.valueOf(o));
89+
} catch (Exception e) {
90+
return null;
91+
}
8392
}
8493

8594
@JsonIgnoreProperties(ignoreUnknown = true)
8695
public static class WeatherReport {
8796
private Double latitude;
8897
private Double longitude;
8998
private String timezone;
90-
private List<String> times;
91-
@JsonProperty("temperature_2m")
92-
private List<Double> temperature2m;
93-
private List<Double> precipitation;
94-
@JsonProperty("wind_speed_10m")
95-
private List<Double> windSpeed10m;
96-
@JsonProperty("relative_humidity_2m")
97-
private List<Double> relativeHumidity2m;
98-
99-
public Double getLatitude() { return latitude; }
100-
public void setLatitude(Double latitude) { this.latitude = latitude; }
101-
public Double getLongitude() { return longitude; }
102-
public void setLongitude(Double longitude) { this.longitude = longitude; }
103-
public String getTimezone() { return timezone; }
104-
public void setTimezone(String timezone) { this.timezone = timezone; }
105-
public List<String> getTimes() { return times; }
106-
public void setTimes(List<String> times) { this.times = times; }
107-
public List<Double> getTemperature2m() { return temperature2m; }
108-
public void setTemperature2m(List<Double> temperature2m) { this.temperature2m = temperature2m; }
109-
public List<Double> getPrecipitation() { return precipitation; }
110-
public void setPrecipitation(List<Double> precipitation) { this.precipitation = precipitation; }
111-
public List<Double> getWindSpeed10m() { return windSpeed10m; }
112-
public void setWindSpeed10m(List<Double> windSpeed10m) { this.windSpeed10m = windSpeed10m; }
113-
public List<Double> getRelativeHumidity2m() { return relativeHumidity2m; }
114-
public void setRelativeHumidity2m(List<Double> relativeHumidity2m) { this.relativeHumidity2m = relativeHumidity2m; }
99+
private Hourly hourly;
100+
101+
public Double getLatitude() {
102+
return latitude;
103+
}
104+
105+
public void setLatitude(Double latitude) {
106+
this.latitude = latitude;
107+
}
108+
109+
public Double getLongitude() {
110+
return longitude;
111+
}
112+
113+
public void setLongitude(Double longitude) {
114+
this.longitude = longitude;
115+
}
116+
117+
public String getTimezone() {
118+
return timezone;
119+
}
120+
121+
public void setTimezone(String timezone) {
122+
this.timezone = timezone;
123+
}
124+
125+
public Hourly getHourly() {
126+
return hourly;
127+
}
128+
129+
public void setHourly(Hourly hourly) {
130+
this.hourly = hourly;
131+
}
132+
133+
// Nested class to match the "hourly" object structure
134+
@JsonIgnoreProperties(ignoreUnknown = true)
135+
public static class Hourly {
136+
private List<String> time;
137+
@JsonProperty("temperature_2m")
138+
private List<Double> temperature2m;
139+
private List<Double> precipitation;
140+
@JsonProperty("wind_speed_10m")
141+
private List<Double> windSpeed10m;
142+
@JsonProperty("relative_humidity_2m")
143+
private List<Double> relativeHumidity2m;
144+
145+
public List<String> getTime() {
146+
return time;
147+
}
148+
149+
public void setTime(List<String> time) {
150+
this.time = time;
151+
}
152+
153+
public List<Double> getTemperature2m() {
154+
return temperature2m;
155+
}
156+
157+
public void setTemperature2m(List<Double> temperature2m) {
158+
this.temperature2m = temperature2m;
159+
}
160+
161+
public List<Double> getPrecipitation() {
162+
return precipitation;
163+
}
164+
165+
public void setPrecipitation(List<Double> precipitation) {
166+
this.precipitation = precipitation;
167+
}
168+
169+
public List<Double> getWindSpeed10m() {
170+
return windSpeed10m;
171+
}
172+
173+
public void setWindSpeed10m(List<Double> windSpeed10m) {
174+
this.windSpeed10m = windSpeed10m;
175+
}
176+
177+
public List<Double> getRelativeHumidity2m() {
178+
return relativeHumidity2m;
179+
}
180+
181+
public void setRelativeHumidity2m(List<Double> relativeHumidity2m) {
182+
this.relativeHumidity2m = relativeHumidity2m;
183+
}
184+
}
115185
}
116186
}

src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ spring.thymeleaf.cache=false
44

55
# Google Gemini API configuration (Google AI Studio / Generative Language API)
66
# Provide via environment variable for security in production
7-
ai.gemini.api-key=${GOOGLE_GEMINI_API_KEY:}
7+
ai.gemini.api-key=${AI_API_KEY:}
88
ai.gemini.model=${GOOGLE_GEMINI_MODEL:gemini-1.5-flash}

src/main/resources/templates/report.html

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
}
8686
</style>
8787
<script src="https://www.gstatic.com/charts/loader.js"></script>
88+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
8889
</head>
8990

9091
<body>
@@ -102,18 +103,18 @@ <h1>
102103

103104
<div id="loading" class="muted">Loading weather data…</div>
104105

106+
<div id="aiSummary" class="card" style="margin-top: 1rem;">
107+
<h2 style="margin-top:0; font-size: 1.2rem;">AI summary & activity suggestions</h2>
108+
<div id="aiSummaryContent" class="muted">Generating AI summary…</div>
109+
</div>
110+
105111
<div id="charts" class="charts" style="display:none">
106112
<div id="tempChart" class="chart"></div>
107113
<div id="precipChart" class="chart"></div>
108114
<div id="windChart" class="chart"></div>
109115
<div id="humidityChart" class="chart"></div>
110116
</div>
111117

112-
<div id="aiSummary" class="card" style="margin-top: 1rem;">
113-
<h2 style="margin-top:0; font-size: 1.2rem;">AI summary & activity suggestions</h2>
114-
<div id="aiSummaryContent" class="muted">Generating AI summary…</div>
115-
</div>
116-
117118
<script id="report-json" type="application/json" th:utext="${reportJson}">{}</script>
118119

119120
<script>
@@ -286,13 +287,8 @@ <h2 style="margin-top:0; font-size: 1.2rem;">AI summary & activity suggestions</
286287
return;
287288
}
288289
const summary = data?.summary || 'No AI summary available.';
289-
target.textContent = '';
290-
// Render as simple paragraphs, split on double newlines
291-
summary.split(/\n\n+/).forEach(p => {
292-
const para = document.createElement('p');
293-
para.textContent = p;
294-
target.appendChild(para);
295-
});
290+
// Render markdown using marked.js
291+
target.innerHTML = marked.parse(summary);
296292
target.classList.remove('muted');
297293
} catch (err) {
298294
target.textContent = 'AI summary unavailable.';

0 commit comments

Comments
 (0)