|
3 | 3 | import logging |
4 | 4 | from typing import Optional |
5 | 5 |
|
6 | | -import google.generativeai as genai |
7 | | -from google.api_core.exceptions import GoogleAPICallError |
| 6 | +from google import genai |
| 7 | +from google.genai import errors, types |
8 | 8 |
|
9 | 9 | from frigate.config import GenAIProviderEnum |
10 | 10 | from frigate.genai import GenAIClient, register_genai_provider |
|
16 | 16 | class GeminiClient(GenAIClient): |
17 | 17 | """Generative AI client for Frigate using Gemini.""" |
18 | 18 |
|
19 | | - provider: genai.GenerativeModel |
| 19 | + provider: genai.Client |
20 | 20 |
|
21 | 21 | def _init_provider(self): |
22 | 22 | """Initialize the client.""" |
23 | | - genai.configure(api_key=self.genai_config.api_key) |
24 | | - return genai.GenerativeModel( |
25 | | - self.genai_config.model, **self.genai_config.provider_options |
| 23 | + # Merge provider_options into HttpOptions |
| 24 | + http_options_dict = { |
| 25 | + "api_version": "v1", |
| 26 | + "timeout": int(self.timeout * 1000), # requires milliseconds |
| 27 | + } |
| 28 | + |
| 29 | + if isinstance(self.genai_config.provider_options, dict): |
| 30 | + http_options_dict.update(self.genai_config.provider_options) |
| 31 | + |
| 32 | + return genai.Client( |
| 33 | + api_key=self.genai_config.api_key, |
| 34 | + http_options=types.HttpOptions(**http_options_dict), |
26 | 35 | ) |
27 | 36 |
|
28 | 37 | def _send(self, prompt: str, images: list[bytes]) -> Optional[str]: |
29 | 38 | """Submit a request to Gemini.""" |
30 | | - data = [ |
31 | | - { |
32 | | - "mime_type": "image/jpeg", |
33 | | - "data": img, |
34 | | - } |
35 | | - for img in images |
| 39 | + contents = [ |
| 40 | + types.Part.from_bytes(data=img, mime_type="image/jpeg") for img in images |
36 | 41 | ] + [prompt] |
37 | 42 | try: |
38 | 43 | # Merge runtime_options into generation_config if provided |
39 | 44 | generation_config_dict = {"candidate_count": 1} |
40 | 45 | generation_config_dict.update(self.genai_config.runtime_options) |
41 | 46 |
|
42 | | - response = self.provider.generate_content( |
43 | | - data, |
44 | | - generation_config=genai.types.GenerationConfig( |
45 | | - **generation_config_dict |
46 | | - ), |
47 | | - request_options=genai.types.RequestOptions( |
48 | | - timeout=self.timeout, |
| 47 | + response = self.provider.models.generate_content( |
| 48 | + model=self.genai_config.model, |
| 49 | + contents=contents, |
| 50 | + config=types.GenerateContentConfig( |
| 51 | + **generation_config_dict, |
49 | 52 | ), |
50 | 53 | ) |
51 | | - except GoogleAPICallError as e: |
| 54 | + except errors.APIError as e: |
52 | 55 | logger.warning("Gemini returned an error: %s", str(e)) |
53 | 56 | return None |
| 57 | + except Exception as e: |
| 58 | + logger.warning("An unexpected error occurred with Gemini: %s", str(e)) |
| 59 | + return None |
| 60 | + |
54 | 61 | try: |
55 | 62 | description = response.text.strip() |
56 | | - except ValueError: |
| 63 | + except (ValueError, AttributeError): |
57 | 64 | # No description was generated |
58 | 65 | return None |
59 | 66 | return description |
|
0 commit comments