Move the Alert Digest into a shared partial template, and add it to the today, tomorrow, and daily reports

This commit is contained in:
2026-06-16 20:53:27 -05:00
parent b57110e5c8
commit d321492995
9 changed files with 58 additions and 30 deletions

View File

@@ -76,9 +76,10 @@ fail rendering instead of producing incomplete Markdown.
Daily and Tomorrow call the shared `daypart_forecast` partial. Today calls Daily and Tomorrow call the shared `daypart_forecast` partial. Today calls
`today_daypart_forecast` so it can omit elapsed or missing dayparts. Daily, `today_daypart_forecast` so it can omit elapsed or missing dayparts. Daily,
Today, Tomorrow, and Hourly call the shared `precipitation_timing` partial. Today, Tomorrow, and Hourly call the shared `alert_digest` and
Partial files are parsed with each top-level template at render time and `precipitation_timing` partials. Partial files are parsed with each top-level
receive the same typed render context as the caller. template at render time and receive the same typed render context as the
caller.
## Schema Contract ## Schema Contract

View File

@@ -16,6 +16,7 @@ are:
Shared named partials live under `internal/reporttemplate/templates/partials/`: Shared named partials live under `internal/reporttemplate/templates/partials/`:
- `alert_digest.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly
- `daypart_forecast.md.tmpl`, used by Daily and Tomorrow - `daypart_forecast.md.tmpl`, used by Daily and Tomorrow
- `today_daypart_forecast.md.tmpl`, used by Today - `today_daypart_forecast.md.tmpl`, used by Today
- `precipitation_timing.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly - `precipitation_timing.md.tmpl`, used by Daily, Today, Tomorrow, and Hourly
@@ -113,8 +114,8 @@ Tomorrow generated text uses the same `.GeneratedText.Summary`,
Hourly. `.GeneratedText.ForecastDiscussion` is a slice of paragraphs and should Hourly. `.GeneratedText.ForecastDiscussion` is a slice of paragraphs and should
be rendered with `range`. be rendered with `range`.
Tomorrow uses the shared `daypart_forecast` and `precipitation_timing` Tomorrow uses the shared `alert_digest`, `daypart_forecast`, and
partials. `precipitation_timing` partials.
Tomorrow modules include the Hourly module fields plus: Tomorrow modules include the Hourly module fields plus:
@@ -144,7 +145,8 @@ Daily generated text uses `.GeneratedText.Summary`,
`.GeneratedText.Confidence`. Forecast discussion is a slice of paragraphs and `.GeneratedText.Confidence`. Forecast discussion is a slice of paragraphs and
should be rendered with `range`. should be rendered with `range`.
Daily uses the shared `daypart_forecast` and `precipitation_timing` partials. Daily uses the shared `alert_digest`, `daypart_forecast`, and
`precipitation_timing` partials.
Daily uses template ID `daily`, generated-text schema ID `daily`, and prompt Daily uses template ID `daily`, generated-text schema ID `daily`, and prompt
source `internal/reporttemplate/prompts/daily.generated_text.md`. source `internal/reporttemplate/prompts/daily.generated_text.md`.
@@ -179,7 +181,7 @@ should be rendered with `range`.
Today uses the `today_daypart_forecast` partial so elapsed or missing dayparts Today uses the `today_daypart_forecast` partial so elapsed or missing dayparts
can be omitted while Daily and Tomorrow keep their fallback row. It also uses can be omitted while Daily and Tomorrow keep their fallback row. It also uses
the shared `precipitation_timing` partial. the shared `alert_digest` and `precipitation_timing` partials.
Today uses template ID `today`, generated-text schema ID `today`, and prompt Today uses template ID `today`, generated-text schema ID `today`, and prompt
source `internal/reporttemplate/prompts/today.generated_text.md`. source `internal/reporttemplate/prompts/today.generated_text.md`.

View File

@@ -19,6 +19,7 @@ var templates = map[string]string{
} }
var templatePartials = []string{ var templatePartials = []string{
"templates/partials/alert_digest.md.tmpl",
"templates/partials/daypart_forecast.md.tmpl", "templates/partials/daypart_forecast.md.tmpl",
"templates/partials/precipitation_timing.md.tmpl", "templates/partials/precipitation_timing.md.tmpl",
"templates/partials/today_daypart_forecast.md.tmpl", "templates/partials/today_daypart_forecast.md.tmpl",

View File

@@ -12,7 +12,7 @@ func TestTemplateLookup(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Template() error = %v", err) t.Fatalf("Template() error = %v", err)
} }
for _, want := range []string{"# {{ .Report.Title }}", "**Updated:**", "## Current Conditions", "## Hourly Forecast", "## Forecast Discussion"} { for _, want := range []string{"# {{ .Report.Title }}", "**Updated:**", `{{ template "alert_digest" . }}`, "## Current Conditions", "## Hourly Forecast", "## Forecast Discussion"} {
if !strings.Contains(source, want) { if !strings.Contains(source, want) {
t.Fatalf("template missing %q:\n%s", want, source) t.Fatalf("template missing %q:\n%s", want, source)
} }
@@ -24,7 +24,7 @@ func TestTomorrowTemplateLookup(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Template() error = %v", err) t.Fatalf("Template() error = %v", err)
} }
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} { for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "alert_digest" . }}`, `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
if !strings.Contains(source, want) { if !strings.Contains(source, want) {
t.Fatalf("template missing %q:\n%s", want, source) t.Fatalf("template missing %q:\n%s", want, source)
} }
@@ -36,7 +36,7 @@ func TestDailyTemplateLookup(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Template() error = %v", err) t.Fatalf("Template() error = %v", err)
} }
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} { for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "alert_digest" . }}`, `{{ template "daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
if !strings.Contains(source, want) { if !strings.Contains(source, want) {
t.Fatalf("template missing %q:\n%s", want, source) t.Fatalf("template missing %q:\n%s", want, source)
} }
@@ -48,7 +48,7 @@ func TestTodayTemplateLookup(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Template() error = %v", err) t.Fatalf("Template() error = %v", err)
} }
for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", "## Current Conditions", `{{ template "today_daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} { for _, want := range []string{"# {{ .Report.Title }}", "**Forecast date:**", `{{ template "alert_digest" . }}`, "## Current Conditions", `{{ template "today_daypart_forecast" . }}`, `{{ template "precipitation_timing" . }}`, "## Forecast Discussion"} {
if !strings.Contains(source, want) { if !strings.Contains(source, want) {
t.Fatalf("template missing %q:\n%s", want, source) t.Fatalf("template missing %q:\n%s", want, source)
} }
@@ -285,8 +285,8 @@ func TestRenderHourly(t *testing.T) {
} }
assertOrderedText(t, text, []string{ assertOrderedText(t, text, []string{
"# Hourly Report", "# Hourly Report",
"## Current Conditions",
"## Active Alerts", "## Active Alerts",
"## Current Conditions",
"## Hourly Forecast", "## Hourly Forecast",
"## Precipitation Timing", "## Precipitation Timing",
"## Forecast Discussion", "## Forecast Discussion",
@@ -351,6 +351,9 @@ func TestRenderTomorrow(t *testing.T) {
{PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."}, {PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."},
}, },
}, },
AlertDigest: &testAlertDigest{
Relevant: []testAlert{{Event: "Wind Advisory", Headline: "Wind Advisory until 8:00 PM", Severity: "Moderate"}},
},
}, },
}) })
if err != nil { if err != nil {
@@ -362,6 +365,8 @@ func TestRenderTomorrow(t *testing.T) {
"**Forecast date:** Monday, June 15, 2026", "**Forecast date:** Monday, June 15, 2026",
"**Updated:** Sunday, June 14, 2026 at 9:14 AM", "**Updated:** Sunday, June 14, 2026 at 9:14 AM",
"Tomorrow starts dry before showers return later in the day.", "Tomorrow starts dry before showers return later in the day.",
"## Active Alerts",
"- **Wind Advisory**: Wind Advisory until 8:00 PM",
"- **Overnight:** Partly cloudy, with temperatures falling from the mid 60s to the upper 50s.", "- **Overnight:** Partly cloudy, with temperatures falling from the mid 60s to the upper 50s.",
"- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.", "- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.",
"- **Afternoon:** Sunny, with temperatures in the upper 70s. Chance of precipitation is 70%.", "- **Afternoon:** Sunny, with temperatures in the upper 70s. Chance of precipitation is 70%.",
@@ -384,6 +389,8 @@ func TestRenderTomorrow(t *testing.T) {
} }
assertOrderedText(t, text, []string{ assertOrderedText(t, text, []string{
"# Monday's Weather", "# Monday's Weather",
"Tomorrow starts dry before showers return later in the day.",
"## Active Alerts",
"## Daypart Forecast", "## Daypart Forecast",
"- **Overnight:**", "- **Overnight:**",
"- **Morning:**", "- **Morning:**",
@@ -442,6 +449,9 @@ func TestRenderDaily(t *testing.T) {
{PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."}, {PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."},
}, },
}, },
AlertDigest: &testAlertDigest{
Relevant: []testAlert{{Event: "Flood Watch", Headline: "Flood Watch until 6:00 PM", Severity: "Moderate"}},
},
}, },
}) })
if err != nil { if err != nil {
@@ -453,6 +463,8 @@ func TestRenderDaily(t *testing.T) {
"**Forecast date:** Monday, June 15, 2026", "**Forecast date:** Monday, June 15, 2026",
"**Updated:** Sunday, June 14, 2026 at 9:14 AM", "**Updated:** Sunday, June 14, 2026 at 9:14 AM",
"The selected day starts dry before showers return later in the day.", "The selected day starts dry before showers return later in the day.",
"## Active Alerts",
"- **Flood Watch**: Flood Watch until 6:00 PM",
"- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.", "- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.",
"- **Afternoon:** Showers, with temperatures in the upper 70s. Chance of precipitation is 70%.", "- **Afternoon:** Showers, with temperatures in the upper 70s. Chance of precipitation is 70%.",
"- **3:00 PM** to **6:00 PM**: Expect showers. The peak precipitation chance is 70% at 3:00 PM.", "- **3:00 PM** to **6:00 PM**: Expect showers. The peak precipitation chance is 70% at 3:00 PM.",
@@ -466,6 +478,8 @@ func TestRenderDaily(t *testing.T) {
} }
assertOrderedText(t, text, []string{ assertOrderedText(t, text, []string{
"# Monday's Weather", "# Monday's Weather",
"The selected day starts dry before showers return later in the day.",
"## Active Alerts",
"## Daypart Forecast", "## Daypart Forecast",
"- **Morning:**", "- **Morning:**",
"- **Afternoon:**", "- **Afternoon:**",
@@ -535,6 +549,9 @@ func TestRenderToday(t *testing.T) {
{PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."}, {PeriodBeginsHourLabel: "3:00 PM", PeriodEndsHourLabel: "6:00 PM", MaxPopPercent: intPtr(70), MaxPopHourLabel: "3:00 PM", ExpectationPhrase: "Expect showers."},
}, },
}, },
AlertDigest: &testAlertDigest{
Relevant: []testAlert{{Event: "Wind Advisory", Headline: "Wind Advisory until 8:00 PM", Severity: "Moderate"}},
},
TodayPlanning: &testTodayPlanning{ TodayPlanning: &testTodayPlanning{
MorningReadiness: []string{"Morning weather looks routine."}, MorningReadiness: []string{"Morning weather looks routine."},
LateDayChangeWatch: []string{"Watch late-day shower timing."}, LateDayChangeWatch: []string{"Watch late-day shower timing."},
@@ -550,6 +567,8 @@ func TestRenderToday(t *testing.T) {
"**Forecast date:** Monday, June 15, 2026", "**Forecast date:** Monday, June 15, 2026",
"**Updated:** Monday, June 15, 2026 at 7:14 AM", "**Updated:** Monday, June 15, 2026 at 7:14 AM",
"Today starts dry before showers return later in the day.", "Today starts dry before showers return later in the day.",
"## Active Alerts",
"- **Wind Advisory**: Wind Advisory until 8:00 PM",
"Currently, it is 58°F and clear. It feels like 57°F, with a relative humidity of 61% and winds from the northwest at 9 mph.", "Currently, it is 58°F and clear. It feels like 57°F, with a relative humidity of 61% and winds from the northwest at 9 mph.",
"- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.", "- **Morning:** Sunny, with temperatures rising from the upper 50s to the upper 60s.",
"- **Afternoon:** Showers, with temperatures in the upper 70s. Chance of precipitation is 70%.", "- **Afternoon:** Showers, with temperatures in the upper 70s. Chance of precipitation is 70%.",
@@ -564,6 +583,8 @@ func TestRenderToday(t *testing.T) {
} }
assertOrderedText(t, text, []string{ assertOrderedText(t, text, []string{
"# Today's Weather", "# Today's Weather",
"Today starts dry before showers return later in the day.",
"## Active Alerts",
"## Current Conditions", "## Current Conditions",
"## Daypart Forecast", "## Daypart Forecast",
"- **Morning:**", "- **Morning:**",
@@ -652,6 +673,12 @@ func TestRenderDaypartTemplatesUseRichHelperFields(t *testing.T) {
t.Fatalf("rendered template missing %q:\n%s", want, text) t.Fatalf("rendered template missing %q:\n%s", want, text)
} }
} }
if strings.Contains(text, "## Active Alerts") {
t.Fatalf("rendered template includes empty Active Alerts section:\n%s", text)
}
if strings.Contains(text, "\n\n\n") {
t.Fatalf("rendered template includes excess blank lines:\n%s", text)
}
}) })
} }
} }
@@ -903,18 +930,21 @@ type testModules struct {
type testTomorrowModules struct { type testTomorrowModules struct {
Dayparts []testTomorrowDaypart Dayparts []testTomorrowDaypart
PrecipTiming *testPrecipTiming PrecipTiming *testPrecipTiming
AlertDigest *testAlertDigest
} }
type testTodayModules struct { type testTodayModules struct {
CurrentConditions *testCurrentConditions CurrentConditions *testCurrentConditions
Dayparts []testTomorrowDaypart Dayparts []testTomorrowDaypart
PrecipTiming *testPrecipTiming PrecipTiming *testPrecipTiming
AlertDigest *testAlertDigest
TodayPlanning *testTodayPlanning TodayPlanning *testTodayPlanning
} }
type testDailyModules struct { type testDailyModules struct {
Dayparts []testDailyDaypart Dayparts []testDailyDaypart
PrecipTiming *testPrecipTiming PrecipTiming *testPrecipTiming
AlertDigest *testAlertDigest
} }
type testTodayPlanning struct { type testTodayPlanning struct {

View File

@@ -5,9 +5,7 @@
{{ .GeneratedText.Summary }} {{ .GeneratedText.Summary }}
{{ template "daypart_forecast" . }} {{ template "alert_digest" . }}{{ template "daypart_forecast" . }}{{ if and .Modules.PrecipTiming .Modules.PrecipTiming.PrecipitationWindows }}{{ template "precipitation_timing" . }}{{ else }}{{ end -}}
{{ template "precipitation_timing" . }}
## Forecast Discussion ## Forecast Discussion
{{ range .GeneratedText.ForecastDiscussion }} {{ range .GeneratedText.ForecastDiscussion }}
{{ . }} {{ . }}

View File

@@ -4,16 +4,10 @@
{{ .GeneratedText.Summary }} {{ .GeneratedText.Summary }}
## Current Conditions {{ template "alert_digest" . }}## Current Conditions
{{ with .Modules.CurrentConditions }}{{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }}{{ else }}Current conditions are unavailable.{{ end }} {{ with .Modules.CurrentConditions }}{{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }}{{ else }}Current conditions are unavailable.{{ end }}
{{ if and .Modules.AlertDigest .Modules.AlertDigest.Relevant }}## Active Alerts
{{ range .Modules.AlertDigest.Relevant -}}
- **{{ if .Event }}{{ .Event }}{{ else }}{{ .Headline }}{{ end }}**{{ with .Headline }}: {{ . }}{{ end }}
{{ end }}
{{ end -}}
## Hourly Forecast ## Hourly Forecast
{{ with .Modules.HourlyForecast }}{{ range .Periods -}} {{ with .Modules.HourlyForecast }}{{ range .Periods -}}
- **{{ if .HourLabel }}{{ .HourLabel }}{{ else }}{{ .Name }}{{ end }}:**{{ with .TemperatureF }} {{ . }}°F{{ end }}{{ with .TextDescriptionLower }} and {{ . }}{{ else }}{{ with .TextDescription }} and {{ . }}{{ end }}{{ end }}.{{ if .MentionPrecipitation }}{{ with .ProbabilityOfPrecipitationPercent }} Probability of precipitation is {{ . }}%.{{ end }}{{ end }} - **{{ if .HourLabel }}{{ .HourLabel }}{{ else }}{{ .Name }}{{ end }}:**{{ with .TemperatureF }} {{ . }}°F{{ end }}{{ with .TextDescriptionLower }} and {{ . }}{{ else }}{{ with .TextDescription }} and {{ . }}{{ end }}{{ end }}.{{ if .MentionPrecipitation }}{{ with .ProbabilityOfPrecipitationPercent }} Probability of precipitation is {{ . }}%.{{ end }}{{ end }}

View File

@@ -0,0 +1,6 @@
{{ define "alert_digest" }}{{ if and .Modules.AlertDigest .Modules.AlertDigest.Relevant }}## Active Alerts
{{ range .Modules.AlertDigest.Relevant -}}
- **{{ if .Event }}{{ .Event }}{{ else }}{{ .Headline }}{{ end }}**{{ with .Headline }}: {{ . }}{{ end }}
{{ end }}
{{ end }}{{ end }}

View File

@@ -5,14 +5,12 @@
{{ .GeneratedText.Summary }} {{ .GeneratedText.Summary }}
{{ with .Modules.CurrentConditions }} {{ template "alert_digest" . }}{{ with .Modules.CurrentConditions }}
## Current Conditions ## Current Conditions
{{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }} {{ with .TemperatureF }}Currently, it is {{ . }}°F{{ with $.Modules.CurrentConditions.ConditionTextLower }} and {{ . }}{{ end }}.{{ else }}{{ with .ConditionText }}Currently, it is {{ . }}.{{ else }}Current conditions are unavailable.{{ end }}{{ end }}{{ with .ApparentTemperatureF }} It feels like {{ . }}°F{{ with $.Modules.CurrentConditions.RelativeHumidityPercent }}, with a relative humidity of {{ . }}%{{ end }}{{ with $.Modules.CurrentConditions.WindDirectionText }} and winds from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}{{ end }}.{{ else }}{{ with .RelativeHumidityPercent }} Relative humidity is {{ . }}%.{{ end }}{{ with .WindDirectionText }} Winds are from the {{ . }}{{ with $.Modules.CurrentConditions.WindSpeedMph }} at {{ . }} mph{{ end }}.{{ end }}{{ end }}
{{ end }} {{ end -}}
{{ template "today_daypart_forecast" . }} {{ template "today_daypart_forecast" . }}{{ if and .Modules.PrecipTiming .Modules.PrecipTiming.PrecipitationWindows }}{{ template "precipitation_timing" . }}{{ else }}{{ end -}}
{{ template "precipitation_timing" . }}
## Forecast Discussion ## Forecast Discussion
{{ range .GeneratedText.ForecastDiscussion }} {{ range .GeneratedText.ForecastDiscussion }}
{{ . }} {{ . }}

View File

@@ -5,9 +5,7 @@
{{ .GeneratedText.Summary }} {{ .GeneratedText.Summary }}
{{ template "daypart_forecast" . }} {{ template "alert_digest" . }}{{ template "daypart_forecast" . }}{{ if and .Modules.PrecipTiming .Modules.PrecipTiming.PrecipitationWindows }}{{ template "precipitation_timing" . }}{{ else }}{{ end -}}
{{ template "precipitation_timing" . }}
## Forecast Discussion ## Forecast Discussion
{{ range .GeneratedText.ForecastDiscussion }} {{ range .GeneratedText.ForecastDiscussion }}
{{ . }} {{ . }}