From 36182e97c61fffdebf11cbdff9f03187a177f474 Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Tue, 14 May 2024 17:59:45 +0000 Subject: [PATCH 01/12] Fix and improve --- google/generativeai/generative_models.py | 10 ++++++---- google/generativeai/models.py | 24 +++++++++++------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/google/generativeai/generative_models.py b/google/generativeai/generative_models.py index a0e7df1e2..8924b9ae4 100644 --- a/google/generativeai/generative_models.py +++ b/google/generativeai/generative_models.py @@ -389,7 +389,7 @@ def start_chat( >>> response = chat.send_message("Hello?") Arguments: - history: An iterable of `glm.Content` objects, or equvalents to initialize the session. + history: An iterable of `glm.Content` objects, or equivalents to initialize the session. """ if self._generation_config.get("candidate_count", 1) > 1: raise ValueError("Can't chat with `candidate_count > 1`") @@ -403,11 +403,13 @@ def start_chat( class ChatSession: """Contains an ongoing conversation with the model. - >>> model = genai.GenerativeModel(model="gemini-pro") + >>> model = genai.GenerativeModel('models/gemini-pro') >>> chat = model.start_chat() >>> response = chat.send_message("Hello") >>> print(response.text) - >>> response = chat.send_message(...) + >>> response = chat.send_message("Hello again") + >>> print(response.text) + >>> response = chat.send_message(... This `ChatSession` object collects the messages sent and received, in its `ChatSession.history` attribute. @@ -446,7 +448,7 @@ def send_message( Appends the request and response to the conversation history. - >>> model = genai.GenerativeModel(model="gemini-pro") + >>> model = genai.GenerativeModel('models/gemini-pro') >>> chat = model.start_chat() >>> response = chat.send_message("Hello") >>> print(response.text) diff --git a/google/generativeai/models.py b/google/generativeai/models.py index 7c7b8a5cf..3de641574 100644 --- a/google/generativeai/models.py +++ b/google/generativeai/models.py @@ -33,29 +33,27 @@ def get_model( client=None, request_options: dict[str, Any] | None = None, ) -> model_types.Model | model_types.TunedModel: - """Given a model name, fetch the `types.Model` or `types.TunedModel` object. + """Given a model name, fetch the `types.Model` ``` import pprint - model = genai.get_tuned_model(model_name): + model = genai.get_model('models/gemini-pro') pprint.pprint(model) ``` Args: - name: The name of the model to fetch. + name: The name of the model to fetch. Should start with `models/` client: The client to use. request_options: Options for the request. Returns: - A `types.Model` or `types.TunedModel` object. + A `types.Model` """ name = model_types.make_model_name(name) if name.startswith("models/"): return get_base_model(name, client=client, request_options=request_options) - elif name.startswith("tunedModels/"): - return get_tuned_model(name, client=client, request_options=request_options) else: - raise ValueError("Model names must start with `models/` or `tunedModels/`") + raise ValueError("Model names must start with `models/` received: {name}") def get_base_model( @@ -68,12 +66,12 @@ def get_base_model( ``` import pprint - model = genai.get_model('models/chat-bison-001'): + model = genai.get_base_model('models/chat-bison-001') pprint.pprint(model) ``` Args: - name: The name of the model to fetch. + name: The name of the model to fetch. Should start with `models/` client: The client to use. request_options: Options for the request. @@ -88,7 +86,7 @@ def get_base_model( name = model_types.make_model_name(name) if not name.startswith("models/"): - raise ValueError(f"Base model names must start with `models/`, got: {name}") + raise ValueError(f"Base model names must start with `models/`, received: {name}") result = client.get_model(name=name, **request_options) result = type(result).to_dict(result) @@ -105,12 +103,12 @@ def get_tuned_model( ``` import pprint - model = genai.get_tuned_model('tunedModels/my-model-1234'): + model = genai.get_tuned_model('tunedModels/gemini-1.0-pro-001') pprint.pprint(model) ``` Args: - name: The name of the model to fetch. + name: The name of the model to fetch. Should start with `tunedModels/` client: The client to use. request_options: Options for the request. @@ -126,7 +124,7 @@ def get_tuned_model( name = model_types.make_model_name(name) if not name.startswith("tunedModels/"): - raise ValueError("Tuned model names must start with `tunedModels/`") + raise ValueError("Tuned model names must start with `tunedModels/` received: {name}") result = client.get_tuned_model(name=name, **request_options) From 23216f1e35dc24e0d7e37434951599dae31fde3b Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 06:54:42 +0000 Subject: [PATCH 02/12] Fix `_make_grounding_passages` , `_make_generate_answer_request` --- google/generativeai/answer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/google/generativeai/answer.py b/google/generativeai/answer.py index f17a82a17..d41b0502d 100644 --- a/google/generativeai/answer.py +++ b/google/generativeai/answer.py @@ -94,7 +94,7 @@ def _make_grounding_passages(source: GroundingPassagesOptions) -> glm.GroundingP if not isinstance(source, Iterable): raise TypeError( - f"`source` must be a valid `GroundingPassagesOptions` type object got a: `{type(source)}`." + f"The 'source' argument must be an instance of 'GroundingPassagesOptions', but got a '{type(source).__name__}' object instead." ) passages = [] @@ -182,7 +182,7 @@ def _make_generate_answer_request( temperature: float | None = None, ) -> glm.GenerateAnswerRequest: """ - Calls the API to generate a grounded answer from the model. + constructs a glm.GenerateAnswerRequest object by organizing the input parameters for the API call to generate a grounded answer from the model. Args: model: Name of the model used to generate the grounded response. @@ -219,7 +219,7 @@ def _make_generate_answer_request( elif semantic_retriever is not None: semantic_retriever = _make_semantic_retriever_config(semantic_retriever, contents[-1]) else: - TypeError( + raise TypeError( f"The source must be either an `inline_passages` xor `semantic_retriever_config`, but both are `None`" ) From 1858763077d9dda28d3d7bf884ed763e466ca850 Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 07:35:58 +0000 Subject: [PATCH 03/12] fix get_default_permission_client and get_default_permission_async_client --- google/generativeai/client.py | 4 +-- google/generativeai/types/permission_types.py | 28 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/google/generativeai/client.py b/google/generativeai/client.py index e8e91ae7e..31160757f 100644 --- a/google/generativeai/client.py +++ b/google/generativeai/client.py @@ -328,9 +328,9 @@ def get_default_retriever_async_client() -> glm.RetrieverAsyncClient: return _client_manager.get_default_client("retriever_async") -def get_dafault_permission_client() -> glm.PermissionServiceClient: +def get_default_permission_client() -> glm.PermissionServiceClient: return _client_manager.get_default_client("permission") -def get_dafault_permission_async_client() -> glm.PermissionServiceAsyncClient: +def get_default_permission_async_client() -> glm.PermissionServiceAsyncClient: return _client_manager.get_default_client("permission_async") diff --git a/google/generativeai/types/permission_types.py b/google/generativeai/types/permission_types.py index ef9242999..db1867695 100644 --- a/google/generativeai/types/permission_types.py +++ b/google/generativeai/types/permission_types.py @@ -22,8 +22,8 @@ from google.protobuf import field_mask_pb2 -from google.generativeai.client import get_dafault_permission_client -from google.generativeai.client import get_dafault_permission_async_client +from google.generativeai.client import get_default_permission_client +from google.generativeai.client import get_default_permission_async_client from google.generativeai.utils import flatten_update_paths from google.generativeai import string_utils @@ -107,7 +107,7 @@ def delete( Delete permission (self). """ if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() delete_request = glm.DeletePermissionRequest(name=self.name) client.delete_permission(request=delete_request) @@ -119,7 +119,7 @@ async def delete_async( This is the async version of `Permission.delete`. """ if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() delete_request = glm.DeletePermissionRequest(name=self.name) await client.delete_permission(request=delete_request) @@ -146,7 +146,7 @@ def update( `Permission` object with specified updates. """ if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() updates = flatten_update_paths(updates) for update_path in updates: @@ -176,7 +176,7 @@ async def update_async( This is the async version of `Permission.update`. """ if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() updates = flatten_update_paths(updates) for update_path in updates: @@ -224,7 +224,7 @@ def get( Requested permission as an instance of `Permission`. """ if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() get_perm_request = glm.GetPermissionRequest(name=name) get_perm_response = client.get_permission(request=get_perm_request) get_perm_response = type(get_perm_response).to_dict(get_perm_response) @@ -240,7 +240,7 @@ async def get_async( This is the async version of `Permission.get`. """ if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() get_perm_request = glm.GetPermissionRequest(name=name) get_perm_response = await client.get_permission(request=get_perm_request) get_perm_response = type(get_perm_response).to_dict(get_perm_response) @@ -313,7 +313,7 @@ def create( ValueError: When email_address is not specified and grantee_type is not set to EVERYONE. """ if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() request = self._make_create_permission_request( role=role, grantee_type=grantee_type, email_address=email_address @@ -333,7 +333,7 @@ async def create_async( This is the async version of `PermissionAdapter.create_permission`. """ if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() request = self._make_create_permission_request( role=role, grantee_type=grantee_type, email_address=email_address @@ -358,7 +358,7 @@ def list( Paginated list of `Permission` objects. """ if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() request = glm.ListPermissionsRequest( parent=self.parent, page_size=page_size # pytype: disable=attribute-error @@ -376,7 +376,7 @@ async def list_async( This is the async version of `PermissionAdapter.list_permissions`. """ if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() request = glm.ListPermissionsRequest( parent=self.parent, page_size=page_size # pytype: disable=attribute-error @@ -400,7 +400,7 @@ def transfer_ownership( if self.parent.startswith("corpora"): raise NotImplementedError("Can'/t transfer_ownership for a Corpus") if client is None: - client = get_dafault_permission_client() + client = get_default_permission_client() transfer_request = glm.TransferOwnershipRequest( name=self.parent, email_address=email_address # pytype: disable=attribute-error ) @@ -415,7 +415,7 @@ async def transfer_ownership_async( if self.parent.startswith("corpora"): raise NotImplementedError("Can'/t transfer_ownership for a Corpus") if client is None: - client = get_dafault_permission_async_client() + client = get_default_permission_async_client() transfer_request = glm.TransferOwnershipRequest( name=self.parent, email_address=email_address # pytype: disable=attribute-error ) From 1889d62b4402cf465f30866014118ecfb992fc1f Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 07:54:35 +0000 Subject: [PATCH 04/12] Add how to test all in CONTRIBUTING.md --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e51ac7205..ee6f6cbb9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,6 +68,12 @@ Use the builtin unittest package: python -m unittest ``` +To ensure the integrity of the codebase, we have a suite of tests located in the `generative-ai-python/tests` directory. +You can run all these tests using Python's built-in `unittest` module. Open a terminal and navigate to the root directory of the project. Then, execute the following command: + +``` +python -m unittest discover -s /workspaces/generative-ai-python/tests +``` Or to debug, use: ```commandline From 193eef323cb06b2f3edfb8a40dad0fa18daeaff7 Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 11:51:35 +0000 Subject: [PATCH 05/12] fix back support for `tunedModels/` in `get_model` function --- google/generativeai/models.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/google/generativeai/models.py b/google/generativeai/models.py index 3de641574..d9994cc33 100644 --- a/google/generativeai/models.py +++ b/google/generativeai/models.py @@ -52,9 +52,10 @@ def get_model( name = model_types.make_model_name(name) if name.startswith("models/"): return get_base_model(name, client=client, request_options=request_options) + elif name.startswith("tunedModels/"): + return get_tuned_model(name, client=client, request_options=request_options) else: - raise ValueError("Model names must start with `models/` received: {name}") - + raise ValueError(f"Model names must start with `models/` or `tunedModels/`. Received: {name}") def get_base_model( name: model_types.BaseModelNameOptions, From e18742d853eba6f0fc87d2a1e695d8813ae8ede3 Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 12:03:14 +0000 Subject: [PATCH 06/12] Add pytest to CONTRIBUTING.md --- CONTRIBUTING.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee6f6cbb9..6960aa5b2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,18 +62,29 @@ This "editable" mode lets you edit the source without needing to reinstall the p ### Testing -Use the builtin unittest package: +To ensure the integrity of the codebase, we have a suite of tests located in the `generative-ai-python/tests` directory. + +You can run all these tests using Python's built-in `unittest` module or the `pytest` library. + +For `unittest`, open a terminal and navigate to the root directory of the project. Then, execute the following command: ``` - python -m unittest +python -m unittest discover -s /workspaces/generative-ai-python/tests ``` -To ensure the integrity of the codebase, we have a suite of tests located in the `generative-ai-python/tests` directory. -You can run all these tests using Python's built-in `unittest` module. Open a terminal and navigate to the root directory of the project. Then, execute the following command: +Alternatively, if you prefer using `pytest`, you can install it using pip: ``` -python -m unittest discover -s /workspaces/generative-ai-python/tests +pip install pytest ``` + +Then, run the tests with the following command: + +``` +pytest /workspaces/generative-ai-python/tests +``` + + Or to debug, use: ```commandline From 211896fae77c315557d249ae8fe2b151e2ac7b88 Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 12:54:57 +0000 Subject: [PATCH 07/12] Break down test_generate_text for better debugging. --- tests/notebook/text_model_test.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/notebook/text_model_test.py b/tests/notebook/text_model_test.py index 9239ac9c3..8565a2d21 100644 --- a/tests/notebook/text_model_test.py +++ b/tests/notebook/text_model_test.py @@ -68,20 +68,46 @@ def _generate_text( class TextModelTestCase(absltest.TestCase): - def test_generate_text(self): + def test_generate_text_without_args(self): model = TestModel() result = model.call_model("prompt goes in") self.assertEqual(result.text_results[0], "prompt goes in_1") + + def test_generate_text_without_args_none_results(self): + model = TestModel() + + result = model.call_model("prompt goes in") self.assertIsNone(result.text_results[1]) self.assertIsNone(result.text_results[2]) self.assertIsNone(result.text_results[3]) + def test_generate_text_with_args_first_result(self): + model = TestModel() args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) + result = model.call_model("prompt goes in", args) self.assertEqual(result.text_results[0], "prompt goes in_1") + + def test_generate_text_with_args_model_name(self): + model = TestModel() + args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) + + result = model.call_model("prompt goes in", args) self.assertEqual(result.text_results[1], "model_name") + + def test_generate_text_with_args_temperature(self): + model = TestModel() + args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) + + result = model.call_model("prompt goes in", args) self.assertEqual(result.text_results[2], 0.42) + + def test_generate_text_with_args_candidate_count(self): + model = TestModel() + args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) + + result = model.call_model("prompt goes in", args) self.assertEqual(result.text_results[3], 5) def test_retry(self): From a1df9377fc857647eca53a87dd82e58c1ae9308d Mon Sep 17 00:00:00 2001 From: Faisal Alsrheed <47912291+Faisal-Alsrheed@users.noreply.github.com> Date: Wed, 15 May 2024 14:12:30 +0000 Subject: [PATCH 08/12] Add pip install nose2 to CONTRIBUTING.md --- CONTRIBUTING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6960aa5b2..6a30ff1b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,8 +88,9 @@ pytest /workspaces/generative-ai-python/tests Or to debug, use: ```commandline +pip install nose2 + nose2 --debugger -``` ### Type checking From b225be2099e86ed6d7fee74df146f757a6c46ef0 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Thu, 16 May 2024 18:09:26 -0700 Subject: [PATCH 09/12] Format Change-Id: I4e222f3e01cb8d350ae293b35a88fd5f718fe3dc --- google/generativeai/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/google/generativeai/models.py b/google/generativeai/models.py index d9994cc33..16932921a 100644 --- a/google/generativeai/models.py +++ b/google/generativeai/models.py @@ -55,7 +55,10 @@ def get_model( elif name.startswith("tunedModels/"): return get_tuned_model(name, client=client, request_options=request_options) else: - raise ValueError(f"Model names must start with `models/` or `tunedModels/`. Received: {name}") + raise ValueError( + f"Model names must start with `models/` or `tunedModels/`. Received: {name}" + ) + def get_base_model( name: model_types.BaseModelNameOptions, From b3dd0c301e34f1fa5d77c4cb896c2dcdbb79879a Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Fri, 17 May 2024 11:29:07 -0700 Subject: [PATCH 10/12] fix sloppy types in tests Change-Id: I3ad717ca26e5d170e4bbef23076e528badaaaacb --- tests/notebook/text_model_test.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/notebook/text_model_test.py b/tests/notebook/text_model_test.py index 8565a2d21..428d44b26 100644 --- a/tests/notebook/text_model_test.py +++ b/tests/notebook/text_model_test.py @@ -78,9 +78,9 @@ def test_generate_text_without_args_none_results(self): model = TestModel() result = model.call_model("prompt goes in") - self.assertIsNone(result.text_results[1]) - self.assertIsNone(result.text_results[2]) - self.assertIsNone(result.text_results[3]) + self.assertEqual(result.text_results[1], "None") + self.assertEqual(result.text_results[2], "None") + self.assertEqual(result.text_results[3], "None") def test_generate_text_with_args_first_result(self): model = TestModel() @@ -99,16 +99,16 @@ def test_generate_text_with_args_model_name(self): def test_generate_text_with_args_temperature(self): model = TestModel() args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) - result = model.call_model("prompt goes in", args) - self.assertEqual(result.text_results[2], 0.42) + + self.assertEqual(result.text_results[2], str(0.42)) def test_generate_text_with_args_candidate_count(self): model = TestModel() args = model_lib.ModelArguments(model="model_name", temperature=0.42, candidate_count=5) result = model.call_model("prompt goes in", args) - self.assertEqual(result.text_results[3], 5) + self.assertEqual(result.text_results[3], str(5)) def test_retry(self): model = TestModel() From a8c7be780323cd1f00639a8222a523ff9e81ebb7 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Fri, 17 May 2024 11:29:53 -0700 Subject: [PATCH 11/12] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a30ff1b3..e8fd7dbd4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,10 @@ You can run all these tests using Python's built-in `unittest` module or the `py For `unittest`, open a terminal and navigate to the root directory of the project. Then, execute the following command: ``` -python -m unittest discover -s /workspaces/generative-ai-python/tests +python -m unittest discover -s tests + +# or more simply +python -m unittest ``` Alternatively, if you prefer using `pytest`, you can install it using pip: From f918bdba895f1a65a1c6037e6636bb6f7892c718 Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Fri, 17 May 2024 11:30:24 -0700 Subject: [PATCH 12/12] Update CONTRIBUTING.md --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8fd7dbd4..9415df2a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,7 +84,10 @@ pip install pytest Then, run the tests with the following command: ``` -pytest /workspaces/generative-ai-python/tests +pytest tests + +# or more simply +pytest ```