196 lines
6.9 KiB
Go
196 lines
6.9 KiB
Go
package generatedtext
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/briefing"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/facts"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
|
|
"gitea.maximumdirect.net/eric/weatherreporter/internal/reporttemplate"
|
|
)
|
|
|
|
const (
|
|
schemaIDHourly = "hourly"
|
|
schemaIDDaily = "daily"
|
|
schemaIDToday = "today"
|
|
schemaIDTomorrow = "tomorrow"
|
|
|
|
templateIDHourly = "hourly"
|
|
templateIDDaily = "daily"
|
|
templateIDToday = "today"
|
|
templateIDTomorrow = "tomorrow"
|
|
)
|
|
|
|
type validator func([]byte) (any, []byte, error)
|
|
|
|
type renderContextBuilder func(report.ID, string, briefing.Metadata, module.Snapshot, facts.CollectedFacts, facts.DerivedFacts, any) (any, error)
|
|
|
|
type catalogEntry struct {
|
|
schemaID string
|
|
templateID string
|
|
validate validator
|
|
renderContextBuilder renderContextBuilder
|
|
}
|
|
|
|
type Handler struct {
|
|
reportID report.ID
|
|
schemaID string
|
|
templateID string
|
|
validate validator
|
|
renderContextBuilder renderContextBuilder
|
|
}
|
|
|
|
var catalog = []catalogEntry{
|
|
{
|
|
schemaID: schemaIDHourly,
|
|
templateID: templateIDHourly,
|
|
validate: validateHourly,
|
|
renderContextBuilder: buildHourlyContext,
|
|
},
|
|
{
|
|
schemaID: schemaIDDaily,
|
|
templateID: templateIDDaily,
|
|
validate: validateDaily,
|
|
renderContextBuilder: buildDailyContext,
|
|
},
|
|
{
|
|
schemaID: schemaIDToday,
|
|
templateID: templateIDToday,
|
|
validate: validateToday,
|
|
renderContextBuilder: buildTodayContext,
|
|
},
|
|
{
|
|
schemaID: schemaIDTomorrow,
|
|
templateID: templateIDTomorrow,
|
|
validate: validateTomorrow,
|
|
renderContextBuilder: buildTomorrowContext,
|
|
},
|
|
}
|
|
|
|
func LookupDefinition(definition report.Definition) (Handler, error) {
|
|
if definition.GenerationMode != report.GenerationModeGeneratedTextTemplate {
|
|
return Handler{}, fmt.Errorf("report %q uses generation mode %q, not %q", definition.ID, definition.GenerationMode, report.GenerationModeGeneratedTextTemplate)
|
|
}
|
|
|
|
var schemaKnown, templateKnown bool
|
|
for _, entry := range catalog {
|
|
if entry.schemaID == definition.GeneratedTextSchemaID {
|
|
schemaKnown = true
|
|
}
|
|
if entry.templateID == definition.TemplateID {
|
|
templateKnown = true
|
|
}
|
|
if entry.schemaID == definition.GeneratedTextSchemaID && entry.templateID == definition.TemplateID {
|
|
return Handler{
|
|
reportID: definition.ID,
|
|
schemaID: entry.schemaID,
|
|
templateID: entry.templateID,
|
|
validate: entry.validate,
|
|
renderContextBuilder: entry.renderContextBuilder,
|
|
}, nil
|
|
}
|
|
}
|
|
if !schemaKnown {
|
|
return Handler{}, fmt.Errorf("generated text schema %q is not supported for report %q", definition.GeneratedTextSchemaID, definition.ID)
|
|
}
|
|
if !templateKnown {
|
|
return Handler{}, fmt.Errorf("report template %q is not supported for report %q", definition.TemplateID, definition.ID)
|
|
}
|
|
return Handler{}, fmt.Errorf("generated text schema %q and report template %q are not supported together for report %q", definition.GeneratedTextSchemaID, definition.TemplateID, definition.ID)
|
|
}
|
|
|
|
func (h Handler) SchemaID() string {
|
|
return h.schemaID
|
|
}
|
|
|
|
func (h Handler) TemplateID() string {
|
|
return h.templateID
|
|
}
|
|
|
|
func (h Handler) Schema() ([]byte, error) {
|
|
data, err := reporttemplate.Schema(h.schemaID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("load generated text schema %q for report %q: %w", h.schemaID, h.reportID, err)
|
|
}
|
|
return data, nil
|
|
}
|
|
|
|
func (h Handler) Template() (string, error) {
|
|
source, err := reporttemplate.Template(h.templateID)
|
|
if err != nil {
|
|
return "", fmt.Errorf("load report template %q for report %q: %w", h.templateID, h.reportID, err)
|
|
}
|
|
return source, nil
|
|
}
|
|
|
|
func (h Handler) Validate(data []byte) (any, []byte, error) {
|
|
if h.validate == nil {
|
|
return nil, nil, fmt.Errorf("generated text validator is not registered for schema %q on report %q", h.schemaID, h.reportID)
|
|
}
|
|
return h.validate(data)
|
|
}
|
|
|
|
func (h Handler) BuildRenderContext(metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
|
if h.renderContextBuilder == nil {
|
|
return nil, fmt.Errorf("render-context builder is not registered for template %q on report %q", h.templateID, h.reportID)
|
|
}
|
|
return h.renderContextBuilder(h.reportID, h.templateID, metadata, snapshot, collected, derived, generated)
|
|
}
|
|
|
|
func (h Handler) Render(data any) ([]byte, error) {
|
|
rendered, err := reporttemplate.Render(h.templateID, data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("render report template %q for report %q: %w", h.templateID, h.reportID, err)
|
|
}
|
|
return rendered, nil
|
|
}
|
|
|
|
func validateHourly(data []byte) (any, []byte, error) {
|
|
return ValidateHourly(data)
|
|
}
|
|
|
|
func validateDaily(data []byte) (any, []byte, error) {
|
|
return ValidateDaily(data)
|
|
}
|
|
|
|
func validateToday(data []byte) (any, []byte, error) {
|
|
return ValidateToday(data)
|
|
}
|
|
|
|
func validateTomorrow(data []byte) (any, []byte, error) {
|
|
return ValidateTomorrow(data)
|
|
}
|
|
|
|
func buildHourlyContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
|
hourly, ok := generated.(Hourly)
|
|
if !ok {
|
|
return nil, fmt.Errorf("report template %q requires hourly generated text for report %q", templateID, reportID)
|
|
}
|
|
return BuildHourlyRenderContext(metadata, snapshot, hourly, collected, derived)
|
|
}
|
|
|
|
func buildDailyContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
|
daily, ok := generated.(Daily)
|
|
if !ok {
|
|
return nil, fmt.Errorf("report template %q requires daily generated text for report %q", templateID, reportID)
|
|
}
|
|
return BuildDailyRenderContext(metadata, snapshot, daily, collected, derived)
|
|
}
|
|
|
|
func buildTodayContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
|
today, ok := generated.(Today)
|
|
if !ok {
|
|
return nil, fmt.Errorf("report template %q requires today generated text for report %q", templateID, reportID)
|
|
}
|
|
return BuildTodayRenderContext(metadata, snapshot, today, collected, derived)
|
|
}
|
|
|
|
func buildTomorrowContext(reportID report.ID, templateID string, metadata briefing.Metadata, snapshot module.Snapshot, collected facts.CollectedFacts, derived facts.DerivedFacts, generated any) (any, error) {
|
|
tomorrow, ok := generated.(Tomorrow)
|
|
if !ok {
|
|
return nil, fmt.Errorf("report template %q requires tomorrow generated text for report %q", templateID, reportID)
|
|
}
|
|
return BuildTomorrowRenderContext(metadata, snapshot, tomorrow, collected, derived)
|
|
}
|