-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathanthropic.go
187 lines (157 loc) · 5.2 KB
/
anthropic.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Package main provides functionality to interact with the Anthropic API
// for summarizing Reddit posts using Claude AI models.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
)
const (
// API related constants
anthropicAPIEndpoint = "https://api.anthropic.com/v1/messages"
anthropicAPIVersion = "2023-06-01"
defaultModel = "claude-3-haiku-20240307"
// Environment variable names
envAnthropicAPIKey = "ANTHROPIC_API_KEY"
envAnthropicModel = "ANTHROPIC_MODEL"
// Request parameters
defaultMaxTokens = 1000
defaultTemperature = 0.7
// Output formatting
summaryHeader = "=== Claude's Summary ===\n"
)
// promptTemplate defines the template for the summarization request
const promptTemplate = `Please provide a concise summary of these Reddit posts and discussions.
Focus on:
- Main themes and topics; group similar topics together if possible
- Key points from popular comments
- Notable trends or patterns
- Overall community sentiment
Rules:
- Don't reply with anything but summary.
- Don't reply with the summary for each post. You must cover themes, trends and key points.
Posts to analyze:
%s`
// Message represents a single message in the conversation with Claude
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
// AnthropicRequest represents the structure of a request to the Anthropic API
type AnthropicRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
MaxTokens int `json:"max_tokens"`
Temperature float64 `json:"temperature"`
}
// AnthropicResponse represents the structure of a response from the Anthropic API
type AnthropicResponse struct {
Content []struct {
Text string `json:"text"`
} `json:"content"`
Error *struct {
Message string `json:"error,omitempty"`
} `json:"error,omitempty"`
}
// summarizePosts takes a string of Reddit posts and returns a summarized version using the Anthropic API
func summarizePosts(text string) (string, error) {
// Get model from environment or use default
model := getEnvOrDefault(envAnthropicModel, defaultModel)
log.Printf("INFO: Making Anthropic API call with model: %s", model)
// Get API key from environment
apiKey, err := getRequiredEnvVar(envAnthropicAPIKey)
if err != nil {
return "", err
}
// Prepare the API request
request := createAnthropicRequest(model, text)
// Make the API call
response, err := makeAnthropicAPICall(request, apiKey)
if err != nil {
return "", fmt.Errorf("API call failed: %v", err)
}
// Format and return the response
return formatResponse(response)
}
// getEnvOrDefault returns the value of an environment variable or a default value if not set
func getEnvOrDefault(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// getRequiredEnvVar returns the value of a required environment variable or an error if not set
func getRequiredEnvVar(key string) (string, error) {
value := os.Getenv(key)
if value == "" {
return "", fmt.Errorf("%s environment variable is not set", key)
}
return value, nil
}
// createAnthropicRequest creates a new request structure for the Anthropic API
func createAnthropicRequest(model, text string) AnthropicRequest {
return AnthropicRequest{
Model: model,
Messages: []Message{
{
Role: "user",
Content: fmt.Sprintf(promptTemplate, text),
},
},
MaxTokens: defaultMaxTokens,
Temperature: defaultTemperature,
}
}
// makeAnthropicAPICall sends the request to the Anthropic API and returns the response
func makeAnthropicAPICall(request AnthropicRequest, apiKey string) (*AnthropicResponse, error) {
// Marshal request to JSON
jsonData, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("error marshaling request: %v", err)
}
// Create HTTP request
req, err := http.NewRequest("POST", anthropicAPIEndpoint, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("error creating request: %v", err)
}
// Set headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-api-key", apiKey)
req.Header.Set("anthropic-version", anthropicAPIVersion)
// Make the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error making request: %v", err)
}
defer resp.Body.Close()
// Read response body
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("ERROR: Error in Anthropic API call: %v", err)
return nil, fmt.Errorf("error reading response: %v", err)
}
log.Printf("INFO: Anthropic API call successful with status: %d", resp.StatusCode)
// Parse response
var response AnthropicResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("error unmarshaling response: %v", err)
}
// Check for API errors
if response.Error != nil {
return nil, fmt.Errorf("API error: %s", response.Error.Message)
}
return &response, nil
}
// formatResponse formats the API response into the desired output format
func formatResponse(response *AnthropicResponse) (string, error) {
if len(response.Content) == 0 {
return "", fmt.Errorf("no content in response")
}
return summaryHeader + strings.TrimSpace(response.Content[0].Text), nil
}