first commit
This commit is contained in:
99
internal/deepseek/deepseek.go
Normal file
99
internal/deepseek/deepseek.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// Package deepseek provides a minimal client for the DeepSeek API,
|
||||
// which is compatible with the OpenAI chat completions format.
|
||||
package deepseek
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
apiURL = "https://api.deepseek.com/chat/completions"
|
||||
model = "deepseek-coder"
|
||||
|
||||
systemPrompt = `You are an expert code reviewer. When given a pull request diff, you:
|
||||
- Identify bugs, logic errors, and edge cases
|
||||
- Flag security vulnerabilities (injections, auth issues, data exposure, etc.)
|
||||
- Note performance concerns
|
||||
- Point out style or maintainability issues
|
||||
- Highlight anything that looks unfinished or unclear
|
||||
|
||||
Be specific: reference file names and line numbers where relevant.
|
||||
Be concise: skip praise for obvious or trivial things.
|
||||
Format your response in Markdown with clear sections.
|
||||
If the diff is clean, say so briefly.`
|
||||
)
|
||||
|
||||
// Client is a DeepSeek API client.
|
||||
type Client struct {
|
||||
APIKey string
|
||||
http *http.Client
|
||||
}
|
||||
|
||||
// New creates a new DeepSeek client.
|
||||
func New(apiKey string) *Client {
|
||||
return &Client{
|
||||
APIKey: apiKey,
|
||||
http: &http.Client{Timeout: 120 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
type chatMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
type chatRequest struct {
|
||||
Model string `json:"model"`
|
||||
Messages []chatMessage `json:"messages"`
|
||||
}
|
||||
|
||||
type chatResponse struct {
|
||||
Choices []struct {
|
||||
Message chatMessage `json:"message"`
|
||||
} `json:"choices"`
|
||||
Error *struct {
|
||||
Message string `json:"message"`
|
||||
} `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Review sends a PR diff to deepseek-coder and returns the review text.
|
||||
func (c *Client) Review(title, diff string) (string, error) {
|
||||
userContent := fmt.Sprintf("Please review this pull request.\n\n**Title:** %s\n\n```diff\n%s\n```", title, diff)
|
||||
|
||||
body, _ := json.Marshal(chatRequest{
|
||||
Model: model,
|
||||
Messages: []chatMessage{
|
||||
{Role: "system", Content: systemPrompt},
|
||||
{Role: "user", Content: userContent},
|
||||
},
|
||||
})
|
||||
|
||||
req, err := http.NewRequest("POST", apiURL, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+c.APIKey)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var r chatResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
|
||||
return "", fmt.Errorf("deepseek: decode response: %w", err)
|
||||
}
|
||||
if r.Error != nil {
|
||||
return "", fmt.Errorf("deepseek: %s", r.Error.Message)
|
||||
}
|
||||
if len(r.Choices) == 0 {
|
||||
return "", fmt.Errorf("deepseek: empty response")
|
||||
}
|
||||
return r.Choices[0].Message.Content, nil
|
||||
}
|
||||
Reference in New Issue
Block a user