Generate Daily reports through scriptorium
This commit is contained in:
@@ -4,6 +4,8 @@ package app
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/adapters/scriptorium"
|
||||
@@ -59,12 +61,12 @@ type DailyBriefingRequest struct {
|
||||
OutputPath string
|
||||
}
|
||||
|
||||
type DailyPreparationRequest struct {
|
||||
Config config.Config
|
||||
Resolved report.Resolved
|
||||
DataPackagePath string
|
||||
Renderer Renderer
|
||||
Store state.Store
|
||||
type DailyReportRequest struct {
|
||||
Config config.Config
|
||||
Resolved report.Resolved
|
||||
OutputPath string
|
||||
Renderer Renderer
|
||||
Store state.Store
|
||||
}
|
||||
|
||||
type DailyBriefingResult struct {
|
||||
@@ -72,20 +74,24 @@ type DailyBriefingResult struct {
|
||||
OutputPath string
|
||||
}
|
||||
|
||||
type DailyPreparationResult struct {
|
||||
type DailyReportResult struct {
|
||||
Briefing briefing.Package
|
||||
BriefingPath string
|
||||
DataPackage promptinput.Package
|
||||
DataPackagePath string
|
||||
PreflightPath string
|
||||
ReportPath string
|
||||
OutputPath string
|
||||
Metadata state.Metadata
|
||||
MetadataPath string
|
||||
PriorSnapshot *state.PriorSnapshot
|
||||
RenderResult *scriptorium.RenderResult
|
||||
RunResult *scriptorium.RunResult
|
||||
}
|
||||
|
||||
type Renderer interface {
|
||||
Render(context.Context, scriptorium.RenderRequest) (*scriptorium.RenderResult, error)
|
||||
Run(context.Context, scriptorium.RunRequest) (*scriptorium.RunResult, error)
|
||||
}
|
||||
|
||||
func Generate(ctx context.Context, req GenerateRequest) error {
|
||||
@@ -94,10 +100,10 @@ func Generate(ctx context.Context, req GenerateRequest) error {
|
||||
return err
|
||||
}
|
||||
if resolved.Definition.ID == report.DailyToday {
|
||||
_, err := PrepareDailyReport(ctx, DailyPreparationRequest{
|
||||
Config: req.Config,
|
||||
Resolved: resolved,
|
||||
DataPackagePath: req.OutputPath,
|
||||
_, err := GenerateDailyReport(ctx, DailyReportRequest{
|
||||
Config: req.Config,
|
||||
Resolved: resolved,
|
||||
OutputPath: req.OutputPath,
|
||||
})
|
||||
return err
|
||||
}
|
||||
@@ -226,7 +232,7 @@ func GenerateDailyBriefing(ctx context.Context, req DailyBriefingRequest) (*Dail
|
||||
return &DailyBriefingResult{Package: pkg, OutputPath: outputPath}, nil
|
||||
}
|
||||
|
||||
func PrepareDailyReport(ctx context.Context, req DailyPreparationRequest) (*DailyPreparationResult, error) {
|
||||
func GenerateDailyReport(ctx context.Context, req DailyReportRequest) (*DailyReportResult, error) {
|
||||
store := req.Store
|
||||
if store == nil {
|
||||
defaultStore, err := defaultStore(req.Config)
|
||||
@@ -269,11 +275,6 @@ func PrepareDailyReport(ctx context.Context, req DailyPreparationRequest) (*Dail
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.DataPackagePath != "" && req.DataPackagePath != dataPackagePath {
|
||||
if err := promptinput.Save(req.DataPackagePath, dataPackage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
renderer := req.Renderer
|
||||
if renderer == nil {
|
||||
@@ -313,16 +314,46 @@ func PrepareDailyReport(ctx context.Context, req DailyPreparationRequest) (*Dail
|
||||
return nil, renderErr
|
||||
}
|
||||
|
||||
return &DailyPreparationResult{
|
||||
reportPath, err := store.PrepareRenderedReport(ctx, req.Resolved)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runResult, runErr := renderer.Run(ctx, scriptorium.RunRequest{
|
||||
PromptID: req.Resolved.Definition.PromptID,
|
||||
DataPackagePath: dataPackagePath,
|
||||
OutputPath: reportPath,
|
||||
})
|
||||
if runErr == nil && req.OutputPath != "" && req.OutputPath != reportPath {
|
||||
if err := copyFileAtomic(reportPath, req.OutputPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
outputPath := reportPath
|
||||
if req.OutputPath != "" {
|
||||
outputPath = req.OutputPath
|
||||
}
|
||||
metadata.RenderedReportPath = reportPath
|
||||
metadataPath, metadataErr = store.SaveMetadata(ctx, metadata)
|
||||
if metadataErr != nil {
|
||||
return nil, metadataErr
|
||||
}
|
||||
if runErr != nil {
|
||||
return nil, runErr
|
||||
}
|
||||
|
||||
return &DailyReportResult{
|
||||
Briefing: briefingPackage,
|
||||
BriefingPath: briefingPath,
|
||||
DataPackage: dataPackage,
|
||||
DataPackagePath: dataPackagePath,
|
||||
PreflightPath: preflightPath,
|
||||
ReportPath: reportPath,
|
||||
OutputPath: outputPath,
|
||||
Metadata: metadata,
|
||||
MetadataPath: metadataPath,
|
||||
PriorSnapshot: priorSnapshot,
|
||||
RenderResult: renderResult,
|
||||
RunResult: runResult,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -354,3 +385,30 @@ func BuildDailyBriefing(req DailyBriefingRequest, bundle *forecast.Bundle) (brie
|
||||
func defaultStore(cfg config.Config) (*state.FilesystemStore, error) {
|
||||
return state.NewFilesystemStore(cfg.Workspace)
|
||||
}
|
||||
|
||||
func copyFileAtomic(source string, target string) error {
|
||||
data, err := os.ReadFile(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read rendered report %q: %w", source, err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
||||
return fmt.Errorf("create report output directory %q: %w", filepath.Dir(target), err)
|
||||
}
|
||||
tmp, err := os.CreateTemp(filepath.Dir(target), "."+filepath.Base(target)+".*.tmp")
|
||||
if err != nil {
|
||||
return fmt.Errorf("create temporary report output file: %w", err)
|
||||
}
|
||||
tmpName := tmp.Name()
|
||||
defer os.Remove(tmpName)
|
||||
if _, err := tmp.Write(data); err != nil {
|
||||
tmp.Close()
|
||||
return fmt.Errorf("write temporary report output file: %w", err)
|
||||
}
|
||||
if err := tmp.Close(); err != nil {
|
||||
return fmt.Errorf("close temporary report output file: %w", err)
|
||||
}
|
||||
if err := os.Rename(tmpName, target); err != nil {
|
||||
return fmt.Errorf("save report output %q: %w", target, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user