feat: done vibing
This commit is contained in:
27 files changed
+1922
-13
No files matched your search
@@ -0,0 +1,77 @@
|
||||
package analyze
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/anthropics/anthropic-sdk-go"
|
||||
|
||||
"github.com/ytshih/stonks/internal/config"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("api", newAPIAnalyzer)
|
||||
}
|
||||
|
||||
const defaultAPIModel = anthropic.ModelClaudeOpus5
|
||||
|
||||
// apiAnalyzer calls the Claude Messages API directly, billed per token.
|
||||
// Reads credentials the standard way (ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN
|
||||
// / an `ant auth login` profile) via the zero-arg client constructor.
|
||||
type apiAnalyzer struct {
|
||||
client anthropic.Client
|
||||
model anthropic.Model
|
||||
effort anthropic.OutputConfigEffort
|
||||
}
|
||||
|
||||
func newAPIAnalyzer(cfg config.AnalyzerConfig) (Analyzer, error) {
|
||||
model := anthropic.Model(cfg.Model)
|
||||
if cfg.Model == "" {
|
||||
model = defaultAPIModel
|
||||
}
|
||||
|
||||
effort := anthropic.OutputConfigEffortMedium
|
||||
if cfg.Effort != "" {
|
||||
effort = anthropic.OutputConfigEffort(cfg.Effort)
|
||||
}
|
||||
|
||||
return &apiAnalyzer{
|
||||
client: anthropic.NewClient(),
|
||||
model: model,
|
||||
effort: effort,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *apiAnalyzer) Analyze(ctx context.Context, prompt string) (string, error) {
|
||||
resp, err := a.client.Messages.New(ctx, anthropic.MessageNewParams{
|
||||
Model: a.model,
|
||||
MaxTokens: 4096,
|
||||
System: []anthropic.TextBlockParam{{Text: SystemPrompt}},
|
||||
OutputConfig: anthropic.OutputConfigParam{
|
||||
Effort: a.effort,
|
||||
},
|
||||
Messages: []anthropic.MessageParam{
|
||||
anthropic.NewUserMessage(anthropic.NewTextBlock(prompt)),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("analyze (api mode): %w", err)
|
||||
}
|
||||
|
||||
if resp.StopReason == anthropic.StopReasonRefusal {
|
||||
return "", fmt.Errorf("analyze (api mode): request refused by safety classifiers")
|
||||
}
|
||||
|
||||
var out strings.Builder
|
||||
for _, block := range resp.Content {
|
||||
if text, ok := block.AsAny().(anthropic.TextBlock); ok {
|
||||
out.WriteString(text.Text)
|
||||
}
|
||||
}
|
||||
if out.Len() == 0 {
|
||||
return "", fmt.Errorf("analyze (api mode): response contained no text content (stop_reason=%s)", resp.StopReason)
|
||||
}
|
||||
|
||||
return out.String(), nil
|
||||
}
|
||||
Reference in new issue
Block a user