package inflation import ( "embed" "fmt" "html/template" "io" "net/http" "os" "time" "git.tijl.dev/tijl/tijl.dev-core/internal/config" "git.tijl.dev/tijl/tijl.dev-core/modules/i18n" log "git.tijl.dev/tijl/tijl.dev-core/modules/logger" "git.tijl.dev/tijl/tijl.dev-core/modules/web" "github.com/go-echarts/go-echarts/v2/charts" "github.com/go-echarts/go-echarts/v2/opts" "github.com/gofiber/fiber/v2" ) type Datas struct { Name string ProcessFunction func(map[time.Time]float32) map[time.Time]float32 } var rawData = make(map[string]map[time.Time]float32) var datas = map[string]Datas{ "CPIAUCSL": { Name: "CPI USA BASE", ProcessFunction: toPercentNeg, }, "PCEPI": { Name: "PCECPI USA", ProcessFunction: toPercentNeg, }, "M2SL": { Name: "M2 USA", ProcessFunction: toPercentNeg, }, "CP0000EZ19M086NEST": { Name: "HICP ECB", ProcessFunction: toPercentNeg, }, "MABMM301EZM189S": { Name: "M3 ECB", ProcessFunction: toPercentNeg, }, "CBBTCUSD": { Name: "Bitcoin", ProcessFunction: toPercent, }, "APU0000708111": { Name: "Eggs", ProcessFunction: toPercent, }, } //go:embed locales/* var Embed embed.FS func Setup() { err := LoadData() if err != nil { log.Error().Err(err).Msg("inflation.Setup: Error loading data") } i18n.RegisterTranslations(Embed, "locales") web.RegisterAppSetupFunc(func(a *fiber.App) { a.Get("app/inflation", func(c *fiber.Ctx) error { processedData := make(map[string]map[time.Time]float32) for id, data := range datas { processedData[id] = data.ProcessFunction(rawData[id]) } line := charts.NewLine() startYear, endYear := getYearRange(processedData) yearList := createYearList(startYear, endYear) for seriesID, timeData := range processedData { aggregatedData := aggregateDataByYear(timeData) yAxisT := []opts.LineData{} var useAmount float32 = 1 for _, year := range yearList { if value, exists := aggregatedData[year]; exists { current := (value / 100) * useAmount useAmount = useAmount + current yAxisT = append(yAxisT, opts.LineData{Value: useAmount}) } else { yAxisT = append(yAxisT, opts.LineData{Value: nil}) } } line.AddSeries(datas[seriesID].Name, yAxisT) } line.SetXAxis(yearList) line.SetGlobalOptions( charts.WithTitleOpts(opts.Title{ Title: "Inflation", Subtitle: "Copyright Tijl 2024", }), charts.WithDataZoomOpts(opts.DataZoom{ Orient: "horizontal", Type: "slider", }), ) rendered := line.RenderSnippet() data := *web.Common(c) data["Title"] = "tmp" data["RenderedScript"] = template.JS(handleScriptElement(rendered.Script)) data["RenderedElement"] = template.HTML(rendered.Element) return c.Render("apps/inflation/index", data, "layouts/base") }) a.Get("/app/inflation/base", func(c *fiber.Ctx) error { processedData := make(map[string]map[time.Time]float32) for id, data := range datas { processedData[id] = data.ProcessFunction(rawData[id]) } line := charts.NewLine() startYear, endYear := getYearRange(processedData) yearList := createYearList(startYear, endYear) for seriesID, timeData := range processedData { aggregatedData := aggregateDataByYear(timeData) yAxisT := []opts.LineData{} for _, year := range yearList { if value, exists := aggregatedData[year]; exists { yAxisT = append(yAxisT, opts.LineData{Value: value}) } else { yAxisT = append(yAxisT, opts.LineData{Value: nil}) } } line.AddSeries(datas[seriesID].Name, yAxisT) } line.SetXAxis(yearList) line.SetGlobalOptions( charts.WithTitleOpts(opts.Title{ Title: "Inflation", Subtitle: "Copyright Tijl 2024", }), charts.WithDataZoomOpts(opts.DataZoom{ Orient: "horizontal", Type: "slider", }), ) rendered := line.RenderSnippet() data := *web.Common(c) data["Title"] = "tmp" data["RenderedScript"] = template.JS(handleScriptElement(rendered.Script)) data["RenderedElement"] = template.HTML(rendered.Element) return c.Render("apps/inflation/index", data, "layouts/base") }) }, 1000) } func LoadData() error { var baseDataPath = config.Config.DataLocation + "/apps/inflation/data/" if _, err := os.Stat(baseDataPath); os.IsNotExist(err) { err := os.MkdirAll(baseDataPath, os.ModePerm) if err != nil { return err } } // Load fred data const fredBaseUrl = "https://fred.stlouisfed.org/graph/fredgraph.csv?id=" for id := range datas { info, err := os.Stat(baseDataPath + id + ".csv") if !os.IsNotExist(err) { modTime := info.ModTime() currentTime := time.Now() if modTime.Year() == currentTime.Year() && modTime.Month() == currentTime.Month() { csvdata, err := readCSV(baseDataPath + id + ".csv") if err != nil { return err } rawData[id] = csvdata continue } } resp, err := http.Get(fredBaseUrl + id) log.Debug().Str("id", id).Msg("inflation.LoadData: getting") if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed to fetch data: %v", resp.Status) } file, err := os.Create(baseDataPath + id + ".csv") if err != nil { return err } defer file.Close() _, err = io.Copy(file, resp.Body) if err != nil { return err } csvdata, err := readCSV(baseDataPath + id + ".csv") if err != nil { return err } rawData[id] = csvdata } return nil }