Gemini API docs: https://ai.google.dev/gemini-api/docs
(ctx context.Context, aiSetting *storepb.AISetting, request *v1pb.AICompletionRequest)
| 191 | |
| 192 | // Gemini API docs: https://ai.google.dev/gemini-api/docs |
| 193 | func callGemini(ctx context.Context, aiSetting *storepb.AISetting, request *v1pb.AICompletionRequest) (*connect.Response[v1pb.AICompletionResponse], error) { |
| 194 | // Convert messages to Gemini format |
| 195 | var contents []geminiContent |
| 196 | for _, m := range request.Messages { |
| 197 | if m.Content == "" { |
| 198 | continue |
| 199 | } |
| 200 | // Gemini uses "user" and "model" as roles |
| 201 | role := m.Role |
| 202 | if role != "user" { |
| 203 | role = "model" |
| 204 | } |
| 205 | contents = append(contents, geminiContent{ |
| 206 | Role: role, |
| 207 | Parts: []geminiPart{ |
| 208 | {Text: m.Content}, |
| 209 | }, |
| 210 | }) |
| 211 | } |
| 212 | |
| 213 | payload := geminiRequest{ |
| 214 | Contents: contents, |
| 215 | GenerationConfig: geminiGenerationConfig{ |
| 216 | Temperature: 0.7, |
| 217 | TopP: 0.95, |
| 218 | TopK: 40, |
| 219 | MaxOutputTokens: 2048, |
| 220 | }, |
| 221 | } |
| 222 | |
| 223 | payloadBytes, err := json.Marshal(payload) |
| 224 | if err != nil { |
| 225 | return nil, errors.Errorf("failed to marshal Gemini request payload: %s", err) |
| 226 | } |
| 227 | |
| 228 | // Gemini API endpoint format: https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent |
| 229 | requestURL, err := url.JoinPath(aiSetting.Endpoint, "models", aiSetting.Model+":generateContent") |
| 230 | if err != nil { |
| 231 | return nil, errors.Wrap(err, "failed to build Gemini request URL") |
| 232 | } |
| 233 | |
| 234 | httpReq, err := http.NewRequestWithContext(ctx, "POST", requestURL, bytes.NewBuffer(payloadBytes)) |
| 235 | if err != nil { |
| 236 | return nil, errors.Errorf("failed to create HTTP request: %s", err) |
| 237 | } |
| 238 | |
| 239 | httpReq.Header.Set("Content-Type", "application/json") |
| 240 | httpReq.Header.Set("x-goog-api-key", aiSetting.ApiKey) |
| 241 | |
| 242 | client := &http.Client{} |
| 243 | httpResp, err := client.Do(httpReq) |
| 244 | if err != nil { |
| 245 | return nil, errors.Errorf("failed to send HTTP request: %s", err) |
| 246 | } |
| 247 | defer httpResp.Body.Close() |
| 248 | |
| 249 | body, err := io.ReadAll(httpResp.Body) |
| 250 | if err != nil { |