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.
- bindai_provider_google/__init__.py +10 -0
- bindai_provider_google/client.py +18 -0
- bindai_provider_google/mapper.py +49 -0
- bindai_provider_google/provider.py +129 -0
- bindai_provider_google-0.1.0.dist-info/METADATA +43 -0
- bindai_provider_google-0.1.0.dist-info/RECORD +9 -0
- bindai_provider_google-0.1.0.dist-info/WHEEL +5 -0
- bindai_provider_google-0.1.0.dist-info/entry_points.txt +2 -0
- bindai_provider_google-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -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 @@
|
|
|
1
|
+
bindai_provider_google
|