bindai-provider-google 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ from bindai_core import ProviderFactory
2
+
3
+ from .provider import GoogleProvider
4
+
5
+
6
+ def register():
7
+ ProviderFactory.register("google", GoogleProvider)
8
+
9
+
10
+ __all__ = ["GoogleProvider", "register"]
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from bindai_core import ProviderConfiguration
4
+ from google import genai
5
+
6
+
7
+ class GoogleClient:
8
+ def __init__(self, configuration: ProviderConfiguration) -> None:
9
+ self._configuration = configuration
10
+ self._client: genai.Client | None = None
11
+
12
+ @property
13
+ def client(self) -> genai.Client:
14
+ if self._client is None:
15
+ self._client = genai.Client(
16
+ api_key=self._configuration.api_key,
17
+ )
18
+ return self._client
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from bindai_core import Message, MessageRole
4
+
5
+
6
+ class GoogleMapper:
7
+ """
8
+ Converts BindAI messages into Google Gemini SDK-compatible content.
9
+ """
10
+
11
+ @staticmethod
12
+ def messages(
13
+ messages: list[Message],
14
+ ) -> tuple[str | None, list[dict]]:
15
+ system: str | None = None
16
+ result: list[dict] = []
17
+
18
+ for message in messages:
19
+ if message.role == MessageRole.SYSTEM:
20
+ system = message.content
21
+ continue
22
+
23
+ if message.role == MessageRole.USER:
24
+ result.append(
25
+ {
26
+ "role": "user",
27
+ "parts": [{"text": message.content}],
28
+ }
29
+ )
30
+ continue
31
+
32
+ if message.role == MessageRole.ASSISTANT:
33
+ result.append(
34
+ {
35
+ "role": "model",
36
+ "parts": [{"text": message.content}],
37
+ }
38
+ )
39
+ continue
40
+
41
+ if message.role == MessageRole.TOOL:
42
+ result.append(
43
+ {
44
+ "role": "user",
45
+ "parts": [{"text": message.content}],
46
+ }
47
+ )
48
+
49
+ return system, result
@@ -0,0 +1,129 @@
1
+ from __future__ import annotations
2
+
3
+ from bindai_core import (
4
+ ModelProvider,
5
+ ModelRequest,
6
+ ModelResponse,
7
+ ProviderCapabilities,
8
+ ProviderConfiguration,
9
+ StreamChunk,
10
+ TokenUsage,
11
+ )
12
+
13
+ from .client import GoogleClient
14
+ from .mapper import GoogleMapper
15
+
16
+
17
+ class GoogleProvider(ModelProvider):
18
+ """
19
+ Google Gemini implementation of ModelProvider.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ configuration: ProviderConfiguration,
25
+ ):
26
+ super().__init__(configuration)
27
+ self._client = GoogleClient(configuration)
28
+
29
+ @property
30
+ def name(self) -> str:
31
+ return "google"
32
+
33
+ @property
34
+ def capabilities(self) -> ProviderCapabilities:
35
+ return ProviderCapabilities(
36
+ chat=True,
37
+ streaming=True,
38
+ vision=True,
39
+ embeddings=False,
40
+ tool_calling=True,
41
+ structured_output=True,
42
+ reasoning=True,
43
+ )
44
+
45
+ def _build_kwargs(
46
+ self,
47
+ request: ModelRequest,
48
+ ) -> dict:
49
+ system, messages = GoogleMapper.messages(
50
+ request.messages,
51
+ )
52
+
53
+ kwargs: dict[str, object] = {
54
+ "model": self.configuration.model,
55
+ "contents": messages,
56
+ }
57
+
58
+ config: dict[str, object] = {}
59
+
60
+ if system is not None:
61
+ config["system_instruction"] = system
62
+
63
+ if request.temperature is not None:
64
+ config["temperature"] = request.temperature
65
+
66
+ if request.max_tokens is not None:
67
+ config["max_output_tokens"] = request.max_tokens
68
+
69
+ if request.top_p is not None:
70
+ config["top_p"] = request.top_p
71
+
72
+ if request.stop is not None:
73
+ config["stop_sequences"] = request.stop
74
+
75
+ if config:
76
+ kwargs["config"] = config
77
+
78
+ return kwargs
79
+
80
+ def generate(
81
+ self,
82
+ request: ModelRequest,
83
+ ) -> ModelResponse:
84
+ response = self._client.client.models.generate_content(
85
+ **self._build_kwargs(request),
86
+ )
87
+
88
+ usage_metadata = response.usage_metadata
89
+
90
+ usage = TokenUsage(
91
+ prompt_tokens=(usage_metadata.prompt_token_count or 0) if usage_metadata else 0,
92
+ completion_tokens=(usage_metadata.candidates_token_count or 0) if usage_metadata else 0,
93
+ total_tokens=(usage_metadata.total_token_count or 0) if usage_metadata else 0,
94
+ )
95
+
96
+ content = response.text or ""
97
+
98
+ finish_reason = None
99
+
100
+ if response.candidates:
101
+ finish_reason = str(response.candidates[0].finish_reason)
102
+
103
+ return ModelResponse(
104
+ content=content,
105
+ usage=usage,
106
+ finish_reason=finish_reason,
107
+ model=response.model_version or self.configuration.model,
108
+ )
109
+
110
+ def stream(
111
+ self,
112
+ request: ModelRequest,
113
+ ):
114
+ response = self._client.client.models.generate_content_stream(
115
+ **self._build_kwargs(request),
116
+ )
117
+
118
+ for chunk in response:
119
+ text = chunk.text or ""
120
+
121
+ if text:
122
+ yield StreamChunk(
123
+ delta=text,
124
+ )
125
+
126
+ yield StreamChunk(
127
+ delta="",
128
+ finished=True,
129
+ )
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: bindai-provider-google
3
+ Version: 0.1.0
4
+ Summary: Google Gemini provider for BindAI
5
+ Requires-Python: >=3.11
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: google-genai>=2.22.0
8
+ Requires-Dist: bindai-core
9
+
10
+ # bindai-provider-google
11
+
12
+ Google Gemini provider for the BindAI framework.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install "bindai[google]"
18
+ ```
19
+
20
+ Or install the provider directly:
21
+
22
+ ```bash
23
+ pip install bindai-provider-google
24
+ ```
25
+
26
+ ## Configuration
27
+
28
+ Set your Google Gemini API key:
29
+
30
+ ```env
31
+ GEMINI_API_KEY=your-api-key
32
+ ```
33
+
34
+ Then configure your BindAI project:
35
+
36
+ ```toml
37
+ provider = "google"
38
+ model = "gemini-2.5-flash"
39
+ ```
40
+
41
+ ## License
42
+
43
+ MIT
@@ -0,0 +1,9 @@
1
+ bindai_provider_google/__init__.py,sha256=42z6pKEAq4-qIdgJM9pOQhHq4ssAinsbBY5tHwX3a1I,194
2
+ bindai_provider_google/client.py,sha256=OqysX1OQK5tXrYWS5kClQTkvpBU_locm9k5zzEnjXhA,514
3
+ bindai_provider_google/mapper.py,sha256=GHFFhb9k2gjsFgMIgVVSDT9nve6GD1zyBXIRArKaYsY,1340
4
+ bindai_provider_google/provider.py,sha256=B45aA8z4Y2zbmonE2CRaa3l8NS_iTE2EM6NAW4i2DkI,3235
5
+ bindai_provider_google-0.1.0.dist-info/METADATA,sha256=WfDjsXWjXd7AXjxpehqnGu_6m8rJbwHsfwNR0zpAV8g,702
6
+ bindai_provider_google-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
7
+ bindai_provider_google-0.1.0.dist-info/entry_points.txt,sha256=vggMe0Hffzlhs_ApaY3e2uppbfQEhVrtlm13RcibF68,60
8
+ bindai_provider_google-0.1.0.dist-info/top_level.txt,sha256=uRmYXUwfRxfAY09Ou_BZ9ICUs0Wqf33J3HvOPMAC7WE,23
9
+ bindai_provider_google-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [bindai.providers]
2
+ google = bindai_provider_google:register
@@ -0,0 +1 @@
1
+ bindai_provider_google