41 lines
1.3 KiB
Go
41 lines
1.3 KiB
Go
// Package analyze turns fetched market data + news into an investment-advice
|
|
// report via Claude, using one of two interchangeable modes: "subscription"
|
|
// (shells out to the `claude` CLI, billed against a Claude Pro/Max
|
|
// subscription) or "api" (calls the Messages API directly, billed per token).
|
|
package analyze
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"gitea.konchin.com/service/stonks/internal/config"
|
|
)
|
|
|
|
// Analyzer sends a prompt to Claude and returns the response text.
|
|
type Analyzer interface {
|
|
Analyze(ctx context.Context, prompt string) (string, error)
|
|
}
|
|
|
|
// Constructor builds an Analyzer from the analyzer config block.
|
|
type Constructor func(cfg config.AnalyzerConfig) (Analyzer, error)
|
|
|
|
var registry = map[string]Constructor{}
|
|
|
|
// Register makes an analyzer constructor available under mode. Called from
|
|
// each mode implementation's init().
|
|
func Register(mode string, ctor Constructor) {
|
|
if _, exists := registry[mode]; exists {
|
|
panic(fmt.Sprintf("analyze: constructor already registered for mode %q", mode))
|
|
}
|
|
registry[mode] = ctor
|
|
}
|
|
|
|
// Build looks up the constructor for cfg.Mode and invokes it.
|
|
func Build(cfg config.AnalyzerConfig) (Analyzer, error) {
|
|
ctor, ok := registry[cfg.Mode]
|
|
if !ok {
|
|
return nil, fmt.Errorf("analyze: no analyzer registered for mode %q", cfg.Mode)
|
|
}
|
|
return ctor(cfg)
|
|
}
|