SouravNath commited on
Commit
0d90d84
·
1 Parent(s): 96bf32b

fix: GeminiClient now uses httpx REST (no deprecated google-generativeai SDK)

Browse files
Files changed (1) hide show
  1. agent/llm_client.py +33 -33
agent/llm_client.py CHANGED
@@ -133,56 +133,56 @@ class GroqClient(LLMClient):
133
 
134
  class GeminiClient(LLMClient):
135
  """
136
- Google Gemini API — free tier.
137
- gemini-1.5-flash: 15 RPM, 1,000,000 tokens/day perfect for SWE-bench eval.
138
- gemini-1.5-pro: 2 RPM, 32,000 tokens/day (slower, use for hard cases).
139
- gemini-2.0-flash: latest, fast, generous free tier.
 
140
 
141
  Sign up: https://aistudio.google.com (no credit card required)
142
  Set env var: GEMINI_API_KEY=AIza...
143
  """
144
 
 
 
145
  def __init__(self, model: str = "gemini-2.0-flash"):
146
  self._model = model
147
- self._genai = None
148
 
149
  @property
150
  def model_name(self) -> str:
151
  return f"gemini/{self._model}"
152
 
153
- def _get_client(self):
154
- if self._genai is None:
155
- try:
156
- import google.generativeai as genai
157
- genai.configure(api_key=os.environ.get("GEMINI_API_KEY"))
158
- self._genai = genai
159
- except ImportError:
160
- raise ImportError("Install: pip install google-generativeai")
161
- return self._genai
162
-
163
  def complete(self, system: str, user: str, max_tokens: int = 4096, temperature: float = 0.2) -> tuple[str, dict]:
164
- genai = self._get_client()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  start = time.monotonic()
166
  try:
167
- model = genai.GenerativeModel(
168
- model_name=self._model,
169
- system_instruction=system,
170
- generation_config=genai.GenerationConfig(
171
- max_output_tokens=max_tokens,
172
- temperature=temperature,
173
- )
174
- )
175
- response = model.generate_content(user)
176
- text = response.text or ""
177
- # Gemini doesn't always return usage metadata in free tier
178
- prompt_tokens = getattr(getattr(response, "usage_metadata", None), "prompt_token_count", 0) or 0
179
- completion_tokens = getattr(getattr(response, "usage_metadata", None), "candidates_token_count", 0) or 0
180
  usage = {
181
- "prompt_tokens": prompt_tokens,
182
- "completion_tokens": completion_tokens,
183
- "total_tokens": prompt_tokens + completion_tokens,
184
  }
185
- logger.info("Gemini %s: %.1fs", self._model, time.monotonic() - start)
186
  return text, usage
187
  except Exception as e:
188
  logger.warning("Gemini error: %s", e)
 
133
 
134
  class GeminiClient(LLMClient):
135
  """
136
+ Google Gemini API via direct REST calls no SDK needed.
137
+ Uses httpx which is already in requirements.txt.
138
+
139
+ gemini-2.0-flash: fast, generous free tier (15 RPM, 1M tokens/day)
140
+ gemini-2.5-flash: newest model, same free tier
141
 
142
  Sign up: https://aistudio.google.com (no credit card required)
143
  Set env var: GEMINI_API_KEY=AIza...
144
  """
145
 
146
+ BASE_URL = "https://generativelanguage.googleapis.com/v1beta/models"
147
+
148
  def __init__(self, model: str = "gemini-2.0-flash"):
149
  self._model = model
 
150
 
151
  @property
152
  def model_name(self) -> str:
153
  return f"gemini/{self._model}"
154
 
 
 
 
 
 
 
 
 
 
 
155
  def complete(self, system: str, user: str, max_tokens: int = 4096, temperature: float = 0.2) -> tuple[str, dict]:
156
+ import httpx
157
+
158
+ api_key = os.environ.get("GEMINI_API_KEY", "")
159
+ if not api_key:
160
+ raise EnvironmentError("GEMINI_API_KEY not set")
161
+
162
+ url = f"{self.BASE_URL}/{self._model}:generateContent?key={api_key}"
163
+ payload = {
164
+ "system_instruction": {"parts": [{"text": system}]},
165
+ "contents": [{"parts": [{"text": user}]}],
166
+ "generationConfig": {
167
+ "maxOutputTokens": max_tokens,
168
+ "temperature": temperature,
169
+ },
170
+ }
171
+
172
  start = time.monotonic()
173
  try:
174
+ resp = httpx.post(url, json=payload, timeout=120)
175
+ resp.raise_for_status()
176
+ data = resp.json()
177
+
178
+ text = data["candidates"][0]["content"]["parts"][0]["text"]
179
+ meta = data.get("usageMetadata", {})
 
 
 
 
 
 
 
180
  usage = {
181
+ "prompt_tokens": meta.get("promptTokenCount", 0),
182
+ "completion_tokens": meta.get("candidatesTokenCount", 0),
183
+ "total_tokens": meta.get("totalTokenCount", 0),
184
  }
185
+ logger.info("Gemini %s: %.1fs | %d tokens", self._model, time.monotonic() - start, usage["total_tokens"])
186
  return text, usage
187
  except Exception as e:
188
  logger.warning("Gemini error: %s", e)