Files
HeatGuard/internal/llm/prompt_test.go
vikingowl 1c9db02334 feat: add web UI with full CRUD setup page
Add server-side rendered setup UI accessible via `heatwave web`.
The dashboard is now re-rendered per request and includes a nav bar
linking to the new /setup page. Setup provides full CRUD for profiles,
rooms, devices, occupants, AC units (with room assignment), scenario
toggles, and forecast fetching — all via POST/redirect/GET forms.

- Add ShowNav field to DashboardData for conditional nav bar
- Extract fetchForecastForProfile() for reuse by web handler
- Create setup.html.tmpl with Tailwind-styled entity sections
- Create web_handlers.go with 15 route handlers and flash cookies
- Switch web.go from pre-rendered to per-request dashboard rendering
- Graceful dashboard fallback when no forecast data exists
2026-02-09 10:39:00 +01:00

94 lines
2.2 KiB
Go

package llm
import (
"strings"
"testing"
)
func testSummaryInput() SummaryInput {
return SummaryInput{
Date: "2025-07-15",
PeakTempC: 37.2,
MinNightTempC: 22.5,
RiskLevel: "high",
TopHeatSources: []HeatSource{{Name: "Gaming PC", Watts: 200}, {Name: "Monitor", Watts: 80}},
ACHeadroomBTUH: 4500,
BudgetStatus: "marginal",
ActiveWarnings: []string{"DWD: Amtliche WARNUNG vor HITZE"},
RiskWindows: []RiskWindowSummary{{StartHour: 11, EndHour: 18, PeakTempC: 37.2, Level: "high"}},
}
}
func TestBuildSummaryPrompt_ContainsAllFields(t *testing.T) {
p := BuildSummaryPrompt(testSummaryInput())
checks := []string{
"2025-07-15",
"37.2",
"22.5",
"high",
"Gaming PC",
"200W",
"4500 BTU/h",
"marginal",
"WARNUNG",
"11:00",
"18:00",
}
for _, c := range checks {
if !strings.Contains(p, c) {
t.Errorf("prompt missing %q", c)
}
}
}
func TestBuildRewriteActionPrompt(t *testing.T) {
p := BuildRewriteActionPrompt(ActionInput{
ActionName: "Close south-facing shutters",
Description: "Block direct sun",
TempC: 34.5,
Hour: 9,
})
if !strings.Contains(p, "Close south-facing shutters") {
t.Error("missing action name")
}
if !strings.Contains(p, "34.5") {
t.Error("missing temperature")
}
if !strings.Contains(p, "09:00") {
t.Error("missing hour")
}
}
func TestBuildHeatPlanPrompt(t *testing.T) {
input := HeatPlanInput{
Summary: testSummaryInput(),
Timeline: []TimelineSlotSummary{
{Hour: 12, TempC: 35, RiskLevel: "high", BudgetStatus: "marginal", Actions: []string{"Hydration"}},
},
CareChecklist: []string{"Check elderly occupants at 14:00"},
}
p := BuildHeatPlanPrompt(input)
if !strings.Contains(p, "Timeline:") {
t.Error("missing timeline section")
}
if !strings.Contains(p, "Hydration") {
t.Error("missing actions")
}
if !strings.Contains(p, "Care checklist:") {
t.Error("missing care checklist")
}
}
func TestSystemPrompts_NotEmpty(t *testing.T) {
if SummarizeSystemPrompt() == "" {
t.Error("empty summarize system prompt")
}
if RewriteActionSystemPrompt() == "" {
t.Error("empty rewrite system prompt")
}
if HeatPlanSystemPrompt() == "" {
t.Error("empty heatplan system prompt")
}
}