package ai import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" ) type geminiProvider struct { apiKey string model string client *http.Client } func newGemini(apiKey, model string) *geminiProvider { if model == "" { model = "gemini-2.0-flash" } return &geminiProvider{ apiKey: apiKey, model: model, client: &http.Client{}, } } func (p *geminiProvider) Name() string { return "gemini" } func (p *geminiProvider) Summarize(ctx context.Context, prompt string, _ GenOptions) (string, error) { url := fmt.Sprintf( "https://generativelanguage.googleapis.com/v1beta/models/%s:generateContent?key=%s", p.model, p.apiKey, ) body := map[string]interface{}{ "contents": []map[string]interface{}{ {"parts": []map[string]string{{"text": prompt}}}, }, } b, _ := json.Marshal(body) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(b)) if err != nil { return "", err } req.Header.Set("Content-Type", "application/json") resp, err := p.client.Do(req) if err != nil { return "", err } defer resp.Body.Close() raw, _ := io.ReadAll(resp.Body) if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("gemini API error %d: %s", resp.StatusCode, raw) } var result struct { Candidates []struct { Content struct { Parts []struct { Text string `json:"text"` } `json:"parts"` } `json:"content"` } `json:"candidates"` } if err := json.Unmarshal(raw, &result); err != nil { return "", err } if len(result.Candidates) == 0 || len(result.Candidates[0].Content.Parts) == 0 { return "", nil } return result.Candidates[0].Content.Parts[0].Text, nil } func (p *geminiProvider) ListModels(ctx context.Context) ([]string, error) { url := fmt.Sprintf("https://generativelanguage.googleapis.com/v1beta/models?key=%s", p.apiKey) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } resp, err := p.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() raw, _ := io.ReadAll(resp.Body) if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("gemini list models error %d: %s", resp.StatusCode, raw) } var result struct { Models []struct { Name string `json:"name"` SupportedMethods []string `json:"supportedGenerationMethods"` } `json:"models"` } if err := json.Unmarshal(raw, &result); err != nil { return nil, err } var names []string for _, m := range result.Models { for _, method := range m.SupportedMethods { if method == "generateContent" { // name is "models/gemini-xxx", strip prefix id := m.Name if len(id) > 7 { id = id[7:] // strip "models/" } names = append(names, id) break } } } return names, nil }