From 9fa07076da34b16ceecccee0f92dfe7c67201d76 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Wed, 7 Feb 2024 09:42:44 -0800 Subject: [PATCH 01/83] Add trace_as_chain_group metadata (#17187) --- libs/core/langchain_core/callbacks/manager.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libs/core/langchain_core/callbacks/manager.py b/libs/core/langchain_core/callbacks/manager.py index e216f479832ac..b1f103871f131 100644 --- a/libs/core/langchain_core/callbacks/manager.py +++ b/libs/core/langchain_core/callbacks/manager.py @@ -67,6 +67,7 @@ def trace_as_chain_group( example_id: Optional[Union[str, UUID]] = None, run_id: Optional[UUID] = None, tags: Optional[List[str]] = None, + metadata: Optional[Dict[str, Any]] = None, ) -> Generator[CallbackManagerForChainGroup, None, None]: """Get a callback manager for a chain group in a context manager. Useful for grouping different calls together as a single run even if @@ -83,6 +84,8 @@ def trace_as_chain_group( run_id (UUID, optional): The ID of the run. tags (List[str], optional): The inheritable tags to apply to all runs. Defaults to None. + metadata (Dict[str, Any], optional): The metadata to apply to all runs. + Defaults to None. Note: must have LANGCHAIN_TRACING_V2 env var set to true to see the trace in LangSmith. @@ -95,7 +98,7 @@ def trace_as_chain_group( llm_input = "Foo" with trace_as_chain_group("group_name", inputs={"input": llm_input}) as manager: # Use the callback manager for the chain group - res = llm.predict(llm_input, callbacks=manager) + res = llm.invoke(llm_input, {"callbacks": manager}) manager.on_chain_end({"output": res}) """ # noqa: E501 from langchain_core.tracers.context import _get_trace_callbacks @@ -106,6 +109,7 @@ def trace_as_chain_group( cm = CallbackManager.configure( inheritable_callbacks=cb, inheritable_tags=tags, + inheritable_metadata=metadata, ) run_manager = cm.on_chain_start({"name": group_name}, inputs or {}, run_id=run_id) @@ -141,6 +145,7 @@ async def atrace_as_chain_group( example_id: Optional[Union[str, UUID]] = None, run_id: Optional[UUID] = None, tags: Optional[List[str]] = None, + metadata: Optional[Dict[str, Any]] = None, ) -> AsyncGenerator[AsyncCallbackManagerForChainGroup, None]: """Get an async callback manager for a chain group in a context manager. Useful for grouping different async calls together as a single run even if @@ -157,6 +162,8 @@ async def atrace_as_chain_group( run_id (UUID, optional): The ID of the run. tags (List[str], optional): The inheritable tags to apply to all runs. Defaults to None. + metadata (Dict[str, Any], optional): The metadata to apply to all runs. + Defaults to None. Returns: AsyncCallbackManager: The async callback manager for the chain group. @@ -168,7 +175,7 @@ async def atrace_as_chain_group( llm_input = "Foo" async with atrace_as_chain_group("group_name", inputs={"input": llm_input}) as manager: # Use the async callback manager for the chain group - res = await llm.apredict(llm_input, callbacks=manager) + res = await llm.ainvoke(llm_input, {"callbacks": manager}) await manager.on_chain_end({"output": res}) """ # noqa: E501 from langchain_core.tracers.context import _get_trace_callbacks @@ -176,7 +183,9 @@ async def atrace_as_chain_group( cb = _get_trace_callbacks( project_name, example_id, callback_manager=callback_manager ) - cm = AsyncCallbackManager.configure(inheritable_callbacks=cb, inheritable_tags=tags) + cm = AsyncCallbackManager.configure( + inheritable_callbacks=cb, inheritable_tags=tags, inheritable_metadata=metadata + ) run_manager = await cm.on_chain_start( {"name": group_name}, inputs or {}, run_id=run_id From 302989a2b1b8b0228d9de406b91edc88979e5e58 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Wed, 7 Feb 2024 19:26:14 +0100 Subject: [PATCH 02/83] allow optional newline in the action responses of JSON Agent parser (#17186) Based on my experiments, the newline isn't always there, so we can make the regex slightly more robust by allowing an optional newline after the bacticks --- .../langchain/agents/output_parsers/react_json_single_input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langchain/langchain/agents/output_parsers/react_json_single_input.py b/libs/langchain/langchain/agents/output_parsers/react_json_single_input.py index c58e1804ab171..0ca9ed2ffd82d 100644 --- a/libs/langchain/langchain/agents/output_parsers/react_json_single_input.py +++ b/libs/langchain/langchain/agents/output_parsers/react_json_single_input.py @@ -42,7 +42,7 @@ class ReActJsonSingleInputOutputParser(AgentOutputParser): """ - pattern = re.compile(r"^.*?`{3}(?:json)?\n(.*?)`{3}.*?$", re.DOTALL) + pattern = re.compile(r"^.*?`{3}(?:json)?\n?(.*?)`{3}.*?$", re.DOTALL) """Regex pattern to parse the output.""" def get_format_instructions(self) -> str: From f87b38a559dcd084d85e2a98d6e34397d7f5d5d3 Mon Sep 17 00:00:00 2001 From: chyroc Date: Thu, 8 Feb 2024 04:09:30 +0800 Subject: [PATCH 03/83] google-genai[minor]: support functions call (#15146) Co-authored-by: Erick Friis --- .../langchain_google_genai/chat_models.py | 129 ++- libs/partners/google-genai/poetry.lock | 741 +++++++++--------- .../integration_tests/test_function_call.py | 34 + 3 files changed, 520 insertions(+), 384 deletions(-) create mode 100644 libs/partners/google-genai/tests/integration_tests/test_function_call.py diff --git a/libs/partners/google-genai/langchain_google_genai/chat_models.py b/libs/partners/google-genai/langchain_google_genai/chat_models.py index d30990c5b6e4b..426d279aa0178 100644 --- a/libs/partners/google-genai/langchain_google_genai/chat_models.py +++ b/libs/partners/google-genai/langchain_google_genai/chat_models.py @@ -26,6 +26,7 @@ # TODO: remove ignore once the google package is published with types import google.generativeai as genai # type: ignore[import] import requests +from google.ai.generativelanguage_v1beta import FunctionCall from langchain_core.callbacks.manager import ( AsyncCallbackManagerForLLMRun, CallbackManagerForLLMRun, @@ -341,16 +342,90 @@ def _parse_chat_history( return messages +def _retrieve_function_call_response( + parts: List[genai.types.PartType], +) -> Optional[Dict]: + for idx, part in enumerate(parts): + if part.function_call and part.function_call.name: + fc: FunctionCall = part.function_call + return { + "function_call": { + "name": fc.name, + "arguments": dict(fc.args.items()), + } + } + return None + + +def _convert_function_call_req(function_calls: Union[Dict, List[Dict]]) -> Dict: + function_declarations = [] + if isinstance(function_calls, dict): + function_declarations.append(_convert_fc_type(function_calls)) + else: + for fc in function_calls: + function_declarations.append(_convert_fc_type(fc)) + return { + "function_declarations": function_declarations, + } + + +def _convert_fc_type(fc: Dict) -> Dict: + # type_: "Type" + # format_: str + # description: str + # nullable: bool + # enum: MutableSequence[str] + # items: "Schema" + # properties: MutableMapping[str, "Schema"] + # required: MutableSequence[str] + if "parameters" in fc: + fc["parameters"] = _convert_fc_type(fc["parameters"]) + if "properties" in fc: + for k, v in fc["properties"].items(): + fc["properties"][k] = _convert_fc_type(v) + if "type" in fc: + # STRING = 1 + # NUMBER = 2 + # INTEGER = 3 + # BOOLEAN = 4 + # ARRAY = 5 + # OBJECT = 6 + if fc["type"] == "string": + fc["type_"] = 1 + elif fc["type"] == "number": + fc["type_"] = 2 + elif fc["type"] == "integer": + fc["type_"] = 3 + elif fc["type"] == "boolean": + fc["type_"] = 4 + elif fc["type"] == "array": + fc["type_"] = 5 + elif fc["type"] == "object": + fc["type_"] = 6 + del fc["type"] + if "format" in fc: + fc["format_"] = fc["format"] + del fc["format"] + + for k, v in fc.items(): + if isinstance(v, dict): + fc[k] = _convert_fc_type(v) + + return fc + + def _parts_to_content( parts: List[genai.types.PartType], -) -> Union[str, List[Union[Dict[Any, Any], str]]]: +) -> Tuple[Union[str, List[Union[Dict[Any, Any], str]]], Optional[Dict]]: """Converts a list of Gemini API Part objects into a list of LangChain messages.""" + function_call_resp = _retrieve_function_call_response(parts) + if len(parts) == 1 and parts[0].text is not None and not parts[0].inline_data: # Simple text response. The typical response - return parts[0].text + return parts[0].text, function_call_resp elif not parts: logger.warning("Gemini produced an empty response.") - return "" + return "", function_call_resp messages: List[Union[Dict[Any, Any], str]] = [] for part in parts: if part.text is not None: @@ -363,7 +438,7 @@ def _parts_to_content( else: # TODO: Handle inline_data if that's a thing? raise ChatGoogleGenerativeAIError(f"Unexpected part type. {part}") - return messages + return messages, function_call_resp def _response_to_result( @@ -390,16 +465,24 @@ def _response_to_result( "model": ai_msg_t, "user": human_msg_t, } + for candidate in response.candidates: content = candidate.content - parts_content = _parts_to_content(content.parts) + parts_content, additional_kwargs = _parts_to_content(content.parts) if content.role not in role_map: logger.warning( f"Unrecognized role: {content.role}. Treating as a ChatMessage." ) - msg = chat_msg_t(content=parts_content, role=content.role) + msg = chat_msg_t( + content=parts_content, + role=content.role, + additional_kwargs=additional_kwargs or {}, + ) else: - msg = role_map[content.role](content=parts_content) + msg = role_map[content.role]( + content=parts_content, + additional_kwargs=additional_kwargs or {}, + ) generation_info = {} if candidate.finish_reason: generation_info["finish_reason"] = candidate.finish_reason.name @@ -527,7 +610,11 @@ def _generate( run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - params, chat, message = self._prepare_chat(messages, stop=stop) + params, chat, message = self._prepare_chat( + messages, + stop=stop, + functions=kwargs.get("functions"), + ) response: genai.types.GenerateContentResponse = _chat_with_retry( content=message, **params, @@ -542,7 +629,11 @@ async def _agenerate( run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> ChatResult: - params, chat, message = self._prepare_chat(messages, stop=stop) + params, chat, message = self._prepare_chat( + messages, + stop=stop, + functions=kwargs.get("functions"), + ) response: genai.types.GenerateContentResponse = await _achat_with_retry( content=message, **params, @@ -557,7 +648,11 @@ def _stream( run_manager: Optional[CallbackManagerForLLMRun] = None, **kwargs: Any, ) -> Iterator[ChatGenerationChunk]: - params, chat, message = self._prepare_chat(messages, stop=stop) + params, chat, message = self._prepare_chat( + messages, + stop=stop, + functions=kwargs.get("functions"), + ) response: genai.types.GenerateContentResponse = _chat_with_retry( content=message, **params, @@ -584,7 +679,11 @@ async def _astream( run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, **kwargs: Any, ) -> AsyncIterator[ChatGenerationChunk]: - params, chat, message = self._prepare_chat(messages, stop=stop) + params, chat, message = self._prepare_chat( + messages, + stop=stop, + functions=kwargs.get("functions"), + ) async for chunk in await _achat_with_retry( content=message, **params, @@ -609,13 +708,19 @@ def _prepare_chat( stop: Optional[List[str]] = None, **kwargs: Any, ) -> Tuple[Dict[str, Any], genai.ChatSession, genai.types.ContentDict]: + cli = self.client + functions = kwargs.pop("functions", None) + if functions: + tools = _convert_function_call_req(functions) + cli = genai.GenerativeModel(model_name=self.model, tools=tools) + params = self._prepare_params(stop, **kwargs) history = _parse_chat_history( messages, convert_system_message_to_human=self.convert_system_message_to_human, ) message = history.pop() - chat = self.client.start_chat(history=history) + chat = cli.start_chat(history=history) return params, chat, message def get_num_tokens(self, text: str) -> int: diff --git a/libs/partners/google-genai/poetry.lock b/libs/partners/google-genai/poetry.lock index edddadcb57d17..dc37a3fc067ad 100644 --- a/libs/partners/google-genai/poetry.lock +++ b/libs/partners/google-genai/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -13,19 +13,20 @@ files = [ [[package]] name = "anyio" -version = "4.1.0" +version = "4.2.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.1.0-py3-none-any.whl", hash = "sha256:56a415fbc462291813a94528a779597226619c8e78af7de0507333f700011e5f"}, - {file = "anyio-4.1.0.tar.gz", hash = "sha256:5a0bec7085176715be77df87fc66d6c9d70626bd752fcc85f57cdbee5b3760da"}, + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] @@ -45,13 +46,13 @@ files = [ [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] [[package]] @@ -197,13 +198,13 @@ test = ["pytest (>=6)"] [[package]] name = "freezegun" -version = "1.3.1" +version = "1.4.0" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" files = [ - {file = "freezegun-1.3.1-py3-none-any.whl", hash = "sha256:065e77a12624d05531afa87ade12a0b9bdb53495c4573893252a055b545ce3ea"}, - {file = "freezegun-1.3.1.tar.gz", hash = "sha256:48984397b3b58ef5dfc645d6a304b0060f612bcecfdaaf45ce8aff0077a6cb6a"}, + {file = "freezegun-1.4.0-py3-none-any.whl", hash = "sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6"}, + {file = "freezegun-1.4.0.tar.gz", hash = "sha256:10939b0ba0ff5adaecf3b06a5c2f73071d9678e507c5eaedb23c761d56ac774b"}, ] [package.dependencies] @@ -227,13 +228,13 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 [[package]] name = "google-api-core" -version = "2.15.0" +version = "2.16.2" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.15.0.tar.gz", hash = "sha256:abc978a72658f14a2df1e5e12532effe40f94f868f6e23d95133bd6abcca35ca"}, - {file = "google_api_core-2.15.0-py3-none-any.whl", hash = "sha256:2aa56d2be495551e66bbff7f729b790546f87d5c90e74781aa77233bcb395a8a"}, + {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, + {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, ] [package.dependencies] @@ -257,13 +258,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-auth" -version = "2.25.2" +version = "2.27.0" description = "Google Authentication Library" optional = false python-versions = ">=3.7" files = [ - {file = "google-auth-2.25.2.tar.gz", hash = "sha256:42f707937feb4f5e5a39e6c4f343a17300a459aaf03141457ba505812841cc40"}, - {file = "google_auth-2.25.2-py2.py3-none-any.whl", hash = "sha256:473a8dfd0135f75bb79d878436e568f2695dce456764bf3a02b6f8c540b1d256"}, + {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, ] [package.dependencies] @@ -318,84 +319,84 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] [[package]] name = "grpcio" -version = "1.60.0" +version = "1.60.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.7" files = [ - {file = "grpcio-1.60.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:d020cfa595d1f8f5c6b343530cd3ca16ae5aefdd1e832b777f9f0eb105f5b139"}, - {file = "grpcio-1.60.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:b98f43fcdb16172dec5f4b49f2fece4b16a99fd284d81c6bbac1b3b69fcbe0ff"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:20e7a4f7ded59097c84059d28230907cd97130fa74f4a8bfd1d8e5ba18c81491"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452ca5b4afed30e7274445dd9b441a35ece656ec1600b77fff8c216fdf07df43"}, - {file = "grpcio-1.60.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43e636dc2ce9ece583b3e2ca41df5c983f4302eabc6d5f9cd04f0562ee8ec1ae"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e306b97966369b889985a562ede9d99180def39ad42c8014628dd3cc343f508"}, - {file = "grpcio-1.60.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f897c3b127532e6befdcf961c415c97f320d45614daf84deba0a54e64ea2457b"}, - {file = "grpcio-1.60.0-cp310-cp310-win32.whl", hash = "sha256:b87efe4a380887425bb15f220079aa8336276398dc33fce38c64d278164f963d"}, - {file = "grpcio-1.60.0-cp310-cp310-win_amd64.whl", hash = "sha256:a9c7b71211f066908e518a2ef7a5e211670761651039f0d6a80d8d40054047df"}, - {file = "grpcio-1.60.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:fb464479934778d7cc5baf463d959d361954d6533ad34c3a4f1d267e86ee25fd"}, - {file = "grpcio-1.60.0-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4b44d7e39964e808b071714666a812049765b26b3ea48c4434a3b317bac82f14"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:90bdd76b3f04bdb21de5398b8a7c629676c81dfac290f5f19883857e9371d28c"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91229d7203f1ef0ab420c9b53fe2ca5c1fbeb34f69b3bc1b5089466237a4a134"}, - {file = "grpcio-1.60.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b36a2c6d4920ba88fa98075fdd58ff94ebeb8acc1215ae07d01a418af4c0253"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:297eef542156d6b15174a1231c2493ea9ea54af8d016b8ca7d5d9cc65cfcc444"}, - {file = "grpcio-1.60.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:87c9224acba0ad8bacddf427a1c2772e17ce50b3042a789547af27099c5f751d"}, - {file = "grpcio-1.60.0-cp311-cp311-win32.whl", hash = "sha256:95ae3e8e2c1b9bf671817f86f155c5da7d49a2289c5cf27a319458c3e025c320"}, - {file = "grpcio-1.60.0-cp311-cp311-win_amd64.whl", hash = "sha256:467a7d31554892eed2aa6c2d47ded1079fc40ea0b9601d9f79204afa8902274b"}, - {file = "grpcio-1.60.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:a7152fa6e597c20cb97923407cf0934e14224af42c2b8d915f48bc3ad2d9ac18"}, - {file = "grpcio-1.60.0-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:7db16dd4ea1b05ada504f08d0dca1cd9b926bed3770f50e715d087c6f00ad748"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:b0571a5aef36ba9177e262dc88a9240c866d903a62799e44fd4aae3f9a2ec17e"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fd9584bf1bccdfff1512719316efa77be235469e1e3295dce64538c4773840b"}, - {file = "grpcio-1.60.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6a478581b1a1a8fdf3318ecb5f4d0cda41cacdffe2b527c23707c9c1b8fdb55"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:77c8a317f0fd5a0a2be8ed5cbe5341537d5c00bb79b3bb27ba7c5378ba77dbca"}, - {file = "grpcio-1.60.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1c30bb23a41df95109db130a6cc1b974844300ae2e5d68dd4947aacba5985aa5"}, - {file = "grpcio-1.60.0-cp312-cp312-win32.whl", hash = "sha256:2aef56e85901c2397bd557c5ba514f84de1f0ae5dd132f5d5fed042858115951"}, - {file = "grpcio-1.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:e381fe0c2aa6c03b056ad8f52f8efca7be29fb4d9ae2f8873520843b6039612a"}, - {file = "grpcio-1.60.0-cp37-cp37m-linux_armv7l.whl", hash = "sha256:92f88ca1b956eb8427a11bb8b4a0c0b2b03377235fc5102cb05e533b8693a415"}, - {file = "grpcio-1.60.0-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:e278eafb406f7e1b1b637c2cf51d3ad45883bb5bd1ca56bc05e4fc135dfdaa65"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:a48edde788b99214613e440fce495bbe2b1e142a7f214cce9e0832146c41e324"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de2ad69c9a094bf37c1102b5744c9aec6cf74d2b635558b779085d0263166454"}, - {file = "grpcio-1.60.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:073f959c6f570797272f4ee9464a9997eaf1e98c27cb680225b82b53390d61e6"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c826f93050c73e7769806f92e601e0efdb83ec8d7c76ddf45d514fee54e8e619"}, - {file = "grpcio-1.60.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9e30be89a75ee66aec7f9e60086fadb37ff8c0ba49a022887c28c134341f7179"}, - {file = "grpcio-1.60.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b0fb2d4801546598ac5cd18e3ec79c1a9af8b8f2a86283c55a5337c5aeca4b1b"}, - {file = "grpcio-1.60.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:9073513ec380434eb8d21970e1ab3161041de121f4018bbed3146839451a6d8e"}, - {file = "grpcio-1.60.0-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:74d7d9fa97809c5b892449b28a65ec2bfa458a4735ddad46074f9f7d9550ad13"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:1434ca77d6fed4ea312901122dc8da6c4389738bf5788f43efb19a838ac03ead"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e61e76020e0c332a98290323ecfec721c9544f5b739fab925b6e8cbe1944cf19"}, - {file = "grpcio-1.60.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675997222f2e2f22928fbba640824aebd43791116034f62006e19730715166c0"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5208a57eae445ae84a219dfd8b56e04313445d146873117b5fa75f3245bc1390"}, - {file = "grpcio-1.60.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:428d699c8553c27e98f4d29fdc0f0edc50e9a8a7590bfd294d2edb0da7be3629"}, - {file = "grpcio-1.60.0-cp38-cp38-win32.whl", hash = "sha256:83f2292ae292ed5a47cdcb9821039ca8e88902923198f2193f13959360c01860"}, - {file = "grpcio-1.60.0-cp38-cp38-win_amd64.whl", hash = "sha256:705a68a973c4c76db5d369ed573fec3367d7d196673fa86614b33d8c8e9ebb08"}, - {file = "grpcio-1.60.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:c193109ca4070cdcaa6eff00fdb5a56233dc7610216d58fb81638f89f02e4968"}, - {file = "grpcio-1.60.0-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:676e4a44e740deaba0f4d95ba1d8c5c89a2fcc43d02c39f69450b1fa19d39590"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5ff21e000ff2f658430bde5288cb1ac440ff15c0d7d18b5fb222f941b46cb0d2"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c86343cf9ff7b2514dd229bdd88ebba760bd8973dac192ae687ff75e39ebfab"}, - {file = "grpcio-1.60.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fd3b3968ffe7643144580f260f04d39d869fcc2cddb745deef078b09fd2b328"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:30943b9530fe3620e3b195c03130396cd0ee3a0d10a66c1bee715d1819001eaf"}, - {file = "grpcio-1.60.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b10241250cb77657ab315270b064a6c7f1add58af94befa20687e7c8d8603ae6"}, - {file = "grpcio-1.60.0-cp39-cp39-win32.whl", hash = "sha256:79a050889eb8d57a93ed21d9585bb63fca881666fc709f5d9f7f9372f5e7fd03"}, - {file = "grpcio-1.60.0-cp39-cp39-win_amd64.whl", hash = "sha256:8a97a681e82bc11a42d4372fe57898d270a2707f36c45c6676e49ce0d5c41353"}, - {file = "grpcio-1.60.0.tar.gz", hash = "sha256:2199165a1affb666aa24adf0c97436686d0a61bc5fc113c037701fb7c7fceb96"}, + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.60.0)"] +protobuf = ["grpcio-tools (>=1.60.1)"] [[package]] name = "grpcio-status" -version = "1.60.0" +version = "1.60.1" description = "Status proto mapping for gRPC" optional = false python-versions = ">=3.6" files = [ - {file = "grpcio-status-1.60.0.tar.gz", hash = "sha256:f10e0b6db3adc0fdc244b71962814ee982996ef06186446b5695b9fa635aa1ab"}, - {file = "grpcio_status-1.60.0-py3-none-any.whl", hash = "sha256:7d383fa36e59c1e61d380d91350badd4d12ac56e4de2c2b831b050362c3c572e"}, + {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, + {file = "grpcio_status-1.60.1-py3-none-any.whl", hash = "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0"}, ] [package.dependencies] googleapis-common-protos = ">=1.5.5" -grpcio = ">=1.60.0" +grpcio = ">=1.60.1" protobuf = ">=4.21.6" [[package]] @@ -447,7 +448,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.0" +version = "0.1.19" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -457,7 +458,7 @@ develop = true [package.dependencies] anyio = ">=3,<5" jsonpatch = "^1.33" -langsmith = "~0.0.63" +langsmith = ">=0.0.83,<0.1" packaging = "^23.2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -473,13 +474,13 @@ url = "../../core" [[package]] name = "langsmith" -version = "0.0.69" +version = "0.0.87" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.69-py3-none-any.whl", hash = "sha256:49a2546bb83eedb0552673cf81a068bb08078d6d48471f4f1018e1d5c6aa46b1"}, - {file = "langsmith-0.0.69.tar.gz", hash = "sha256:8fb5297f274db0576ec650d9bab0319acfbb6622d62bc5bb9fe31c6235dc0358"}, + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, ] [package.dependencies] @@ -549,47 +550,47 @@ files = [ [[package]] name = "numpy" -version = "1.26.2" +version = "1.26.4" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, - {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, - {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, - {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, - {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, - {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, - {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, - {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, - {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, - {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, - {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, - {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, - {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, - {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, - {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, - {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, - {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, - {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, - {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, - {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, - {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, - {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, - {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, ] [[package]] @@ -605,80 +606,98 @@ files = [ [[package]] name = "pillow" -version = "10.1.0" +version = "10.2.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, - {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, - {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, - {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, - {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, - {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, - {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, - {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, - {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, - {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, - {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, - {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, - {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, - {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, - {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, - {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, - {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, - {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, - {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, - {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, - {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, - {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, - {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, - {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, + {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, + {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, + {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, + {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, + {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, + {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, + {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, + {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, + {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, + {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, + {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, + {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, + {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, + {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, + {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, + {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, + {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, + {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, + {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, + {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, + {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, + {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, + {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, + {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, + {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, + {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, + {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, + {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, + {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, + {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, + {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, + {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, + {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, ] [package.extras] docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.4.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, + {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, ] [package.extras] @@ -704,22 +723,22 @@ testing = ["google-api-core[grpc] (>=1.31.5)"] [[package]] name = "protobuf" -version = "4.25.1" +version = "4.25.2" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7"}, - {file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b"}, - {file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb"}, - {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7"}, - {file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd"}, - {file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0"}, - {file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510"}, - {file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10"}, - {file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6"}, - {file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2"}, + {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, ] [[package]] @@ -749,18 +768,18 @@ pyasn1 = ">=0.4.6,<0.6.0" [[package]] name = "pydantic" -version = "2.5.2" +version = "2.6.1" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, - {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, + {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, + {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.5" +pydantic-core = "2.16.2" typing-extensions = ">=4.6.1" [package.extras] @@ -768,116 +787,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.5" +version = "2.16.2" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, - {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, - {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, - {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, - {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, - {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, - {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, - {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, - {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, - {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, - {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, - {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, - {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, - {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, - {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, - {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, + {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, + {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, + {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, + {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, + {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, + {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, + {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, + {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, + {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, + {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, + {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, + {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, + {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, ] [package.dependencies] @@ -885,13 +878,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -942,13 +935,13 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] [[package]] name = "pytest-watcher" -version = "0.3.4" +version = "0.3.5" description = "Automatically rerun your tests on file modifications" optional = false python-versions = ">=3.7.0,<4.0.0" files = [ - {file = "pytest_watcher-0.3.4-py3-none-any.whl", hash = "sha256:edd2bd9c8a1fb14d48c9f4947234065eb9b4c1acedc0bf213b1f12501dfcffd3"}, - {file = "pytest_watcher-0.3.4.tar.gz", hash = "sha256:d39491ba15b589221bb9a78ef4bed3d5d1503aed08209b1a138aeb95b9117a18"}, + {file = "pytest_watcher-0.3.5-py3-none-any.whl", hash = "sha256:af00ca52c7be22dc34c0fd3d7ffef99057207a73b05dc5161fe3b2fe91f58130"}, + {file = "pytest_watcher-0.3.5.tar.gz", hash = "sha256:8896152460ba2b1a8200c12117c6611008ec96c8b2d811f0a05ab8a82b043ff8"}, ] [package.dependencies] @@ -994,6 +987,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1065,28 +1059,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.1.7" +version = "0.1.15" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7f80496854fdc65b6659c271d2c26e90d4d401e6a4a31908e7e334fab4645aac"}, - {file = "ruff-0.1.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1ea109bdb23c2a4413f397ebd8ac32cb498bee234d4191ae1a310af760e5d287"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0c2de9dd9daf5e07624c24add25c3a490dbf74b0e9bca4145c632457b3b42a"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:69a4bed13bc1d5dabf3902522b5a2aadfebe28226c6269694283c3b0cecb45fd"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de02ca331f2143195a712983a57137c5ec0f10acc4aa81f7c1f86519e52b92a1"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:45b38c3f8788a65e6a2cab02e0f7adfa88872696839d9882c13b7e2f35d64c5f"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c64cb67b2025b1ac6d58e5ffca8f7b3f7fd921f35e78198411237e4f0db8e73"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dcc6bb2f4df59cb5b4b40ff14be7d57012179d69c6565c1da0d1f013d29951b"}, - {file = "ruff-0.1.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2bb4bb6bbe921f6b4f5b6fdd8d8468c940731cb9406f274ae8c5ed7a78c478"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:276a89bcb149b3d8c1b11d91aa81898fe698900ed553a08129b38d9d6570e717"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:90c958fe950735041f1c80d21b42184f1072cc3975d05e736e8d66fc377119ea"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6b05e3b123f93bb4146a761b7a7d57af8cb7384ccb2502d29d736eaade0db519"}, - {file = "ruff-0.1.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:290ecab680dce94affebefe0bbca2322a6277e83d4f29234627e0f8f6b4fa9ce"}, - {file = "ruff-0.1.7-py3-none-win32.whl", hash = "sha256:416dfd0bd45d1a2baa3b1b07b1b9758e7d993c256d3e51dc6e03a5e7901c7d80"}, - {file = "ruff-0.1.7-py3-none-win_amd64.whl", hash = "sha256:4af95fd1d3b001fc41325064336db36e3d27d2004cdb6d21fd617d45a172dd96"}, - {file = "ruff-0.1.7-py3-none-win_arm64.whl", hash = "sha256:0683b7bfbb95e6df3c7c04fe9d78f631f8e8ba4868dfc932d43d690698057e2e"}, - {file = "ruff-0.1.7.tar.gz", hash = "sha256:dffd699d07abf54833e5f6cc50b85a6ff043715da8788c4a79bcd4ab4734d306"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, ] [[package]] @@ -1113,17 +1107,17 @@ files = [ [[package]] name = "syrupy" -version = "4.6.0" +version = "4.6.1" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.8.1,<4" files = [ - {file = "syrupy-4.6.0-py3-none-any.whl", hash = "sha256:747aae1bcf3cb3249e33b1e6d81097874d23615982d5686ebe637875b0775a1b"}, - {file = "syrupy-4.6.0.tar.gz", hash = "sha256:231b1f5d00f1f85048ba81676c79448076189c4aef4d33f21ae32f3b4c565a54"}, + {file = "syrupy-4.6.1-py3-none-any.whl", hash = "sha256:203e52f9cb9fa749cf683f29bd68f02c16c3bc7e7e5fe8f2fc59bdfe488ce133"}, + {file = "syrupy-4.6.1.tar.gz", hash = "sha256:37a835c9ce7857eeef86d62145885e10b3cb9615bc6abeb4ce404b3f18e1bb36"}, ] [package.dependencies] -pytest = ">=7.0.0,<8.0.0" +pytest = ">=7.0.0,<9.0.0" [[package]] name = "tenacity" @@ -1172,35 +1166,35 @@ telegram = ["requests"] [[package]] name = "types-google-cloud-ndb" -version = "2.2.0.1" +version = "2.2.0.20240205" description = "Typing stubs for google-cloud-ndb" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-google-cloud-ndb-2.2.0.1.tar.gz", hash = "sha256:3dd5f7437d3f4192a32b69e9b21da582d897303680f2eaac5d070749fd866586"}, - {file = "types_google_cloud_ndb-2.2.0.1-py3-none-any.whl", hash = "sha256:88b4800f4c6421a34894bd9f61aee562605d5cc151d454d4d97241fd680b1cb1"}, + {file = "types-google-cloud-ndb-2.2.0.20240205.tar.gz", hash = "sha256:8384b060f37cfde1786ca7bb7ba48037ef6b2e47bf29c02512cd275b92fa75fe"}, + {file = "types_google_cloud_ndb-2.2.0.20240205-py3-none-any.whl", hash = "sha256:d410fdb23085e186b2cb2501e7457fa7af2cf36ab40194b05ad15e12860a94e6"}, ] [[package]] name = "types-pillow" -version = "10.1.0.2" +version = "10.2.0.20240206" description = "Typing stubs for Pillow" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-Pillow-10.1.0.2.tar.gz", hash = "sha256:525c1c5ee67b0ac1721c40d2bc618226ef2123c347e527e14e05b920721a13b9"}, - {file = "types_Pillow-10.1.0.2-py3-none-any.whl", hash = "sha256:131078ffa547bf9a201d39ffcdc65633e108148085f4f1b07d4647fcfec6e923"}, + {file = "types-Pillow-10.2.0.20240206.tar.gz", hash = "sha256:f0de5107ff8362ffdbbd53ec896202ac905e6ab22ae784b46bcdad160ea143b9"}, + {file = "types_Pillow-10.2.0.20240206-py3-none-any.whl", hash = "sha256:abc339ae28af5916146a7729261480d68ac902cd4ff57e0bdd402eee7962644d"}, ] [[package]] name = "types-requests" -version = "2.31.0.10" +version = "2.31.0.20240125" description = "Typing stubs for requests" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, - {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, + {file = "types-requests-2.31.0.20240125.tar.gz", hash = "sha256:03a28ce1d7cd54199148e043b2079cdded22d6795d19a2c2a6791a4b2b5e2eb5"}, + {file = "types_requests-2.31.0.20240125-py3-none-any.whl", hash = "sha256:9592a9a4cb92d6d75d9b491a41477272b710e021011a2a3061157e2fb1f1a5d1"}, ] [package.dependencies] @@ -1219,54 +1213,57 @@ files = [ [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "watchdog" -version = "3.0.0" +version = "4.0.0" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, - {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, - {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, - {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, - {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, - {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, - {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, - {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, - {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, ] [package.extras] diff --git a/libs/partners/google-genai/tests/integration_tests/test_function_call.py b/libs/partners/google-genai/tests/integration_tests/test_function_call.py new file mode 100644 index 0000000000000..7a45bdf66613d --- /dev/null +++ b/libs/partners/google-genai/tests/integration_tests/test_function_call.py @@ -0,0 +1,34 @@ +"""Test ChatGoogleGenerativeAI function call.""" + +from langchain_google_genai.chat_models import ( + ChatGoogleGenerativeAI, +) + + +def test_function_call() -> None: + functions = [ + { + "name": "get_weather", + "description": "Determine weather in my location", + "parameters": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state e.g. San Francisco, CA", + }, + "unit": {"type": "string", "enum": ["c", "f"]}, + }, + "required": ["location"], + }, + } + ] + llm = ChatGoogleGenerativeAI(model="gemini-pro").bind(functions=functions) + res = llm.invoke("what weather is today in san francisco?") + assert res + assert res.additional_kwargs + assert "function_call" in res.additional_kwargs + assert "get_weather" == res.additional_kwargs["function_call"]["name"] + arguments = res.additional_kwargs["function_call"]["arguments"] + assert isinstance(arguments, dict) + assert "location" in arguments From 65798289a446d4baca2c5dd7a408bdff40f50846 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Wed, 7 Feb 2024 12:10:58 -0800 Subject: [PATCH 04/83] core[minor]: Use batched tracing in sdk (#16305) Remove threadpool executor usage in langchain tracer, this is now handled by sdk --- libs/core/langchain_core/tracers/langchain.py | 54 +++++++------------ libs/core/poetry.lock | 29 ++++++++-- libs/core/pyproject.toml | 2 +- .../smith/evaluation/runner_utils.py | 1 - 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/libs/core/langchain_core/tracers/langchain.py b/libs/core/langchain_core/tracers/langchain.py index ef4defb28b81f..91b54224bd2c5 100644 --- a/libs/core/langchain_core/tracers/langchain.py +++ b/libs/core/langchain_core/tracers/langchain.py @@ -2,10 +2,9 @@ from __future__ import annotations import logging -import weakref -from concurrent.futures import Future, ThreadPoolExecutor, wait +from concurrent.futures import ThreadPoolExecutor from datetime import datetime, timezone -from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union from uuid import UUID from langsmith import Client @@ -27,7 +26,6 @@ logger = logging.getLogger(__name__) _LOGGED = set() -_TRACERS: weakref.WeakSet[LangChainTracer] = weakref.WeakSet() _CLIENT: Optional[Client] = None _EXECUTOR: Optional[ThreadPoolExecutor] = None @@ -43,10 +41,9 @@ def log_error_once(method: str, exception: Exception) -> None: def wait_for_all_tracers() -> None: """Wait for all tracers to finish.""" - global _TRACERS - for tracer in list(_TRACERS): - if tracer is not None: - tracer.wait_for_futures() + global _CLIENT + if _CLIENT is not None and _CLIENT.tracing_queue is not None: + _CLIENT.tracing_queue.join() def get_client() -> Client: @@ -74,7 +71,6 @@ def __init__( project_name: Optional[str] = None, client: Optional[Client] = None, tags: Optional[List[str]] = None, - use_threading: bool = True, **kwargs: Any, ) -> None: """Initialize the LangChain tracer.""" @@ -84,12 +80,8 @@ def __init__( ) self.project_name = project_name or ls_utils.get_tracer_project() self.client = client or get_client() - self._futures: weakref.WeakSet[Future] = weakref.WeakSet() self.tags = tags or [] - self.executor = _get_executor() if use_threading else None self.latest_run: Optional[Run] = None - global _TRACERS - _TRACERS.add(self) def on_chat_model_start( self, @@ -181,75 +173,69 @@ def _update_run_single(self, run: Run) -> None: log_error_once("patch", e) raise - def _submit(self, function: Callable[[Run], None], run: Run) -> None: - """Submit a function to the executor.""" - if self.executor is None: - function(run) - else: - self._futures.add(self.executor.submit(function, run)) - def _on_llm_start(self, run: Run) -> None: """Persist an LLM run.""" if run.parent_run_id is None: run.reference_example_id = self.example_id - self._submit(self._persist_run_single, run) + self._persist_run_single(run) def _on_chat_model_start(self, run: Run) -> None: """Persist an LLM run.""" if run.parent_run_id is None: run.reference_example_id = self.example_id - self._submit(self._persist_run_single, run) + self._persist_run_single(run) def _on_llm_end(self, run: Run) -> None: """Process the LLM Run.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_llm_error(self, run: Run) -> None: """Process the LLM Run upon error.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_chain_start(self, run: Run) -> None: """Process the Chain Run upon start.""" if run.parent_run_id is None: run.reference_example_id = self.example_id - self._submit(self._persist_run_single, run) + self._persist_run_single(run) def _on_chain_end(self, run: Run) -> None: """Process the Chain Run.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_chain_error(self, run: Run) -> None: """Process the Chain Run upon error.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_tool_start(self, run: Run) -> None: """Process the Tool Run upon start.""" if run.parent_run_id is None: run.reference_example_id = self.example_id - self._submit(self._persist_run_single, run) + self._persist_run_single(run) def _on_tool_end(self, run: Run) -> None: """Process the Tool Run.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_tool_error(self, run: Run) -> None: """Process the Tool Run upon error.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_retriever_start(self, run: Run) -> None: """Process the Retriever Run upon start.""" if run.parent_run_id is None: run.reference_example_id = self.example_id - self._submit(self._persist_run_single, run) + self._persist_run_single(run) def _on_retriever_end(self, run: Run) -> None: """Process the Retriever Run.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def _on_retriever_error(self, run: Run) -> None: """Process the Retriever Run upon error.""" - self._submit(self._update_run_single, run) + self._update_run_single(run) def wait_for_futures(self) -> None: """Wait for the given futures to complete.""" - wait(self._futures) + if self.client is not None and self.client.tracing_queue is not None: + self.client.tracing_queue.join() diff --git a/libs/core/poetry.lock b/libs/core/poetry.lock index 8d8b5159d2e04..b8b0e512b26ea 100644 --- a/libs/core/poetry.lock +++ b/libs/core/poetry.lock @@ -1124,13 +1124,13 @@ files = [ [[package]] name = "langsmith" -version = "0.0.83" +version = "0.0.87" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.83-py3-none-any.whl", hash = "sha256:a5bb7ac58c19a415a9d5f51db56dd32ee2cd7343a00825bbc2018312eb3d122a"}, - {file = "langsmith-0.0.83.tar.gz", hash = "sha256:94427846b334ad9bdbec3266fee12903fe9f5448f628667689d0412012aaf392"}, + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, ] [package.dependencies] @@ -1164,6 +1164,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -1943,6 +1953,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1950,8 +1961,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1968,6 +1987,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1975,6 +1995,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -2745,4 +2766,4 @@ extended-testing = ["jinja2"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "6cd163ca8c15acc3053e17fa86acce4c27c2d737ebcad633db93c0d7aa3a4a53" +content-hash = "fec5bca68972fa7f7eea00a3cf3e158424bafdf028573611c575c3859ab289c5" diff --git a/libs/core/pyproject.toml b/libs/core/pyproject.toml index 5b61e7f192a44..274d35dcf4ceb 100644 --- a/libs/core/pyproject.toml +++ b/libs/core/pyproject.toml @@ -11,7 +11,7 @@ repository = "https://github.com/langchain-ai/langchain" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" pydantic = ">=1,<3" -langsmith = ">=0.0.83,<0.1" +langsmith = "^0.0.87" tenacity = "^8.1.0" jsonpatch = "^1.33" anyio = ">=3,<5" diff --git a/libs/langchain/langchain/smith/evaluation/runner_utils.py b/libs/langchain/langchain/smith/evaluation/runner_utils.py index ce50c1500af58..feb199e8d0e7d 100644 --- a/libs/langchain/langchain/smith/evaluation/runner_utils.py +++ b/libs/langchain/langchain/smith/evaluation/runner_utils.py @@ -1145,7 +1145,6 @@ def prepare( LangChainTracer( project_name=project.name, client=client, - use_threading=False, example_id=example.id, ), EvaluatorCallbackHandler( From 78409634fed33167c27ebf91983945ec9de148cf Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:28:05 -0800 Subject: [PATCH 05/83] core[patch]: Release 0.1.20 (#17194) --- libs/core/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/pyproject.toml b/libs/core/pyproject.toml index 274d35dcf4ceb..40c47e0a2e83b 100644 --- a/libs/core/pyproject.toml +++ b/libs/core/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-core" -version = "0.1.19" +version = "0.1.20" description = "Building applications with LLMs through composability" authors = [] license = "MIT" From 4ae91733aa84718abfb610c50d724ca38145e092 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 12:35:27 -0800 Subject: [PATCH 06/83] infra: fix core release (#17195) core doesn't have any min deps to test --- .github/workflows/_release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml index 4fe5cdaf5030a..06bcef9a04068 100644 --- a/.github/workflows/_release.yml +++ b/.github/workflows/_release.yml @@ -182,6 +182,7 @@ jobs: working-directory: ${{ inputs.working-directory }} - name: Get minimum versions + if: ${{ !startsWith(inputs.working-directory, 'libs/core') }} working-directory: ${{ inputs.working-directory }} id: min-version run: | @@ -191,6 +192,7 @@ jobs: echo "min-versions=$min_versions" - name: Run unit tests with minimum dependency versions + if: ${{ !startsWith(inputs.working-directory, 'libs/core') }} env: MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }} run: | From f87acf0340cc200a6b29fadd5f2e216cd7d0a26c Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 12:49:02 -0800 Subject: [PATCH 07/83] infra: better conditional (#17197) --- .github/workflows/_release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml index 06bcef9a04068..a0b31c866497b 100644 --- a/.github/workflows/_release.yml +++ b/.github/workflows/_release.yml @@ -182,7 +182,6 @@ jobs: working-directory: ${{ inputs.working-directory }} - name: Get minimum versions - if: ${{ !startsWith(inputs.working-directory, 'libs/core') }} working-directory: ${{ inputs.working-directory }} id: min-version run: | @@ -192,7 +191,7 @@ jobs: echo "min-versions=$min_versions" - name: Run unit tests with minimum dependency versions - if: ${{ !startsWith(inputs.working-directory, 'libs/core') }} + if: ${{ steps.min-version.outputs.min-versions != '' }} env: MIN_VERSIONS: ${{ steps.min-version.outputs.min-versions }} run: | From ecf8042a109a7f8547e4b427e5813c743409ad26 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Wed, 7 Feb 2024 21:50:54 +0100 Subject: [PATCH 08/83] templates: Add neo4j semantic layer with ollama template (#17192) A template with JSON-based agent using Mixtral via Ollama. --------- Co-authored-by: Erick Friis --- templates/neo4j-semantic-ollama/README.md | 104 + templates/neo4j-semantic-ollama/ingest.py | 59 + templates/neo4j-semantic-ollama/main.py | 17 + .../neo4j_semantic_ollama/__init__.py | 3 + .../neo4j_semantic_ollama/agent.py | 110 ++ .../neo4j_semantic_ollama/information_tool.py | 74 + .../neo4j_semantic_ollama/memory_tool.py | 73 + .../recommendation_tool.py | 164 ++ .../neo4j_semantic_ollama/smalltalk_tool.py | 39 + .../neo4j_semantic_ollama/utils.py | 84 + templates/neo4j-semantic-ollama/poetry.lock | 1753 +++++++++++++++++ .../neo4j-semantic-ollama/pyproject.toml | 33 + .../neo4j-semantic-ollama/static/workflow.png | Bin 0 -> 524624 bytes .../neo4j-semantic-ollama/tests/__init__.py | 0 14 files changed, 2513 insertions(+) create mode 100644 templates/neo4j-semantic-ollama/README.md create mode 100644 templates/neo4j-semantic-ollama/ingest.py create mode 100644 templates/neo4j-semantic-ollama/main.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/__init__.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/agent.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/information_tool.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/memory_tool.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/recommendation_tool.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/smalltalk_tool.py create mode 100644 templates/neo4j-semantic-ollama/neo4j_semantic_ollama/utils.py create mode 100644 templates/neo4j-semantic-ollama/poetry.lock create mode 100644 templates/neo4j-semantic-ollama/pyproject.toml create mode 100644 templates/neo4j-semantic-ollama/static/workflow.png create mode 100644 templates/neo4j-semantic-ollama/tests/__init__.py diff --git a/templates/neo4j-semantic-ollama/README.md b/templates/neo4j-semantic-ollama/README.md new file mode 100644 index 0000000000000..70a5ab15c97de --- /dev/null +++ b/templates/neo4j-semantic-ollama/README.md @@ -0,0 +1,104 @@ +# neo4j-semantic-ollama + +This template is designed to implement an agent capable of interacting with a graph database like Neo4j through a semantic layer using Mixtral as a JSON-based agent. +The semantic layer equips the agent with a suite of robust tools, allowing it to interact with the graph database based on the user's intent. +Learn more about the semantic layer template in the [corresponding blog post](https://medium.com/towards-data-science/enhancing-interaction-between-language-models-and-graph-databases-via-a-semantic-layer-0a78ad3eba49). + +![Diagram illustrating the workflow of the Neo4j semantic layer with an agent interacting with tools like Information, Recommendation, and Memory, connected to a knowledge graph.](https://raw.githubusercontent.com/langchain-ai/langchain/master/templates/neo4j-semantic-ollama/static/workflow.png "Neo4j Semantic Layer Workflow Diagram") + +## Tools + +The agent utilizes several tools to interact with the Neo4j graph database effectively: + +1. **Information tool**: + - Retrieves data about movies or individuals, ensuring the agent has access to the latest and most relevant information. +2. **Recommendation Tool**: + - Provides movie recommendations based upon user preferences and input. +3. **Memory Tool**: + - Stores information about user preferences in the knowledge graph, allowing for a personalized experience over multiple interactions. +4. **Smalltalk Tool**: + - Allows an agent to deal with smalltalk. + +## Environment Setup + +Before using this template, you need to set up Ollama and Neo4j database. + +1. Follow instructions [here](https://python.langchain.com/docs/integrations/chat/ollama) to download Ollama. + +2. Download your LLM of interest: + + * This package uses `mixtral`: `ollama pull mixtral` + * You can choose from many LLMs [here](https://ollama.ai/library) + +You need to define the following environment variables + +``` +OLLAMA_BASE_URL= +NEO4J_URI= +NEO4J_USERNAME= +NEO4J_PASSWORD= +``` + +## Populating with data + +If you want to populate the DB with an example movie dataset, you can run `python ingest.py`. +The script import information about movies and their rating by users. +Additionally, the script creates two [fulltext indices](https://neo4j.com/docs/cypher-manual/current/indexes-for-full-text-search/), which are used to map information from user input to the database. + +## Usage + +To use this package, you should first have the LangChain CLI installed: + +```shell +pip install -U "langchain-cli[serve]" +``` + +To create a new LangChain project and install this as the only package, you can do: + +```shell +langchain app new my-app --package neo4j-semantic-ollama +``` + +If you want to add this to an existing project, you can just run: + +```shell +langchain app add neo4j-semantic-ollama +``` + +And add the following code to your `server.py` file: +```python +from neo4j_semantic_layer import agent_executor as neo4j_semantic_agent + +add_routes(app, neo4j_semantic_agent, path="/neo4j-semantic-ollama") +``` + +(Optional) Let's now configure LangSmith. +LangSmith will help us trace, monitor and debug LangChain applications. +LangSmith is currently in private beta, you can sign up [here](https://smith.langchain.com/). +If you don't have access, you can skip this section + +```shell +export LANGCHAIN_TRACING_V2=true +export LANGCHAIN_API_KEY= +export LANGCHAIN_PROJECT= # if not specified, defaults to "default" +``` + +If you are inside this directory, then you can spin up a LangServe instance directly by: + +```shell +langchain serve +``` + +This will start the FastAPI app with a server is running locally at +[http://localhost:8000](http://localhost:8000) + +We can see all templates at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) +We can access the playground at [http://127.0.0.1:8000/neo4j-semantic-ollama/playground](http://127.0.0.1:8000/neo4j-semantic-ollama/playground) + +We can access the template from code with: + +```python +from langserve.client import RemoteRunnable + +runnable = RemoteRunnable("http://localhost:8000/neo4j-semantic-ollama") +``` diff --git a/templates/neo4j-semantic-ollama/ingest.py b/templates/neo4j-semantic-ollama/ingest.py new file mode 100644 index 0000000000000..973b4c93c9c59 --- /dev/null +++ b/templates/neo4j-semantic-ollama/ingest.py @@ -0,0 +1,59 @@ +from langchain_community.graphs import Neo4jGraph + +# Instantiate connection to Neo4j +graph = Neo4jGraph() + +# Define unique constraints +graph.query("CREATE CONSTRAINT IF NOT EXISTS FOR (m:Movie) REQUIRE m.id IS UNIQUE;") +graph.query("CREATE CONSTRAINT IF NOT EXISTS FOR (u:User) REQUIRE u.id IS UNIQUE;") +graph.query("CREATE CONSTRAINT IF NOT EXISTS FOR (p:Person) REQUIRE p.name IS UNIQUE;") +graph.query("CREATE CONSTRAINT IF NOT EXISTS FOR (g:Genre) REQUIRE g.name IS UNIQUE;") + +# Import movie information + +movies_query = """ +LOAD CSV WITH HEADERS FROM +'https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/movies/movies.csv' +AS row +CALL { + WITH row + MERGE (m:Movie {id:row.movieId}) + SET m.released = date(row.released), + m.title = row.title, + m.imdbRating = toFloat(row.imdbRating) + FOREACH (director in split(row.director, '|') | + MERGE (p:Person {name:trim(director)}) + MERGE (p)-[:DIRECTED]->(m)) + FOREACH (actor in split(row.actors, '|') | + MERGE (p:Person {name:trim(actor)}) + MERGE (p)-[:ACTED_IN]->(m)) + FOREACH (genre in split(row.genres, '|') | + MERGE (g:Genre {name:trim(genre)}) + MERGE (m)-[:IN_GENRE]->(g)) +} IN TRANSACTIONS +""" + +graph.query(movies_query) + +# Import rating information +rating_query = """ +LOAD CSV WITH HEADERS FROM +'https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/movies/ratings.csv' +AS row +CALL { + WITH row + MATCH (m:Movie {id:row.movieId}) + MERGE (u:User {id:row.userId}) + MERGE (u)-[r:RATED]->(m) + SET r.rating = toFloat(row.rating), + r.timestamp = row.timestamp +} IN TRANSACTIONS OF 10000 ROWS +""" + +graph.query(rating_query) + +# Define fulltext indices +graph.query("CREATE FULLTEXT INDEX movie IF NOT EXISTS FOR (m:Movie) ON EACH [m.title]") +graph.query( + "CREATE FULLTEXT INDEX person IF NOT EXISTS FOR (p:Person) ON EACH [p.name]" +) diff --git a/templates/neo4j-semantic-ollama/main.py b/templates/neo4j-semantic-ollama/main.py new file mode 100644 index 0000000000000..d6ee3a919695e --- /dev/null +++ b/templates/neo4j-semantic-ollama/main.py @@ -0,0 +1,17 @@ +from neo4j_semantic_ollama import agent_executor + +if __name__ == "__main__": + original_query = "What do you know about person John?" + followup_query = "John Travolta" + chat_history = [ + ( + "What do you know about person John?", + "I found multiple people named John. Could you please specify " + "which one you are interested in? Here are some options:" + "\n\n1. John Travolta\n2. John McDonough", + ) + ] + print(agent_executor.invoke({"input": original_query})) + print( + agent_executor.invoke({"input": followup_query, "chat_history": chat_history}) + ) diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/__init__.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/__init__.py new file mode 100644 index 0000000000000..0b540e6327fa2 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/__init__.py @@ -0,0 +1,3 @@ +from neo4j_semantic_ollama.agent import agent_executor + +__all__ = ["agent_executor"] diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/agent.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/agent.py new file mode 100644 index 0000000000000..ad4010d6cfc92 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/agent.py @@ -0,0 +1,110 @@ +import os +from typing import List, Tuple + +from langchain.agents import AgentExecutor +from langchain.agents.format_scratchpad import format_log_to_messages +from langchain.agents.output_parsers import ( + ReActJsonSingleInputOutputParser, +) +from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain.pydantic_v1 import BaseModel, Field +from langchain.schema import AIMessage, HumanMessage +from langchain.tools.render import render_text_description_and_args +from langchain_community.chat_models import ChatOllama + +from neo4j_semantic_ollama.information_tool import InformationTool +from neo4j_semantic_ollama.memory_tool import MemoryTool +from neo4j_semantic_ollama.recommendation_tool import RecommenderTool +from neo4j_semantic_ollama.smalltalk_tool import SmalltalkTool + +llm = ChatOllama( + model="mixtral", + temperature=0, + base_url=os.environ["OLLAMA_BASE_URL"], + streaming=True, +) +chat_model_with_stop = llm.bind(stop=["\nObservation"]) +tools = [InformationTool(), RecommenderTool(), MemoryTool(), SmalltalkTool()] + +# Inspiration taken from hub.pull("hwchase17/react-json") +system_message = f"""Answer the following questions as best you can. +You can answer directly if the user is greeting you or similar. +Otherise, you have access to the following tools: + +{render_text_description_and_args(tools).replace('{', '{{').replace('}', '}}')} + +The way you use the tools is by specifying a json blob. +Specifically, this json should have a `action` key (with the name of the tool to use) +and a `action_input` key (with the input to the tool going here). +The only values that should be in the "action" field are: {[t.name for t in tools]} +The $JSON_BLOB should only contain a SINGLE action, +do NOT return a list of multiple actions. +Here is an example of a valid $JSON_BLOB: +``` +{{{{ + "action": $TOOL_NAME, + "action_input": $INPUT +}}}} +``` +The $JSON_BLOB must always be enclosed with triple backticks! + +ALWAYS use the following format: +Question: the input question you must answer +Thought: you should always think about what to do +Action:``` +$JSON_BLOB +``` +Observation: the result of the action... +(this Thought/Action/Observation can repeat N times) +Thought: I now know the final answer +Final Answer: the final answer to the original input question + +Begin! Reminder to always use the exact characters `Final Answer` when responding.' +""" + +prompt = ChatPromptTemplate.from_messages( + [ + ( + "user", + system_message, + ), + MessagesPlaceholder(variable_name="chat_history"), + ("user", "{input}"), + MessagesPlaceholder(variable_name="agent_scratchpad"), + ] +) + + +def _format_chat_history(chat_history: List[Tuple[str, str]]): + buffer = [] + for human, ai in chat_history: + buffer.append(HumanMessage(content=human)) + buffer.append(AIMessage(content=ai)) + return buffer + + +agent = ( + { + "input": lambda x: x["input"], + "agent_scratchpad": lambda x: format_log_to_messages(x["intermediate_steps"]), + "chat_history": lambda x: _format_chat_history(x["chat_history"]) + if x.get("chat_history") + else [], + } + | prompt + | chat_model_with_stop + | ReActJsonSingleInputOutputParser() +) + + +# Add typing for input +class AgentInput(BaseModel): + input: str + chat_history: List[Tuple[str, str]] = Field( + ..., extra={"widget": {"type": "chat", "input": "input", "output": "output"}} + ) + + +agent_executor = AgentExecutor(agent=agent, tools=tools).with_types( + input_type=AgentInput +) diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/information_tool.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/information_tool.py new file mode 100644 index 0000000000000..9ed31d2723ee3 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/information_tool.py @@ -0,0 +1,74 @@ +from typing import Optional, Type + +from langchain.callbacks.manager import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) + +# Import things that are needed generically +from langchain.pydantic_v1 import BaseModel, Field +from langchain.tools import BaseTool + +from neo4j_semantic_ollama.utils import get_candidates, graph + +description_query = """ +MATCH (m:Movie|Person) +WHERE m.title = $candidate OR m.name = $candidate +MATCH (m)-[r:ACTED_IN|DIRECTED|HAS_GENRE]-(t) +WITH m, type(r) as type, collect(coalesce(t.name, t.title)) as names +WITH m, type+": "+reduce(s="", n IN names | s + n + ", ") as types +WITH m, collect(types) as contexts +WITH m, "type:" + labels(m)[0] + "\ntitle: "+ coalesce(m.title, m.name) + + "\nyear: "+coalesce(m.released,"") +"\n" + + reduce(s="", c in contexts | s + substring(c, 0, size(c)-2) +"\n") as context +RETURN context LIMIT 1 +""" + + +def get_information(entity: str, type: str) -> str: + candidates = get_candidates(entity, type) + if not candidates: + return "No information was found about the movie or person in the database" + elif len(candidates) > 1: + newline = "\n" + return ( + "Need additional information, which of these " + f"did you mean: {newline + newline.join(str(d) for d in candidates)}" + ) + data = graph.query( + description_query, params={"candidate": candidates[0]["candidate"]} + ) + return data[0]["context"] + + +class InformationInput(BaseModel): + entity: str = Field(description="movie or a person mentioned in the question") + entity_type: str = Field( + description="type of the entity. Available options are 'movie' or 'person'" + ) + + +class InformationTool(BaseTool): + name = "Information" + description = ( + "useful for when you need to answer questions about various actors or movies" + ) + args_schema: Type[BaseModel] = InformationInput + + def _run( + self, + entity: str, + entity_type: str, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the tool.""" + return get_information(entity, entity_type) + + async def _arun( + self, + entity: str, + entity_type: str, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + """Use the tool asynchronously.""" + return get_information(entity, entity_type) diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/memory_tool.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/memory_tool.py new file mode 100644 index 0000000000000..f455f70c4b7b1 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/memory_tool.py @@ -0,0 +1,73 @@ +from typing import Optional, Type + +from langchain.callbacks.manager import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) + +# Import things that are needed generically +from langchain.pydantic_v1 import BaseModel, Field +from langchain.tools import BaseTool + +from neo4j_semantic_ollama.utils import get_candidates, get_user_id, graph + +store_rating_query = """ +MERGE (u:User {userId:$user_id}) +WITH u +UNWIND $candidates as row +MATCH (m:Movie {title: row.candidate}) +MERGE (u)-[r:RATED]->(m) +SET r.rating = toFloat($rating) +RETURN distinct + 'Create a final answer saying that preference has been stored' AS response +""" + + +def store_movie_rating(movie: str, rating: int): + user_id = get_user_id() + candidates = get_candidates(movie, "movie") + if not candidates: + return "This movie is not in our database" + response = graph.query( + store_rating_query, + params={"user_id": user_id, "candidates": candidates, "rating": rating}, + ) + try: + return response[0]["response"] + except Exception as e: + print(e) + return "Something went wrong" + + +class MemoryInput(BaseModel): + movie: str = Field(description="movie the user liked") + rating: int = Field( + description=( + "Rating from 1 to 5, where one represents heavy dislike " + "and 5 represent the user loved the movie" + ) + ) + + +class MemoryTool(BaseTool): + name = "Memory" + description = "useful for memorizing which movies the user liked" + args_schema: Type[BaseModel] = MemoryInput + + def _run( + self, + movie: str, + rating: int, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the tool.""" + return store_movie_rating(movie, rating) + + async def _arun( + self, + movie: str, + rating: int, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + """Use the tool asynchronously.""" + return store_movie_rating(movie, rating) diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/recommendation_tool.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/recommendation_tool.py new file mode 100644 index 0000000000000..dc85c7c739859 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/recommendation_tool.py @@ -0,0 +1,164 @@ +from typing import Optional, Type + +from langchain.callbacks.manager import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) +from langchain.pydantic_v1 import BaseModel, Field +from langchain.tools import BaseTool + +from neo4j_semantic_ollama.utils import get_candidates, get_user_id, graph + +recommendation_query_db_history = """ + MERGE (u:User {userId:$user_id}) + WITH u + // get recommendation candidates + OPTIONAL MATCH (u)-[r1:RATED]->()<-[r2:RATED]-()-[r3:RATED]->(recommendation) + WHERE r1.rating > 3.5 AND r2.rating > 3.5 AND r3.rating > 3.5 + AND NOT EXISTS {(u)-[:RATED]->(recommendation)} + // rank and limit recommendations + WITH u, recommendation, count(*) AS count + ORDER BY count DESC LIMIT 3 +RETURN 'title:' + recommendation.title + '\nactors:' + +apoc.text.join([(recommendation)<-[:ACTED_IN]-(a) | a.name], ',') + +'\ngenre:' + apoc.text.join([(recommendation)-[:IN_GENRE]->(a) | a.name], ',') +AS movie +""" + +recommendation_query_genre = """ +MATCH (m:Movie)-[:IN_GENRE]->(g:Genre {name:$genre}) +// filter out already seen movies by the user +WHERE NOT EXISTS { + (m)<-[:RATED]-(:User {userId:$user_id}) +} +// rank and limit recommendations +WITH m AS recommendation +ORDER BY recommendation.imdbRating DESC LIMIT 3 +RETURN 'title:' + recommendation.title + '\nactors:' + +apoc.text.join([(recommendation)<-[:ACTED_IN]-(a) | a.name], ',') + +'\ngenre:' + apoc.text.join([(recommendation)-[:IN_GENRE]->(a) | a.name], ',') +AS movie +""" + + +def recommendation_query_movie(genre: bool) -> str: + return f""" +MATCH (m1:Movie)<-[r1:RATED]-()-[r2:RATED]->(m2:Movie) +WHERE r1.rating > 3.5 AND r2.rating > 3.5 and m1.title IN $movieTitles +// filter out already seen movies by the user +AND NOT EXISTS {{ + (m2)<-[:RATED]-(:User {{userId:$user_id}}) +}} +{'AND EXISTS {(m2)-[:IN_GENRE]->(:Genre {name:$genre})}' if genre else ''} +// rank and limit recommendations +WITH m2 AS recommendation, count(*) AS count +ORDER BY count DESC LIMIT 3 +RETURN 'title:' + recommendation.title + '\nactors:' + +apoc.text.join([(recommendation)<-[:ACTED_IN]-(a) | a.name], ',') + +'\ngenre:' + apoc.text.join([(recommendation)-[:IN_GENRE]->(a) | a.name], ',') +AS movie +""" + + +nl = "\n" + + +def recommend_movie(movie: Optional[str] = None, genre: Optional[str] = None) -> str: + """ + Recommends movies based on user's history and preference + for a specific movie and/or genre. + Returns: + str: A string containing a list of recommended movies, or an error message. + """ + user_id = get_user_id() + params = {"user_id": user_id, "genre": genre} + if not movie and not genre: + # Try to recommend a movie based on the information in the db + response = graph.query(recommendation_query_db_history, params) + try: + return ( + 'Recommended movies are: ' + f'{f"###Movie {nl}".join([el["movie"] for el in response])}' + ) + except Exception: + return "Can you tell us about some of the movies you liked?" + if not movie and genre: + # Recommend top voted movies in the genre the user haven't seen before + response = graph.query(recommendation_query_genre, params) + try: + return ( + 'Recommended movies are: ' + f'{f"###Movie {nl}".join([el["movie"] for el in response])}' + ) + except Exception: + return "Something went wrong" + + candidates = get_candidates(movie, "movie") + if not candidates: + return "The movie you mentioned wasn't found in the database" + params["movieTitles"] = [el["candidate"] for el in candidates] + query = recommendation_query_movie(bool(genre)) + response = graph.query(query, params) + try: + return ( + 'Recommended movies are: ' + f'{f"###Movie {nl}".join([el["movie"] for el in response])}' + ) + except Exception: + return "Something went wrong" + + +all_genres = [ + "Action", + "Adventure", + "Animation", + "Children", + "Comedy", + "Crime", + "Documentary", + "Drama", + "Fantasy", + "Film-Noir", + "Horror", + "IMAX", + "Musical", + "Mystery", + "Romance", + "Sci-Fi", + "Thriller", + "War", + "Western", +] + + +class RecommenderInput(BaseModel): + movie: Optional[str] = Field(description="movie used for recommendation") + genre: Optional[str] = Field( + description=( + "genre used for recommendation. Available options are:" f"{all_genres}" + ) + ) + + +class RecommenderTool(BaseTool): + name = "Recommender" + description = "useful for when you need to recommend a movie" + args_schema: Type[BaseModel] = RecommenderInput + + def _run( + self, + movie: Optional[str] = None, + genre: Optional[str] = None, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the tool.""" + return recommend_movie(movie, genre) + + async def _arun( + self, + movie: Optional[str] = None, + genre: Optional[str] = None, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + """Use the tool asynchronously.""" + return recommend_movie(movie, genre) diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/smalltalk_tool.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/smalltalk_tool.py new file mode 100644 index 0000000000000..0b2469f2d1091 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/smalltalk_tool.py @@ -0,0 +1,39 @@ +from typing import Optional, Type + +from langchain.callbacks.manager import ( + AsyncCallbackManagerForToolRun, + CallbackManagerForToolRun, +) +from langchain.pydantic_v1 import BaseModel, Field +from langchain.tools import BaseTool + +response = ( + "Create a final answer that says if they " + "have any questions about movies or actors" +) + + +class SmalltalkInput(BaseModel): + query: Optional[str] = Field(description="user query") + + +class SmalltalkTool(BaseTool): + name = "Smalltalk" + description = "useful for when user greets you or wants to smalltalk" + args_schema: Type[BaseModel] = SmalltalkInput + + def _run( + self, + query: Optional[str] = None, + run_manager: Optional[CallbackManagerForToolRun] = None, + ) -> str: + """Use the tool.""" + return response + + async def _arun( + self, + query: Optional[str] = None, + run_manager: Optional[AsyncCallbackManagerForToolRun] = None, + ) -> str: + """Use the tool asynchronously.""" + return response diff --git a/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/utils.py b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/utils.py new file mode 100644 index 0000000000000..ae83928bd5196 --- /dev/null +++ b/templates/neo4j-semantic-ollama/neo4j_semantic_ollama/utils.py @@ -0,0 +1,84 @@ +from typing import Dict, List + +from langchain_community.graphs import Neo4jGraph + +graph = Neo4jGraph() + + +def get_user_id() -> int: + """ + Placeholder for a function that would normally retrieve + a user's ID + """ + return 1 + + +def remove_lucene_chars(text: str) -> str: + """Remove Lucene special characters""" + special_chars = [ + "+", + "-", + "&", + "|", + "!", + "(", + ")", + "{", + "}", + "[", + "]", + "^", + '"', + "~", + "*", + "?", + ":", + "\\", + ] + for char in special_chars: + if char in text: + text = text.replace(char, " ") + return text.strip() + + +def generate_full_text_query(input: str) -> str: + """ + Generate a full-text search query for a given input string. + + This function constructs a query string suitable for a full-text search. + It processes the input string by splitting it into words and appending a + similarity threshold (~0.8) to each word, then combines them using the AND + operator. Useful for mapping movies and people from user questions + to database values, and allows for some misspelings. + """ + full_text_query = "" + words = [el for el in remove_lucene_chars(input).split() if el] + for word in words[:-1]: + full_text_query += f" {word}~0.8 AND" + full_text_query += f" {words[-1]}~0.8" + return full_text_query.strip() + + +candidate_query = """ +CALL db.index.fulltext.queryNodes($index, $fulltextQuery, {limit: $limit}) +YIELD node +RETURN coalesce(node.name, node.title) AS candidate, + [el in labels(node) WHERE el IN ['Person', 'Movie'] | el][0] AS label +""" + + +def get_candidates(input: str, type: str, limit: int = 3) -> List[Dict[str, str]]: + """ + Retrieve a list of candidate entities from database based on the input string. + + This function queries the Neo4j database using a full-text search. It takes the + input string, generates a full-text query, and executes this query against the + specified index in the database. The function returns a list of candidates + matching the query, with each candidate being a dictionary containing their name + (or title) and label (either 'Person' or 'Movie'). + """ + ft_query = generate_full_text_query(input) + candidates = graph.query( + candidate_query, {"fulltextQuery": ft_query, "index": type, "limit": limit} + ) + return candidates diff --git a/templates/neo4j-semantic-ollama/poetry.lock b/templates/neo4j-semantic-ollama/poetry.lock new file mode 100644 index 0000000000000..4aefece720327 --- /dev/null +++ b/templates/neo4j-semantic-ollama/poetry.lock @@ -0,0 +1,1753 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "aiohttp" +version = "3.9.3" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, + {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, + {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, + {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, + {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, +] + +[package.dependencies] +aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.4" +description = "Easily serialize dataclasses to and from JSON." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dataclasses_json-0.6.4-py3-none-any.whl", hash = "sha256:f90578b8a3177f7552f4e1a6e535e84293cd5da421fcce0642d49c0d7bdf8df2"}, + {file = "dataclasses_json-0.6.4.tar.gz", hash = "sha256:73696ebf24936560cca79a2430cbc4f3dd23ac7bf46ed17f38e5e5e7657a6377"}, +] + +[package.dependencies] +marshmallow = ">=3.18.0,<4.0.0" +typing-inspect = ">=0.4.0,<1" + +[[package]] +name = "distro" +version = "1.9.0" +description = "Distro - an OS platform information API" +optional = false +python-versions = ">=3.6" +files = [ + {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, + {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.109.2" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"}, + {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.36.3,<0.37.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "frozenlist" +version = "1.4.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.41" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"}, + {file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] + +[[package]] +name = "greenlet" +version = "3.0.3" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.2" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] + +[[package]] +name = "httpx" +version = "0.26.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, + {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx-sse" +version = "0.4.0" +description = "Consume Server-Sent Event (SSE) messages with HTTPX." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, + {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, +] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "langchain" +version = "0.1.5" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain-0.1.5-py3-none-any.whl", hash = "sha256:4614118d4a95b2e7ba3611a0b6b21707a259a21652a04fbe3c31205bcf3fcd50"}, + {file = "langchain-0.1.5.tar.gz", hash = "sha256:69603a5bb21b044ddea69d38131dbbf47475afdf79728644faa67d1ad325d652"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} +dataclasses-json = ">=0.5.7,<0.7" +jsonpatch = ">=1.33,<2.0" +langchain-community = ">=0.0.17,<0.1" +langchain-core = ">=0.1.16,<0.2" +langsmith = ">=0.0.83,<0.1" +numpy = ">=1,<2" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (<2)"] +clarifai = ["clarifai (>=9.1.0)"] +cli = ["typer (>=0.9.0,<0.10.0)"] +cohere = ["cohere (>=4,<5)"] +docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] +embeddings = ["sentence-transformers (>=2,<3)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +javascript = ["esprima (>=4.0.1,<5.0.0)"] +llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] +openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] +qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] +text-helpers = ["chardet (>=5.1.0,<6.0.0)"] + +[[package]] +name = "langchain-cli" +version = "0.0.21" +description = "CLI for interacting with LangChain" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_cli-0.0.21-py3-none-any.whl", hash = "sha256:cd5c83597ef857704db983aa1743d7c2e6da52d634f735a7610630347347583e"}, + {file = "langchain_cli-0.0.21.tar.gz", hash = "sha256:d36a40955533ce0217b9a89c11bf593b18d8b40f2abbc81c9a531eb23f54809f"}, +] + +[package.dependencies] +gitpython = ">=3.1.40,<4.0.0" +langserve = {version = ">=0.0.16", extras = ["all"]} +tomlkit = ">=0.12.2,<0.13.0" +typer = {version = ">=0.9.0,<0.10.0", extras = ["all"]} +uvicorn = ">=0.23.2,<0.24.0" + +[[package]] +name = "langchain-community" +version = "0.0.18" +description = "Community contributed LangChain integrations." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_community-0.0.18-py3-none-any.whl", hash = "sha256:b87e20c1fa3f37e9608d7ccc08b4d8ed86f875b8c1e735d0464ae986e41c5a71"}, + {file = "langchain_community-0.0.18.tar.gz", hash = "sha256:f044f331b418f16148b76929f27cc2107fce2d190ea3fae0cdaf155ceda9892f"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +dataclasses-json = ">=0.5.7,<0.7" +langchain-core = ">=0.1.19,<0.2" +langsmith = ">=0.0.83,<0.1" +numpy = ">=1,<2" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +cli = ["typer (>=0.9.0,<0.10.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] + +[[package]] +name = "langchain-core" +version = "0.1.20" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_core-0.1.20-py3-none-any.whl", hash = "sha256:fe43e5f401a8bdb16f8d67f790016810ee11c224d9a85a1e3afb099dc425960d"}, + {file = "langchain_core-0.1.20.tar.gz", hash = "sha256:8a67291166e498c97e52ee1c63f876a30799e0af91ce7b163ce88b90fa024039"}, +] + +[package.dependencies] +anyio = ">=3,<5" +jsonpatch = ">=1.33,<2.0" +langsmith = ">=0.0.87,<0.0.88" +packaging = ">=23.2,<24.0" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +extended-testing = ["jinja2 (>=3,<4)"] + +[[package]] +name = "langserve" +version = "0.0.41" +description = "" +optional = false +python-versions = ">=3.8.1,<4.0.0" +files = [ + {file = "langserve-0.0.41-py3-none-any.whl", hash = "sha256:99583a6a4f2a6c3f98ffcf0c9eeed2a1ef6278b0cfaf9d789dfd517c49d0062a"}, + {file = "langserve-0.0.41.tar.gz", hash = "sha256:8583d9d01b202b4111e21e3c94d91ca6b61093ebff55fdfd0f92c6c8d155a6e5"}, +] + +[package.dependencies] +fastapi = {version = ">=0.90.1,<1", optional = true, markers = "extra == \"server\" or extra == \"all\""} +httpx = ">=0.23.0" +httpx-sse = {version = ">=0.3.1", optional = true, markers = "extra == \"client\" or extra == \"all\""} +langchain = ">=0.0.333" +orjson = ">=2" +pydantic = ">=1" +sse-starlette = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"server\" or extra == \"all\""} + +[package.extras] +all = ["fastapi (>=0.90.1,<1)", "httpx-sse (>=0.3.1)", "sse-starlette (>=1.3.0,<2.0.0)"] +client = ["httpx-sse (>=0.3.1)"] +server = ["fastapi (>=0.90.1,<1)", "sse-starlette (>=1.3.0,<2.0.0)"] + +[[package]] +name = "langsmith" +version = "0.0.87" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "marshmallow" +version = "3.20.2" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, + {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["pre-commit (>=2.4,<4.0)"] +tests = ["pytest", "pytz", "simplejson"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "multidict" +version = "6.0.5" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "neo4j" +version = "5.17.0" +description = "Neo4j Bolt driver for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "neo4j-5.17.0.tar.gz", hash = "sha256:dcd7150a0c3834a89a6e27505e614f340376f31c97c48ba60dc70a220ee85e3b"}, +] + +[package.dependencies] +pytz = "*" + +[package.extras] +numpy = ["numpy (>=1.7.0,<2.0.0)"] +pandas = ["numpy (>=1.7.0,<2.0.0)", "pandas (>=1.1.0,<3.0.0)"] +pyarrow = ["pyarrow (>=1.0.0)"] + +[[package]] +name = "numpy" +version = "1.24.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"}, + {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"}, + {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"}, + {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"}, + {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"}, + {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"}, + {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"}, + {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"}, + {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"}, + {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"}, + {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"}, + {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"}, + {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"}, + {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"}, + {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"}, + {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"}, + {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"}, + {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"}, + {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"}, +] + +[[package]] +name = "openai" +version = "1.11.1" +description = "The official Python library for the openai API" +optional = false +python-versions = ">=3.7.1" +files = [ + {file = "openai-1.11.1-py3-none-any.whl", hash = "sha256:e0f388ce499f53f58079d0c1f571f356f2b168b84d0d24a412506b6abc714980"}, + {file = "openai-1.11.1.tar.gz", hash = "sha256:f66b8fe431af43e09594147ef3cdcb79758285de72ebafd52be9700a2af41e99"}, +] + +[package.dependencies] +anyio = ">=3.5.0,<5" +distro = ">=1.7.0,<2" +httpx = ">=0.23.0,<1" +pydantic = ">=1.9.0,<3" +sniffio = "*" +tqdm = ">4" +typing-extensions = ">=4.7,<5" + +[package.extras] +datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] + +[[package]] +name = "orjson" +version = "3.9.13" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.9.13-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f"}, + {file = "orjson-3.9.13-cp310-none-win32.whl", hash = "sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc"}, + {file = "orjson-3.9.13-cp310-none-win_amd64.whl", hash = "sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f"}, + {file = "orjson-3.9.13-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b"}, + {file = "orjson-3.9.13-cp311-none-win32.whl", hash = "sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d"}, + {file = "orjson-3.9.13-cp311-none-win_amd64.whl", hash = "sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43"}, + {file = "orjson-3.9.13-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff"}, + {file = "orjson-3.9.13-cp312-none-win_amd64.whl", hash = "sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c"}, + {file = "orjson-3.9.13-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585"}, + {file = "orjson-3.9.13-cp38-none-win32.whl", hash = "sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c"}, + {file = "orjson-3.9.13-cp38-none-win_amd64.whl", hash = "sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d"}, + {file = "orjson-3.9.13-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11"}, + {file = "orjson-3.9.13-cp39-none-win32.whl", hash = "sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37"}, + {file = "orjson-3.9.13-cp39-none-win_amd64.whl", hash = "sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4"}, + {file = "orjson-3.9.13.tar.gz", hash = "sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pydantic" +version = "2.6.1" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, + {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.16.2" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.16.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, + {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, + {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, + {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, + {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, + {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, + {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, + {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, + {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, + {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, + {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, + {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, + {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, + {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pytz" +version = "2024.1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.7.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.25" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-win32.whl", hash = "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-win_amd64.whl", hash = "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-win32.whl", hash = "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-win32.whl", hash = "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-win_amd64.whl", hash = "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-win32.whl", hash = "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-win_amd64.whl", hash = "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-win32.whl", hash = "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-win_amd64.whl", hash = "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-win32.whl", hash = "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-win_amd64.whl", hash = "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7"}, + {file = "SQLAlchemy-2.0.25-py3-none-any.whl", hash = "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3"}, + {file = "SQLAlchemy-2.0.25.tar.gz", hash = "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "sse-starlette" +version = "1.8.2" +description = "SSE plugin for Starlette" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sse_starlette-1.8.2-py3-none-any.whl", hash = "sha256:70cc7ef5aca4abe8a25dec1284cce4fe644dd7bf0c406d3e852e516092b7f849"}, + {file = "sse_starlette-1.8.2.tar.gz", hash = "sha256:e0f9b8dec41adc092a0a6e0694334bd3cfd3084c44c497a6ebc1fb4bdd919acd"}, +] + +[package.dependencies] +anyio = "*" +fastapi = "*" +starlette = "*" +uvicorn = "*" + +[[package]] +name = "starlette" +version = "0.36.3" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, + {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "tenacity" +version = "8.2.3" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "typer" +version = "0.9.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, + {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} +rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} +shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "urllib3" +version = "2.2.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.23.2" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.23.2-py3-none-any.whl", hash = "sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53"}, + {file = "uvicorn-0.23.2.tar.gz", hash = "sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "yarl" +version = "1.9.4" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, + {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, + {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, + {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, + {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "2.0" +python-versions = ">=3.8.1,<4.0" +content-hash = "73382a4881f17030e9418464de411dab25ffc6aae9f27448fa44ba4bcef3ec68" diff --git a/templates/neo4j-semantic-ollama/pyproject.toml b/templates/neo4j-semantic-ollama/pyproject.toml new file mode 100644 index 0000000000000..e112e3fad9dc3 --- /dev/null +++ b/templates/neo4j-semantic-ollama/pyproject.toml @@ -0,0 +1,33 @@ +[tool.poetry] +name = "neo4j-semantic-ollama" +version = "0.1.0" +description = "Build a semantic layer with Mixtral via Ollama to allow an agent to interact with a graph database in consistent and robust way." +authors = [ + "Tomaz Bratanic ", +] +readme = "README.md" + +[tool.poetry.dependencies] +python = ">=3.8.1,<4.0" +langchain = "^0.1" +openai = "<2" +neo4j = "^5.14.0" + +[tool.poetry.group.dev.dependencies] +langchain-cli = ">=0.0.21" + +[tool.langserve] +export_module = "neo4j_semantic_ollama" +export_attr = "agent_executor" + +[tool.templates-hub] +use-case = "semantic_layer" +author = "Neo4j" +integrations = ["Neo4j", "Ollama"] +tags = ["search", "graph-database", "function-calling"] + +[build-system] +requires = [ + "poetry-core", +] +build-backend = "poetry.core.masonry.api" diff --git a/templates/neo4j-semantic-ollama/static/workflow.png b/templates/neo4j-semantic-ollama/static/workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..f62b720beef83b835f5ea4c25636dbb68f907f4f GIT binary patch literal 524624 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
W@zh3IefC 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 literal 0 HcmV?d00001 diff --git a/templates/neo4j-semantic-ollama/tests/__init__.py b/templates/neo4j-semantic-ollama/tests/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d From 1cf5a5858fbb184059ca2f217d296cf55ab433a7 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 12:58:01 -0800 Subject: [PATCH 09/83] remove pg_essay.txt (#17198) Added in #16159 --- pg_essay.txt | 351 --------------------------------------------------- 1 file changed, 351 deletions(-) delete mode 100644 pg_essay.txt diff --git a/pg_essay.txt b/pg_essay.txt deleted file mode 100644 index 0bce3830b9968..0000000000000 --- a/pg_essay.txt +++ /dev/null @@ -1,351 +0,0 @@ -What I Worked On - -February 2021 - -Before college the two main things I worked on, outside of school, were writing and programming. I didn't write essays. I wrote what beginning writers were supposed to write then, and probably still are: short stories. My stories were awful. They had hardly any plot, just characters with strong feelings, which I imagined made them deep. - -The first programs I tried writing were on the IBM 1401 that our school district used for what was then called "data processing." This was in 9th grade, so I was 13 or 14. The school district's 1401 happened to be in the basement of our junior high school, and my friend Rich Draves and I got permission to use it. It was like a mini Bond villain's lair down there, with all these alien-looking machines — CPU, disk drives, printer, card reader — sitting up on a raised floor under bright fluorescent lights. - -The language we used was an early version of Fortran. You had to type programs on punch cards, then stack them in the card reader and press a button to load the program into memory and run it. The result would ordinarily be to print something on the spectacularly loud printer. - -I was puzzled by the 1401. I couldn't figure out what to do with it. And in retrospect there's not much I could have done with it. The only form of input to programs was data stored on punched cards, and I didn't have any data stored on punched cards. The only other option was to do things that didn't rely on any input, like calculate approximations of pi, but I didn't know enough math to do anything interesting of that type. So I'm not surprised I can't remember any programs I wrote, because they can't have done much. My clearest memory is of the moment I learned it was possible for programs not to terminate, when one of mine didn't. On a machine without time-sharing, this was a social as well as a technical error, as the data center manager's expression made clear. - -With microcomputers, everything changed. Now you could have a computer sitting right in front of you, on a desk, that could respond to your keystrokes as it was running instead of just churning through a stack of punch cards and then stopping. [1] - -The first of my friends to get a microcomputer built it himself. It was sold as a kit by Heathkit. I remember vividly how impressed and envious I felt watching him sitting in front of it, typing programs right into the computer. - -Computers were expensive in those days and it took me years of nagging before I convinced my father to buy one, a TRS-80, in about 1980. The gold standard then was the Apple II, but a TRS-80 was good enough. This was when I really started programming. I wrote simple games, a program to predict how high my model rockets would fly, and a word processor that my father used to write at least one book. There was only room in memory for about 2 pages of text, so he'd write 2 pages at a time and then print them out, but it was a lot better than a typewriter. - -Though I liked programming, I didn't plan to study it in college. In college I was going to study philosophy, which sounded much more powerful. It seemed, to my naive high school self, to be the study of the ultimate truths, compared to which the things studied in other fields would be mere domain knowledge. What I discovered when I got to college was that the other fields took up so much of the space of ideas that there wasn't much left for these supposed ultimate truths. All that seemed left for philosophy were edge cases that people in other fields felt could safely be ignored. - -I couldn't have put this into words when I was 18. All I knew at the time was that I kept taking philosophy courses and they kept being boring. So I decided to switch to AI. - -AI was in the air in the mid 1980s, but there were two things especially that made me want to work on it: a novel by Heinlein called The Moon is a Harsh Mistress, which featured an intelligent computer called Mike, and a PBS documentary that showed Terry Winograd using SHRDLU. I haven't tried rereading The Moon is a Harsh Mistress, so I don't know how well it has aged, but when I read it I was drawn entirely into its world. It seemed only a matter of time before we'd have Mike, and when I saw Winograd using SHRDLU, it seemed like that time would be a few years at most. All you had to do was teach SHRDLU more words. - -There weren't any classes in AI at Cornell then, not even graduate classes, so I started trying to teach myself. Which meant learning Lisp, since in those days Lisp was regarded as the language of AI. The commonly used programming languages then were pretty primitive, and programmers' ideas correspondingly so. The default language at Cornell was a Pascal-like language called PL/I, and the situation was similar elsewhere. Learning Lisp expanded my concept of a program so fast that it was years before I started to have a sense of where the new limits were. This was more like it; this was what I had expected college to do. It wasn't happening in a class, like it was supposed to, but that was ok. For the next couple years I was on a roll. I knew what I was going to do. - -For my undergraduate thesis, I reverse-engineered SHRDLU. My God did I love working on that program. It was a pleasing bit of code, but what made it even more exciting was my belief — hard to imagine now, but not unique in 1985 — that it was already climbing the lower slopes of intelligence. - -I had gotten into a program at Cornell that didn't make you choose a major. You could take whatever classes you liked, and choose whatever you liked to put on your degree. I of course chose "Artificial Intelligence." When I got the actual physical diploma, I was dismayed to find that the quotes had been included, which made them read as scare-quotes. At the time this bothered me, but now it seems amusingly accurate, for reasons I was about to discover. - -I applied to 3 grad schools: MIT and Yale, which were renowned for AI at the time, and Harvard, which I'd visited because Rich Draves went there, and was also home to Bill Woods, who'd invented the type of parser I used in my SHRDLU clone. Only Harvard accepted me, so that was where I went. - -I don't remember the moment it happened, or if there even was a specific moment, but during the first year of grad school I realized that AI, as practiced at the time, was a hoax. By which I mean the sort of AI in which a program that's told "the dog is sitting on the chair" translates this into some formal representation and adds it to the list of things it knows. - -What these programs really showed was that there's a subset of natural language that's a formal language. But a very proper subset. It was clear that there was an unbridgeable gap between what they could do and actually understanding natural language. It was not, in fact, simply a matter of teaching SHRDLU more words. That whole way of doing AI, with explicit data structures representing concepts, was not going to work. Its brokenness did, as so often happens, generate a lot of opportunities to write papers about various band-aids that could be applied to it, but it was never going to get us Mike. - -So I looked around to see what I could salvage from the wreckage of my plans, and there was Lisp. I knew from experience that Lisp was interesting for its own sake and not just for its association with AI, even though that was the main reason people cared about it at the time. So I decided to focus on Lisp. In fact, I decided to write a book about Lisp hacking. It's scary to think how little I knew about Lisp hacking when I started writing that book. But there's nothing like writing a book about something to help you learn it. The book, On Lisp, wasn't published till 1993, but I wrote much of it in grad school. - -Computer Science is an uneasy alliance between two halves, theory and systems. The theory people prove things, and the systems people build things. I wanted to build things. I had plenty of respect for theory — indeed, a sneaking suspicion that it was the more admirable of the two halves — but building things seemed so much more exciting. - -The problem with systems work, though, was that it didn't last. Any program you wrote today, no matter how good, would be obsolete in a couple decades at best. People might mention your software in footnotes, but no one would actually use it. And indeed, it would seem very feeble work. Only people with a sense of the history of the field would even realize that, in its time, it had been good. - -There were some surplus Xerox Dandelions floating around the computer lab at one point. Anyone who wanted one to play around with could have one. I was briefly tempted, but they were so slow by present standards; what was the point? No one else wanted one either, so off they went. That was what happened to systems work. - -I wanted not just to build things, but to build things that would last. - -In this dissatisfied state I went in 1988 to visit Rich Draves at CMU, where he was in grad school. One day I went to visit the Carnegie Institute, where I'd spent a lot of time as a kid. While looking at a painting there I realized something that might seem obvious, but was a big surprise to me. There, right on the wall, was something you could make that would last. Paintings didn't become obsolete. Some of the best ones were hundreds of years old. - -And moreover this was something you could make a living doing. Not as easily as you could by writing software, of course, but I thought if you were really industrious and lived really cheaply, it had to be possible to make enough to survive. And as an artist you could be truly independent. You wouldn't have a boss, or even need to get research funding. - -I had always liked looking at paintings. Could I make them? I had no idea. I'd never imagined it was even possible. I knew intellectually that people made art — that it didn't just appear spontaneously — but it was as if the people who made it were a different species. They either lived long ago or were mysterious geniuses doing strange things in profiles in Life magazine. The idea of actually being able to make art, to put that verb before that noun, seemed almost miraculous. - -That fall I started taking art classes at Harvard. Grad students could take classes in any department, and my advisor, Tom Cheatham, was very easy going. If he even knew about the strange classes I was taking, he never said anything. - -So now I was in a PhD program in computer science, yet planning to be an artist, yet also genuinely in love with Lisp hacking and working away at On Lisp. In other words, like many a grad student, I was working energetically on multiple projects that were not my thesis. - -I didn't see a way out of this situation. I didn't want to drop out of grad school, but how else was I going to get out? I remember when my friend Robert Morris got kicked out of Cornell for writing the internet worm of 1988, I was envious that he'd found such a spectacular way to get out of grad school. - -Then one day in April 1990 a crack appeared in the wall. I ran into professor Cheatham and he asked if I was far enough along to graduate that June. I didn't have a word of my dissertation written, but in what must have been the quickest bit of thinking in my life, I decided to take a shot at writing one in the 5 weeks or so that remained before the deadline, reusing parts of On Lisp where I could, and I was able to respond, with no perceptible delay "Yes, I think so. I'll give you something to read in a few days." - -I picked applications of continuations as the topic. In retrospect I should have written about macros and embedded languages. There's a whole world there that's barely been explored. But all I wanted was to get out of grad school, and my rapidly written dissertation sufficed, just barely. - -Meanwhile I was applying to art schools. I applied to two: RISD in the US, and the Accademia di Belli Arti in Florence, which, because it was the oldest art school, I imagined would be good. RISD accepted me, and I never heard back from the Accademia, so off to Providence I went. - -I'd applied for the BFA program at RISD, which meant in effect that I had to go to college again. This was not as strange as it sounds, because I was only 25, and art schools are full of people of different ages. RISD counted me as a transfer sophomore and said I had to do the foundation that summer. The foundation means the classes that everyone has to take in fundamental subjects like drawing, color, and design. - -Toward the end of the summer I got a big surprise: a letter from the Accademia, which had been delayed because they'd sent it to Cambridge England instead of Cambridge Massachusetts, inviting me to take the entrance exam in Florence that fall. This was now only weeks away. My nice landlady let me leave my stuff in her attic. I had some money saved from consulting work I'd done in grad school; there was probably enough to last a year if I lived cheaply. Now all I had to do was learn Italian. - -Only stranieri (foreigners) had to take this entrance exam. In retrospect it may well have been a way of excluding them, because there were so many stranieri attracted by the idea of studying art in Florence that the Italian students would otherwise have been outnumbered. I was in decent shape at painting and drawing from the RISD foundation that summer, but I still don't know how I managed to pass the written exam. I remember that I answered the essay question by writing about Cezanne, and that I cranked up the intellectual level as high as I could to make the most of my limited vocabulary. [2] - -I'm only up to age 25 and already there are such conspicuous patterns. Here I was, yet again about to attend some august institution in the hopes of learning about some prestigious subject, and yet again about to be disappointed. The students and faculty in the painting department at the Accademia were the nicest people you could imagine, but they had long since arrived at an arrangement whereby the students wouldn't require the faculty to teach anything, and in return the faculty wouldn't require the students to learn anything. And at the same time all involved would adhere outwardly to the conventions of a 19th century atelier. We actually had one of those little stoves, fed with kindling, that you see in 19th century studio paintings, and a nude model sitting as close to it as possible without getting burned. Except hardly anyone else painted her besides me. The rest of the students spent their time chatting or occasionally trying to imitate things they'd seen in American art magazines. - -Our model turned out to live just down the street from me. She made a living from a combination of modelling and making fakes for a local antique dealer. She'd copy an obscure old painting out of a book, and then he'd take the copy and maltreat it to make it look old. [3] - -While I was a student at the Accademia I started painting still lives in my bedroom at night. These paintings were tiny, because the room was, and because I painted them on leftover scraps of canvas, which was all I could afford at the time. Painting still lives is different from painting people, because the subject, as its name suggests, can't move. People can't sit for more than about 15 minutes at a time, and when they do they don't sit very still. So the traditional m.o. for painting people is to know how to paint a generic person, which you then modify to match the specific person you're painting. Whereas a still life you can, if you want, copy pixel by pixel from what you're seeing. You don't want to stop there, of course, or you get merely photographic accuracy, and what makes a still life interesting is that it's been through a head. You want to emphasize the visual cues that tell you, for example, that the reason the color changes suddenly at a certain point is that it's the edge of an object. By subtly emphasizing such things you can make paintings that are more realistic than photographs not just in some metaphorical sense, but in the strict information-theoretic sense. [4] - -I liked painting still lives because I was curious about what I was seeing. In everyday life, we aren't consciously aware of much we're seeing. Most visual perception is handled by low-level processes that merely tell your brain "that's a water droplet" without telling you details like where the lightest and darkest points are, or "that's a bush" without telling you the shape and position of every leaf. This is a feature of brains, not a bug. In everyday life it would be distracting to notice every leaf on every bush. But when you have to paint something, you have to look more closely, and when you do there's a lot to see. You can still be noticing new things after days of trying to paint something people usually take for granted, just as you can after days of trying to write an essay about something people usually take for granted. - -This is not the only way to paint. I'm not 100% sure it's even a good way to paint. But it seemed a good enough bet to be worth trying. - -Our teacher, professor Ulivi, was a nice guy. He could see I worked hard, and gave me a good grade, which he wrote down in a sort of passport each student had. But the Accademia wasn't teaching me anything except Italian, and my money was running out, so at the end of the first year I went back to the US. - -I wanted to go back to RISD, but I was now broke and RISD was very expensive, so I decided to get a job for a year and then return to RISD the next fall. I got one at a company called Interleaf, which made software for creating documents. You mean like Microsoft Word? Exactly. That was how I learned that low end software tends to eat high end software. But Interleaf still had a few years to live yet. [5] - -Interleaf had done something pretty bold. Inspired by Emacs, they'd added a scripting language, and even made the scripting language a dialect of Lisp. Now they wanted a Lisp hacker to write things in it. This was the closest thing I've had to a normal job, and I hereby apologize to my boss and coworkers, because I was a bad employee. Their Lisp was the thinnest icing on a giant C cake, and since I didn't know C and didn't want to learn it, I never understood most of the software. Plus I was terribly irresponsible. This was back when a programming job meant showing up every day during certain working hours. That seemed unnatural to me, and on this point the rest of the world is coming around to my way of thinking, but at the time it caused a lot of friction. Toward the end of the year I spent much of my time surreptitiously working on On Lisp, which I had by this time gotten a contract to publish. - -The good part was that I got paid huge amounts of money, especially by art student standards. In Florence, after paying my part of the rent, my budget for everything else had been $7 a day. Now I was getting paid more than 4 times that every hour, even when I was just sitting in a meeting. By living cheaply I not only managed to save enough to go back to RISD, but also paid off my college loans. - -I learned some useful things at Interleaf, though they were mostly about what not to do. I learned that it's better for technology companies to be run by product people than sales people (though sales is a real skill and people who are good at it are really good at it), that it leads to bugs when code is edited by too many people, that cheap office space is no bargain if it's depressing, that planned meetings are inferior to corridor conversations, that big, bureaucratic customers are a dangerous source of money, and that there's not much overlap between conventional office hours and the optimal time for hacking, or conventional offices and the optimal place for it. - -But the most important thing I learned, and which I used in both Viaweb and Y Combinator, is that the low end eats the high end: that it's good to be the "entry level" option, even though that will be less prestigious, because if you're not, someone else will be, and will squash you against the ceiling. Which in turn means that prestige is a danger sign. - -When I left to go back to RISD the next fall, I arranged to do freelance work for the group that did projects for customers, and this was how I survived for the next several years. When I came back to visit for a project later on, someone told me about a new thing called HTML, which was, as he described it, a derivative of SGML. Markup language enthusiasts were an occupational hazard at Interleaf and I ignored him, but this HTML thing later became a big part of my life. - -In the fall of 1992 I moved back to Providence to continue at RISD. The foundation had merely been intro stuff, and the Accademia had been a (very civilized) joke. Now I was going to see what real art school was like. But alas it was more like the Accademia than not. Better organized, certainly, and a lot more expensive, but it was now becoming clear that art school did not bear the same relationship to art that medical school bore to medicine. At least not the painting department. The textile department, which my next door neighbor belonged to, seemed to be pretty rigorous. No doubt illustration and architecture were too. But painting was post-rigorous. Painting students were supposed to express themselves, which to the more worldly ones meant to try to cook up some sort of distinctive signature style. - -A signature style is the visual equivalent of what in show business is known as a "schtick": something that immediately identifies the work as yours and no one else's. For example, when you see a painting that looks like a certain kind of cartoon, you know it's by Roy Lichtenstein. So if you see a big painting of this type hanging in the apartment of a hedge fund manager, you know he paid millions of dollars for it. That's not always why artists have a signature style, but it's usually why buyers pay a lot for such work. [6] - -There were plenty of earnest students too: kids who "could draw" in high school, and now had come to what was supposed to be the best art school in the country, to learn to draw even better. They tended to be confused and demoralized by what they found at RISD, but they kept going, because painting was what they did. I was not one of the kids who could draw in high school, but at RISD I was definitely closer to their tribe than the tribe of signature style seekers. - -I learned a lot in the color class I took at RISD, but otherwise I was basically teaching myself to paint, and I could do that for free. So in 1993 I dropped out. I hung around Providence for a bit, and then my college friend Nancy Parmet did me a big favor. A rent-controlled apartment in a building her mother owned in New York was becoming vacant. Did I want it? It wasn't much more than my current place, and New York was supposed to be where the artists were. So yes, I wanted it! [7] - -Asterix comics begin by zooming in on a tiny corner of Roman Gaul that turns out not to be controlled by the Romans. You can do something similar on a map of New York City: if you zoom in on the Upper East Side, there's a tiny corner that's not rich, or at least wasn't in 1993. It's called Yorkville, and that was my new home. Now I was a New York artist — in the strictly technical sense of making paintings and living in New York. - -I was nervous about money, because I could sense that Interleaf was on the way down. Freelance Lisp hacking work was very rare, and I didn't want to have to program in another language, which in those days would have meant C++ if I was lucky. So with my unerring nose for financial opportunity, I decided to write another book on Lisp. This would be a popular book, the sort of book that could be used as a textbook. I imagined myself living frugally off the royalties and spending all my time painting. (The painting on the cover of this book, ANSI Common Lisp, is one that I painted around this time.) - -The best thing about New York for me was the presence of Idelle and Julian Weber. Idelle Weber was a painter, one of the early photorealists, and I'd taken her painting class at Harvard. I've never known a teacher more beloved by her students. Large numbers of former students kept in touch with her, including me. After I moved to New York I became her de facto studio assistant. - -She liked to paint on big, square canvases, 4 to 5 feet on a side. One day in late 1994 as I was stretching one of these monsters there was something on the radio about a famous fund manager. He wasn't that much older than me, and was super rich. The thought suddenly occurred to me: why don't I become rich? Then I'll be able to work on whatever I want. - -Meanwhile I'd been hearing more and more about this new thing called the World Wide Web. Robert Morris showed it to me when I visited him in Cambridge, where he was now in grad school at Harvard. It seemed to me that the web would be a big deal. I'd seen what graphical user interfaces had done for the popularity of microcomputers. It seemed like the web would do the same for the internet. - -If I wanted to get rich, here was the next train leaving the station. I was right about that part. What I got wrong was the idea. I decided we should start a company to put art galleries online. I can't honestly say, after reading so many Y Combinator applications, that this was the worst startup idea ever, but it was up there. Art galleries didn't want to be online, and still don't, not the fancy ones. That's not how they sell. I wrote some software to generate web sites for galleries, and Robert wrote some to resize images and set up an http server to serve the pages. Then we tried to sign up galleries. To call this a difficult sale would be an understatement. It was difficult to give away. A few galleries let us make sites for them for free, but none paid us. - -Then some online stores started to appear, and I realized that except for the order buttons they were identical to the sites we'd been generating for galleries. This impressive-sounding thing called an "internet storefront" was something we already knew how to build. - -So in the summer of 1995, after I submitted the camera-ready copy of ANSI Common Lisp to the publishers, we started trying to write software to build online stores. At first this was going to be normal desktop software, which in those days meant Windows software. That was an alarming prospect, because neither of us knew how to write Windows software or wanted to learn. We lived in the Unix world. But we decided we'd at least try writing a prototype store builder on Unix. Robert wrote a shopping cart, and I wrote a new site generator for stores — in Lisp, of course. - -We were working out of Robert's apartment in Cambridge. His roommate was away for big chunks of time, during which I got to sleep in his room. For some reason there was no bed frame or sheets, just a mattress on the floor. One morning as I was lying on this mattress I had an idea that made me sit up like a capital L. What if we ran the software on the server, and let users control it by clicking on links? Then we'd never have to write anything to run on users' computers. We could generate the sites on the same server we'd serve them from. Users wouldn't need anything more than a browser. - -This kind of software, known as a web app, is common now, but at the time it wasn't clear that it was even possible. To find out, we decided to try making a version of our store builder that you could control through the browser. A couple days later, on August 12, we had one that worked. The UI was horrible, but it proved you could build a whole store through the browser, without any client software or typing anything into the command line on the server. - -Now we felt like we were really onto something. I had visions of a whole new generation of software working this way. You wouldn't need versions, or ports, or any of that crap. At Interleaf there had been a whole group called Release Engineering that seemed to be at least as big as the group that actually wrote the software. Now you could just update the software right on the server. - -We started a new company we called Viaweb, after the fact that our software worked via the web, and we got $10,000 in seed funding from Idelle's husband Julian. In return for that and doing the initial legal work and giving us business advice, we gave him 10% of the company. Ten years later this deal became the model for Y Combinator's. We knew founders needed something like this, because we'd needed it ourselves. - -At this stage I had a negative net worth, because the thousand dollars or so I had in the bank was more than counterbalanced by what I owed the government in taxes. (Had I diligently set aside the proper proportion of the money I'd made consulting for Interleaf? No, I had not.) So although Robert had his graduate student stipend, I needed that seed funding to live on. - -We originally hoped to launch in September, but we got more ambitious about the software as we worked on it. Eventually we managed to build a WYSIWYG site builder, in the sense that as you were creating pages, they looked exactly like the static ones that would be generated later, except that instead of leading to static pages, the links all referred to closures stored in a hash table on the server. - -It helped to have studied art, because the main goal of an online store builder is to make users look legit, and the key to looking legit is high production values. If you get page layouts and fonts and colors right, you can make a guy running a store out of his bedroom look more legit than a big company. - -(If you're curious why my site looks so old-fashioned, it's because it's still made with this software. It may look clunky today, but in 1996 it was the last word in slick.) - -In September, Robert rebelled. "We've been working on this for a month," he said, "and it's still not done." This is funny in retrospect, because he would still be working on it almost 3 years later. But I decided it might be prudent to recruit more programmers, and I asked Robert who else in grad school with him was really good. He recommended Trevor Blackwell, which surprised me at first, because at that point I knew Trevor mainly for his plan to reduce everything in his life to a stack of notecards, which he carried around with him. But Rtm was right, as usual. Trevor turned out to be a frighteningly effective hacker. - -It was a lot of fun working with Robert and Trevor. They're the two most independent-minded people I know, and in completely different ways. If you could see inside Rtm's brain it would look like a colonial New England church, and if you could see inside Trevor's it would look like the worst excesses of Austrian Rococo. - -We opened for business, with 6 stores, in January 1996. It was just as well we waited a few months, because although we worried we were late, we were actually almost fatally early. There was a lot of talk in the press then about ecommerce, but not many people actually wanted online stores. [8] - -There were three main parts to the software: the editor, which people used to build sites and which I wrote, the shopping cart, which Robert wrote, and the manager, which kept track of orders and statistics, and which Trevor wrote. In its time, the editor was one of the best general-purpose site builders. I kept the code tight and didn't have to integrate with any other software except Robert's and Trevor's, so it was quite fun to work on. If all I'd had to do was work on this software, the next 3 years would have been the easiest of my life. Unfortunately I had to do a lot more, all of it stuff I was worse at than programming, and the next 3 years were instead the most stressful. - -There were a lot of startups making ecommerce software in the second half of the 90s. We were determined to be the Microsoft Word, not the Interleaf. Which meant being easy to use and inexpensive. It was lucky for us that we were poor, because that caused us to make Viaweb even more inexpensive than we realized. We charged $100 a month for a small store and $300 a month for a big one. This low price was a big attraction, and a constant thorn in the sides of competitors, but it wasn't because of some clever insight that we set the price low. We had no idea what businesses paid for things. $300 a month seemed like a lot of money to us. - -We did a lot of things right by accident like that. For example, we did what's now called "doing things that don't scale," although at the time we would have described it as "being so lame that we're driven to the most desperate measures to get users." The most common of which was building stores for them. This seemed particularly humiliating, since the whole reason d'etre of our software was that people could use it to make their own stores. But anything to get users. - -We learned a lot more about retail than we wanted to know. For example, that if you could only have a small image of a man's shirt (and all images were small then by present standards), it was better to have a closeup of the collar than a picture of the whole shirt. The reason I remember learning this was that it meant I had to rescan about 30 images of men's shirts. My first set of scans were so beautiful too. - -Though this felt wrong, it was exactly the right thing to be doing. Building stores for users taught us about retail, and about how it felt to use our software. I was initially both mystified and repelled by "business" and thought we needed a "business person" to be in charge of it, but once we started to get users, I was converted, in much the same way I was converted to fatherhood once I had kids. Whatever users wanted, I was all theirs. Maybe one day we'd have so many users that I couldn't scan their images for them, but in the meantime there was nothing more important to do. - -Another thing I didn't get at the time is that growth rate is the ultimate test of a startup. Our growth rate was fine. We had about 70 stores at the end of 1996 and about 500 at the end of 1997. I mistakenly thought the thing that mattered was the absolute number of users. And that is the thing that matters in the sense that that's how much money you're making, and if you're not making enough, you might go out of business. But in the long term the growth rate takes care of the absolute number. If we'd been a startup I was advising at Y Combinator, I would have said: Stop being so stressed out, because you're doing fine. You're growing 7x a year. Just don't hire too many more people and you'll soon be profitable, and then you'll control your own destiny. - -Alas I hired lots more people, partly because our investors wanted me to, and partly because that's what startups did during the Internet Bubble. A company with just a handful of employees would have seemed amateurish. So we didn't reach breakeven until about when Yahoo bought us in the summer of 1998. Which in turn meant we were at the mercy of investors for the entire life of the company. And since both we and our investors were noobs at startups, the result was a mess even by startup standards. - -It was a huge relief when Yahoo bought us. In principle our Viaweb stock was valuable. It was a share in a business that was profitable and growing rapidly. But it didn't feel very valuable to me; I had no idea how to value a business, but I was all too keenly aware of the near-death experiences we seemed to have every few months. Nor had I changed my grad student lifestyle significantly since we started. So when Yahoo bought us it felt like going from rags to riches. Since we were going to California, I bought a car, a yellow 1998 VW GTI. I remember thinking that its leather seats alone were by far the most luxurious thing I owned. - -The next year, from the summer of 1998 to the summer of 1999, must have been the least productive of my life. I didn't realize it at the time, but I was worn out from the effort and stress of running Viaweb. For a while after I got to California I tried to continue my usual m.o. of programming till 3 in the morning, but fatigue combined with Yahoo's prematurely aged culture and grim cube farm in Santa Clara gradually dragged me down. After a few months it felt disconcertingly like working at Interleaf. - -Yahoo had given us a lot of options when they bought us. At the time I thought Yahoo was so overvalued that they'd never be worth anything, but to my astonishment the stock went up 5x in the next year. I hung on till the first chunk of options vested, then in the summer of 1999 I left. It had been so long since I'd painted anything that I'd half forgotten why I was doing this. My brain had been entirely full of software and men's shirts for 4 years. But I had done this to get rich so I could paint, I reminded myself, and now I was rich, so I should go paint. - -When I said I was leaving, my boss at Yahoo had a long conversation with me about my plans. I told him all about the kinds of pictures I wanted to paint. At the time I was touched that he took such an interest in me. Now I realize it was because he thought I was lying. My options at that point were worth about $2 million a month. If I was leaving that kind of money on the table, it could only be to go and start some new startup, and if I did, I might take people with me. This was the height of the Internet Bubble, and Yahoo was ground zero of it. My boss was at that moment a billionaire. Leaving then to start a new startup must have seemed to him an insanely, and yet also plausibly, ambitious plan. - -But I really was quitting to paint, and I started immediately. There was no time to lose. I'd already burned 4 years getting rich. Now when I talk to founders who are leaving after selling their companies, my advice is always the same: take a vacation. That's what I should have done, just gone off somewhere and done nothing for a month or two, but the idea never occurred to me. - -So I tried to paint, but I just didn't seem to have any energy or ambition. Part of the problem was that I didn't know many people in California. I'd compounded this problem by buying a house up in the Santa Cruz Mountains, with a beautiful view but miles from anywhere. I stuck it out for a few more months, then in desperation I went back to New York, where unless you understand about rent control you'll be surprised to hear I still had my apartment, sealed up like a tomb of my old life. Idelle was in New York at least, and there were other people trying to paint there, even though I didn't know any of them. - -When I got back to New York I resumed my old life, except now I was rich. It was as weird as it sounds. I resumed all my old patterns, except now there were doors where there hadn't been. Now when I was tired of walking, all I had to do was raise my hand, and (unless it was raining) a taxi would stop to pick me up. Now when I walked past charming little restaurants I could go in and order lunch. It was exciting for a while. Painting started to go better. I experimented with a new kind of still life where I'd paint one painting in the old way, then photograph it and print it, blown up, on canvas, and then use that as the underpainting for a second still life, painted from the same objects (which hopefully hadn't rotted yet). - -Meanwhile I looked for an apartment to buy. Now I could actually choose what neighborhood to live in. Where, I asked myself and various real estate agents, is the Cambridge of New York? Aided by occasional visits to actual Cambridge, I gradually realized there wasn't one. Huh. - -Around this time, in the spring of 2000, I had an idea. It was clear from our experience with Viaweb that web apps were the future. Why not build a web app for making web apps? Why not let people edit code on our server through the browser, and then host the resulting applications for them? [9] You could run all sorts of services on the servers that these applications could use just by making an API call: making and receiving phone calls, manipulating images, taking credit card payments, etc. - -I got so excited about this idea that I couldn't think about anything else. It seemed obvious that this was the future. I didn't particularly want to start another company, but it was clear that this idea would have to be embodied as one, so I decided to move to Cambridge and start it. I hoped to lure Robert into working on it with me, but there I ran into a hitch. Robert was now a postdoc at MIT, and though he'd made a lot of money the last time I'd lured him into working on one of my schemes, it had also been a huge time sink. So while he agreed that it sounded like a plausible idea, he firmly refused to work on it. - -Hmph. Well, I'd do it myself then. I recruited Dan Giffin, who had worked for Viaweb, and two undergrads who wanted summer jobs, and we got to work trying to build what it's now clear is about twenty companies and several open-source projects worth of software. The language for defining applications would of course be a dialect of Lisp. But I wasn't so naive as to assume I could spring an overt Lisp on a general audience; we'd hide the parentheses, like Dylan did. - -By then there was a name for the kind of company Viaweb was, an "application service provider," or ASP. This name didn't last long before it was replaced by "software as a service," but it was current for long enough that I named this new company after it: it was going to be called Aspra. - -I started working on the application builder, Dan worked on network infrastructure, and the two undergrads worked on the first two services (images and phone calls). But about halfway through the summer I realized I really didn't want to run a company — especially not a big one, which it was looking like this would have to be. I'd only started Viaweb because I needed the money. Now that I didn't need money anymore, why was I doing this? If this vision had to be realized as a company, then screw the vision. I'd build a subset that could be done as an open-source project. - -Much to my surprise, the time I spent working on this stuff was not wasted after all. After we started Y Combinator, I would often encounter startups working on parts of this new architecture, and it was very useful to have spent so much time thinking about it and even trying to write some of it. - -The subset I would build as an open-source project was the new Lisp, whose parentheses I now wouldn't even have to hide. A lot of Lisp hackers dream of building a new Lisp, partly because one of the distinctive features of the language is that it has dialects, and partly, I think, because we have in our minds a Platonic form of Lisp that all existing dialects fall short of. I certainly did. So at the end of the summer Dan and I switched to working on this new dialect of Lisp, which I called Arc, in a house I bought in Cambridge. - -The following spring, lightning struck. I was invited to give a talk at a Lisp conference, so I gave one about how we'd used Lisp at Viaweb. Afterward I put a postscript file of this talk online, on paulgraham.com, which I'd created years before using Viaweb but had never used for anything. In one day it got 30,000 page views. What on earth had happened? The referring urls showed that someone had posted it on Slashdot. [10] - -Wow, I thought, there's an audience. If I write something and put it on the web, anyone can read it. That may seem obvious now, but it was surprising then. In the print era there was a narrow channel to readers, guarded by fierce monsters known as editors. The only way to get an audience for anything you wrote was to get it published as a book, or in a newspaper or magazine. Now anyone could publish anything. - -This had been possible in principle since 1993, but not many people had realized it yet. I had been intimately involved with building the infrastructure of the web for most of that time, and a writer as well, and it had taken me 8 years to realize it. Even then it took me several years to understand the implications. It meant there would be a whole new generation of essays. [11] - -In the print era, the channel for publishing essays had been vanishingly small. Except for a few officially anointed thinkers who went to the right parties in New York, the only people allowed to publish essays were specialists writing about their specialties. There were so many essays that had never been written, because there had been no way to publish them. Now they could be, and I was going to write them. [12] - -I've worked on several different things, but to the extent there was a turning point where I figured out what to work on, it was when I started publishing essays online. From then on I knew that whatever else I did, I'd always write essays too. - -I knew that online essays would be a marginal medium at first. Socially they'd seem more like rants posted by nutjobs on their GeoCities sites than the genteel and beautifully typeset compositions published in The New Yorker. But by this point I knew enough to find that encouraging instead of discouraging. - -One of the most conspicuous patterns I've noticed in my life is how well it has worked, for me at least, to work on things that weren't prestigious. Still life has always been the least prestigious form of painting. Viaweb and Y Combinator both seemed lame when we started them. I still get the glassy eye from strangers when they ask what I'm writing, and I explain that it's an essay I'm going to publish on my web site. Even Lisp, though prestigious intellectually in something like the way Latin is, also seems about as hip. - -It's not that unprestigious types of work are good per se. But when you find yourself drawn to some kind of work despite its current lack of prestige, it's a sign both that there's something real to be discovered there, and that you have the right kind of motives. Impure motives are a big danger for the ambitious. If anything is going to lead you astray, it will be the desire to impress people. So while working on things that aren't prestigious doesn't guarantee you're on the right track, it at least guarantees you're not on the most common type of wrong one. - -Over the next several years I wrote lots of essays about all kinds of different topics. O'Reilly reprinted a collection of them as a book, called Hackers & Painters after one of the essays in it. I also worked on spam filters, and did some more painting. I used to have dinners for a group of friends every thursday night, which taught me how to cook for groups. And I bought another building in Cambridge, a former candy factory (and later, twas said, porn studio), to use as an office. - -One night in October 2003 there was a big party at my house. It was a clever idea of my friend Maria Daniels, who was one of the thursday diners. Three separate hosts would all invite their friends to one party. So for every guest, two thirds of the other guests would be people they didn't know but would probably like. One of the guests was someone I didn't know but would turn out to like a lot: a woman called Jessica Livingston. A couple days later I asked her out. - -Jessica was in charge of marketing at a Boston investment bank. This bank thought it understood startups, but over the next year, as she met friends of mine from the startup world, she was surprised how different reality was. And how colorful their stories were. So she decided to compile a book of interviews with startup founders. - -When the bank had financial problems and she had to fire half her staff, she started looking for a new job. In early 2005 she interviewed for a marketing job at a Boston VC firm. It took them weeks to make up their minds, and during this time I started telling her about all the things that needed to be fixed about venture capital. They should make a larger number of smaller investments instead of a handful of giant ones, they should be funding younger, more technical founders instead of MBAs, they should let the founders remain as CEO, and so on. - -One of my tricks for writing essays had always been to give talks. The prospect of having to stand up in front of a group of people and tell them something that won't waste their time is a great spur to the imagination. When the Harvard Computer Society, the undergrad computer club, asked me to give a talk, I decided I would tell them how to start a startup. Maybe they'd be able to avoid the worst of the mistakes we'd made. - -So I gave this talk, in the course of which I told them that the best sources of seed funding were successful startup founders, because then they'd be sources of advice too. Whereupon it seemed they were all looking expectantly at me. Horrified at the prospect of having my inbox flooded by business plans (if I'd only known), I blurted out "But not me!" and went on with the talk. But afterward it occurred to me that I should really stop procrastinating about angel investing. I'd been meaning to since Yahoo bought us, and now it was 7 years later and I still hadn't done one angel investment. - -Meanwhile I had been scheming with Robert and Trevor about projects we could work on together. I missed working with them, and it seemed like there had to be something we could collaborate on. - -As Jessica and I were walking home from dinner on March 11, at the corner of Garden and Walker streets, these three threads converged. Screw the VCs who were taking so long to make up their minds. We'd start our own investment firm and actually implement the ideas we'd been talking about. I'd fund it, and Jessica could quit her job and work for it, and we'd get Robert and Trevor as partners too. [13] - -Once again, ignorance worked in our favor. We had no idea how to be angel investors, and in Boston in 2005 there were no Ron Conways to learn from. So we just made what seemed like the obvious choices, and some of the things we did turned out to be novel. - -There are multiple components to Y Combinator, and we didn't figure them all out at once. The part we got first was to be an angel firm. In those days, those two words didn't go together. There were VC firms, which were organized companies with people whose job it was to make investments, but they only did big, million dollar investments. And there were angels, who did smaller investments, but these were individuals who were usually focused on other things and made investments on the side. And neither of them helped founders enough in the beginning. We knew how helpless founders were in some respects, because we remembered how helpless we'd been. For example, one thing Julian had done for us that seemed to us like magic was to get us set up as a company. We were fine writing fairly difficult software, but actually getting incorporated, with bylaws and stock and all that stuff, how on earth did you do that? Our plan was not only to make seed investments, but to do for startups everything Julian had done for us. - -YC was not organized as a fund. It was cheap enough to run that we funded it with our own money. That went right by 99% of readers, but professional investors are thinking "Wow, that means they got all the returns." But once again, this was not due to any particular insight on our part. We didn't know how VC firms were organized. It never occurred to us to try to raise a fund, and if it had, we wouldn't have known where to start. [14] - -The most distinctive thing about YC is the batch model: to fund a bunch of startups all at once, twice a year, and then to spend three months focusing intensively on trying to help them. That part we discovered by accident, not merely implicitly but explicitly due to our ignorance about investing. We needed to get experience as investors. What better way, we thought, than to fund a whole bunch of startups at once? We knew undergrads got temporary jobs at tech companies during the summer. Why not organize a summer program where they'd start startups instead? We wouldn't feel guilty for being in a sense fake investors, because they would in a similar sense be fake founders. So while we probably wouldn't make much money out of it, we'd at least get to practice being investors on them, and they for their part would probably have a more interesting summer than they would working at Microsoft. - -We'd use the building I owned in Cambridge as our headquarters. We'd all have dinner there once a week — on tuesdays, since I was already cooking for the thursday diners on thursdays — and after dinner we'd bring in experts on startups to give talks. - -We knew undergrads were deciding then about summer jobs, so in a matter of days we cooked up something we called the Summer Founders Program, and I posted an announcement on my site, inviting undergrads to apply. I had never imagined that writing essays would be a way to get "deal flow," as investors call it, but it turned out to be the perfect source. [15] We got 225 applications for the Summer Founders Program, and we were surprised to find that a lot of them were from people who'd already graduated, or were about to that spring. Already this SFP thing was starting to feel more serious than we'd intended. - -We invited about 20 of the 225 groups to interview in person, and from those we picked 8 to fund. They were an impressive group. That first batch included reddit, Justin Kan and Emmett Shear, who went on to found Twitch, Aaron Swartz, who had already helped write the RSS spec and would a few years later become a martyr for open access, and Sam Altman, who would later become the second president of YC. I don't think it was entirely luck that the first batch was so good. You had to be pretty bold to sign up for a weird thing like the Summer Founders Program instead of a summer job at a legit place like Microsoft or Goldman Sachs. - -The deal for startups was based on a combination of the deal we did with Julian ($10k for 10%) and what Robert said MIT grad students got for the summer ($6k). We invested $6k per founder, which in the typical two-founder case was $12k, in return for 6%. That had to be fair, because it was twice as good as the deal we ourselves had taken. Plus that first summer, which was really hot, Jessica brought the founders free air conditioners. [16] - -Fairly quickly I realized that we had stumbled upon the way to scale startup funding. Funding startups in batches was more convenient for us, because it meant we could do things for a lot of startups at once, but being part of a batch was better for the startups too. It solved one of the biggest problems faced by founders: the isolation. Now you not only had colleagues, but colleagues who understood the problems you were facing and could tell you how they were solving them. - -As YC grew, we started to notice other advantages of scale. The alumni became a tight community, dedicated to helping one another, and especially the current batch, whose shoes they remembered being in. We also noticed that the startups were becoming one another's customers. We used to refer jokingly to the "YC GDP," but as YC grows this becomes less and less of a joke. Now lots of startups get their initial set of customers almost entirely from among their batchmates. - -I had not originally intended YC to be a full-time job. I was going to do three things: hack, write essays, and work on YC. As YC grew, and I grew more excited about it, it started to take up a lot more than a third of my attention. But for the first few years I was still able to work on other things. - -In the summer of 2006, Robert and I started working on a new version of Arc. This one was reasonably fast, because it was compiled into Scheme. To test this new Arc, I wrote Hacker News in it. It was originally meant to be a news aggregator for startup founders and was called Startup News, but after a few months I got tired of reading about nothing but startups. Plus it wasn't startup founders we wanted to reach. It was future startup founders. So I changed the name to Hacker News and the topic to whatever engaged one's intellectual curiosity. - -HN was no doubt good for YC, but it was also by far the biggest source of stress for me. If all I'd had to do was select and help founders, life would have been so easy. And that implies that HN was a mistake. Surely the biggest source of stress in one's work should at least be something close to the core of the work. Whereas I was like someone who was in pain while running a marathon not from the exertion of running, but because I had a blister from an ill-fitting shoe. When I was dealing with some urgent problem during YC, there was about a 60% chance it had to do with HN, and a 40% chance it had do with everything else combined. [17] - -As well as HN, I wrote all of YC's internal software in Arc. But while I continued to work a good deal in Arc, I gradually stopped working on Arc, partly because I didn't have time to, and partly because it was a lot less attractive to mess around with the language now that we had all this infrastructure depending on it. So now my three projects were reduced to two: writing essays and working on YC. - -YC was different from other kinds of work I've done. Instead of deciding for myself what to work on, the problems came to me. Every 6 months there was a new batch of startups, and their problems, whatever they were, became our problems. It was very engaging work, because their problems were quite varied, and the good founders were very effective. If you were trying to learn the most you could about startups in the shortest possible time, you couldn't have picked a better way to do it. - -There were parts of the job I didn't like. Disputes between cofounders, figuring out when people were lying to us, fighting with people who maltreated the startups, and so on. But I worked hard even at the parts I didn't like. I was haunted by something Kevin Hale once said about companies: "No one works harder than the boss." He meant it both descriptively and prescriptively, and it was the second part that scared me. I wanted YC to be good, so if how hard I worked set the upper bound on how hard everyone else worked, I'd better work very hard. - -One day in 2010, when he was visiting California for interviews, Robert Morris did something astonishing: he offered me unsolicited advice. I can only remember him doing that once before. One day at Viaweb, when I was bent over double from a kidney stone, he suggested that it would be a good idea for him to take me to the hospital. That was what it took for Rtm to offer unsolicited advice. So I remember his exact words very clearly. "You know," he said, "you should make sure Y Combinator isn't the last cool thing you do." - -At the time I didn't understand what he meant, but gradually it dawned on me that he was saying I should quit. This seemed strange advice, because YC was doing great. But if there was one thing rarer than Rtm offering advice, it was Rtm being wrong. So this set me thinking. It was true that on my current trajectory, YC would be the last thing I did, because it was only taking up more of my attention. It had already eaten Arc, and was in the process of eating essays too. Either YC was my life's work or I'd have to leave eventually. And it wasn't, so I would. - -In the summer of 2012 my mother had a stroke, and the cause turned out to be a blood clot caused by colon cancer. The stroke destroyed her balance, and she was put in a nursing home, but she really wanted to get out of it and back to her house, and my sister and I were determined to help her do it. I used to fly up to Oregon to visit her regularly, and I had a lot of time to think on those flights. On one of them I realized I was ready to hand YC over to someone else. - -I asked Jessica if she wanted to be president, but she didn't, so we decided we'd try to recruit Sam Altman. We talked to Robert and Trevor and we agreed to make it a complete changing of the guard. Up till that point YC had been controlled by the original LLC we four had started. But we wanted YC to last for a long time, and to do that it couldn't be controlled by the founders. So if Sam said yes, we'd let him reorganize YC. Robert and I would retire, and Jessica and Trevor would become ordinary partners. - -When we asked Sam if he wanted to be president of YC, initially he said no. He wanted to start a startup to make nuclear reactors. But I kept at it, and in October 2013 he finally agreed. We decided he'd take over starting with the winter 2014 batch. For the rest of 2013 I left running YC more and more to Sam, partly so he could learn the job, and partly because I was focused on my mother, whose cancer had returned. - -She died on January 15, 2014. We knew this was coming, but it was still hard when it did. - -I kept working on YC till March, to help get that batch of startups through Demo Day, then I checked out pretty completely. (I still talk to alumni and to new startups working on things I'm interested in, but that only takes a few hours a week.) - -What should I do next? Rtm's advice hadn't included anything about that. I wanted to do something completely different, so I decided I'd paint. I wanted to see how good I could get if I really focused on it. So the day after I stopped working on YC, I started painting. I was rusty and it took a while to get back into shape, but it was at least completely engaging. [18] - -I spent most of the rest of 2014 painting. I'd never been able to work so uninterruptedly before, and I got to be better than I had been. Not good enough, but better. Then in November, right in the middle of a painting, I ran out of steam. Up till that point I'd always been curious to see how the painting I was working on would turn out, but suddenly finishing this one seemed like a chore. So I stopped working on it and cleaned my brushes and haven't painted since. So far anyway. - -I realize that sounds rather wimpy. But attention is a zero sum game. If you can choose what to work on, and you choose a project that's not the best one (or at least a good one) for you, then it's getting in the way of another project that is. And at 50 there was some opportunity cost to screwing around. - -I started writing essays again, and wrote a bunch of new ones over the next few months. I even wrote a couple that weren't about startups. Then in March 2015 I started working on Lisp again. - -The distinctive thing about Lisp is that its core is a language defined by writing an interpreter in itself. It wasn't originally intended as a programming language in the ordinary sense. It was meant to be a formal model of computation, an alternative to the Turing machine. If you want to write an interpreter for a language in itself, what's the minimum set of predefined operators you need? The Lisp that John McCarthy invented, or more accurately discovered, is an answer to that question. [19] - -McCarthy didn't realize this Lisp could even be used to program computers till his grad student Steve Russell suggested it. Russell translated McCarthy's interpreter into IBM 704 machine language, and from that point Lisp started also to be a programming language in the ordinary sense. But its origins as a model of computation gave it a power and elegance that other languages couldn't match. It was this that attracted me in college, though I didn't understand why at the time. - -McCarthy's 1960 Lisp did nothing more than interpret Lisp expressions. It was missing a lot of things you'd want in a programming language. So these had to be added, and when they were, they weren't defined using McCarthy's original axiomatic approach. That wouldn't have been feasible at the time. McCarthy tested his interpreter by hand-simulating the execution of programs. But it was already getting close to the limit of interpreters you could test that way — indeed, there was a bug in it that McCarthy had overlooked. To test a more complicated interpreter, you'd have had to run it, and computers then weren't powerful enough. - -Now they are, though. Now you could continue using McCarthy's axiomatic approach till you'd defined a complete programming language. And as long as every change you made to McCarthy's Lisp was a discoveredness-preserving transformation, you could, in principle, end up with a complete language that had this quality. Harder to do than to talk about, of course, but if it was possible in principle, why not try? So I decided to take a shot at it. It took 4 years, from March 26, 2015 to October 12, 2019. It was fortunate that I had a precisely defined goal, or it would have been hard to keep at it for so long. - -I wrote this new Lisp, called Bel, in itself in Arc. That may sound like a contradiction, but it's an indication of the sort of trickery I had to engage in to make this work. By means of an egregious collection of hacks I managed to make something close enough to an interpreter written in itself that could actually run. Not fast, but fast enough to test. - -I had to ban myself from writing essays during most of this time, or I'd never have finished. In late 2015 I spent 3 months writing essays, and when I went back to working on Bel I could barely understand the code. Not so much because it was badly written as because the problem is so convoluted. When you're working on an interpreter written in itself, it's hard to keep track of what's happening at what level, and errors can be practically encrypted by the time you get them. - -So I said no more essays till Bel was done. But I told few people about Bel while I was working on it. So for years it must have seemed that I was doing nothing, when in fact I was working harder than I'd ever worked on anything. Occasionally after wrestling for hours with some gruesome bug I'd check Twitter or HN and see someone asking "Does Paul Graham still code?" - -Working on Bel was hard but satisfying. I worked on it so intensively that at any given time I had a decent chunk of the code in my head and could write more there. I remember taking the boys to the coast on a sunny day in 2015 and figuring out how to deal with some problem involving continuations while I watched them play in the tide pools. It felt like I was doing life right. I remember that because I was slightly dismayed at how novel it felt. The good news is that I had more moments like this over the next few years. - -In the summer of 2016 we moved to England. We wanted our kids to see what it was like living in another country, and since I was a British citizen by birth, that seemed the obvious choice. We only meant to stay for a year, but we liked it so much that we still live there. So most of Bel was written in England. - -In the fall of 2019, Bel was finally finished. Like McCarthy's original Lisp, it's a spec rather than an implementation, although like McCarthy's Lisp it's a spec expressed as code. - -Now that I could write essays again, I wrote a bunch about topics I'd had stacked up. I kept writing essays through 2020, but I also started to think about other things I could work on. How should I choose what to do? Well, how had I chosen what to work on in the past? I wrote an essay for myself to answer that question, and I was surprised how long and messy the answer turned out to be. If this surprised me, who'd lived it, then I thought perhaps it would be interesting to other people, and encouraging to those with similarly messy lives. So I wrote a more detailed version for others to read, and this is the last sentence of it. - - - - - - - - - -Notes - -[1] My experience skipped a step in the evolution of computers: time-sharing machines with interactive OSes. I went straight from batch processing to microcomputers, which made microcomputers seem all the more exciting. - -[2] Italian words for abstract concepts can nearly always be predicted from their English cognates (except for occasional traps like polluzione). It's the everyday words that differ. So if you string together a lot of abstract concepts with a few simple verbs, you can make a little Italian go a long way. - -[3] I lived at Piazza San Felice 4, so my walk to the Accademia went straight down the spine of old Florence: past the Pitti, across the bridge, past Orsanmichele, between the Duomo and the Baptistery, and then up Via Ricasoli to Piazza San Marco. I saw Florence at street level in every possible condition, from empty dark winter evenings to sweltering summer days when the streets were packed with tourists. - -[4] You can of course paint people like still lives if you want to, and they're willing. That sort of portrait is arguably the apex of still life painting, though the long sitting does tend to produce pained expressions in the sitters. - -[5] Interleaf was one of many companies that had smart people and built impressive technology, and yet got crushed by Moore's Law. In the 1990s the exponential growth in the power of commodity (i.e. Intel) processors rolled up high-end, special-purpose hardware and software companies like a bulldozer. - -[6] The signature style seekers at RISD weren't specifically mercenary. In the art world, money and coolness are tightly coupled. Anything expensive comes to be seen as cool, and anything seen as cool will soon become equally expensive. - -[7] Technically the apartment wasn't rent-controlled but rent-stabilized, but this is a refinement only New Yorkers would know or care about. The point is that it was really cheap, less than half market price. - -[8] Most software you can launch as soon as it's done. But when the software is an online store builder and you're hosting the stores, if you don't have any users yet, that fact will be painfully obvious. So before we could launch publicly we had to launch privately, in the sense of recruiting an initial set of users and making sure they had decent-looking stores. - -[9] We'd had a code editor in Viaweb for users to define their own page styles. They didn't know it, but they were editing Lisp expressions underneath. But this wasn't an app editor, because the code ran when the merchants' sites were generated, not when shoppers visited them. - -[10] This was the first instance of what is now a familiar experience, and so was what happened next, when I read the comments and found they were full of angry people. How could I claim that Lisp was better than other languages? Weren't they all Turing complete? People who see the responses to essays I write sometimes tell me how sorry they feel for me, but I'm not exaggerating when I reply that it has always been like this, since the very beginning. It comes with the territory. An essay must tell readers things they don't already know, and some people dislike being told such things. - -[11] People put plenty of stuff on the internet in the 90s of course, but putting something online is not the same as publishing it online. Publishing online means you treat the online version as the (or at least a) primary version. - -[12] There is a general lesson here that our experience with Y Combinator also teaches: Customs continue to constrain you long after the restrictions that caused them have disappeared. Customary VC practice had once, like the customs about publishing essays, been based on real constraints. Startups had once been much more expensive to start, and proportionally rare. Now they could be cheap and common, but the VCs' customs still reflected the old world, just as customs about writing essays still reflected the constraints of the print era. - -Which in turn implies that people who are independent-minded (i.e. less influenced by custom) will have an advantage in fields affected by rapid change (where customs are more likely to be obsolete). - -Here's an interesting point, though: you can't always predict which fields will be affected by rapid change. Obviously software and venture capital will be, but who would have predicted that essay writing would be? - -[13] Y Combinator was not the original name. At first we were called Cambridge Seed. But we didn't want a regional name, in case someone copied us in Silicon Valley, so we renamed ourselves after one of the coolest tricks in the lambda calculus, the Y combinator. - -I picked orange as our color partly because it's the warmest, and partly because no VC used it. In 2005 all the VCs used staid colors like maroon, navy blue, and forest green, because they were trying to appeal to LPs, not founders. The YC logo itself is an inside joke: the Viaweb logo had been a white V on a red circle, so I made the YC logo a white Y on an orange square. - -[14] YC did become a fund for a couple years starting in 2009, because it was getting so big I could no longer afford to fund it personally. But after Heroku got bought we had enough money to go back to being self-funded. - -[15] I've never liked the term "deal flow," because it implies that the number of new startups at any given time is fixed. This is not only false, but it's the purpose of YC to falsify it, by causing startups to be founded that would not otherwise have existed. - -[16] She reports that they were all different shapes and sizes, because there was a run on air conditioners and she had to get whatever she could, but that they were all heavier than she could carry now. - -[17] Another problem with HN was a bizarre edge case that occurs when you both write essays and run a forum. When you run a forum, you're assumed to see if not every conversation, at least every conversation involving you. And when you write essays, people post highly imaginative misinterpretations of them on forums. Individually these two phenomena are tedious but bearable, but the combination is disastrous. You actually have to respond to the misinterpretations, because the assumption that you're present in the conversation means that not responding to any sufficiently upvoted misinterpretation reads as a tacit admission that it's correct. But that in turn encourages more; anyone who wants to pick a fight with you senses that now is their chance. - -[18] The worst thing about leaving YC was not working with Jessica anymore. We'd been working on YC almost the whole time we'd known each other, and we'd neither tried nor wanted to separate it from our personal lives, so leaving was like pulling up a deeply rooted tree. - -[19] One way to get more precise about the concept of invented vs discovered is to talk about space aliens. Any sufficiently advanced alien civilization would certainly know about the Pythagorean theorem, for example. I believe, though with less certainty, that they would also know about the Lisp in McCarthy's 1960 paper. - -But if so there's no reason to suppose that this is the limit of the language that might be known to them. Presumably aliens need numbers and errors and I/O too. So it seems likely there exists at least one path out of McCarthy's Lisp along which discoveredness is preserved. - - - -Thanks to Trevor Blackwell, John Collison, Patrick Collison, Daniel Gackle, Ralph Hazell, Jessica Livingston, Robert Morris, and Harj Taggar for reading drafts of this. From 2281f00198625ca155b0f3b87c2c147e0c0f4bbe Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 7 Feb 2024 22:46:17 +0100 Subject: [PATCH 10/83] langchain: Standardize `output_parser.py` across all agent types for custom `FORMAT_INSTRUCTIONS` (#17168) - **Description:** This PR standardizes the `output_parser.py` file across all agent types to ensure a uniform parsing mechanism is implemented. It introduces a cohesive structure and common interface for output parsing, facilitating easier modifications and extensions by users. The standardized approach enhances maintainability and scalability of the codebase by providing a consistent pattern for output parsing, which can be easily understood and utilized across different agent types. This PR builds upon the foundation set by a previously merged PR, which focused exclusively on standardizing the `output_parser.py` for the `conversational_agent` ([PR #16945](https://github.com/langchain-ai/langchain/pull/16945)). With this new update, I extend the standardization efforts to encompass `output_parser.py` files across all agent types. This enhancement not only unifies the parsing mechanism across the board but also introduces the flexibility for users to incorporate custom `FORMAT_INSTRUCTIONS`. - **Issue:** https://github.com/langchain-ai/langchain/issues/10721 https://github.com/langchain-ai/langchain/issues/4044 - **Dependencies:** No new dependencies required for this change - **Twitter handle:** With my github user is enough. Thanks I hope you accept my PR. --- libs/langchain/langchain/agents/chat/output_parser.py | 6 +++++- .../langchain/agents/conversational/output_parser.py | 6 +++++- .../langchain/agents/conversational_chat/output_parser.py | 1 + libs/langchain/langchain/agents/mrkl/output_parser.py | 6 +++++- .../langchain/agents/structured_chat/output_parser.py | 7 ++++++- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libs/langchain/langchain/agents/chat/output_parser.py b/libs/langchain/langchain/agents/chat/output_parser.py index 069a7fdbb5cd7..cdb8c0d0dae1d 100644 --- a/libs/langchain/langchain/agents/chat/output_parser.py +++ b/libs/langchain/langchain/agents/chat/output_parser.py @@ -14,11 +14,15 @@ class ChatOutputParser(AgentOutputParser): """Output parser for the chat agent.""" + format_instructions: str = FORMAT_INSTRUCTIONS + """Default formatting instructions""" + pattern = re.compile(r"^.*?`{3}(?:json)?\n(.*?)`{3}.*?$", re.DOTALL) """Regex pattern to parse the output.""" def get_format_instructions(self) -> str: - return FORMAT_INSTRUCTIONS + """Returns formatting instructions for the given output parser.""" + return self.format_instructions def parse(self, text: str) -> Union[AgentAction, AgentFinish]: includes_answer = FINAL_ANSWER_ACTION in text diff --git a/libs/langchain/langchain/agents/conversational/output_parser.py b/libs/langchain/langchain/agents/conversational/output_parser.py index 6d0446b81bf22..e74e626faa99e 100644 --- a/libs/langchain/langchain/agents/conversational/output_parser.py +++ b/libs/langchain/langchain/agents/conversational/output_parser.py @@ -14,8 +14,12 @@ class ConvoOutputParser(AgentOutputParser): ai_prefix: str = "AI" """Prefix to use before AI output.""" + format_instructions: str = FORMAT_INSTRUCTIONS + """Default formatting instructions""" + def get_format_instructions(self) -> str: - return FORMAT_INSTRUCTIONS + """Returns formatting instructions for the given output parser.""" + return self.format_instructions def parse(self, text: str) -> Union[AgentAction, AgentFinish]: if f"{self.ai_prefix}:" in text: diff --git a/libs/langchain/langchain/agents/conversational_chat/output_parser.py b/libs/langchain/langchain/agents/conversational_chat/output_parser.py index ea3a380f4bc92..6fd330ccf8d18 100644 --- a/libs/langchain/langchain/agents/conversational_chat/output_parser.py +++ b/libs/langchain/langchain/agents/conversational_chat/output_parser.py @@ -15,6 +15,7 @@ class ConvoOutputParser(AgentOutputParser): """Output parser for the conversational agent.""" format_instructions: str = FORMAT_INSTRUCTIONS + """Default formatting instructions""" def get_format_instructions(self) -> str: """Returns formatting instructions for the given output parser.""" diff --git a/libs/langchain/langchain/agents/mrkl/output_parser.py b/libs/langchain/langchain/agents/mrkl/output_parser.py index b716c49db4808..f6489c2a79289 100644 --- a/libs/langchain/langchain/agents/mrkl/output_parser.py +++ b/libs/langchain/langchain/agents/mrkl/output_parser.py @@ -22,8 +22,12 @@ class MRKLOutputParser(AgentOutputParser): """MRKL Output parser for the chat agent.""" + format_instructions: str = FORMAT_INSTRUCTIONS + """Default formatting instructions""" + def get_format_instructions(self) -> str: - return FORMAT_INSTRUCTIONS + """Returns formatting instructions for the given output parser.""" + return self.format_instructions def parse(self, text: str) -> Union[AgentAction, AgentFinish]: includes_answer = FINAL_ANSWER_ACTION in text diff --git a/libs/langchain/langchain/agents/structured_chat/output_parser.py b/libs/langchain/langchain/agents/structured_chat/output_parser.py index eb85d6684b6e8..2f91a8352a0e6 100644 --- a/libs/langchain/langchain/agents/structured_chat/output_parser.py +++ b/libs/langchain/langchain/agents/structured_chat/output_parser.py @@ -20,10 +20,15 @@ class StructuredChatOutputParser(AgentOutputParser): """Output parser for the structured chat agent.""" + format_instructions: str = FORMAT_INSTRUCTIONS + """Default formatting instructions""" + pattern = re.compile(r"```(?:json\s+)?(\W.*?)```", re.DOTALL) + """Regex pattern to parse the output.""" def get_format_instructions(self) -> str: - return FORMAT_INSTRUCTIONS + """Returns formatting instructions for the given output parser.""" + return self.format_instructions def parse(self, text: str) -> Union[AgentAction, AgentFinish]: try: From af74301ab981a0421f84bbff6921b7feca79dbfe Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:15:30 -0800 Subject: [PATCH 11/83] core[patch], community[patch]: link extraction continue on failure (#17200) --- .../document_loaders/recursive_url_loader.py | 32 +++++++++++------ .../langchain_community/vectorstores/kdbai.py | 4 +-- libs/core/langchain_core/utils/html.py | 35 +++++++++++++------ 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/libs/community/langchain_community/document_loaders/recursive_url_loader.py b/libs/community/langchain_community/document_loaders/recursive_url_loader.py index 6fca4edf86a80..c24ab1730fd35 100644 --- a/libs/community/langchain_community/document_loaders/recursive_url_loader.py +++ b/libs/community/langchain_community/document_loaders/recursive_url_loader.py @@ -93,6 +93,7 @@ def __init__( link_regex: Union[str, re.Pattern, None] = None, headers: Optional[dict] = None, check_response_status: bool = False, + continue_on_failure: bool = True, ) -> None: """Initialize with URL to crawl and any subdirectories to exclude. @@ -117,6 +118,8 @@ def __init__( link_regex: Regex for extracting sub-links from the raw html of a web page. check_response_status: If True, check HTTP response status and skip URLs with error responses (400-599). + continue_on_failure: If True, continue if getting or parsing a link raises + an exception. Otherwise, raise the exception. """ self.url = url @@ -142,6 +145,7 @@ def __init__( self._lock = asyncio.Lock() if self.use_async else None self.headers = headers self.check_response_status = check_response_status + self.continue_on_failure = continue_on_failure def _get_child_links_recursive( self, url: str, visited: Set[str], *, depth: int = 0 @@ -164,11 +168,14 @@ def _get_child_links_recursive( if self.check_response_status and 400 <= response.status_code <= 599: raise ValueError(f"Received HTTP status {response.status_code}") except Exception as e: - logger.warning( - f"Unable to load from {url}. Received error {e} of type " - f"{e.__class__.__name__}" - ) - return + if self.continue_on_failure: + logger.warning( + f"Unable to load from {url}. Received error {e} of type " + f"{e.__class__.__name__}" + ) + return + else: + raise e content = self.extractor(response.text) if content: yield Document( @@ -184,6 +191,7 @@ def _get_child_links_recursive( pattern=self.link_regex, prevent_outside=self.prevent_outside, exclude_prefixes=self.exclude_dirs, + continue_on_failure=self.continue_on_failure, ) for link in sub_links: # Check all unvisited links @@ -237,13 +245,16 @@ async def _async_get_child_links_recursive( if self.check_response_status and 400 <= response.status <= 599: raise ValueError(f"Received HTTP status {response.status}") except (aiohttp.client_exceptions.InvalidURL, Exception) as e: - logger.warning( - f"Unable to load {url}. Received error {e} of type " - f"{e.__class__.__name__}" - ) if close_session: await session.close() - return [] + if self.continue_on_failure: + logger.warning( + f"Unable to load {url}. Received error {e} of type " + f"{e.__class__.__name__}" + ) + return [] + else: + raise e results = [] content = self.extractor(text) if content: @@ -261,6 +272,7 @@ async def _async_get_child_links_recursive( pattern=self.link_regex, prevent_outside=self.prevent_outside, exclude_prefixes=self.exclude_dirs, + continue_on_failure=self.continue_on_failure, ) # Recursively call the function to get the children of the children diff --git a/libs/community/langchain_community/vectorstores/kdbai.py b/libs/community/langchain_community/vectorstores/kdbai.py index 1122b691d439b..9ac1a7d580a82 100644 --- a/libs/community/langchain_community/vectorstores/kdbai.py +++ b/libs/community/langchain_community/vectorstores/kdbai.py @@ -14,7 +14,7 @@ class KDBAI(VectorStore): - """`KDB.AI` vector store [https://kdb.ai](https://kdb.ai) + """`KDB.AI` vector store. To use, you should have the `kdbai_client` python package installed. @@ -25,7 +25,7 @@ class KDBAI(VectorStore): distance_strategy: One option from DistanceStrategy.EUCLIDEAN_DISTANCE, DistanceStrategy.DOT_PRODUCT or DistanceStrategy.COSINE. - See the example [notebook](https://github.com/KxSystems/langchain/blob/KDB.AI/docs/docs/integrations/vectorstores/kdbai.ipynb). + See the example https://github.com/KxSystems/langchain/blob/KDB.AI/docs/docs/integrations/vectorstores/kdbai.ipynb. """ def __init__( diff --git a/libs/core/langchain_core/utils/html.py b/libs/core/langchain_core/utils/html.py index bbea15f0fa435..837b19ed101da 100644 --- a/libs/core/langchain_core/utils/html.py +++ b/libs/core/langchain_core/utils/html.py @@ -1,7 +1,10 @@ +import logging import re from typing import List, Optional, Sequence, Union from urllib.parse import urljoin, urlparse +logger = logging.getLogger(__name__) + PREFIXES_TO_IGNORE = ("javascript:", "mailto:", "#") SUFFIXES_TO_IGNORE = ( ".css", @@ -52,6 +55,7 @@ def extract_sub_links( pattern: Union[str, re.Pattern, None] = None, prevent_outside: bool = True, exclude_prefixes: Sequence[str] = (), + continue_on_failure: bool = False, ) -> List[str]: """Extract all links from a raw html string and convert into absolute paths. @@ -63,25 +67,34 @@ def extract_sub_links( prevent_outside: If True, ignore external links which are not children of the base url. exclude_prefixes: Exclude any URLs that start with one of these prefixes. - + continue_on_failure: If True, continue if parsing a specific link raises an + exception. Otherwise, raise the exception. Returns: List[str]: sub links """ base_url_to_use = base_url if base_url is not None else url parsed_base_url = urlparse(base_url_to_use) + parsed_url = urlparse(url) all_links = find_all_links(raw_html, pattern=pattern) absolute_paths = set() for link in all_links: - parsed_link = urlparse(link) - # Some may be absolute links like https://to/path - if parsed_link.scheme == "http" or parsed_link.scheme == "https": - absolute_path = link - # Some may have omitted the protocol like //to/path - elif link.startswith("//"): - absolute_path = f"{urlparse(url).scheme}:{link}" - else: - absolute_path = urljoin(url, parsed_link.path) - absolute_paths.add(absolute_path) + try: + parsed_link = urlparse(link) + # Some may be absolute links like https://to/path + if parsed_link.scheme == "http" or parsed_link.scheme == "https": + absolute_path = link + # Some may have omitted the protocol like //to/path + elif link.startswith("//"): + absolute_path = f"{parsed_url.scheme}:{link}" + else: + absolute_path = urljoin(url, parsed_link.path) + absolute_paths.add(absolute_path) + except Exception as e: + if continue_on_failure: + logger.warning(f"Unable to load link {link}. Raised exception:\n\n{e}") + continue + else: + raise e results = [] for path in absolute_paths: From 00757567bad62e9cfaaa09b7b3f2486bd7d49d92 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:20:20 -0800 Subject: [PATCH 12/83] core[patch]: Release 0.1.21 (#17202) --- libs/core/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/pyproject.toml b/libs/core/pyproject.toml index 40c47e0a2e83b..12b241f5f9e9f 100644 --- a/libs/core/pyproject.toml +++ b/libs/core/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-core" -version = "0.1.20" +version = "0.1.21" description = "Building applications with LLMs through composability" authors = [] license = "MIT" From a13dc47a088a7fa5335a0e327279992f047d8278 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 14:52:37 -0800 Subject: [PATCH 13/83] cli[patch]: copyright 2024 default (#17204) --- libs/cli/langchain_cli/integration_template/LICENSE | 2 +- libs/cli/langchain_cli/package_template/LICENSE | 2 +- templates/retrieval-agent-fireworks/LICENSE | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/cli/langchain_cli/integration_template/LICENSE b/libs/cli/langchain_cli/integration_template/LICENSE index 426b65090341f..fc0602feecdd6 100644 --- a/libs/cli/langchain_cli/integration_template/LICENSE +++ b/libs/cli/langchain_cli/integration_template/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 LangChain, Inc. +Copyright (c) 2024 LangChain, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/libs/cli/langchain_cli/package_template/LICENSE b/libs/cli/langchain_cli/package_template/LICENSE index 426b65090341f..fc0602feecdd6 100644 --- a/libs/cli/langchain_cli/package_template/LICENSE +++ b/libs/cli/langchain_cli/package_template/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 LangChain, Inc. +Copyright (c) 2024 LangChain, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/templates/retrieval-agent-fireworks/LICENSE b/templates/retrieval-agent-fireworks/LICENSE index 426b65090341f..fc0602feecdd6 100644 --- a/templates/retrieval-agent-fireworks/LICENSE +++ b/templates/retrieval-agent-fireworks/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 LangChain, Inc. +Copyright (c) 2024 LangChain, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 6f1403b9b6155704ca2d35950c16a0924cbb03ed Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:37:01 -0800 Subject: [PATCH 14/83] community[patch]: Release 0.0.19 (#17207) Co-authored-by: Erick Friis --- libs/community/poetry.lock | 131 ++++++++++++++++++---------------- libs/community/pyproject.toml | 4 +- 2 files changed, 70 insertions(+), 65 deletions(-) diff --git a/libs/community/poetry.lock b/libs/community/poetry.lock index 207f139f811e9..fccdc9749fbc8 100644 --- a/libs/community/poetry.lock +++ b/libs/community/poetry.lock @@ -702,17 +702,17 @@ files = [ [[package]] name = "boto3" -version = "1.34.36" +version = "1.34.37" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.8" files = [ - {file = "boto3-1.34.36-py3-none-any.whl", hash = "sha256:1e38a4ea4bb8bc66fbb858abb411820709fda5d6c5604c2da0f696653d49c684"}, - {file = "boto3-1.34.36.tar.gz", hash = "sha256:7ec36deb7ccc9c4943510692303cf93883ef61dc2c79f8bd4d75ee42209559d3"}, + {file = "boto3-1.34.37-py3-none-any.whl", hash = "sha256:65acfe7f1cf2a9b7df3d4edb87c8022e02685825bd1957e7bb678cc0d09f5e5f"}, + {file = "boto3-1.34.37.tar.gz", hash = "sha256:73f5ec89cb3ddb3ed577317889fd2f2df783f66b6502a9a4239979607e33bf74"}, ] [package.dependencies] -botocore = ">=1.34.36,<1.35.0" +botocore = ">=1.34.37,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -721,13 +721,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.36" +version = "1.34.37" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.8" files = [ - {file = "botocore-1.34.36-py3-none-any.whl", hash = "sha256:3f39ae0165f1a27f621fc91a46fb59f87e819671fad106c230dadcc724892f70"}, - {file = "botocore-1.34.36.tar.gz", hash = "sha256:89c3dc15b6ffae146029df636d51b9952740051204c444ec765286b081c917bc"}, + {file = "botocore-1.34.37-py3-none-any.whl", hash = "sha256:2a5bf33aacd2d970afd3d492e179e06ea98a5469030d5cfe7a2ad9995f7bb2ef"}, + {file = "botocore-1.34.37.tar.gz", hash = "sha256:3c46ddb1679e6ef45ca78b48665398636bda532a07cd476e4b500697d13d9a99"}, ] [package.dependencies] @@ -2478,33 +2478,35 @@ grpc = ["grpcio (>=1.38.0,<2.0dev)", "grpcio-status (>=1.38.0,<2.0.dev0)"] [[package]] name = "google-cloud-documentai" -version = "2.22.0" +version = "2.23.0" description = "Google Cloud Documentai API client library" optional = true python-versions = ">=3.7" files = [ - {file = "google-cloud-documentai-2.22.0.tar.gz", hash = "sha256:e033457a95634aac250452600f4e4464f39073b5c00f5a1f8636f1fa83a93e73"}, - {file = "google_cloud_documentai-2.22.0-py2.py3-none-any.whl", hash = "sha256:68b0c7962e4880879dfe23723de8c3beed9604342b4617913ca32437105d7e33"}, + {file = "google-cloud-documentai-2.23.0.tar.gz", hash = "sha256:2ce954dae90024662d39258060b753992d5564d64a08badda635c7d25f7079b1"}, + {file = "google_cloud_documentai-2.23.0-py2.py3-none-any.whl", hash = "sha256:560b00c18e6a3b5c603052ccc9987afdc6886d6c71f883a7a2aa97a8f739f1fa"}, ] [package.dependencies] google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} +google-auth = ">=2.14.1,<3.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" [[package]] name = "google-cloud-resource-manager" -version = "1.12.0" +version = "1.12.1" description = "Google Cloud Resource Manager API client library" optional = false python-versions = ">=3.7" files = [ - {file = "google-cloud-resource-manager-1.12.0.tar.gz", hash = "sha256:c2c4ae53e5f9ff612e4cf961f1bac3f9100ae54a5122c1b1cd4236e884d112c5"}, - {file = "google_cloud_resource_manager-1.12.0-py2.py3-none-any.whl", hash = "sha256:a7128e5ed4ff35d42669a833c0841cda065123ece58ca468c3ea656983de13dc"}, + {file = "google-cloud-resource-manager-1.12.1.tar.gz", hash = "sha256:25b3112c984ef6a2569ca7047160b2341c528c70e1d2e72deb99686aa2e167dd"}, + {file = "google_cloud_resource_manager-1.12.1-py2.py3-none-any.whl", hash = "sha256:6a0b97886998fb076a71a7e9679a1187f6bed97519e0dff13352e7946513d458"}, ] [package.dependencies] google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} +google-auth = ">=2.14.1,<3.0.0dev" grpc-google-iam-v1 = ">=0.12.4,<1.0.0dev" proto-plus = ">=1.22.3,<2.0.0dev" protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" @@ -3174,13 +3176,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.29.1" +version = "6.29.2" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.29.1-py3-none-any.whl", hash = "sha256:e5dfba210fc9da74a5dae8fa6c41f816e11bd18d10381b2517d9a0d57cc987c4"}, - {file = "ipykernel-6.29.1.tar.gz", hash = "sha256:1547352b32da95a2761011a8dac2af930c26a0703dfa07690d16b7d74dac0ba1"}, + {file = "ipykernel-6.29.2-py3-none-any.whl", hash = "sha256:50384f5c577a260a1d53f1f59a828c7266d321c9b7d00d345693783f66616055"}, + {file = "ipykernel-6.29.2.tar.gz", hash = "sha256:3bade28004e3ff624ed57974948116670604ac5f676d12339693f3142176d3f0"}, ] [package.dependencies] @@ -3932,7 +3934,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.1.19" +version = "0.1.21" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.8.1,<4.0" @@ -3942,7 +3944,7 @@ develop = true [package.dependencies] anyio = ">=3,<5" jsonpatch = "^1.33" -langsmith = ">=0.0.83,<0.1" +langsmith = "^0.0.87" packaging = "^23.2" pydantic = ">=1,<3" PyYAML = ">=5.3" @@ -3958,13 +3960,13 @@ url = "../core" [[package]] name = "langsmith" -version = "0.0.86" +version = "0.0.87" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.86-py3-none-any.whl", hash = "sha256:7af15c36edb8c9fd9ae5c6d4fb940eb1da668b630a703d63c90c91e9be53aefb"}, - {file = "langsmith-0.0.86.tar.gz", hash = "sha256:c1572824664810c4425b17f2d1e9a59d53992e6898df22a37236c62d3c80f59e"}, + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, ] [package.dependencies] @@ -4749,13 +4751,13 @@ test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>= [[package]] name = "nbconvert" -version = "7.15.0" +version = "7.16.0" description = "Converting Jupyter Notebooks" optional = false python-versions = ">=3.8" files = [ - {file = "nbconvert-7.15.0-py3-none-any.whl", hash = "sha256:0efd3ca74fd1525560e0312cec235e57dfbf3c5c775c7e61e04c532b28f8da6f"}, - {file = "nbconvert-7.15.0.tar.gz", hash = "sha256:ff3f54a1a5e1e024beb9fde8946d05b6d0bf68cd14b5f2f9dc5b545c8bc71055"}, + {file = "nbconvert-7.16.0-py3-none-any.whl", hash = "sha256:ad3dc865ea6e2768d31b7eb6c7ab3be014927216a5ece3ef276748dd809054c7"}, + {file = "nbconvert-7.16.0.tar.gz", hash = "sha256:813e6553796362489ae572e39ba1bff978536192fb518e10826b0e8cadf03ec8"}, ] [package.dependencies] @@ -5159,13 +5161,13 @@ numpy = [ [[package]] name = "oracle-ads" -version = "2.10.0" +version = "2.10.1" description = "Oracle Accelerated Data Science SDK" optional = true python-versions = ">=3.8" files = [ - {file = "oracle_ads-2.10.0-py3-none-any.whl", hash = "sha256:df2572d8470915ca2c1d9fe4154930e23080c96695316a0caaff56e2d78d46cd"}, - {file = "oracle_ads-2.10.0.tar.gz", hash = "sha256:90d63250928867fe0a3b4730dc20ea5eed6587d6e069f5fe9f6414eae9df6a1b"}, + {file = "oracle_ads-2.10.1-py3-none-any.whl", hash = "sha256:b3379df8ab8e9c7c1040fa4ea3cb52c6898f9c32b2412c76d8827da76708708f"}, + {file = "oracle_ads-2.10.1.tar.gz", hash = "sha256:8084004c94e6eb5ae56bc7f1b8d95fbdbd1ba43ceb87878c199cfc164529e7ac"}, ] [package.dependencies] @@ -5189,11 +5191,12 @@ tabulate = ">=0.8.9" tqdm = ">=4.59.0" [package.extras] +anomaly = ["autots", "datapane", "oracle-automlx[anomaly] (==23.2.3)", "oracle_ads[opctl]", "oracledb"] bds = ["hdfs[kerberos]", "ibis-framework[impala]", "sqlalchemy"] boosted = ["lightgbm (<4.0.0)", "xgboost"] data = ["datefinder (>=0.7.1)", "fastavro (>=0.24.2)", "htmllistparse (>=0.6.0)", "openpyxl (>=3.0.7)", "oracledb (>=1.0)", "pandavro (>=1.6.0)", "sqlalchemy (>=1.4.1,<=1.4.46)"] feature-store-marketplace = ["kubernetes", "oracle-ads[opctl]"] -forecast = ["autots[additional]", "conda-pack", "datapane", "holidays (==0.21.13)", "inflection", "nbconvert", "nbformat", "neuralprophet", "numpy", "oci-cli", "oci-cli", "optuna (==2.9.0)", "oracle-ads", "oracle-automlx[forecasting] (==23.2.3)", "plotly", "pmdarima", "prophet", "py-cpuinfo", "rich", "shap", "sktime", "statsmodels"] +forecast = ["autots[additional]", "conda-pack", "datapane", "holidays (==0.21.13)", "inflection", "nbconvert", "nbformat", "neuralprophet", "numpy", "oci-cli", "oci-cli", "optuna (==2.9.0)", "oracle-ads", "oracle-automlx[forecasting] (==23.2.3)", "oracledb", "plotly", "pmdarima", "prophet", "py-cpuinfo", "rich", "shap", "sktime", "statsmodels"] geo = ["geopandas", "oracle_ads[viz]"] huggingface = ["transformers"] llm = ["evaluate (>=0.4.0)", "langchain (>=0.0.295)"] @@ -5206,7 +5209,7 @@ spark = ["pyspark (>=3.0.0)"] tensorflow = ["oracle_ads[viz]", "tensorflow"] text = ["spacy", "wordcloud (>=1.8.1)"] torch = ["oracle_ads[viz]", "torch", "torchvision"] -viz = ["bokeh (>=2.3.0,<=2.4.3)", "folium (>=0.12.1)", "graphviz (<0.17)", "scipy (>=1.5.4)", "seaborn (>=0.11.0)"] +viz = ["bokeh (>=3.0.0,<3.2.0)", "folium (>=0.12.1)", "graphviz (<0.17)", "scipy (>=1.5.4)", "seaborn (>=0.11.0)"] [[package]] name = "orjson" @@ -7998,17 +8001,17 @@ mpmath = ">=0.19" [[package]] name = "syrupy" -version = "4.6.0" +version = "4.6.1" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.8.1,<4" files = [ - {file = "syrupy-4.6.0-py3-none-any.whl", hash = "sha256:747aae1bcf3cb3249e33b1e6d81097874d23615982d5686ebe637875b0775a1b"}, - {file = "syrupy-4.6.0.tar.gz", hash = "sha256:231b1f5d00f1f85048ba81676c79448076189c4aef4d33f21ae32f3b4c565a54"}, + {file = "syrupy-4.6.1-py3-none-any.whl", hash = "sha256:203e52f9cb9fa749cf683f29bd68f02c16c3bc7e7e5fe8f2fc59bdfe488ce133"}, + {file = "syrupy-4.6.1.tar.gz", hash = "sha256:37a835c9ce7857eeef86d62145885e10b3cb9615bc6abeb4ce404b3f18e1bb36"}, ] [package.dependencies] -pytest = ">=7.0.0,<8.0.0" +pytest = ">=7.0.0,<9.0.0" [[package]] name = "tabulate" @@ -8776,38 +8779,40 @@ tests = ["Werkzeug (==2.0.3)", "aiohttp", "boto3", "httplib2", "httpx", "pytest" [[package]] name = "watchdog" -version = "3.0.0" +version = "4.0.0" description = "Filesystem events monitoring" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, - {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, - {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, - {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, - {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, - {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, - {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, - {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, - {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, - {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, - {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, - {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, - {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, - {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, ] [package.extras] @@ -9324,4 +9329,4 @@ extended-testing = ["aiosqlite", "aleph-alpha-client", "anthropic", "arxiv", "as [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "d9be7110a6f92c4ba724d671b82d89f3776b096ba4c9b2ad97c9765f35bdba05" +content-hash = "9e795e7b2f95e3bd1daa3d92129172e21c6c0c1b5dc82e4791872f39a33472aa" diff --git a/libs/community/pyproject.toml b/libs/community/pyproject.toml index cf34ca4aac64f..926e9a7ee5524 100644 --- a/libs/community/pyproject.toml +++ b/libs/community/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-community" -version = "0.0.18" +version = "0.0.19" description = "Community contributed LangChain integrations." authors = [] license = "MIT" @@ -9,7 +9,7 @@ repository = "https://github.com/langchain-ai/langchain" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" -langchain-core = ">=0.1.19,<0.2" +langchain-core = ">=0.1.21,<0.2" SQLAlchemy = ">=1.4,<3" requests = "^2" PyYAML = ">=5.3" From 19ff81e74f51ab3857eaf933f947f5a891127428 Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Wed, 7 Feb 2024 15:46:13 -0800 Subject: [PATCH 15/83] Fix stream events/log with some kinds of non addable output (#17205) --- libs/core/langchain_core/tracers/log_stream.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/core/langchain_core/tracers/log_stream.py b/libs/core/langchain_core/tracers/log_stream.py index c6b8da943a3d1..db56626451649 100644 --- a/libs/core/langchain_core/tracers/log_stream.py +++ b/libs/core/langchain_core/tracers/log_stream.py @@ -572,6 +572,7 @@ async def consume_astream() -> None: try: final_output = final_output + chunk # type: ignore except TypeError: + prev_final_output = None final_output = chunk patches: List[Dict[str, Any]] = [] if with_streamed_output_list: From 52be84a603f8d4ab764d652cdf49ff5b82be5d03 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 15:47:32 -0800 Subject: [PATCH 16/83] google-vertexai[patch]: serializable citation metadata, release 0.0.4 (#17145) was breaking in langserve before --- .../langchain_google_vertexai/_utils.py | 7 ++++++- libs/partners/google-vertexai/pyproject.toml | 2 +- .../tests/integration_tests/test_tools.py | 18 +++++++++--------- .../tests/unit_tests/test_chat_models.py | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/libs/partners/google-vertexai/langchain_google_vertexai/_utils.py b/libs/partners/google-vertexai/langchain_google_vertexai/_utils.py index 4f0bdf3723b02..feedd701a6197 100644 --- a/libs/partners/google-vertexai/langchain_google_vertexai/_utils.py +++ b/libs/partners/google-vertexai/langchain_google_vertexai/_utils.py @@ -5,6 +5,7 @@ from typing import Any, Callable, Dict, Optional, Union import google.api_core +import proto # type: ignore[import-untyped] from google.api_core.gapic_v1.client_info import ClientInfo from google.cloud import storage from langchain_core.callbacks import ( @@ -114,7 +115,11 @@ def get_generation_info( } for rating in candidate.safety_ratings ], - "citation_metadata": candidate.citation_metadata, + "citation_metadata": ( + proto.Message.to_dict(candidate.citation_metadata) + if candidate.citation_metadata + else None + ), } # https://cloud.google.com/vertex-ai/docs/generative-ai/model-reference/text-chat#response_body else: diff --git a/libs/partners/google-vertexai/pyproject.toml b/libs/partners/google-vertexai/pyproject.toml index f9d2f890cbbab..a9283e2d5c862 100644 --- a/libs/partners/google-vertexai/pyproject.toml +++ b/libs/partners/google-vertexai/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-google-vertexai" -version = "0.0.3" +version = "0.0.4" description = "An integration package connecting GoogleVertexAI and LangChain" authors = [] readme = "README.md" diff --git a/libs/partners/google-vertexai/tests/integration_tests/test_tools.py b/libs/partners/google-vertexai/tests/integration_tests/test_tools.py index a688476bfc7ad..f239727ecac9a 100644 --- a/libs/partners/google-vertexai/tests/integration_tests/test_tools.py +++ b/libs/partners/google-vertexai/tests/integration_tests/test_tools.py @@ -1,6 +1,6 @@ import os import re -from typing import List, Union +from typing import Any, List, Union from langchain_core.agents import AgentAction, AgentActionMessageLog, AgentFinish from langchain_core.messages import AIMessageChunk @@ -44,11 +44,11 @@ def parse(self, text: str) -> Union[AgentAction, AgentFinish]: def test_tools() -> None: - from langchain.agents import AgentExecutor # type: ignore[import-not-found] - from langchain.agents.format_scratchpad import ( # type: ignore[import-not-found] + from langchain.agents import AgentExecutor + from langchain.agents.format_scratchpad import ( format_to_openai_function_messages, ) - from langchain.chains import LLMMathChain # type: ignore[import-not-found] + from langchain.chains import LLMMathChain llm = ChatVertexAI(model_name="gemini-pro") math_chain = LLMMathChain.from_llm(llm=llm) @@ -67,8 +67,8 @@ def test_tools() -> None: ) llm_with_tools = llm.bind(functions=tools) - agent = ( - { # type: ignore[var-annotated] + agent: Any = ( + { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] @@ -115,7 +115,7 @@ def test_multiple_tools() -> None: from langchain.agents import AgentExecutor from langchain.agents.format_scratchpad import format_to_openai_function_messages from langchain.chains import LLMMathChain - from langchain.utilities import ( # type: ignore[import-not-found] + from langchain.utilities import ( GoogleSearchAPIWrapper, ) @@ -149,8 +149,8 @@ def test_multiple_tools() -> None: ) llm_with_tools = llm.bind(functions=tools) - agent = ( - { # type: ignore[var-annotated] + agent: Any = ( + { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] diff --git a/libs/partners/google-vertexai/tests/unit_tests/test_chat_models.py b/libs/partners/google-vertexai/tests/unit_tests/test_chat_models.py index 052cf559f0fda..6bcbb6e5abff3 100644 --- a/libs/partners/google-vertexai/tests/unit_tests/test_chat_models.py +++ b/libs/partners/google-vertexai/tests/unit_tests/test_chat_models.py @@ -187,7 +187,7 @@ def test_default_params_gemini() -> None: StubGeminiResponse( text="Goodbye", content=Mock(parts=[Mock(function_call=None)]), - citation_metadata=Mock(), + citation_metadata=None, ) ] mock_chat = MagicMock() From e17173c4036e7d2302a6c696e5c5de6757cf41d7 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 15:49:56 -0800 Subject: [PATCH 17/83] google-vertexai[patch]: function calling integration test (#17209) --- .../integration_tests/test_chat_models.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libs/partners/google-vertexai/tests/integration_tests/test_chat_models.py b/libs/partners/google-vertexai/tests/integration_tests/test_chat_models.py index f2981a0801812..94c7ea6a55b79 100644 --- a/libs/partners/google-vertexai/tests/integration_tests/test_chat_models.py +++ b/libs/partners/google-vertexai/tests/integration_tests/test_chat_models.py @@ -1,4 +1,6 @@ """Test ChatGoogleVertexAI chat model.""" + +import json from typing import Optional, cast import pytest @@ -9,6 +11,7 @@ SystemMessage, ) from langchain_core.outputs import ChatGeneration, LLMResult +from langchain_core.pydantic_v1 import BaseModel from langchain_google_vertexai.chat_models import ChatVertexAI @@ -220,3 +223,26 @@ def test_chat_vertexai_system_message(model_name: Optional[str]) -> None: response = model([system_message, message1, message2, message3]) assert isinstance(response, AIMessage) assert isinstance(response.content, str) + + +def test_chat_vertexai_gemini_function_calling() -> None: + class MyModel(BaseModel): + name: str + age: int + + model = ChatVertexAI(model_name="gemini-pro").bind(functions=[MyModel]) + message = HumanMessage(content="My name is Erick and I am 27 years old") + response = model.invoke([message]) + assert isinstance(response, AIMessage) + assert isinstance(response.content, str) + assert response.content == "" + function_call = response.additional_kwargs.get("function_call") + assert function_call + assert function_call["name"] == "MyModel" + arguments_str = function_call.get("arguments") + assert arguments_str + arguments = json.loads(arguments_str) + assert arguments == { + "name": "Erick", + "age": 27.0, + } From 2ecf3182187c480568d9a21bd9194ce549a77420 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 17:07:31 -0800 Subject: [PATCH 18/83] google-genai[patch]: match function call interface (#17213) should match vertex --- .../langchain_google_genai/_function_utils.py | 135 ++++++++++++++++++ .../langchain_google_genai/chat_models.py | 73 ++-------- .../integration_tests/test_function_call.py | 54 ++++++- 3 files changed, 198 insertions(+), 64 deletions(-) create mode 100644 libs/partners/google-genai/langchain_google_genai/_function_utils.py diff --git a/libs/partners/google-genai/langchain_google_genai/_function_utils.py b/libs/partners/google-genai/langchain_google_genai/_function_utils.py new file mode 100644 index 0000000000000..665987c352d46 --- /dev/null +++ b/libs/partners/google-genai/langchain_google_genai/_function_utils.py @@ -0,0 +1,135 @@ +from __future__ import annotations + +from typing import ( + Dict, + List, + Type, + Union, +) + +from langchain_core.pydantic_v1 import BaseModel +from langchain_core.tools import BaseTool +from langchain_core.utils.json_schema import dereference_refs + +FunctionCallType = Union[BaseTool, Type[BaseModel], Dict] + +TYPE_ENUM = { + "string": 1, + "number": 2, + "integer": 3, + "boolean": 4, + "array": 5, + "object": 6, +} + + +def convert_to_genai_function_declarations( + function_calls: List[FunctionCallType], +) -> Dict: + function_declarations = [] + for fc in function_calls: + function_declarations.append(_convert_to_genai_function(fc)) + return { + "function_declarations": function_declarations, + } + + +def _convert_to_genai_function(fc: FunctionCallType) -> Dict: + """ + Produce + + { + "name": "get_weather", + "description": "Determine weather in my location", + "parameters": { + "properties": { + "location": { + "description": "The city and state e.g. San Francisco, CA", + "type_": 1 + }, + "unit": { "enum": ["c", "f"], "type_": 1 } + }, + "required": ["location"], + "type_": 6 + } + } + + """ + if isinstance(fc, BaseTool): + return _convert_tool_to_genai_function(fc) + elif isinstance(fc, type) and issubclass(fc, BaseModel): + return _convert_pydantic_to_genai_function(fc) + elif isinstance(fc, dict): + return { + **fc, + "parameters": { + "properties": { + k: { + "type_": TYPE_ENUM[v["type"]], + "description": v.get("description"), + } + for k, v in fc["parameters"]["properties"].items() + }, + "required": fc["parameters"].get("required", []), + "type_": TYPE_ENUM[fc["parameters"]["type"]], + }, + } + else: + raise ValueError(f"Unsupported function call type {fc}") + + +def _convert_tool_to_genai_function(tool: BaseTool) -> Dict: + if tool.args_schema: + schema = dereference_refs(tool.args_schema.schema()) + schema.pop("definitions", None) + + return { + "name": tool.name or schema["title"], + "description": tool.description or schema["description"], + "parameters": { + "properties": { + k: { + "type_": TYPE_ENUM[v["type"]], + "description": v.get("description"), + } + for k, v in schema["properties"].items() + }, + "required": schema["required"], + "type_": TYPE_ENUM[schema["type"]], + }, + } + else: + return { + "name": tool.name, + "description": tool.description, + "parameters": { + "properties": { + "__arg1": {"type": "string"}, + }, + "required": ["__arg1"], + "type_": TYPE_ENUM["object"], + }, + } + + +def _convert_pydantic_to_genai_function( + pydantic_model: Type[BaseModel], +) -> Dict: + schema = dereference_refs(pydantic_model.schema()) + schema.pop("definitions", None) + + return { + "name": schema["title"], + "description": schema.get("description", ""), + "parameters": { + "properties": { + k: { + "type_": TYPE_ENUM[v["type"]], + "description": v.get("description"), + } + for k, v in schema["properties"].items() + }, + "required": schema["required"], + "type_": TYPE_ENUM[schema["type"]], + }, + } diff --git a/libs/partners/google-genai/langchain_google_genai/chat_models.py b/libs/partners/google-genai/langchain_google_genai/chat_models.py index 426d279aa0178..2bf9cf8cc3d7c 100644 --- a/libs/partners/google-genai/langchain_google_genai/chat_models.py +++ b/libs/partners/google-genai/langchain_google_genai/chat_models.py @@ -1,6 +1,7 @@ from __future__ import annotations import base64 +import json import logging import os from io import BytesIO @@ -54,6 +55,9 @@ ) from langchain_google_genai._common import GoogleGenerativeAIError +from langchain_google_genai._function_utils import ( + convert_to_genai_function_declarations, +) from langchain_google_genai.llms import GoogleModelFamily, _BaseGoogleGenerativeAI IMAGE_TYPES: Tuple = () @@ -351,69 +355,14 @@ def _retrieve_function_call_response( return { "function_call": { "name": fc.name, - "arguments": dict(fc.args.items()), + "arguments": json.dumps( + dict(fc.args.items()) + ), # dump to match other function calling llms for now } } return None -def _convert_function_call_req(function_calls: Union[Dict, List[Dict]]) -> Dict: - function_declarations = [] - if isinstance(function_calls, dict): - function_declarations.append(_convert_fc_type(function_calls)) - else: - for fc in function_calls: - function_declarations.append(_convert_fc_type(fc)) - return { - "function_declarations": function_declarations, - } - - -def _convert_fc_type(fc: Dict) -> Dict: - # type_: "Type" - # format_: str - # description: str - # nullable: bool - # enum: MutableSequence[str] - # items: "Schema" - # properties: MutableMapping[str, "Schema"] - # required: MutableSequence[str] - if "parameters" in fc: - fc["parameters"] = _convert_fc_type(fc["parameters"]) - if "properties" in fc: - for k, v in fc["properties"].items(): - fc["properties"][k] = _convert_fc_type(v) - if "type" in fc: - # STRING = 1 - # NUMBER = 2 - # INTEGER = 3 - # BOOLEAN = 4 - # ARRAY = 5 - # OBJECT = 6 - if fc["type"] == "string": - fc["type_"] = 1 - elif fc["type"] == "number": - fc["type_"] = 2 - elif fc["type"] == "integer": - fc["type_"] = 3 - elif fc["type"] == "boolean": - fc["type_"] = 4 - elif fc["type"] == "array": - fc["type_"] = 5 - elif fc["type"] == "object": - fc["type_"] = 6 - del fc["type"] - if "format" in fc: - fc["format_"] = fc["format"] - del fc["format"] - - for k, v in fc.items(): - if isinstance(v, dict): - fc[k] = _convert_fc_type(v) - - return fc - - def _parts_to_content( parts: List[genai.types.PartType], ) -> Tuple[Union[str, List[Union[Dict[Any, Any], str]]], Optional[Dict]]: @@ -708,11 +657,11 @@ def _prepare_chat( stop: Optional[List[str]] = None, **kwargs: Any, ) -> Tuple[Dict[str, Any], genai.ChatSession, genai.types.ContentDict]: - cli = self.client + client = self.client functions = kwargs.pop("functions", None) if functions: - tools = _convert_function_call_req(functions) - cli = genai.GenerativeModel(model_name=self.model, tools=tools) + tools = convert_to_genai_function_declarations(functions) + client = genai.GenerativeModel(model_name=self.model, tools=tools) params = self._prepare_params(stop, **kwargs) history = _parse_chat_history( @@ -720,7 +669,7 @@ def _prepare_chat( convert_system_message_to_human=self.convert_system_message_to_human, ) message = history.pop() - chat = cli.start_chat(history=history) + chat = client.start_chat(history=history) return params, chat, message def get_num_tokens(self, text: str) -> int: diff --git a/libs/partners/google-genai/tests/integration_tests/test_function_call.py b/libs/partners/google-genai/tests/integration_tests/test_function_call.py index 7a45bdf66613d..57d0005a3bdc1 100644 --- a/libs/partners/google-genai/tests/integration_tests/test_function_call.py +++ b/libs/partners/google-genai/tests/integration_tests/test_function_call.py @@ -1,5 +1,11 @@ """Test ChatGoogleGenerativeAI function call.""" +import json + +from langchain_core.messages import AIMessage +from langchain_core.pydantic_v1 import BaseModel +from langchain_core.tools import tool + from langchain_google_genai.chat_models import ( ChatGoogleGenerativeAI, ) @@ -29,6 +35,50 @@ def test_function_call() -> None: assert res.additional_kwargs assert "function_call" in res.additional_kwargs assert "get_weather" == res.additional_kwargs["function_call"]["name"] - arguments = res.additional_kwargs["function_call"]["arguments"] - assert isinstance(arguments, dict) + arguments_str = res.additional_kwargs["function_call"]["arguments"] + assert isinstance(arguments_str, str) + arguments = json.loads(arguments_str) assert "location" in arguments + + +def test_tool_call() -> None: + @tool + def search_tool(query: str) -> str: + """Searches the web for `query` and returns the result.""" + raise NotImplementedError + + llm = ChatGoogleGenerativeAI(model="gemini-pro").bind(functions=[search_tool]) + response = llm.invoke("weather in san francisco") + assert isinstance(response, AIMessage) + assert isinstance(response.content, str) + assert response.content == "" + function_call = response.additional_kwargs.get("function_call") + assert function_call + assert function_call["name"] == "search_tool" + arguments_str = function_call.get("arguments") + assert arguments_str + arguments = json.loads(arguments_str) + assert "query" in arguments + + +class MyModel(BaseModel): + name: str + age: int + + +def test_pydantic_call() -> None: + llm = ChatGoogleGenerativeAI(model="gemini-pro").bind(functions=[MyModel]) + response = llm.invoke("my name is Erick and I am 27 years old") + assert isinstance(response, AIMessage) + assert isinstance(response.content, str) + assert response.content == "" + function_call = response.additional_kwargs.get("function_call") + assert function_call + assert function_call["name"] == "MyModel" + arguments_str = function_call.get("arguments") + assert arguments_str + arguments = json.loads(arguments_str) + assert arguments == { + "name": "Erick", + "age": 27.0, + } From 927ab77d6e839d7e12aaab00faa9b527afa4a214 Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 17:14:50 -0800 Subject: [PATCH 19/83] google-genai[patch]: no error for FunctionMessage (#17215) Both should eventually match this: https://github.com/langchain-ai/langchain/blob/master/libs/partners/google-vertexai/langchain_google_vertexai/chat_models.py#L179 But seems undocumented / can't find types in genai package --- .../google-genai/langchain_google_genai/chat_models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/partners/google-genai/langchain_google_genai/chat_models.py b/libs/partners/google-genai/langchain_google_genai/chat_models.py index 2bf9cf8cc3d7c..2f0d35428d58c 100644 --- a/libs/partners/google-genai/langchain_google_genai/chat_models.py +++ b/libs/partners/google-genai/langchain_google_genai/chat_models.py @@ -39,6 +39,7 @@ BaseMessage, ChatMessage, ChatMessageChunk, + FunctionMessage, HumanMessage, HumanMessageChunk, SystemMessage, @@ -326,14 +327,20 @@ def _parse_chat_history( continue elif isinstance(message, AIMessage): role = "model" + # TODO: Handle AImessage with function call + parts = _convert_to_parts(message.content) elif isinstance(message, HumanMessage): role = "user" + parts = _convert_to_parts(message.content) + elif isinstance(message, FunctionMessage): + role = "user" + # TODO: Handle FunctionMessage + parts = _convert_to_parts(message.content) else: raise ValueError( f"Unexpected message with type {type(message)} at the position {i}." ) - parts = _convert_to_parts(message.content) if raw_system_message: if role == "model": raise ValueError( From 41538375027f184cb2ad31e792c95ef19923accc Mon Sep 17 00:00:00 2001 From: Erick Friis Date: Wed, 7 Feb 2024 17:15:09 -0800 Subject: [PATCH 20/83] google-genai[patch]: release 0.0.7 (#17193) --- libs/partners/google-genai/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/partners/google-genai/pyproject.toml b/libs/partners/google-genai/pyproject.toml index 28884a3cbf13f..46e16db696823 100644 --- a/libs/partners/google-genai/pyproject.toml +++ b/libs/partners/google-genai/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langchain-google-genai" -version = "0.0.6.post1" +version = "0.0.7" description = "An integration package connecting Google's genai package and LangChain" authors = [] readme = "README.md" From aeb6b3890171144da3ea262139b9df7dc3f26d8e Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 17:18:48 -0800 Subject: [PATCH 21/83] docs: cleanup fleet integration (#17214) Causing search issues --- .../retrievers/fleet_context.ipynb | 77 +++---------------- 1 file changed, 9 insertions(+), 68 deletions(-) diff --git a/docs/docs/integrations/retrievers/fleet_context.ipynb b/docs/docs/integrations/retrievers/fleet_context.ipynb index 5587fcbc64589..736184a83666d 100644 --- a/docs/docs/integrations/retrievers/fleet_context.ipynb +++ b/docs/docs/integrations/retrievers/fleet_context.ipynb @@ -104,8 +104,7 @@ "source": [ "## Retriever chunks\n", "\n", - "As part of their embedding process, the Fleet AI team first chunked long documents before embedding them. This means the vectors correspond to sections of pages in the LangChain docs, not entire pages. By default, when we spin up a retriever from these embeddings, we'll be retrieving these embedded chunks.", - "\n", + "As part of their embedding process, the Fleet AI team first chunked long documents before embedding them. This means the vectors correspond to sections of pages in the LangChain docs, not entire pages. By default, when we spin up a retriever from these embeddings, we'll be retrieving these embedded chunks.\n", "\n", "We will be using Fleet Context's `download_embeddings()` to grab Langchain's documentation embeddings. You can view all supported libraries' documentation at https://fleet.so/context." ] @@ -125,24 +124,10 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "519c6898-3ef7-4b0d-94e3-e60ac7da51a3", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Document(page_content=\"# Vector store-backed retriever A vector store retriever is a retriever that uses a vector store to retrieve documents. It is a lightweight wrapper around the vector store class to make it conform to the retriever interface. It uses the search methods implemented by a vector store, like similarity search and MMR, to query the texts in the vector store. Once you construct a vector store, it's very easy to construct a retriever. Let's walk through an example.\", metadata={'id': 'f509f20d-4c63-4a5a-a40a-5c4c0f099839', 'library_id': '4506492b-70de-49f1-ba2e-d65bd7048a28', 'page_id': 'd78cf422-2dab-4860-80fe-d71a3619b02f', 'parent': 'c153ebd9-2611-4a43-9db6-daa1f5f214f6', 'section_id': '', 'section_index': 0, 'text': \"# Vector store-backed retriever A vector store retriever is a retriever that uses a vector store to retrieve documents. It is a lightweight wrapper around the vector store class to make it conform to the retriever interface. It uses the search methods implemented by a vector store, like similarity search and MMR, to query the texts in the vector store. Once you construct a vector store, it's very easy to construct a retriever. Let's walk through an example.\", 'title': 'Vector store-backed retriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/vectorstore'}),\n", - " Document(page_content='# MultiVector Retriever It can often be beneficial to store multiple vectors per document. There are multiple use cases where this is beneficial. LangChain has a base `MultiVectorRetriever` which makes querying this type of setup easy. A lot of the complexity lies in how to create the multiple vectors per document. This notebook covers some of the common ways to create those vectors and use the `MultiVectorRetriever`. The methods to create multiple vectors per document include: - Smaller chunks: split a document into smaller chunks, and embed those (this is ParentDocumentRetriever). - Summary: create a summary for each document, embed that along with (or instead of) the document. - Hypothetical questions: create hypothetical questions that each document would be appropriate to answer, embed those along with (or instead of) the document. Note that this also enables another method of adding embeddings - manually.', metadata={'id': 'e06e6bb5-127a-49f7-9511-247d279d0d83', 'library_id': '4506492b-70de-49f1-ba2e-d65bd7048a28', 'page_id': '7c7dd0de-25e0-4e1d-9237-cfd2674c29d4', 'parent': 'beec5531-16a7-453c-80ab-c5628e0236ce', 'section_id': '', 'section_index': 0, 'text': '# MultiVector Retriever It can often be beneficial to store multiple vectors per document. There are multiple use cases where this is beneficial. LangChain has a base `MultiVectorRetriever` which makes querying this type of setup easy. A lot of the complexity lies in how to create the multiple vectors per document. This notebook covers some of the common ways to create those vectors and use the `MultiVectorRetriever`. The methods to create multiple vectors per document include: - Smaller chunks: split a document into smaller chunks, and embed those (this is ParentDocumentRetriever). - Summary: create a summary for each document, embed that along with (or instead of) the document. - Hypothetical questions: create hypothetical questions that each document would be appropriate to answer, embed those along with (or instead of) the document. Note that this also enables another method of adding embeddings - manually.', 'title': 'MultiVector Retriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector'}),\n", - " Document(page_content='# MultiQueryRetriever Distance-based vector database retrieval embeds (represents) queries in high-dimensional space and finds similar embedded documents based on \"distance\". But, retrieval may produce different results with subtle changes in query wording or if the embeddings do not capture the semantics of the data well. Prompt engineering / tuning is sometimes done to manually address these problems, but can be tedious. The `MultiQueryRetriever` automates the process of prompt tuning by using an LLM to generate multiple queries from different perspectives for a given user input query. For each query, it retrieves a set of relevant documents and takes the unique union across all queries to get a larger set of potentially relevant documents. By generating multiple perspectives on the same question, the `MultiQueryRetriever` might be able to overcome some of the limitations of the distance-based retrieval and get a richer set of results.', metadata={'id': 'dc3b8e5b-a591-4a46-bfeb-a91b36affae1', 'library_id': '4506492b-70de-49f1-ba2e-d65bd7048a28', 'page_id': '31f80e84-c5db-4da2-939c-bccf519864a3', 'parent': 'f7c20633-6a60-4ca3-96b1-13fee66e321d', 'section_id': '', 'section_index': 0, 'text': '# MultiQueryRetriever Distance-based vector database retrieval embeds (represents) queries in high-dimensional space and finds similar embedded documents based on \"distance\". But, retrieval may produce different results with subtle changes in query wording or if the embeddings do not capture the semantics of the data well. Prompt engineering / tuning is sometimes done to manually address these problems, but can be tedious. The `MultiQueryRetriever` automates the process of prompt tuning by using an LLM to generate multiple queries from different perspectives for a given user input query. For each query, it retrieves a set of relevant documents and takes the unique union across all queries to get a larger set of potentially relevant documents. By generating multiple perspectives on the same question, the `MultiQueryRetriever` might be able to overcome some of the limitations of the distance-based retrieval and get a richer set of results.', 'title': 'MultiQueryRetriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever'}),\n", - " Document(page_content='# `langchain.retrievers.multi_vector`.MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) *class *langchain.retrievers.multi_vector.MultiVectorRetriever[[source]](../_modules/langchain/retrievers/multi_vector.html#MultiVectorRetriever)[¶](#langchain.retrievers.multi_vector.MultiVectorRetriever) # Examples using MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) - [MultiVector Retriever](https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector)', metadata={'id': '1f4ca702-35b8-44c0-b33b-18c09a1f787d', 'library_id': '6254c672-7aa0-4233-b0a6-804bd273752b', 'page_id': '87f5d1fb-a1c6-4080-9d2b-7b88794eb6bf', 'parent': '1820c44d-7783-4846-a11c-106b18da015d', 'section_id': 'langchain-retrievers-multi-vector-multivectorretriever', 'section_index': 0, 'text': '# `langchain.retrievers.multi_vector`.MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) *class *langchain.retrievers.multi_vector.MultiVectorRetriever[[source]](../_modules/langchain/retrievers/multi_vector.html#MultiVectorRetriever)[¶](#langchain.retrievers.multi_vector.MultiVectorRetriever) # Examples using MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) - [MultiVector Retriever](https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector)', 'title': 'langchain.retrievers.multi_vector.MultiVectorRetriever — 🦜🔗 LangChain 0.0.322', 'type': None, 'url': 'https://api.python.langchain.com/en/latest/retrievers/langchain.retrievers.multi_vector.MultiVectorRetriever.html#langchain-retrievers-multi-vector-multivectorretriever'})]" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "vecstore_retriever.get_relevant_documents(\"How does the multi vector retriever work\")" ] @@ -184,24 +169,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "540a54c2-b9a0-475c-ada0-91c5f67dd0fa", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[Document(page_content='Vector store-backed retriever | 🦜️🔗 Langchain\\n# Vector store-backed retriever A vector store retriever is a retriever that uses a vector store to retrieve documents. It is a lightweight wrapper around the vector store class to make it conform to the retriever interface. It uses the search methods implemented by a vector store, like similarity search and MMR, to query the texts in the vector store. Once you construct a vector store, it\\'s very easy to construct a retriever. Let\\'s walk through an example.Once you construct a vector store, it\\'s very easy to construct a retriever. Let\\'s walk through an example. ``` from langchain_community.document_loaders import TextLoaderloader = TextLoader(\\'../../../state_of_the_union.txt\\') ``` ``` from langchain.text_splitter import CharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_openai import OpenAIEmbeddingsdocuments = loader.load()text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)texts = text_splitter.split_documents(documents)embeddings = OpenAIEmbeddings()db = FAISS.from_documents(texts, embeddings) ``` ``` Exiting: Cleaning up .chroma directory ``` ``` retriever = db.as_retriever() ``` ``` docs = retriever.get_relevant_documents(\"what did he say about ketanji brown jackson\") ``` ## Maximum marginal relevance retrieval[\\u200b](#maximum-marginal-relevance-retrieval) By default, the vector store retriever uses similarity search.If the underlying vector store supports maximum marginal relevance search, you can specify that as the search type. ``` retriever = db.as_retriever(search_type=\"mmr\") ``` ``` docs = retriever.get_relevant_documents(\"what did he say about ketanji brown jackson\") ``` ## Similarity score threshold retrieval[\\u200b](#similarity-score-threshold-retrieval) You can also a retrieval method that sets a similarity score threshold and only returns documents with a score above that threshold. ``` retriever = db.as_retriever(search_type=\"similarity_score_threshold\", search_kwargs={\"score_threshold\": .5}) ``` ``` docs = retriever.get_relevant_documents(\"what did he say about ketanji brown jackson\") ``` ## Specifying top k[\\u200b](#specifying-top-k) You can also specify search kwargs like `k` to use when doing retrieval.``` retriever = db.as_retriever(search_kwargs={\"k\": 1}) ``` ``` docs = retriever.get_relevant_documents(\"what did he say about ketanji brown jackson\") ``` ``` len(docs) ``` ``` 1 ```', metadata={'title': 'Vector store-backed retriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/vectorstore', 'id': 'c153ebd9-2611-4a43-9db6-daa1f5f214f6'}),\n", - " Document(page_content='MultiVector Retriever | 🦜️🔗 Langchain\\n# MultiVector Retriever It can often be beneficial to store multiple vectors per document. There are multiple use cases where this is beneficial. LangChain has a base `MultiVectorRetriever` which makes querying this type of setup easy. A lot of the complexity lies in how to create the multiple vectors per document. This notebook covers some of the common ways to create those vectors and use the `MultiVectorRetriever`. The methods to create multiple vectors per document include: - Smaller chunks: split a document into smaller chunks, and embed those (this is ParentDocumentRetriever). - Summary: create a summary for each document, embed that along with (or instead of) the document. - Hypothetical questions: create hypothetical questions that each document would be appropriate to answer, embed those along with (or instead of) the document. Note that this also enables another method of adding embeddings - manually.Note that this also enables another method of adding embeddings - manually. This is great because you can explicitly add questions or queries that should lead to a document being recovered, giving you more control. ``` from langchain.retrievers.multi_vector import MultiVectorRetriever ``` ``` from langchain_community.vectorstores import Chromafrom langchain_openai import OpenAIEmbeddingsfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain.storage import InMemoryStorefrom langchain_community.document_loaders import TextLoader ``` ``` loaders = [ TextLoader(\\'../../paul_graham_essay.txt\\'), TextLoader(\\'../../state_of_the_union.txt\\'),]docs = []for l in loaders: docs.extend(l.load())text_splitter = RecursiveCharacterTextSplitter(chunk_size=10000)docs = text_splitter.split_documents(docs) ``` ## Smaller chunks[\\u200b](#smaller-chunks) Often times it can be useful to retrieve larger chunks of information, but embed smaller chunks.This allows for embeddings to capture the semantic meaning as closely as possible, but for as much context as possible to be passed downstream. Note that this is what the `ParentDocumentRetriever` does. Here we show what is going on under the hood.``` # The vectorstore to use to index the child chunksvectorstore = Chroma( collection_name=\"full_documents\", embedding_function=OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()id_key = \"doc_id\"# The retriever (empty to start)retriever = MultiVectorRetriever( vectorstore=vectorstore, docstore=store, id_key=id_key,)import uuiddoc_ids = [str(uuid.uuid4()) for _ in docs] ``` ``` # The splitter to use to create smaller chunkschild_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400) ``` ``` sub_docs = []for i, doc in enumerate(docs): _id = doc_ids[i] _sub_docs = child_text_splitter.split_documents([doc]) for _doc in _sub_docs: _doc.metadata[id_key] = _id sub_docs.extend(_sub_docs) ``` ``` retriever.vectorstore.add_documents(sub_docs)retriever.docstore.mset(list(zip(doc_ids, docs))) ``` ``` # Vectorstore alone retrieves the small chunksretriever.vectorstore.similarity_search(\"justice breyer\")[0] ``` ``` Document(page_content=\\'Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court.Justice Breyer, thank you for your service. \\\\n\\\\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \\', metadata={\\'doc_id\\': \\'10e9cbc0-4ba5-4d79-a09b-c033d1ba7b01\\', \\'source\\': \\'../../state_of_the_union.txt\\'}) ``` ``` # Retriever returns larger chunkslen(retriever.get_relevant_documents(\"justice breyer\")[0].page_content) ``` ``` 9874 ``` ## Summary[\\u200b](#summary) Oftentimes a summary may be able to distill more accurately what a chunk is about, leading to better retrieval. Here we show how to create summaries, and then embed those.``` from langchain_openai import ChatOpenAIfrom langchain_core.prompts import ChatPromptTemplatefrom langchain_core.output_parsers import StrOutputParserimport uuidfrom langchain_core.documents import Document ``` ``` chain = ( {\"doc\": lambda x: x.page_content} | ChatPromptTemplate.from_template(\"Summarize the following document:\\\\n\\\\n{doc}\") | ChatOpenAI(max_retries=0) | StrOutputParser()) ``` ``` summaries = chain.batch(docs, {\"max_concurrency\": 5}) ``` ``` # The vectorstore to use to index the child chunksvectorstore = Chroma( collection_name=\"summaries\", embedding_function=OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()id_key = \"doc_id\"# The retriever (empty to start)retriever = MultiVectorRetriever( vectorstore=vectorstore, docstore=store, id_key=id_key,)doc_ids = [str(uuid.uuid4()) for _ in docs] ``` ``` summary_docs = [Document(page_content=s,metadata={id_key: doc_ids[i]}) for i, s in enumerate(summaries)] ``` ``` retriever.vectorstore.add_documents(summary_docs)retriever.docstore.mset(list(zip(doc_ids, docs))) ``` ``` # # We can also add the original chunks to the vectorstore if we so want# for i, doc in enumerate(docs):# doc.metadata[id_key] = doc_ids[i]# retriever.vectorstore.add_documents(docs) ``` ``` sub_docs = vectorstore.similarity_search(\"justice breyer\") ``` ``` sub_docs[0] ``` ``` Document(page_content=\"The document is a transcript of a speech given by the President of the United States.The President discusses several important issues and initiatives, including the nomination of a Supreme Court Justice, border security and immigration reform, protecting women\\'s rights, advancing LGBTQ+ equality, bipartisan legislation, addressing the opioid epidemic and mental health, supporting veterans, investigating the health effects of burn pits on military personnel, ending cancer, and the strength and resilience of the American people. \", metadata={\\'doc_id\\': \\'79fa2e9f-28d9-4372-8af3-2caf4f1de312\\'}) ``` ``` retrieved_docs = retriever.get_relevant_documents(\"justice breyer\") ``` ``` len(retrieved_docs[0].page_content) ``` ``` 9194 ``` ## Hypothetical Queries[\\u200b](#hypothetical-queries) An LLM can also be used to generate a list of hypothetical questions that could be asked of a particular document.These questions can then be embedded ``` functions = [ { \"name\": \"hypothetical_questions\", \"description\": \"Generate hypothetical questions\", \"parameters\": { \"type\": \"object\", \"properties\": { \"questions\": { \"type\": \"array\", \"items\": { \"type\": \"string\" }, }, }, \"required\": [\"questions\"] } } ] ``` ``` from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParserchain = ( {\"doc\": lambda x: x.page_content} # Only asking for 3 hypothetical questions, but this could be adjusted | ChatPromptTemplate.from_template(\"Generate a list of 3 hypothetical questions that the below document could be used to answer:\\\\n\\\\n{doc}\") | ChatOpenAI(max_retries=0, model=\"gpt-4\").bind(functions=functions, function_call={\"name\": \"hypothetical_questions\"}) | JsonKeyOutputFunctionsParser(key_name=\"questions\")) ``` ``` chain.invoke(docs[0]) ``` ``` [\"What was the author\\'s initial impression of philosophy as a field of study, and how did it change when they got to college?\", \\'Why did the author decide to switch their focus to Artificial Intelligence (AI)? \\', \"What led to the author\\'s disillusionment with the field of AI as it was practiced at the time?\"]``` ``` hypothetical_questions = chain.batch(docs, {\"max_concurrency\": 5}) ``` ``` # The vectorstore to use to index the child chunksvectorstore = Chroma( collection_name=\"hypo-questions\", embedding_function=OpenAIEmbeddings())# The storage layer for the parent documentsstore = InMemoryStore()id_key = \"doc_id\"# The retriever (empty to start)retriever = MultiVectorRetriever( vectorstore=vectorstore, docstore=store, id_key=id_key,)doc_ids = [str(uuid.uuid4()) for _ in docs] ``` ``` question_docs = []for i, question_list in enumerate(hypothetical_questions): question_docs.extend([Document(page_content=s,metadata={id_key: doc_ids[i]}) for s in question_list]) ``` ``` retriever.vectorstore.add_documents(question_docs)retriever.docstore.mset(list(zip(doc_ids, docs))) ``` ``` sub_docs = vectorstore.similarity_search(\"justice breyer\") ``` ``` sub_docs ``` ``` [Document(page_content=\"What is the President\\'s stance on immigration reform?\", metadata={\\'doc_id\\': \\'505d73e3-8350-46ec-a58e-3af032f04ab3\\'}), Document(page_content=\"What is the President\\'s stance on immigration reform? \", metadata={\\'doc_id\\': \\'1c9618f0-7660-4b4f-a37c-509cbbbf6dba\\'}), Document(page_content=\"What is the President\\'s stance on immigration reform? \", metadata={\\'doc_id\\': \\'82c08209-b904-46a8-9532-edd2380950b7\\'}), Document(page_content=\\'What measures is the President proposing to protect the rights of LGBTQ+ Americans? \\', metadata={\\'doc_id\\': \\'82c08209-b904-46a8-9532-edd2380950b7\\'})] ``` ``` retrieved_docs = retriever.get_relevant_documents(\"justice breyer\") ``` ``` len(retrieved_docs[0].page_content) ``` ``` 9194 ```', metadata={'title': 'MultiVector Retriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector', 'id': 'beec5531-16a7-453c-80ab-c5628e0236ce'}),\n", - " Document(page_content='MultiQueryRetriever | 🦜️🔗 Langchain\\n# MultiQueryRetriever Distance-based vector database retrieval embeds (represents) queries in high-dimensional space and finds similar embedded documents based on \"distance\". But, retrieval may produce different results with subtle changes in query wording or if the embeddings do not capture the semantics of the data well. Prompt engineering / tuning is sometimes done to manually address these problems, but can be tedious. The `MultiQueryRetriever` automates the process of prompt tuning by using an LLM to generate multiple queries from different perspectives for a given user input query. For each query, it retrieves a set of relevant documents and takes the unique union across all queries to get a larger set of potentially relevant documents. By generating multiple perspectives on the same question, the `MultiQueryRetriever` might be able to overcome some of the limitations of the distance-based retrieval and get a richer set of results.By generating multiple perspectives on the same question, the `MultiQueryRetriever` might be able to overcome some of the limitations of the distance-based retrieval and get a richer set of results. ``` # Build a sample vectorDBfrom langchain_community.vectorstores import Chromafrom langchain_community.document_loaders import WebBaseLoaderfrom langchain_openai import OpenAIEmbeddingsfrom langchain.text_splitter import RecursiveCharacterTextSplitter# Load blog postloader = WebBaseLoader(\"https://lilianweng.github.io/posts/2023-06-23-agent/\")data = loader.load()# Splittext_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)splits = text_splitter.split_documents(data)# VectorDBembedding = OpenAIEmbeddings()vectordb = Chroma.from_documents(documents=splits, embedding=embedding) ``` #### Simple usage[\\u200b](#simple-usage) Specify the LLM to use for query generation, and the retriever will do the rest.``` from langchain_openai import ChatOpenAIfrom langchain.retrievers.multi_query import MultiQueryRetrieverquestion = \"What are the approaches to Task Decomposition? \"llm = ChatOpenAI(temperature=0)retriever_from_llm = MultiQueryRetriever.from_llm( retriever=vectordb.as_retriever(), llm=llm) ``` ``` # Set logging for the queriesimport logginglogging.basicConfig()logging.getLogger(\"langchain.retrievers.multi_query\").setLevel(logging.INFO) ``` ``` unique_docs = retriever_from_llm.get_relevant_documents(query=question)len(unique_docs) ``` ``` INFO:langchain.retrievers.multi_query:Generated queries: [\\'1. How can Task Decomposition be approached? \\', \\'2. What are the different methods for Task Decomposition? \\', \\'3. What are the various approaches to decomposing tasks?\\'] 5 ``` #### Supplying your own prompt[\\u200b](#supplying-your-own-prompt) You can also supply a prompt along with an output parser to split the results into a list of queries.5 ``` #### Supplying your own prompt[\\u200b](#supplying-your-own-prompt) You can also supply a prompt along with an output parser to split the results into a list of queries. ``` from typing import Listfrom langchain.chains import LLMChainfrom pydantic import BaseModel, Fieldfrom langchain.prompts import PromptTemplatefrom langchain.output_parsers import PydanticOutputParser# Output parser will split the LLM result into a list of queriesclass LineList(BaseModel): # \"lines\" is the key (attribute name) of the parsed output lines: List[str] = Field(description=\"Lines of text\")class LineListOutputParser(PydanticOutputParser): def __init__(self) -> None: super().__init__(pydantic_object=LineList) def parse(self, text: str) -> LineList: lines = text.strip().split(\"\\\\n\") return LineList(lines=lines)output_parser = LineListOutputParser()QUERY_PROMPT = PromptTemplate( input_variables=[\"question\"], template=\"\"\"You are an AI language model assistant.Your task is to generate five different versions of the given user question to retrieve relevant documents from a vector database. By generating multiple perspectives on the user question, your goal is to help the user overcome some of the limitations of the distance-based similarity search. Provide these alternative questions separated by newlines. Original question: {question}\"\"\",)llm = ChatOpenAI(temperature=0)# Chainllm_chain = LLMChain(llm=llm, prompt=QUERY_PROMPT, output_parser=output_parser)# Other inputsquestion = \"What are the approaches to Task Decomposition?\" ``` ``` # Runretriever = MultiQueryRetriever( retriever=vectordb.as_retriever(), llm_chain=llm_chain, parser_key=\"lines\") # \"lines\" is the key (attribute name) of the parsed output# Resultsunique_docs = retriever.get_relevant_documents( query=\"What does the course say about regression? \")len(unique_docs) ``` ``` INFO:langchain.retrievers.multi_query:Generated queries: [\"1.\")len(unique_docs) ``` ``` INFO:langchain.retrievers.multi_query:Generated queries: [\"1. What is the course\\'s perspective on regression? \", \\'2. Can you provide information on regression as discussed in the course? \\', \\'3. How does the course cover the topic of regression? \\', \"4. What are the course\\'s teachings on regression? \", \\'5. In relation to the course, what is mentioned about regression?\\'] 11 ```', metadata={'title': 'MultiQueryRetriever | 🦜️🔗 Langchain', 'type': None, 'url': 'https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever', 'id': 'f7c20633-6a60-4ca3-96b1-13fee66e321d'}),\n", - " Document(page_content='langchain.retrievers.multi_vector.MultiVectorRetriever — 🦜🔗 LangChain 0.0.322\\n# `langchain.retrievers.multi_vector`.MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) *class *langchain.retrievers.multi_vector.MultiVectorRetriever[[source]](../_modules/langchain/retrievers/multi_vector.html#MultiVectorRetriever)[¶](#langchain.retrievers.multi_vector.MultiVectorRetriever) # Examples using MultiVectorRetriever[¶](#langchain-retrievers-multi-vector-multivectorretriever) - [MultiVector Retriever](https://python.langchain.com/docs/modules/data_connection/retrievers/multi_vector)', metadata={'title': 'langchain.retrievers.multi_vector.MultiVectorRetriever — 🦜🔗 LangChain 0.0.322', 'type': None, 'url': 'https://api.python.langchain.com/en/latest/retrievers/langchain.retrievers.multi_vector.MultiVectorRetriever.html#langchain-retrievers-multi-vector-multivectorretriever', 'id': '1820c44d-7783-4846-a11c-106b18da015d'})]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "parent_retriever.get_relevant_documents(\"How does the multi vector retriever work\")" ] @@ -264,40 +235,10 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "f1b9f091-a5f9-4468-9d52-633bf3361f4e", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "To create a FAISS vector store retriever that returns 10 documents per search query, you can use the following code:\n", - "\n", - "```python\n", - "from langchain_openai import OpenAIEmbeddings\n", - "from langchain_community.vectorstores import FAISS\n", - "\n", - "# Assuming you have already loaded and split your documents\n", - "# into `texts` and initialized your `embeddings` object\n", - "\n", - "# Create the FAISS vector store\n", - "db = FAISS.from_documents(texts, embeddings)\n", - "\n", - "# Create the retriever with the desired search kwargs\n", - "retriever = db.as_retriever(search_kwargs={\"k\": 10})\n", - "```\n", - "\n", - "Now, you can use the `retriever` object to get relevant documents using the `get_relevant_documents` method. For example:\n", - "\n", - "```python\n", - "docs = retriever.get_relevant_documents(\"your search query\")\n", - "```\n", - "\n", - "This will return a list of 10 documents that are most relevant to the given search query." - ] - } - ], + "outputs": [], "source": [ "for chunk in chain.invoke(\n", " \"How do I create a FAISS vector store retriever that returns 10 documents per search query\"\n", @@ -308,9 +249,9 @@ ], "metadata": { "kernelspec": { - "display_name": "poetry-venv", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "poetry-venv" + "name": "python3" }, "language_info": { "codemirror_mode": { From 19546081c63bf0590ae32631a04f8cfec7d23fb3 Mon Sep 17 00:00:00 2001 From: Harrison Chase Date: Wed, 7 Feb 2024 17:27:01 -0800 Subject: [PATCH 22/83] templates: add gemini functions agent (#17141) Co-authored-by: Erick Friis --- templates/gemini-functions-agent/LICENSE | 21 + templates/gemini-functions-agent/README.md | 76 + .../gemini_functions_agent/__init__.py | 3 + .../gemini_functions_agent/agent.py | 81 + templates/gemini-functions-agent/main.py | 5 + templates/gemini-functions-agent/poetry.lock | 2002 +++++++++++++++++ .../gemini-functions-agent/pyproject.toml | 33 + .../gemini-functions-agent/tests/__init__.py | 0 8 files changed, 2221 insertions(+) create mode 100644 templates/gemini-functions-agent/LICENSE create mode 100644 templates/gemini-functions-agent/README.md create mode 100644 templates/gemini-functions-agent/gemini_functions_agent/__init__.py create mode 100644 templates/gemini-functions-agent/gemini_functions_agent/agent.py create mode 100644 templates/gemini-functions-agent/main.py create mode 100644 templates/gemini-functions-agent/poetry.lock create mode 100644 templates/gemini-functions-agent/pyproject.toml create mode 100644 templates/gemini-functions-agent/tests/__init__.py diff --git a/templates/gemini-functions-agent/LICENSE b/templates/gemini-functions-agent/LICENSE new file mode 100644 index 0000000000000..426b65090341f --- /dev/null +++ b/templates/gemini-functions-agent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/templates/gemini-functions-agent/README.md b/templates/gemini-functions-agent/README.md new file mode 100644 index 0000000000000..16935c6298eaa --- /dev/null +++ b/templates/gemini-functions-agent/README.md @@ -0,0 +1,76 @@ + +# gemini-functions-agent + +This template creates an agent that uses Google Gemini function calling to communicate its decisions on what actions to take. + +This example creates an agent that can optionally look up information on the internet using Tavily's search engine. + +## Environment Setup + +The following environment variables need to be set: + +Set the `TAVILY_API_KEY` environment variable to access Tavily. + +You will also need to authenticate with Google: + +```shell +gcloud auth application-default login +``` + +## Usage + +To use this package, you should first have the LangChain CLI installed: + +```shell +pip install -U langchain-cli +``` + +To create a new LangChain project and install this as the only package, you can do: + +```shell +langchain app new my-app --package gemini-functions-agent +``` + +If you want to add this to an existing project, you can just run: + +```shell +langchain app add gemini-functions-agent +``` + +And add the following code to your `server.py` file: +```python +from gemini_functions_agent import agent_executor as gemini_functions_agent_chain + +add_routes(app, gemini_functions_agent_chain, path="/openai-functions-agent") +``` + +(Optional) Let's now configure LangSmith. +LangSmith will help us trace, monitor and debug LangChain applications. +LangSmith is currently in private beta, you can sign up [here](https://smith.langchain.com/). +If you don't have access, you can skip this section + +```shell +export LANGCHAIN_TRACING_V2=true +export LANGCHAIN_API_KEY= +export LANGCHAIN_PROJECT= # if not specified, defaults to "default" +``` + +If you are inside this directory, then you can spin up a LangServe instance directly by: + +```shell +langchain serve +``` + +This will start the FastAPI app with a server is running locally at +[http://localhost:8000](http://localhost:8000) + +We can see all templates at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) +We can access the playground at [http://127.0.0.1:8000/gemini-functions-agent/playground](http://127.0.0.1:8000/gemini-functions-agent/playground) + +We can access the template from code with: + +```python +from langserve.client import RemoteRunnable + +runnable = RemoteRunnable("http://localhost:8000/gemini-functions-agent") +``` \ No newline at end of file diff --git a/templates/gemini-functions-agent/gemini_functions_agent/__init__.py b/templates/gemini-functions-agent/gemini_functions_agent/__init__.py new file mode 100644 index 0000000000000..da6719519020f --- /dev/null +++ b/templates/gemini-functions-agent/gemini_functions_agent/__init__.py @@ -0,0 +1,3 @@ +from gemini_functions_agent.agent import agent_executor + +__all__ = ["agent_executor"] diff --git a/templates/gemini-functions-agent/gemini_functions_agent/agent.py b/templates/gemini-functions-agent/gemini_functions_agent/agent.py new file mode 100644 index 0000000000000..79aba8a9445bb --- /dev/null +++ b/templates/gemini-functions-agent/gemini_functions_agent/agent.py @@ -0,0 +1,81 @@ +from typing import List, Tuple + +from langchain.agents import AgentExecutor +from langchain.agents.format_scratchpad import format_to_openai_function_messages +from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser +from langchain.utilities.tavily_search import TavilySearchAPIWrapper +from langchain_community.tools.tavily_search import TavilySearchResults +from langchain_core.messages import AIMessage, HumanMessage +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain_core.pydantic_v1 import BaseModel, Field +from langchain_google_genai import ChatGoogleGenerativeAI + +# Create the tool +search = TavilySearchAPIWrapper() +description = """"A search engine optimized for comprehensive, accurate, \ +and trusted results. Useful for when you need to answer questions \ +about current events or about recent information. \ +Input should be a search query. \ +If the user is asking about something that you don't know about, \ +you should probably use this tool to see if that can provide any information.""" +tavily_tool = TavilySearchResults(api_wrapper=search, description=description) + +tools = [tavily_tool] + +llm = ChatGoogleGenerativeAI(temperature=0, model="gemini-pro") + +prompt = ChatPromptTemplate.from_messages( + [ + MessagesPlaceholder(variable_name="chat_history"), + ("user", "{input}"), + MessagesPlaceholder(variable_name="agent_scratchpad"), + ] +) + +llm_with_tools = llm.bind( + functions=[ + { + "name": tavily_tool.name, + "description": tavily_tool.description, + "parameters": { + "type": "object", + "properties": {"query": {"type": "string"}}, + "required": ["query"], + }, + } + ] +) + + +def _format_chat_history(chat_history: List[Tuple[str, str]]): + buffer = [] + for human, ai in chat_history: + buffer.append(HumanMessage(content=human)) + buffer.append(AIMessage(content=ai)) + return buffer + + +agent = ( + { + "input": lambda x: x["input"], + "chat_history": lambda x: _format_chat_history(x["chat_history"]), + "agent_scratchpad": lambda x: format_to_openai_function_messages( + x["intermediate_steps"] + ), + } + | prompt + | llm_with_tools + | OpenAIFunctionsAgentOutputParser() +) + + +class AgentInput(BaseModel): + input: str + chat_history: List[Tuple[str, str]] = Field( + ..., extra={"widget": {"type": "chat", "input": "input", "output": "output"}} + ) + + +agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True).with_types( + input_type=AgentInput +) diff --git a/templates/gemini-functions-agent/main.py b/templates/gemini-functions-agent/main.py new file mode 100644 index 0000000000000..f0e1f5963f9e6 --- /dev/null +++ b/templates/gemini-functions-agent/main.py @@ -0,0 +1,5 @@ +from openai_functions_agent.agent import agent_executor + +if __name__ == "__main__": + question = "who won the womens world cup in 2023?" + print(agent_executor.invoke({"input": question, "chat_history": []})) diff --git a/templates/gemini-functions-agent/poetry.lock b/templates/gemini-functions-agent/poetry.lock new file mode 100644 index 0000000000000..17c00ed6251b0 --- /dev/null +++ b/templates/gemini-functions-agent/poetry.lock @@ -0,0 +1,2002 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "aiohttp" +version = "3.9.3" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, + {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, + {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, + {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, + {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, +] + +[package.dependencies] +aiosignal = ">=1.1.2" +async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "async-timeout" +version = "4.0.3" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, +] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "cachetools" +version = "5.3.2" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, +] + +[[package]] +name = "certifi" +version = "2024.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "dataclasses-json" +version = "0.6.4" +description = "Easily serialize dataclasses to and from JSON." +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dataclasses_json-0.6.4-py3-none-any.whl", hash = "sha256:f90578b8a3177f7552f4e1a6e535e84293cd5da421fcce0642d49c0d7bdf8df2"}, + {file = "dataclasses_json-0.6.4.tar.gz", hash = "sha256:73696ebf24936560cca79a2430cbc4f3dd23ac7bf46ed17f38e5e5e7657a6377"}, +] + +[package.dependencies] +marshmallow = ">=3.18.0,<4.0.0" +typing-inspect = ">=0.4.0,<1" + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.109.2" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"}, + {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.36.3,<0.37.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "frozenlist" +version = "1.4.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, + {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, + {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, + {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, + {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, + {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, + {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, + {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, + {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, + {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, + {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, + {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, + {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, + {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, + {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, + {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, + {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, + {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, + {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, + {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, + {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, + {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, + {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, + {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, + {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, + {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, + {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, + {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, +] + +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.41" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.41-py3-none-any.whl", hash = "sha256:c36b6634d069b3f719610175020a9aed919421c87552185b085e04fbbdb10b7c"}, + {file = "GitPython-3.1.41.tar.gz", hash = "sha256:ed66e624884f76df22c8e16066d567aaa5a37d5b5fa19db2c6df6f7156db9048"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "sumtypes"] + +[[package]] +name = "google-ai-generativelanguage" +version = "0.4.0" +description = "Google Ai Generativelanguage API client library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-ai-generativelanguage-0.4.0.tar.gz", hash = "sha256:c8199066c08f74c4e91290778329bb9f357ba1ea5d6f82de2bc0d10552bf4f8c"}, + {file = "google_ai_generativelanguage-0.4.0-py3-none-any.whl", hash = "sha256:e4c425376c1ee26c78acbc49a24f735f90ebfa81bf1a06495fae509a2433232c"}, +] + +[package.dependencies] +google-api-core = {version = ">=1.34.0,<2.0.dev0 || >=2.11.dev0,<3.0.0dev", extras = ["grpc"]} +proto-plus = ">=1.22.3,<2.0.0dev" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0dev" + +[[package]] +name = "google-api-core" +version = "2.16.2" +description = "Google API client core library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-api-core-2.16.2.tar.gz", hash = "sha256:032d37b45d1d6bdaf68fb11ff621e2593263a239fa9246e2e94325f9c47876d2"}, + {file = "google_api_core-2.16.2-py3-none-any.whl", hash = "sha256:449ca0e3f14c179b4165b664256066c7861610f70b6ffe54bb01a04e9b466929"}, +] + +[package.dependencies] +google-auth = ">=2.14.1,<3.0.dev0" +googleapis-common-protos = ">=1.56.2,<2.0.dev0" +grpcio = [ + {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0dev", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, +] +grpcio-status = [ + {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}, + {version = ">=1.33.2,<2.0.dev0", optional = true, markers = "python_version < \"3.11\" and extra == \"grpc\""}, +] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +requests = ">=2.18.0,<3.0.0.dev0" + +[package.extras] +grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio (>=1.49.1,<2.0dev)", "grpcio-status (>=1.33.2,<2.0.dev0)", "grpcio-status (>=1.49.1,<2.0.dev0)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] + +[[package]] +name = "google-auth" +version = "2.27.0" +description = "Google Authentication Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "google-auth-2.27.0.tar.gz", hash = "sha256:e863a56ccc2d8efa83df7a80272601e43487fa9a728a376205c86c26aaefa821"}, + {file = "google_auth-2.27.0-py2.py3-none-any.whl", hash = "sha256:8e4bad367015430ff253fe49d500fdc3396c1a434db5740828c728e45bcce245"}, +] + +[package.dependencies] +cachetools = ">=2.0.0,<6.0" +pyasn1-modules = ">=0.2.1" +rsa = ">=3.1.4,<5" + +[package.extras] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] +enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] +reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0.dev0)"] + +[[package]] +name = "google-generativeai" +version = "0.3.2" +description = "Google Generative AI High level API client library and tools." +optional = false +python-versions = ">=3.9" +files = [ + {file = "google_generativeai-0.3.2-py3-none-any.whl", hash = "sha256:8761147e6e167141932dc14a7b7af08f2310dd56668a78d206c19bb8bd85bcd7"}, +] + +[package.dependencies] +google-ai-generativelanguage = "0.4.0" +google-api-core = "*" +google-auth = "*" +protobuf = "*" +tqdm = "*" +typing-extensions = "*" + +[package.extras] +dev = ["Pillow", "absl-py", "black", "ipython", "nose2", "pandas", "pytype", "pyyaml"] + +[[package]] +name = "googleapis-common-protos" +version = "1.62.0" +description = "Common protobufs used in Google APIs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "googleapis-common-protos-1.62.0.tar.gz", hash = "sha256:83f0ece9f94e5672cced82f592d2a5edf527a96ed1794f0bab36d5735c996277"}, + {file = "googleapis_common_protos-1.62.0-py2.py3-none-any.whl", hash = "sha256:4750113612205514f9f6aa4cb00d523a94f3e8c06c5ad2fee466387dc4875f07"}, +] + +[package.dependencies] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" + +[package.extras] +grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] + +[[package]] +name = "greenlet" +version = "3.0.3" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=3.7" +files = [ + {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, + {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, + {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, + {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, + {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, + {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, + {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, + {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, + {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, + {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, + {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, + {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, + {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, + {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, + {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, + {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, + {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, + {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, + {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, + {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, + {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, + {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, + {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, + {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, + {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, + {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, + {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, + {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, +] + +[package.extras] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil"] + +[[package]] +name = "grpcio" +version = "1.60.1" +description = "HTTP/2-based RPC framework" +optional = false +python-versions = ">=3.7" +files = [ + {file = "grpcio-1.60.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:14e8f2c84c0832773fb3958240c69def72357bc11392571f87b2d7b91e0bb092"}, + {file = "grpcio-1.60.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:33aed0a431f5befeffd9d346b0fa44b2c01aa4aeae5ea5b2c03d3e25e0071216"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:fead980fbc68512dfd4e0c7b1f5754c2a8e5015a04dea454b9cada54a8423525"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:082081e6a36b6eb5cf0fd9a897fe777dbb3802176ffd08e3ec6567edd85bc104"}, + {file = "grpcio-1.60.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55ccb7db5a665079d68b5c7c86359ebd5ebf31a19bc1a91c982fd622f1e31ff2"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b54577032d4f235452f77a83169b6527bf4b77d73aeada97d45b2aaf1bf5ce0"}, + {file = "grpcio-1.60.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7d142bcd604166417929b071cd396aa13c565749a4c840d6c702727a59d835eb"}, + {file = "grpcio-1.60.1-cp310-cp310-win32.whl", hash = "sha256:2a6087f234cb570008a6041c8ffd1b7d657b397fdd6d26e83d72283dae3527b1"}, + {file = "grpcio-1.60.1-cp310-cp310-win_amd64.whl", hash = "sha256:f2212796593ad1d0235068c79836861f2201fc7137a99aa2fea7beeb3b101177"}, + {file = "grpcio-1.60.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:79ae0dc785504cb1e1788758c588c711f4e4a0195d70dff53db203c95a0bd303"}, + {file = "grpcio-1.60.1-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:4eec8b8c1c2c9b7125508ff7c89d5701bf933c99d3910e446ed531cd16ad5d87"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8c9554ca8e26241dabe7951aa1fa03a1ba0856688ecd7e7bdbdd286ebc272e4c"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91422ba785a8e7a18725b1dc40fbd88f08a5bb4c7f1b3e8739cab24b04fa8a03"}, + {file = "grpcio-1.60.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cba6209c96828711cb7c8fcb45ecef8c8859238baf15119daa1bef0f6c84bfe7"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c71be3f86d67d8d1311c6076a4ba3b75ba5703c0b856b4e691c9097f9b1e8bd2"}, + {file = "grpcio-1.60.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5ef6cfaf0d023c00002ba25d0751e5995fa0e4c9eec6cd263c30352662cbce"}, + {file = "grpcio-1.60.1-cp311-cp311-win32.whl", hash = "sha256:a09506eb48fa5493c58f946c46754ef22f3ec0df64f2b5149373ff31fb67f3dd"}, + {file = "grpcio-1.60.1-cp311-cp311-win_amd64.whl", hash = "sha256:49c9b6a510e3ed8df5f6f4f3c34d7fbf2d2cae048ee90a45cd7415abab72912c"}, + {file = "grpcio-1.60.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:b58b855d0071575ea9c7bc0d84a06d2edfbfccec52e9657864386381a7ce1ae9"}, + {file = "grpcio-1.60.1-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a731ac5cffc34dac62053e0da90f0c0b8560396a19f69d9703e88240c8f05858"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:cf77f8cf2a651fbd869fbdcb4a1931464189cd210abc4cfad357f1cacc8642a6"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c557e94e91a983e5b1e9c60076a8fd79fea1e7e06848eb2e48d0ccfb30f6e073"}, + {file = "grpcio-1.60.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:069fe2aeee02dfd2135d562d0663fe70fbb69d5eed6eb3389042a7e963b54de8"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb0af13433dbbd1c806e671d81ec75bd324af6ef75171fd7815ca3074fe32bfe"}, + {file = "grpcio-1.60.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2f44c32aef186bbba254129cea1df08a20be414144ac3bdf0e84b24e3f3b2e05"}, + {file = "grpcio-1.60.1-cp312-cp312-win32.whl", hash = "sha256:a212e5dea1a4182e40cd3e4067ee46be9d10418092ce3627475e995cca95de21"}, + {file = "grpcio-1.60.1-cp312-cp312-win_amd64.whl", hash = "sha256:6e490fa5f7f5326222cb9f0b78f207a2b218a14edf39602e083d5f617354306f"}, + {file = "grpcio-1.60.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:4216e67ad9a4769117433814956031cb300f85edc855252a645a9a724b3b6594"}, + {file = "grpcio-1.60.1-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:73e14acd3d4247169955fae8fb103a2b900cfad21d0c35f0dcd0fdd54cd60367"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:6ecf21d20d02d1733e9c820fb5c114c749d888704a7ec824b545c12e78734d1c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33bdea30dcfd4f87b045d404388469eb48a48c33a6195a043d116ed1b9a0196c"}, + {file = "grpcio-1.60.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b69e79d00f78c81eecfb38f4516080dc7f36a198b6b37b928f1c13b3c063e9"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:39aa848794b887120b1d35b1b994e445cc028ff602ef267f87c38122c1add50d"}, + {file = "grpcio-1.60.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72153a0d2e425f45b884540a61c6639436ddafa1829a42056aa5764b84108b8e"}, + {file = "grpcio-1.60.1-cp37-cp37m-win_amd64.whl", hash = "sha256:50d56280b482875d1f9128ce596e59031a226a8b84bec88cb2bf76c289f5d0de"}, + {file = "grpcio-1.60.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:6d140bdeb26cad8b93c1455fa00573c05592793c32053d6e0016ce05ba267549"}, + {file = "grpcio-1.60.1-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:bc808924470643b82b14fe121923c30ec211d8c693e747eba8a7414bc4351a23"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:70c83bb530572917be20c21f3b6be92cd86b9aecb44b0c18b1d3b2cc3ae47df0"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b106bc52e7f28170e624ba61cc7dc6829566e535a6ec68528f8e1afbed1c41f"}, + {file = "grpcio-1.60.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30e980cd6db1088c144b92fe376747328d5554bc7960ce583ec7b7d81cd47287"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c5807e9152eff15f1d48f6b9ad3749196f79a4a050469d99eecb679be592acc"}, + {file = "grpcio-1.60.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1c3dc536b3ee124e8b24feb7533e5c70b9f2ef833e3b2e5513b2897fd46763a"}, + {file = "grpcio-1.60.1-cp38-cp38-win32.whl", hash = "sha256:d7404cebcdb11bb5bd40bf94131faf7e9a7c10a6c60358580fe83913f360f929"}, + {file = "grpcio-1.60.1-cp38-cp38-win_amd64.whl", hash = "sha256:c8754c75f55781515a3005063d9a05878b2cfb3cb7e41d5401ad0cf19de14872"}, + {file = "grpcio-1.60.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:0250a7a70b14000fa311de04b169cc7480be6c1a769b190769d347939d3232a8"}, + {file = "grpcio-1.60.1-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:660fc6b9c2a9ea3bb2a7e64ba878c98339abaf1811edca904ac85e9e662f1d73"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:76eaaba891083fcbe167aa0f03363311a9f12da975b025d30e94b93ac7a765fc"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d97c65ea7e097056f3d1ead77040ebc236feaf7f71489383d20f3b4c28412a"}, + {file = "grpcio-1.60.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb2a2911b028f01c8c64d126f6b632fcd8a9ac975aa1b3855766c94e4107180"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5a1ebbae7e2214f51b1f23b57bf98eeed2cf1ba84e4d523c48c36d5b2f8829ff"}, + {file = "grpcio-1.60.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9a66f4d2a005bc78e61d805ed95dedfcb35efa84b7bba0403c6d60d13a3de2d6"}, + {file = "grpcio-1.60.1-cp39-cp39-win32.whl", hash = "sha256:8d488fbdbf04283f0d20742b64968d44825617aa6717b07c006168ed16488804"}, + {file = "grpcio-1.60.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b7199cd2a55e62e45bfb629a35b71fc2c0cb88f686a047f25b1112d3810904"}, + {file = "grpcio-1.60.1.tar.gz", hash = "sha256:dd1d3a8d1d2e50ad9b59e10aa7f07c7d1be2b367f3f2d33c5fade96ed5460962"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.60.1)"] + +[[package]] +name = "grpcio-status" +version = "1.60.1" +description = "Status proto mapping for gRPC" +optional = false +python-versions = ">=3.6" +files = [ + {file = "grpcio-status-1.60.1.tar.gz", hash = "sha256:61b5aab8989498e8aa142c20b88829ea5d90d18c18c853b9f9e6d407d37bf8b4"}, + {file = "grpcio_status-1.60.1-py3-none-any.whl", hash = "sha256:3034fdb239185b6e0f3169d08c268c4507481e4b8a434c21311a03d9eb5889a0"}, +] + +[package.dependencies] +googleapis-common-protos = ">=1.5.5" +grpcio = ">=1.60.1" +protobuf = ">=4.21.6" + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.2" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, + {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.23.0)"] + +[[package]] +name = "httpx" +version = "0.26.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, + {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx-sse" +version = "0.4.0" +description = "Consume Server-Sent Event (SSE) messages with HTTPX." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"}, + {file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"}, +] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "langchain" +version = "0.1.5" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain-0.1.5-py3-none-any.whl", hash = "sha256:4614118d4a95b2e7ba3611a0b6b21707a259a21652a04fbe3c31205bcf3fcd50"}, + {file = "langchain-0.1.5.tar.gz", hash = "sha256:69603a5bb21b044ddea69d38131dbbf47475afdf79728644faa67d1ad325d652"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} +dataclasses-json = ">=0.5.7,<0.7" +jsonpatch = ">=1.33,<2.0" +langchain-community = ">=0.0.17,<0.1" +langchain-core = ">=0.1.16,<0.2" +langsmith = ">=0.0.83,<0.1" +numpy = ">=1,<2" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (<2)"] +clarifai = ["clarifai (>=9.1.0)"] +cli = ["typer (>=0.9.0,<0.10.0)"] +cohere = ["cohere (>=4,<5)"] +docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"] +embeddings = ["sentence-transformers (>=2,<3)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"] +javascript = ["esprima (>=4.0.1,<5.0.0)"] +llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"] +openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"] +qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"] +text-helpers = ["chardet (>=5.1.0,<6.0.0)"] + +[[package]] +name = "langchain-cli" +version = "0.0.21" +description = "CLI for interacting with LangChain" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_cli-0.0.21-py3-none-any.whl", hash = "sha256:cd5c83597ef857704db983aa1743d7c2e6da52d634f735a7610630347347583e"}, + {file = "langchain_cli-0.0.21.tar.gz", hash = "sha256:d36a40955533ce0217b9a89c11bf593b18d8b40f2abbc81c9a531eb23f54809f"}, +] + +[package.dependencies] +gitpython = ">=3.1.40,<4.0.0" +langserve = {version = ">=0.0.16", extras = ["all"]} +tomlkit = ">=0.12.2,<0.13.0" +typer = {version = ">=0.9.0,<0.10.0", extras = ["all"]} +uvicorn = ">=0.23.2,<0.24.0" + +[[package]] +name = "langchain-community" +version = "0.0.19" +description = "Community contributed LangChain integrations." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_community-0.0.19-py3-none-any.whl", hash = "sha256:ebff8daa0110d53555f4963f1f739b85f9ca63ef82598ece5f5c3f73fe0aa82e"}, + {file = "langchain_community-0.0.19.tar.gz", hash = "sha256:5d18ad9e188b10aaba6361fb2a747cf29b64b21ffb8061933fec090187ca39c2"}, +] + +[package.dependencies] +aiohttp = ">=3.8.3,<4.0.0" +dataclasses-json = ">=0.5.7,<0.7" +langchain-core = ">=0.1.21,<0.2" +langsmith = ">=0.0.83,<0.1" +numpy = ">=1,<2" +PyYAML = ">=5.3" +requests = ">=2,<3" +SQLAlchemy = ">=1.4,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +cli = ["typer (>=0.9.0,<0.10.0)"] +extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)", "zhipuai (>=1.0.7,<2.0.0)"] + +[[package]] +name = "langchain-core" +version = "0.1.21" +description = "Building applications with LLMs through composability" +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langchain_core-0.1.21-py3-none-any.whl", hash = "sha256:9dd1cedc5a3a6081136352e9403d1a87befbab4d36d6ee1877b2e639e85f15ed"}, + {file = "langchain_core-0.1.21.tar.gz", hash = "sha256:b5625901d38121aa449ef73446605032ddd31ac2787be1428c52e9c793ef8229"}, +] + +[package.dependencies] +anyio = ">=3,<5" +jsonpatch = ">=1.33,<2.0" +langsmith = ">=0.0.87,<0.0.88" +packaging = ">=23.2,<24.0" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +requests = ">=2,<3" +tenacity = ">=8.1.0,<9.0.0" + +[package.extras] +extended-testing = ["jinja2 (>=3,<4)"] + +[[package]] +name = "langchain-google-genai" +version = "0.0.7" +description = "An integration package connecting Google's genai package and LangChain" +optional = false +python-versions = ">=3.9,<4.0" +files = [ + {file = "langchain_google_genai-0.0.7-py3-none-any.whl", hash = "sha256:6469d11a1497964fae10cc7c779412cb3383f0c82c5b7a2adb0891b0181e2e19"}, + {file = "langchain_google_genai-0.0.7.tar.gz", hash = "sha256:031946ba396571ac8e14ed9106bf1090663db2196b68675e52326539cddac890"}, +] + +[package.dependencies] +google-generativeai = ">=0.3.1,<0.4.0" +langchain-core = ">=0.1,<0.2" + +[package.extras] +images = ["pillow (>=10.1.0,<11.0.0)"] + +[[package]] +name = "langserve" +version = "0.0.41" +description = "" +optional = false +python-versions = ">=3.8.1,<4.0.0" +files = [ + {file = "langserve-0.0.41-py3-none-any.whl", hash = "sha256:99583a6a4f2a6c3f98ffcf0c9eeed2a1ef6278b0cfaf9d789dfd517c49d0062a"}, + {file = "langserve-0.0.41.tar.gz", hash = "sha256:8583d9d01b202b4111e21e3c94d91ca6b61093ebff55fdfd0f92c6c8d155a6e5"}, +] + +[package.dependencies] +fastapi = {version = ">=0.90.1,<1", optional = true, markers = "extra == \"server\" or extra == \"all\""} +httpx = ">=0.23.0" +httpx-sse = {version = ">=0.3.1", optional = true, markers = "extra == \"client\" or extra == \"all\""} +langchain = ">=0.0.333" +orjson = ">=2" +pydantic = ">=1" +sse-starlette = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"server\" or extra == \"all\""} + +[package.extras] +all = ["fastapi (>=0.90.1,<1)", "httpx-sse (>=0.3.1)", "sse-starlette (>=1.3.0,<2.0.0)"] +client = ["httpx-sse (>=0.3.1)"] +server = ["fastapi (>=0.90.1,<1)", "sse-starlette (>=1.3.0,<2.0.0)"] + +[[package]] +name = "langsmith" +version = "0.0.87" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = ">=3.8.1,<4.0" +files = [ + {file = "langsmith-0.0.87-py3-none-any.whl", hash = "sha256:8903d3811b9fc89eb18f5961c8e6935fbd2d0f119884fbf30dc70b8f8f4121fc"}, + {file = "langsmith-0.0.87.tar.gz", hash = "sha256:36c4cc47e5b54be57d038036a30fb19ce6e4c73048cd7a464b8f25b459694d34"}, +] + +[package.dependencies] +pydantic = ">=1,<3" +requests = ">=2,<3" + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "marshmallow" +version = "3.20.2" +description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +optional = false +python-versions = ">=3.8" +files = [ + {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, + {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, +] + +[package.dependencies] +packaging = ">=17.0" + +[package.extras] +dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["pre-commit (>=2.4,<4.0)"] +tests = ["pytest", "pytz", "simplejson"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "multidict" +version = "6.0.5" +description = "multidict implementation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, + {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, + {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, + {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, + {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, + {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, + {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, + {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, + {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, + {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, + {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, + {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, + {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, + {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, + {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, + {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, + {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, + {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, + {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, + {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, + {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, + {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, + {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, + {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, + {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, + {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, + {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, + {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, + {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, + {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, + {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, + {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, + {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "numpy" +version = "1.26.4" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"}, + {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"}, + {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"}, + {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"}, + {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"}, + {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"}, + {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"}, + {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"}, + {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"}, + {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"}, + {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"}, + {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"}, + {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"}, + {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"}, + {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"}, + {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"}, + {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"}, + {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"}, + {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"}, + {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"}, + {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"}, + {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"}, + {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"}, +] + +[[package]] +name = "orjson" +version = "3.9.13" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.9.13-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:fa6b67f8bef277c2a4aadd548d58796854e7d760964126c3209b19bccc6a74f1"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b812417199eeb169c25f67815cfb66fd8de7ff098bf57d065e8c1943a7ba5c8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7ccd5bd222e5041069ad9d9868ab59e6dbc53ecde8d8c82b919954fbba43b46b"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaaf80957c38e9d3f796f355a80fad945e72cd745e6b64c210e635b7043b673e"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:60da7316131185d0110a1848e9ad15311e6c8938ee0b5be8cbd7261e1d80ee8f"}, + {file = "orjson-3.9.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b98cd948372f0eb219bc309dee4633db1278687161e3280d9e693b6076951d2"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3869d65561f10071d3e7f35ae58fd377056f67d7aaed5222f318390c3ad30339"}, + {file = "orjson-3.9.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43fd6036b16bb6742d03dae62f7bdf8214d06dea47e4353cde7e2bd1358d186f"}, + {file = "orjson-3.9.13-cp310-none-win32.whl", hash = "sha256:0d3ba9d88e20765335260d7b25547d7c571eee2b698200f97afa7d8c7cd668fc"}, + {file = "orjson-3.9.13-cp310-none-win_amd64.whl", hash = "sha256:6e47153db080f5e87e8ba638f1a8b18995eede6b0abb93964d58cf11bcea362f"}, + {file = "orjson-3.9.13-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4584e8eb727bc431baaf1bf97e35a1d8a0109c924ec847395673dfd5f4ef6d6f"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f37f0cdd026ef777a4336e599d8194c8357fc14760c2a5ddcfdf1965d45504b"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d714595d81efab11b42bccd119977d94b25d12d3a806851ff6bfd286a4bce960"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9171e8e1a1f221953e38e84ae0abffe8759002fd8968106ee379febbb5358b33"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab9dbdec3f13f3ea6f937564ce21651844cfbf2725099f2f490426acf683c23"}, + {file = "orjson-3.9.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:811ac076855e33e931549340288e0761873baf29276ad00f221709933c644330"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:860d0f5b42d0c0afd73fa4177709f6e1b966ba691fcd72175affa902052a81d6"}, + {file = "orjson-3.9.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:838b898e8c1f26eb6b8d81b180981273f6f5110c76c22c384979aca854194f1b"}, + {file = "orjson-3.9.13-cp311-none-win32.whl", hash = "sha256:d3222db9df629ef3c3673124f2e05fb72bc4a320c117e953fec0d69dde82e36d"}, + {file = "orjson-3.9.13-cp311-none-win_amd64.whl", hash = "sha256:978117122ca4cc59b28af5322253017f6c5fc03dbdda78c7f4b94ae984c8dd43"}, + {file = "orjson-3.9.13-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:031df1026c7ea8303332d78711f180231e3ae8b564271fb748a03926587c5546"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fd9a2101d04e85086ea6198786a3f016e45475f800712e6833e14bf9ce2832f"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:446d9ad04204e79229ae19502daeea56479e55cbc32634655d886f5a39e91b44"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b57c0954a9fdd2b05b9cec0f5a12a0bdce5bf021a5b3b09323041613972481ab"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:266e55c83f81248f63cc93d11c5e3a53df49a5d2598fa9e9db5f99837a802d5d"}, + {file = "orjson-3.9.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31372ba3a9fe8ad118e7d22fba46bbc18e89039e3bfa89db7bc8c18ee722dca8"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e3b0c4da61f39899561e08e571f54472a09fa71717d9797928af558175ae5243"}, + {file = "orjson-3.9.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2cc03a35bfc71c8ebf96ce49b82c2a7be6af4b3cd3ac34166fdb42ac510bbfff"}, + {file = "orjson-3.9.13-cp312-none-win_amd64.whl", hash = "sha256:49b7e3fe861cb246361825d1a238f2584ed8ea21e714bf6bb17cebb86772e61c"}, + {file = "orjson-3.9.13-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:62e9a99879c4d5a04926ac2518a992134bfa00d546ea5a4cae4b9be454d35a22"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d92a3e835a5100f1d5b566fff79217eab92223ca31900dba733902a182a35ab0"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23f21faf072ed3b60b5954686f98157e073f6a8068eaa58dbde83e87212eda84"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:828c502bb261588f7de897e06cb23c4b122997cb039d2014cb78e7dabe92ef0c"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16946d095212a3dec552572c5d9bca7afa40f3116ad49695a397be07d529f1fa"}, + {file = "orjson-3.9.13-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3deadd8dc0e9ff844b5b656fa30a48dbee1c3b332d8278302dd9637f6b09f627"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9b1b5adc5adf596c59dca57156b71ad301d73956f5bab4039b0e34dbf50b9fa0"}, + {file = "orjson-3.9.13-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ddc089315d030c54f0f03fb38286e2667c05009a78d659f108a8efcfbdf2e585"}, + {file = "orjson-3.9.13-cp38-none-win32.whl", hash = "sha256:ae77275a28667d9c82d4522b681504642055efa0368d73108511647c6499b31c"}, + {file = "orjson-3.9.13-cp38-none-win_amd64.whl", hash = "sha256:730385fdb99a21fce9bb84bb7fcbda72c88626facd74956bda712834b480729d"}, + {file = "orjson-3.9.13-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7e8e4a571d958910272af8d53a9cbe6599f9f5fd496a1bc51211183bb2072cbd"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfad553a36548262e7da0f3a7464270e13900b898800fb571a5d4b298c3f8356"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d691c44604941945b00e0a13b19a7d9c1a19511abadf0080f373e98fdeb6b31"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8c83718346de08d68b3cb1105c5d91e5fc39885d8610fdda16613d4e3941459"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ef57a53bfc2091a7cd50a640d9ae866bd7d92a5225a1bab6baa60ef62583f2"}, + {file = "orjson-3.9.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9156b96afa38db71344522f5517077eaedf62fcd2c9148392ff93d801128809c"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31fb66b41fb2c4c817d9610f0bc7d31345728d7b5295ac78b63603407432a2b2"}, + {file = "orjson-3.9.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8a730bf07feacb0863974e67b206b7c503a62199de1cece2eb0d4c233ec29c11"}, + {file = "orjson-3.9.13-cp39-none-win32.whl", hash = "sha256:5ef58869f3399acbbe013518d8b374ee9558659eef14bca0984f67cb1fbd3c37"}, + {file = "orjson-3.9.13-cp39-none-win_amd64.whl", hash = "sha256:9bcf56efdb83244cde070e82a69c0f03c47c235f0a5cb6c81d9da23af7fbaae4"}, + {file = "orjson-3.9.13.tar.gz", hash = "sha256:fc6bc65b0cf524ee042e0bc2912b9206ef242edfba7426cf95763e4af01f527a"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "proto-plus" +version = "1.23.0" +description = "Beautiful, Pythonic protocol buffers." +optional = false +python-versions = ">=3.6" +files = [ + {file = "proto-plus-1.23.0.tar.gz", hash = "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2"}, + {file = "proto_plus-1.23.0-py3-none-any.whl", hash = "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c"}, +] + +[package.dependencies] +protobuf = ">=3.19.0,<5.0.0dev" + +[package.extras] +testing = ["google-api-core[grpc] (>=1.31.5)"] + +[[package]] +name = "protobuf" +version = "4.25.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "protobuf-4.25.2-cp310-abi3-win32.whl", hash = "sha256:b50c949608682b12efb0b2717f53256f03636af5f60ac0c1d900df6213910fd6"}, + {file = "protobuf-4.25.2-cp310-abi3-win_amd64.whl", hash = "sha256:8f62574857ee1de9f770baf04dde4165e30b15ad97ba03ceac65f760ff018ac9"}, + {file = "protobuf-4.25.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:2db9f8fa64fbdcdc93767d3cf81e0f2aef176284071507e3ede160811502fd3d"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:10894a2885b7175d3984f2be8d9850712c57d5e7587a2410720af8be56cdaf62"}, + {file = "protobuf-4.25.2-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fc381d1dd0516343f1440019cedf08a7405f791cd49eef4ae1ea06520bc1c020"}, + {file = "protobuf-4.25.2-cp38-cp38-win32.whl", hash = "sha256:33a1aeef4b1927431d1be780e87b641e322b88d654203a9e9d93f218ee359e61"}, + {file = "protobuf-4.25.2-cp38-cp38-win_amd64.whl", hash = "sha256:47f3de503fe7c1245f6f03bea7e8d3ec11c6c4a2ea9ef910e3221c8a15516d62"}, + {file = "protobuf-4.25.2-cp39-cp39-win32.whl", hash = "sha256:5e5c933b4c30a988b52e0b7c02641760a5ba046edc5e43d3b94a74c9fc57c1b3"}, + {file = "protobuf-4.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:d66a769b8d687df9024f2985d5137a337f957a0916cf5464d1513eee96a63ff0"}, + {file = "protobuf-4.25.2-py3-none-any.whl", hash = "sha256:a8b7a98d4ce823303145bf3c1a8bdb0f2f4642a414b196f04ad9853ed0c8f830"}, + {file = "protobuf-4.25.2.tar.gz", hash = "sha256:fe599e175cb347efc8ee524bcd4b902d11f7262c0e569ececcb89995c15f0a5e"}, +] + +[[package]] +name = "pyasn1" +version = "0.5.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, +] + +[[package]] +name = "pyasn1-modules" +version = "0.3.0" +description = "A collection of ASN.1-based protocols modules" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, + {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, +] + +[package.dependencies] +pyasn1 = ">=0.4.6,<0.6.0" + +[[package]] +name = "pydantic" +version = "2.6.1" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, + {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.16.2" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.16.2" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, + {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, + {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, + {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, + {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, + {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, + {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, + {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, + {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, + {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, + {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, + {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, + {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, + {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, + {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, + {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, + {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, + {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, + {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, + {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, + {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, + {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, + {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, + {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, + {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, + {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, + {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, + {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, + {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, + {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, + {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.7.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"}, + {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "rsa" +version = "4.9" +description = "Pure-Python RSA implementation" +optional = false +python-versions = ">=3.6,<4" +files = [ + {file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"}, + {file = "rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.25" +description = "Database Abstraction Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4344d059265cc8b1b1be351bfb88749294b87a8b2bbe21dfbe066c4199541ebd"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9e2e59cbcc6ba1488404aad43de005d05ca56e069477b33ff74e91b6319735"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84daa0a2055df9ca0f148a64fdde12ac635e30edbca80e87df9b3aaf419e144a"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc8b7dabe8e67c4832891a5d322cec6d44ef02f432b4588390017f5cec186a84"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5693145220517b5f42393e07a6898acdfe820e136c98663b971906120549da5"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:db854730a25db7c956423bb9fb4bdd1216c839a689bf9cc15fada0a7fb2f4570"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-win32.whl", hash = "sha256:14a6f68e8fc96e5e8f5647ef6cda6250c780612a573d99e4d881581432ef1669"}, + {file = "SQLAlchemy-2.0.25-cp310-cp310-win_amd64.whl", hash = "sha256:87f6e732bccd7dcf1741c00f1ecf33797383128bd1c90144ac8adc02cbb98643"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:342d365988ba88ada8af320d43df4e0b13a694dbd75951f537b2d5e4cb5cd002"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f37c0caf14b9e9b9e8f6dbc81bc56db06acb4363eba5a633167781a48ef036ed"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9373708763ef46782d10e950b49d0235bfe58facebd76917d3f5cbf5971aed"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24f571990c05f6b36a396218f251f3e0dda916e0c687ef6fdca5072743208f5"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75432b5b14dc2fff43c50435e248b45c7cdadef73388e5610852b95280ffd0e9"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:884272dcd3ad97f47702965a0e902b540541890f468d24bd1d98bcfe41c3f018"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-win32.whl", hash = "sha256:e607cdd99cbf9bb80391f54446b86e16eea6ad309361942bf88318bcd452363c"}, + {file = "SQLAlchemy-2.0.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d505815ac340568fd03f719446a589162d55c52f08abd77ba8964fbb7eb5b5f"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0dacf67aee53b16f365c589ce72e766efaabd2b145f9de7c917777b575e3659d"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b801154027107461ee992ff4b5c09aa7cc6ec91ddfe50d02bca344918c3265c6"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59a21853f5daeb50412d459cfb13cb82c089ad4c04ec208cd14dddd99fc23b39"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29049e2c299b5ace92cbed0c1610a7a236f3baf4c6b66eb9547c01179f638ec5"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b64b183d610b424a160b0d4d880995e935208fc043d0302dd29fee32d1ee3f95"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f7a7d7fcc675d3d85fbf3b3828ecd5990b8d61bd6de3f1b260080b3beccf215"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-win32.whl", hash = "sha256:cf18ff7fc9941b8fc23437cc3e68ed4ebeff3599eec6ef5eebf305f3d2e9a7c2"}, + {file = "SQLAlchemy-2.0.25-cp312-cp312-win_amd64.whl", hash = "sha256:91f7d9d1c4dd1f4f6e092874c128c11165eafcf7c963128f79e28f8445de82d5"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bb209a73b8307f8fe4fe46f6ad5979649be01607f11af1eb94aa9e8a3aaf77f0"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:798f717ae7c806d67145f6ae94dc7c342d3222d3b9a311a784f371a4333212c7"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fdd402169aa00df3142149940b3bf9ce7dde075928c1886d9a1df63d4b8de62"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0d3cab3076af2e4aa5693f89622bef7fa770c6fec967143e4da7508b3dceb9b9"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74b080c897563f81062b74e44f5a72fa44c2b373741a9ade701d5f789a10ba23"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-win32.whl", hash = "sha256:87d91043ea0dc65ee583026cb18e1b458d8ec5fc0a93637126b5fc0bc3ea68c4"}, + {file = "SQLAlchemy-2.0.25-cp37-cp37m-win_amd64.whl", hash = "sha256:75f99202324383d613ddd1f7455ac908dca9c2dd729ec8584c9541dd41822a2c"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:420362338681eec03f53467804541a854617faed7272fe71a1bfdb07336a381e"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c88f0c7dcc5f99bdb34b4fd9b69b93c89f893f454f40219fe923a3a2fd11625"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3be4987e3ee9d9a380b66393b77a4cd6d742480c951a1c56a23c335caca4ce3"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a159111a0f58fb034c93eeba211b4141137ec4b0a6e75789ab7a3ef3c7e7e3"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8b8cb63d3ea63b29074dcd29da4dc6a97ad1349151f2d2949495418fd6e48db9"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:736ea78cd06de6c21ecba7416499e7236a22374561493b456a1f7ffbe3f6cdb4"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-win32.whl", hash = "sha256:10331f129982a19df4284ceac6fe87353ca3ca6b4ca77ff7d697209ae0a5915e"}, + {file = "SQLAlchemy-2.0.25-cp38-cp38-win_amd64.whl", hash = "sha256:c55731c116806836a5d678a70c84cb13f2cedba920212ba7dcad53260997666d"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:605b6b059f4b57b277f75ace81cc5bc6335efcbcc4ccb9066695e515dbdb3900"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:665f0a3954635b5b777a55111ababf44b4fc12b1f3ba0a435b602b6387ffd7cf"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecf6d4cda1f9f6cb0b45803a01ea7f034e2f1aed9475e883410812d9f9e3cfcf"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51db269513917394faec5e5c00d6f83829742ba62e2ac4fa5c98d58be91662f"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:790f533fa5c8901a62b6fef5811d48980adeb2f51f1290ade8b5e7ba990ba3de"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1b1180cda6df7af84fe72e4530f192231b1f29a7496951db4ff38dac1687202d"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-win32.whl", hash = "sha256:555651adbb503ac7f4cb35834c5e4ae0819aab2cd24857a123370764dc7d7e24"}, + {file = "SQLAlchemy-2.0.25-cp39-cp39-win_amd64.whl", hash = "sha256:dc55990143cbd853a5d038c05e79284baedf3e299661389654551bd02a6a68d7"}, + {file = "SQLAlchemy-2.0.25-py3-none-any.whl", hash = "sha256:a86b4240e67d4753dc3092d9511886795b3c2852abe599cffe108952f7af7ac3"}, + {file = "SQLAlchemy-2.0.25.tar.gz", hash = "sha256:a2c69a7664fb2d54b8682dd774c3b54f67f84fa123cf84dda2a5f40dcaa04e08"}, +] + +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""} +typing-extensions = ">=4.6.0" + +[package.extras] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] +asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] +mssql = ["pyodbc"] +mssql-pymssql = ["pymssql"] +mssql-pyodbc = ["pyodbc"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] +mysql-connector = ["mysql-connector-python"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] +sqlcipher = ["sqlcipher3_binary"] + +[[package]] +name = "sse-starlette" +version = "1.8.2" +description = "SSE plugin for Starlette" +optional = false +python-versions = ">=3.8" +files = [ + {file = "sse_starlette-1.8.2-py3-none-any.whl", hash = "sha256:70cc7ef5aca4abe8a25dec1284cce4fe644dd7bf0c406d3e852e516092b7f849"}, + {file = "sse_starlette-1.8.2.tar.gz", hash = "sha256:e0f9b8dec41adc092a0a6e0694334bd3cfd3084c44c497a6ebc1fb4bdd919acd"}, +] + +[package.dependencies] +anyio = "*" +fastapi = "*" +starlette = "*" +uvicorn = "*" + +[[package]] +name = "starlette" +version = "0.36.3" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, + {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "tavily-python" +version = "0.1.9" +description = "Python wrapper for the Tavily API" +optional = false +python-versions = ">=3.6" +files = [ + {file = "tavily-python-0.1.9.tar.gz", hash = "sha256:6b43f151f49ad461e370e7b186e205fbeed11c1807e9b393d9aa0a239aa8f89f"}, + {file = "tavily_python-0.1.9-py3-none-any.whl", hash = "sha256:600793dc7096468a3b1371a98e37d9ed9948a7331ee40285ae992838ae2cc9c2"}, +] + +[package.dependencies] +requests = "*" + +[[package]] +name = "tenacity" +version = "8.2.3" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tenacity-8.2.3-py3-none-any.whl", hash = "sha256:ce510e327a630c9e1beaf17d42e6ffacc88185044ad85cf74c0a8887c6a0f88c"}, + {file = "tenacity-8.2.3.tar.gz", hash = "sha256:5398ef0d78e63f40007c1fb4c0bff96e1911394d2fa8d194f77619c05ff6cc8a"}, +] + +[package.extras] +doc = ["reno", "sphinx", "tornado (>=4.5)"] + +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "typer" +version = "0.9.0" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.0-py3-none-any.whl", hash = "sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee"}, + {file = "typer-0.9.0.tar.gz", hash = "sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} +rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} +shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "typing-inspect" +version = "0.9.0" +description = "Runtime inspection utilities for typing module." +optional = false +python-versions = "*" +files = [ + {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, + {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, +] + +[package.dependencies] +mypy-extensions = ">=0.3.0" +typing-extensions = ">=3.7.4" + +[[package]] +name = "urllib3" +version = "2.2.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, + {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.23.2" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.23.2-py3-none-any.whl", hash = "sha256:1f9be6558f01239d4fdf22ef8126c39cb1ad0addf76c40e760549d2c2f43ab53"}, + {file = "uvicorn-0.23.2.tar.gz", hash = "sha256:4d3cc12d7727ba72b64d12d3cc7743124074c0a69f7b201512fc50c3e3f1569a"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "yarl" +version = "1.9.4" +description = "Yet another URL library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, + {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, + {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, + {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, + {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, + {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, + {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, + {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, + {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, + {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, + {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, + {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, + {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, + {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, + {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, + {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, + {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, + {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, + {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, + {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, + {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, + {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, + {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, + {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, + {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, + {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, + {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, + {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, + {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, + {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, + {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, + {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, + {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "2.0" +python-versions = ">=3.9,<4.0" +content-hash = "1a14257d1bca209fddbbc39a4378a4b737120e39505cd4a194e8bb49759530e1" diff --git a/templates/gemini-functions-agent/pyproject.toml b/templates/gemini-functions-agent/pyproject.toml new file mode 100644 index 0000000000000..5648cd2fdc738 --- /dev/null +++ b/templates/gemini-functions-agent/pyproject.toml @@ -0,0 +1,33 @@ +[tool.poetry] +name = "gemini-functions-agent" +version = "0.1.0" +description = "Agent using Gemini function calling to execute functions, including search" +authors = [ + "Harrison Chase", +] +readme = "README.md" + +[tool.poetry.dependencies] +python = ">=3.9,<4.0" +langchain = "^0.1" +tavily-python = "^0.1.9" +langchain-google-genai = ">=0.0.7,<0.1" + +[tool.poetry.group.dev.dependencies] +langchain-cli = ">=0.0.21" + +[tool.langserve] +export_module = "gemini_functions_agent" +export_attr = "agent_executor" + +[tool.templates-hub] +use-case = "research" +author = "LangChain" +integrations = ["Google", "Tavily"] +tags = ["search", "agents", "function-calling"] + +[build-system] +requires = [ + "poetry-core", +] +build-backend = "poetry.core.masonry.api" diff --git a/templates/gemini-functions-agent/tests/__init__.py b/templates/gemini-functions-agent/tests/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d From f92738a6f6c37909d42cda9e0493e5ad05b9af6e Mon Sep 17 00:00:00 2001 From: Dmitry Kankalovich Date: Thu, 8 Feb 2024 04:06:09 +0100 Subject: [PATCH 23/83] langchain[minor], community[minor], core[minor]: Async Cache support and AsyncRedisCache (#15817) * This PR adds async methods to the LLM cache. * Adds an implementation using Redis called AsyncRedisCache. * Adds a docker compose file at the /docker to help spin up docker * Updates redis tests to use a context manager so flushing always happens by default --- docker/docker-compose.yml | 17 ++ libs/community/langchain_community/cache.py | 190 +++++++++++---- libs/core/langchain_core/caches.py | 15 ++ .../language_models/chat_models.py | 4 +- .../langchain_core/language_models/llms.py | 42 +++- libs/langchain/langchain/cache.py | 2 + .../cache/test_redis_cache.py | 218 ++++++++++++++---- libs/langchain/tests/unit_tests/test_cache.py | 93 ++++++-- 8 files changed, 460 insertions(+), 121 deletions(-) create mode 100644 docker/docker-compose.yml diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000000000..ce680ccafda51 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,17 @@ +# docker-compose to make it easier to spin up integration tests. +# Services should use NON standard ports to avoid collision with +version: "3" +name: langchain-tests + +services: + redis: + image: redis/redis-stack-server:latest + # We use non standard ports since + # these instances are used for testing + # and users may already have existing + # redis instances set up locally + # for other projects + ports: + - "6020:6379" + volumes: + - ./redis-volume:/data diff --git a/libs/community/langchain_community/cache.py b/libs/community/langchain_community/cache.py index b200168294279..54996071f8655 100644 --- a/libs/community/langchain_community/cache.py +++ b/libs/community/langchain_community/cache.py @@ -27,6 +27,7 @@ import logging import uuid import warnings +from abc import ABC from datetime import timedelta from functools import lru_cache from typing import ( @@ -351,8 +352,60 @@ def clear(self, **kwargs: Any) -> None: self.redis.flushdb(flush_type=asynchronous) -class RedisCache(BaseCache): - """Cache that uses Redis as a backend.""" +class _RedisCacheBase(BaseCache, ABC): + @staticmethod + def _key(prompt: str, llm_string: str) -> str: + """Compute key from prompt and llm_string""" + return _hash(prompt + llm_string) + + @staticmethod + def _ensure_generation_type(return_val: RETURN_VAL_TYPE) -> None: + for gen in return_val: + if not isinstance(gen, Generation): + raise ValueError( + "RedisCache only supports caching of normal LLM generations, " + f"got {type(gen)}" + ) + + @staticmethod + def _get_generations( + results: dict[str | bytes, str | bytes], + ) -> Optional[List[Generation]]: + generations = [] + if results: + for _, text in results.items(): + try: + generations.append(loads(text)) + except Exception: + logger.warning( + "Retrieving a cache value that could not be deserialized " + "properly. This is likely due to the cache being in an " + "older format. Please recreate your cache to avoid this " + "error." + ) + # In a previous life we stored the raw text directly + # in the table, so assume it's in that format. + generations.append(Generation(text=text)) + return generations if generations else None + + @staticmethod + def _configure_pipeline_for_update( + key: str, pipe: Any, return_val: RETURN_VAL_TYPE, ttl: Optional[int] = None + ) -> None: + pipe.hset( + key, + mapping={ + str(idx): dumps(generation) for idx, generation in enumerate(return_val) + }, + ) + if ttl is not None: + pipe.expire(key, ttl) + + +class RedisCache(_RedisCacheBase): + """ + Cache that uses Redis as a backend. Allows to use a sync `redis.Redis` client. + """ def __init__(self, redis_: Any, *, ttl: Optional[int] = None): """ @@ -360,12 +413,12 @@ def __init__(self, redis_: Any, *, ttl: Optional[int] = None): This method initializes an object with Redis caching capabilities. It takes a `redis_` parameter, which should be an instance of a Redis - client class, allowing the object to interact with a Redis - server for caching purposes. + client class (`redis.Redis`), allowing the object + to interact with a Redis server for caching purposes. Parameters: redis_ (Any): An instance of a Redis client class - (e.g., redis.Redis) used for caching. + (`redis.Redis`) to be used for caching. This allows the object to communicate with a Redis server for caching operations. ttl (int, optional): Time-to-live (TTL) for cached items in seconds. @@ -377,61 +430,27 @@ def __init__(self, redis_: Any, *, ttl: Optional[int] = None): from redis import Redis except ImportError: raise ValueError( - "Could not import redis python package. " + "Could not import `redis` python package. " "Please install it with `pip install redis`." ) if not isinstance(redis_, Redis): - raise ValueError("Please pass in Redis object.") + raise ValueError("Please pass a valid `redis.Redis` client.") self.redis = redis_ self.ttl = ttl - def _key(self, prompt: str, llm_string: str) -> str: - """Compute key from prompt and llm_string""" - return _hash(prompt + llm_string) - def lookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]: """Look up based on prompt and llm_string.""" - generations = [] # Read from a Redis HASH results = self.redis.hgetall(self._key(prompt, llm_string)) - if results: - for _, text in results.items(): - try: - generations.append(loads(text)) - except Exception: - logger.warning( - "Retrieving a cache value that could not be deserialized " - "properly. This is likely due to the cache being in an " - "older format. Please recreate your cache to avoid this " - "error." - ) - # In a previous life we stored the raw text directly - # in the table, so assume it's in that format. - generations.append(Generation(text=text)) - return generations if generations else None + return self._get_generations(results) # type: ignore[arg-type] def update(self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE) -> None: """Update cache based on prompt and llm_string.""" - for gen in return_val: - if not isinstance(gen, Generation): - raise ValueError( - "RedisCache only supports caching of normal LLM generations, " - f"got {type(gen)}" - ) - # Write to a Redis HASH + self._ensure_generation_type(return_val) key = self._key(prompt, llm_string) with self.redis.pipeline() as pipe: - pipe.hset( - key, - mapping={ - str(idx): dumps(generation) - for idx, generation in enumerate(return_val) - }, - ) - if self.ttl is not None: - pipe.expire(key, self.ttl) - + self._configure_pipeline_for_update(key, pipe, return_val, self.ttl) pipe.execute() def clear(self, **kwargs: Any) -> None: @@ -440,6 +459,89 @@ def clear(self, **kwargs: Any) -> None: self.redis.flushdb(asynchronous=asynchronous, **kwargs) +class AsyncRedisCache(_RedisCacheBase): + """ + Cache that uses Redis as a backend. Allows to use an + async `redis.asyncio.Redis` client. + """ + + def __init__(self, redis_: Any, *, ttl: Optional[int] = None): + """ + Initialize an instance of AsyncRedisCache. + + This method initializes an object with Redis caching capabilities. + It takes a `redis_` parameter, which should be an instance of a Redis + client class (`redis.asyncio.Redis`), allowing the object + to interact with a Redis server for caching purposes. + + Parameters: + redis_ (Any): An instance of a Redis client class + (`redis.asyncio.Redis`) to be used for caching. + This allows the object to communicate with a + Redis server for caching operations. + ttl (int, optional): Time-to-live (TTL) for cached items in seconds. + If provided, it sets the time duration for how long cached + items will remain valid. If not provided, cached items will not + have an automatic expiration. + """ + try: + from redis.asyncio import Redis + except ImportError: + raise ValueError( + "Could not import `redis.asyncio` python package. " + "Please install it with `pip install redis`." + ) + if not isinstance(redis_, Redis): + raise ValueError("Please pass a valid `redis.asyncio.Redis` client.") + self.redis = redis_ + self.ttl = ttl + + def lookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]: + """Look up based on prompt and llm_string.""" + raise NotImplementedError( + "This async Redis cache does not implement `lookup()` method. " + "Consider using the async `alookup()` version." + ) + + async def alookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]: + """Look up based on prompt and llm_string. Async version.""" + results = await self.redis.hgetall(self._key(prompt, llm_string)) + return self._get_generations(results) # type: ignore[arg-type] + + def update(self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE) -> None: + """Update cache based on prompt and llm_string.""" + raise NotImplementedError( + "This async Redis cache does not implement `update()` method. " + "Consider using the async `aupdate()` version." + ) + + async def aupdate( + self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE + ) -> None: + """Update cache based on prompt and llm_string. Async version.""" + self._ensure_generation_type(return_val) + key = self._key(prompt, llm_string) + + async with self.redis.pipeline() as pipe: + self._configure_pipeline_for_update(key, pipe, return_val, self.ttl) + await pipe.execute() # type: ignore[attr-defined] + + def clear(self, **kwargs: Any) -> None: + """Clear cache. If `asynchronous` is True, flush asynchronously.""" + raise NotImplementedError( + "This async Redis cache does not implement `clear()` method. " + "Consider using the async `aclear()` version." + ) + + async def aclear(self, **kwargs: Any) -> None: + """ + Clear cache. If `asynchronous` is True, flush asynchronously. + Async version. + """ + asynchronous = kwargs.get("asynchronous", False) + await self.redis.flushdb(asynchronous=asynchronous, **kwargs) + + class RedisSemanticCache(BaseCache): """Cache that uses Redis as a vector-store backend.""" diff --git a/libs/core/langchain_core/caches.py b/libs/core/langchain_core/caches.py index c14959c8f9c6b..626670950ab7d 100644 --- a/libs/core/langchain_core/caches.py +++ b/libs/core/langchain_core/caches.py @@ -4,6 +4,7 @@ from typing import Any, Optional, Sequence from langchain_core.outputs import Generation +from langchain_core.runnables import run_in_executor RETURN_VAL_TYPE = Sequence[Generation] @@ -22,3 +23,17 @@ def update(self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE) -> N @abstractmethod def clear(self, **kwargs: Any) -> None: """Clear cache that can take additional keyword arguments.""" + + async def alookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]: + """Look up based on prompt and llm_string.""" + return await run_in_executor(None, self.lookup, prompt, llm_string) + + async def aupdate( + self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE + ) -> None: + """Update cache based on prompt and llm_string.""" + return await run_in_executor(None, self.update, prompt, llm_string, return_val) + + async def aclear(self, **kwargs: Any) -> None: + """Clear cache that can take additional keyword arguments.""" + return await run_in_executor(None, self.clear, **kwargs) diff --git a/libs/core/langchain_core/language_models/chat_models.py b/libs/core/langchain_core/language_models/chat_models.py index aaf61a7810e1c..6279116093e5f 100644 --- a/libs/core/langchain_core/language_models/chat_models.py +++ b/libs/core/langchain_core/language_models/chat_models.py @@ -622,7 +622,7 @@ async def _agenerate_with_cache( else: llm_string = self._get_llm_string(stop=stop, **kwargs) prompt = dumps(messages) - cache_val = llm_cache.lookup(prompt, llm_string) + cache_val = await llm_cache.alookup(prompt, llm_string) if isinstance(cache_val, list): return ChatResult(generations=cache_val) else: @@ -632,7 +632,7 @@ async def _agenerate_with_cache( ) else: result = await self._agenerate(messages, stop=stop, **kwargs) - llm_cache.update(prompt, llm_string, result.generations) + await llm_cache.aupdate(prompt, llm_string, result.generations) return result @abstractmethod diff --git a/libs/core/langchain_core/language_models/llms.py b/libs/core/langchain_core/language_models/llms.py index 7f987baf88df0..ec2af1b91e088 100644 --- a/libs/core/langchain_core/language_models/llms.py +++ b/libs/core/langchain_core/language_models/llms.py @@ -139,6 +139,26 @@ def get_prompts( return existing_prompts, llm_string, missing_prompt_idxs, missing_prompts +async def aget_prompts( + params: Dict[str, Any], prompts: List[str] +) -> Tuple[Dict[int, List], str, List[int], List[str]]: + """Get prompts that are already cached. Async version.""" + llm_string = str(sorted([(k, v) for k, v in params.items()])) + missing_prompts = [] + missing_prompt_idxs = [] + existing_prompts = {} + llm_cache = get_llm_cache() + for i, prompt in enumerate(prompts): + if llm_cache: + cache_val = await llm_cache.alookup(prompt, llm_string) + if isinstance(cache_val, list): + existing_prompts[i] = cache_val + else: + missing_prompts.append(prompt) + missing_prompt_idxs.append(i) + return existing_prompts, llm_string, missing_prompt_idxs, missing_prompts + + def update_cache( existing_prompts: Dict[int, List], llm_string: str, @@ -157,6 +177,24 @@ def update_cache( return llm_output +async def aupdate_cache( + existing_prompts: Dict[int, List], + llm_string: str, + missing_prompt_idxs: List[int], + new_results: LLMResult, + prompts: List[str], +) -> Optional[dict]: + """Update the cache and get the LLM output. Async version""" + llm_cache = get_llm_cache() + for i, result in enumerate(new_results.generations): + existing_prompts[missing_prompt_idxs[i]] = result + prompt = prompts[missing_prompt_idxs[i]] + if llm_cache: + await llm_cache.aupdate(prompt, llm_string, result) + llm_output = new_results.llm_output + return llm_output + + class BaseLLM(BaseLanguageModel[str], ABC): """Base LLM abstract interface. @@ -869,7 +907,7 @@ async def agenerate( llm_string, missing_prompt_idxs, missing_prompts, - ) = get_prompts(params, prompts) + ) = await aget_prompts(params, prompts) disregard_cache = self.cache is not None and not self.cache new_arg_supported = inspect.signature(self._agenerate).parameters.get( "run_manager" @@ -917,7 +955,7 @@ async def agenerate( new_results = await self._agenerate_helper( missing_prompts, stop, run_managers, bool(new_arg_supported), **kwargs ) - llm_output = update_cache( + llm_output = await aupdate_cache( existing_prompts, llm_string, missing_prompt_idxs, new_results, prompts ) run_info = ( diff --git a/libs/langchain/langchain/cache.py b/libs/langchain/langchain/cache.py index fae1d1cf03261..3c249e964c5a8 100644 --- a/libs/langchain/langchain/cache.py +++ b/libs/langchain/langchain/cache.py @@ -1,6 +1,7 @@ from langchain_community.cache import ( AstraDBCache, AstraDBSemanticCache, + AsyncRedisCache, CassandraCache, CassandraSemanticCache, FullLLMCache, @@ -22,6 +23,7 @@ "SQLAlchemyCache", "SQLiteCache", "UpstashRedisCache", + "AsyncRedisCache", "RedisCache", "RedisSemanticCache", "GPTCache", diff --git a/libs/langchain/tests/integration_tests/cache/test_redis_cache.py b/libs/langchain/tests/integration_tests/cache/test_redis_cache.py index 7b44ade026dab..846c709b97168 100644 --- a/libs/langchain/tests/integration_tests/cache/test_redis_cache.py +++ b/libs/langchain/tests/integration_tests/cache/test_redis_cache.py @@ -1,6 +1,7 @@ """Test Redis cache functionality.""" import uuid -from typing import List, cast +from contextlib import asynccontextmanager, contextmanager +from typing import AsyncGenerator, Generator, List, Optional, cast import pytest from langchain_core.embeddings import Embeddings @@ -8,7 +9,7 @@ from langchain_core.messages import AIMessage, BaseMessage, HumanMessage from langchain_core.outputs import ChatGeneration, Generation, LLMResult -from langchain.cache import RedisCache, RedisSemanticCache +from langchain.cache import AsyncRedisCache, RedisCache, RedisSemanticCache from langchain.globals import get_llm_cache, set_llm_cache from tests.integration_tests.cache.fake_embeddings import ( ConsistentFakeEmbeddings, @@ -17,65 +18,176 @@ from tests.unit_tests.llms.fake_chat_model import FakeChatModel from tests.unit_tests.llms.fake_llm import FakeLLM -REDIS_TEST_URL = "redis://localhost:6379" +# Using a non-standard port to avoid conflicts with potentially local running +# redis instances +# You can spin up a local redis using docker compose +# cd [repository-root]/docker +# docker-compose up redis +REDIS_TEST_URL = "redis://localhost:6020" def random_string() -> str: return str(uuid.uuid4()) -def test_redis_cache_ttl() -> None: +@contextmanager +def get_sync_redis(*, ttl: Optional[int] = 1) -> Generator[RedisCache, None, None]: + """Get a sync RedisCache instance.""" import redis - set_llm_cache(RedisCache(redis_=redis.Redis.from_url(REDIS_TEST_URL), ttl=1)) - llm_cache = cast(RedisCache, get_llm_cache()) - llm_cache.update("foo", "bar", [Generation(text="fizz")]) - key = llm_cache._key("foo", "bar") - assert llm_cache.redis.pttl(key) > 0 + cache = RedisCache(redis_=redis.Redis.from_url(REDIS_TEST_URL), ttl=ttl) + try: + yield cache + finally: + cache.clear() -def test_redis_cache() -> None: - import redis +@asynccontextmanager +async def get_async_redis( + *, ttl: Optional[int] = 1 +) -> AsyncGenerator[AsyncRedisCache, None]: + """Get an async RedisCache instance.""" + from redis.asyncio import Redis - set_llm_cache(RedisCache(redis_=redis.Redis.from_url(REDIS_TEST_URL))) - llm = FakeLLM() - params = llm.dict() - params["stop"] = None - llm_string = str(sorted([(k, v) for k, v in params.items()])) - get_llm_cache().update("foo", llm_string, [Generation(text="fizz")]) - output = llm.generate(["foo"]) - expected_output = LLMResult( - generations=[[Generation(text="fizz")]], - llm_output={}, - ) - assert output == expected_output - llm_cache = cast(RedisCache, get_llm_cache()) - llm_cache.redis.flushall() + cache = AsyncRedisCache(redis_=Redis.from_url(REDIS_TEST_URL), ttl=ttl) + try: + yield cache + finally: + await cache.aclear() + + +def test_redis_cache_ttl() -> None: + from redis import Redis + + with get_sync_redis() as llm_cache: + set_llm_cache(llm_cache) + llm_cache.update("foo", "bar", [Generation(text="fizz")]) + key = llm_cache._key("foo", "bar") + assert isinstance(llm_cache.redis, Redis) + assert llm_cache.redis.pttl(key) > 0 + + +async def test_async_redis_cache_ttl() -> None: + from redis.asyncio import Redis as AsyncRedis + + async with get_async_redis() as redis_cache: + set_llm_cache(redis_cache) + llm_cache = cast(RedisCache, get_llm_cache()) + await llm_cache.aupdate("foo", "bar", [Generation(text="fizz")]) + key = llm_cache._key("foo", "bar") + assert isinstance(llm_cache.redis, AsyncRedis) + assert await llm_cache.redis.pttl(key) > 0 + + +def test_sync_redis_cache() -> None: + with get_sync_redis() as llm_cache: + set_llm_cache(llm_cache) + llm = FakeLLM() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + llm_cache.update("prompt", llm_string, [Generation(text="fizz0")]) + output = llm.generate(["prompt"]) + expected_output = LLMResult( + generations=[[Generation(text="fizz0")]], + llm_output={}, + ) + assert output == expected_output + + +async def test_sync_in_async_redis_cache() -> None: + """Test the sync RedisCache invoked with async methods""" + with get_sync_redis() as llm_cache: + set_llm_cache(llm_cache) + llm = FakeLLM() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + # llm_cache.update("meow", llm_string, [Generation(text="meow")]) + await llm_cache.aupdate("prompt", llm_string, [Generation(text="fizz1")]) + output = await llm.agenerate(["prompt"]) + expected_output = LLMResult( + generations=[[Generation(text="fizz1")]], + llm_output={}, + ) + assert output == expected_output + + +async def test_async_redis_cache() -> None: + async with get_async_redis() as redis_cache: + set_llm_cache(redis_cache) + llm = FakeLLM() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + llm_cache = cast(RedisCache, get_llm_cache()) + await llm_cache.aupdate("prompt", llm_string, [Generation(text="fizz2")]) + output = await llm.agenerate(["prompt"]) + expected_output = LLMResult( + generations=[[Generation(text="fizz2")]], + llm_output={}, + ) + assert output == expected_output + + +async def test_async_in_sync_redis_cache() -> None: + async with get_async_redis() as redis_cache: + set_llm_cache(redis_cache) + llm = FakeLLM() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + llm_cache = cast(RedisCache, get_llm_cache()) + with pytest.raises(NotImplementedError): + llm_cache.update("foo", llm_string, [Generation(text="fizz")]) def test_redis_cache_chat() -> None: - import redis + with get_sync_redis() as redis_cache: + set_llm_cache(redis_cache) + llm = FakeChatModel() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + prompt: List[BaseMessage] = [HumanMessage(content="foo")] + llm_cache = cast(RedisCache, get_llm_cache()) + llm_cache.update( + dumps(prompt), + llm_string, + [ChatGeneration(message=AIMessage(content="fizz"))], + ) + output = llm.generate([prompt]) + expected_output = LLMResult( + generations=[[ChatGeneration(message=AIMessage(content="fizz"))]], + llm_output={}, + ) + assert output == expected_output - set_llm_cache(RedisCache(redis_=redis.Redis.from_url(REDIS_TEST_URL))) - llm = FakeChatModel() - params = llm.dict() - params["stop"] = None - llm_string = str(sorted([(k, v) for k, v in params.items()])) - prompt: List[BaseMessage] = [HumanMessage(content="foo")] - get_llm_cache().update( - dumps(prompt), llm_string, [ChatGeneration(message=AIMessage(content="fizz"))] - ) - output = llm.generate([prompt]) - expected_output = LLMResult( - generations=[[ChatGeneration(message=AIMessage(content="fizz"))]], - llm_output={}, - ) - assert output == expected_output - llm_cache = cast(RedisCache, get_llm_cache()) - llm_cache.redis.flushall() + +async def test_async_redis_cache_chat() -> None: + async with get_async_redis() as redis_cache: + set_llm_cache(redis_cache) + llm = FakeChatModel() + params = llm.dict() + params["stop"] = None + llm_string = str(sorted([(k, v) for k, v in params.items()])) + prompt: List[BaseMessage] = [HumanMessage(content="foo")] + llm_cache = cast(RedisCache, get_llm_cache()) + await llm_cache.aupdate( + dumps(prompt), + llm_string, + [ChatGeneration(message=AIMessage(content="fizz"))], + ) + output = await llm.agenerate([prompt]) + expected_output = LLMResult( + generations=[[ChatGeneration(message=AIMessage(content="fizz"))]], + llm_output={}, + ) + assert output == expected_output def test_redis_semantic_cache() -> None: + """Test redis semantic cache functionality.""" set_llm_cache( RedisSemanticCache( embedding=FakeEmbeddings(), redis_url=REDIS_TEST_URL, score_threshold=0.1 @@ -85,7 +197,8 @@ def test_redis_semantic_cache() -> None: params = llm.dict() params["stop"] = None llm_string = str(sorted([(k, v) for k, v in params.items()])) - get_llm_cache().update("foo", llm_string, [Generation(text="fizz")]) + llm_cache = cast(RedisSemanticCache, get_llm_cache()) + llm_cache.update("foo", llm_string, [Generation(text="fizz")]) output = llm.generate( ["bar"] ) # foo and bar will have the same embedding produced by FakeEmbeddings @@ -95,13 +208,13 @@ def test_redis_semantic_cache() -> None: ) assert output == expected_output # clear the cache - get_llm_cache().clear(llm_string=llm_string) + llm_cache.clear(llm_string=llm_string) output = llm.generate( ["bar"] ) # foo and bar will have the same embedding produced by FakeEmbeddings # expect different output now without cached result assert output != expected_output - get_llm_cache().clear(llm_string=llm_string) + llm_cache.clear(llm_string=llm_string) def test_redis_semantic_cache_multi() -> None: @@ -114,7 +227,8 @@ def test_redis_semantic_cache_multi() -> None: params = llm.dict() params["stop"] = None llm_string = str(sorted([(k, v) for k, v in params.items()])) - get_llm_cache().update( + llm_cache = cast(RedisSemanticCache, get_llm_cache()) + llm_cache.update( "foo", llm_string, [Generation(text="fizz"), Generation(text="Buzz")] ) output = llm.generate( @@ -126,7 +240,7 @@ def test_redis_semantic_cache_multi() -> None: ) assert output == expected_output # clear the cache - get_llm_cache().clear(llm_string=llm_string) + llm_cache.clear(llm_string=llm_string) def test_redis_semantic_cache_chat() -> None: @@ -140,7 +254,8 @@ def test_redis_semantic_cache_chat() -> None: params["stop"] = None llm_string = str(sorted([(k, v) for k, v in params.items()])) prompt: List[BaseMessage] = [HumanMessage(content="foo")] - get_llm_cache().update( + llm_cache = cast(RedisSemanticCache, get_llm_cache()) + llm_cache.update( dumps(prompt), llm_string, [ChatGeneration(message=AIMessage(content="fizz"))] ) output = llm.generate([prompt]) @@ -149,7 +264,7 @@ def test_redis_semantic_cache_chat() -> None: llm_output={}, ) assert output == expected_output - get_llm_cache().clear(llm_string=llm_string) + llm_cache.clear(llm_string=llm_string) @pytest.mark.parametrize("embedding", [ConsistentFakeEmbeddings()]) @@ -192,10 +307,11 @@ def test_redis_semantic_cache_hit( ] for prompt_i_generations in generations ] + llm_cache = cast(RedisSemanticCache, get_llm_cache()) for prompt_i, llm_generations_i in zip(prompts, llm_generations): print(prompt_i) print(llm_generations_i) - get_llm_cache().update(prompt_i, llm_string, llm_generations_i) + llm_cache.update(prompt_i, llm_string, llm_generations_i) llm.generate(prompts) assert llm.generate(prompts) == LLMResult( generations=llm_generations, llm_output={} diff --git a/libs/langchain/tests/unit_tests/test_cache.py b/libs/langchain/tests/unit_tests/test_cache.py index 88260a6f71cfa..5b2e1a4da4e2c 100644 --- a/libs/langchain/tests/unit_tests/test_cache.py +++ b/libs/langchain/tests/unit_tests/test_cache.py @@ -1,4 +1,5 @@ """Test caching for LLMs and ChatModels.""" +import sqlite3 from typing import Dict, Generator, List, Union import pytest @@ -21,7 +22,11 @@ def get_sqlite_cache() -> SQLAlchemyCache: - return SQLAlchemyCache(engine=create_engine("sqlite://")) + return SQLAlchemyCache( + engine=create_engine( + "sqlite://", creator=lambda: sqlite3.connect("file::memory:?cache=shared") + ) + ) CACHE_OPTIONS = [ @@ -35,33 +40,41 @@ def set_cache_and_teardown(request: FixtureRequest) -> Generator[None, None, Non # Will be run before each test cache_instance = request.param set_llm_cache(cache_instance()) - if get_llm_cache(): - get_llm_cache().clear() + if llm_cache := get_llm_cache(): + llm_cache.clear() else: raise ValueError("Cache not set. This should never happen.") yield # Will be run after each test - if get_llm_cache(): - get_llm_cache().clear() + if llm_cache: + llm_cache.clear() set_llm_cache(None) else: raise ValueError("Cache not set. This should never happen.") -def test_llm_caching() -> None: +async def test_llm_caching() -> None: prompt = "How are you?" response = "Test response" cached_response = "Cached test response" llm = FakeListLLM(responses=[response]) - if get_llm_cache(): - get_llm_cache().update( + if llm_cache := get_llm_cache(): + # sync test + llm_cache.update( prompt=prompt, llm_string=create_llm_string(llm), return_val=[Generation(text=cached_response)], ) assert llm(prompt) == cached_response + # async test + await llm_cache.aupdate( + prompt=prompt, + llm_string=create_llm_string(llm), + return_val=[Generation(text=cached_response)], + ) + assert await llm.ainvoke(prompt) == cached_response else: raise ValueError( "The cache not set. This should never happen, as the pytest fixture " @@ -90,14 +103,15 @@ def test_old_sqlite_llm_caching() -> None: assert llm(prompt) == cached_response -def test_chat_model_caching() -> None: +async def test_chat_model_caching() -> None: prompt: List[BaseMessage] = [HumanMessage(content="How are you?")] response = "Test response" cached_response = "Cached test response" cached_message = AIMessage(content=cached_response) llm = FakeListChatModel(responses=[response]) - if get_llm_cache(): - get_llm_cache().update( + if llm_cache := get_llm_cache(): + # sync test + llm_cache.update( prompt=dumps(prompt), llm_string=llm._get_llm_string(), return_val=[ChatGeneration(message=cached_message)], @@ -105,6 +119,16 @@ def test_chat_model_caching() -> None: result = llm(prompt) assert isinstance(result, AIMessage) assert result.content == cached_response + + # async test + await llm_cache.aupdate( + prompt=dumps(prompt), + llm_string=llm._get_llm_string(), + return_val=[ChatGeneration(message=cached_message)], + ) + result = await llm.ainvoke(prompt) + assert isinstance(result, AIMessage) + assert result.content == cached_response else: raise ValueError( "The cache not set. This should never happen, as the pytest fixture " @@ -112,25 +136,38 @@ def test_chat_model_caching() -> None: ) -def test_chat_model_caching_params() -> None: +async def test_chat_model_caching_params() -> None: prompt: List[BaseMessage] = [HumanMessage(content="How are you?")] response = "Test response" cached_response = "Cached test response" cached_message = AIMessage(content=cached_response) llm = FakeListChatModel(responses=[response]) - if get_llm_cache(): - get_llm_cache().update( + if llm_cache := get_llm_cache(): + # sync test + llm_cache.update( prompt=dumps(prompt), llm_string=llm._get_llm_string(functions=[]), return_val=[ChatGeneration(message=cached_message)], ) result = llm(prompt, functions=[]) + result_no_params = llm(prompt) assert isinstance(result, AIMessage) assert result.content == cached_response - result_no_params = llm(prompt) assert isinstance(result_no_params, AIMessage) assert result_no_params.content == response + # async test + await llm_cache.aupdate( + prompt=dumps(prompt), + llm_string=llm._get_llm_string(functions=[]), + return_val=[ChatGeneration(message=cached_message)], + ) + result = await llm.ainvoke(prompt, functions=[]) + result_no_params = await llm.ainvoke(prompt) + assert isinstance(result, AIMessage) + assert result.content == cached_response + assert isinstance(result_no_params, AIMessage) + assert result_no_params.content == response else: raise ValueError( "The cache not set. This should never happen, as the pytest fixture " @@ -138,19 +175,31 @@ def test_chat_model_caching_params() -> None: ) -def test_llm_cache_clear() -> None: +async def test_llm_cache_clear() -> None: prompt = "How are you?" - response = "Test response" + expected_response = "Test response" cached_response = "Cached test response" - llm = FakeListLLM(responses=[response]) - if get_llm_cache(): - get_llm_cache().update( + llm = FakeListLLM(responses=[expected_response]) + if llm_cache := get_llm_cache(): + # sync test + llm_cache.update( + prompt=prompt, + llm_string=create_llm_string(llm), + return_val=[Generation(text=cached_response)], + ) + llm_cache.clear() + response = llm(prompt) + assert response == expected_response + + # async test + await llm_cache.aupdate( prompt=prompt, llm_string=create_llm_string(llm), return_val=[Generation(text=cached_response)], ) - get_llm_cache().clear() - assert llm(prompt) == response + await llm_cache.aclear() + response = await llm.ainvoke(prompt) + assert response == expected_response else: raise ValueError( "The cache not set. This should never happen, as the pytest fixture " From 34d2daffb3169f2d8f83d0c02d6b8159c138f733 Mon Sep 17 00:00:00 2001 From: Luiz Ferreira Date: Thu, 8 Feb 2024 00:08:26 -0300 Subject: [PATCH 24/83] community[patch]: Fix chat openai unit test (#17124) - **Description:** Actually the test named `test_openai_apredict` isn't testing the apredict method from ChatOpenAI. - **Twitter handle:** https://twitter.com/OAlmofadas --- .../tests/unit_tests/chat_models/test_openai.py | 14 +++++++------- .../tests/unit_tests/embeddings/test_openai.py | 6 +----- .../community/tests/unit_tests/llms/test_openai.py | 12 ++++-------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/libs/community/tests/unit_tests/chat_models/test_openai.py b/libs/community/tests/unit_tests/chat_models/test_openai.py index 22fde4f335d9f..ad7033e4ea8a4 100644 --- a/libs/community/tests/unit_tests/chat_models/test_openai.py +++ b/libs/community/tests/unit_tests/chat_models/test_openai.py @@ -17,9 +17,9 @@ @pytest.mark.requires("openai") def test_openai_model_param() -> None: - llm = ChatOpenAI(model="foo") + llm = ChatOpenAI(model="foo", openai_api_key="foo") assert llm.model_name == "foo" - llm = ChatOpenAI(model_name="foo") + llm = ChatOpenAI(model_name="foo", openai_api_key="foo") assert llm.model_name == "foo" @@ -81,7 +81,7 @@ def mock_completion() -> dict: @pytest.mark.requires("openai") def test_openai_predict(mock_completion: dict) -> None: - llm = ChatOpenAI() + llm = ChatOpenAI(openai_api_key="foo") mock_client = MagicMock() completed = False @@ -103,11 +103,11 @@ def mock_create(*args: Any, **kwargs: Any) -> Any: @pytest.mark.requires("openai") async def test_openai_apredict(mock_completion: dict) -> None: - llm = ChatOpenAI() + llm = ChatOpenAI(openai_api_key="foo") mock_client = MagicMock() completed = False - def mock_create(*args: Any, **kwargs: Any) -> Any: + async def mock_create(*args: Any, **kwargs: Any) -> Any: nonlocal completed completed = True return mock_completion @@ -115,9 +115,9 @@ def mock_create(*args: Any, **kwargs: Any) -> Any: mock_client.create = mock_create with patch.object( llm, - "client", + "async_client", mock_client, ): - res = llm.predict("bar") + res = await llm.apredict("bar") assert res == "Bar Baz" assert completed diff --git a/libs/community/tests/unit_tests/embeddings/test_openai.py b/libs/community/tests/unit_tests/embeddings/test_openai.py index e9c3979138be4..c9499722ff5ec 100644 --- a/libs/community/tests/unit_tests/embeddings/test_openai.py +++ b/libs/community/tests/unit_tests/embeddings/test_openai.py @@ -1,11 +1,7 @@ -import os - import pytest from langchain_community.embeddings.openai import OpenAIEmbeddings -os.environ["OPENAI_API_KEY"] = "foo" - @pytest.mark.requires("openai") def test_openai_invalid_model_kwargs() -> None: @@ -16,5 +12,5 @@ def test_openai_invalid_model_kwargs() -> None: @pytest.mark.requires("openai") def test_openai_incorrect_field() -> None: with pytest.warns(match="not default parameter"): - llm = OpenAIEmbeddings(foo="bar") + llm = OpenAIEmbeddings(foo="bar", openai_api_key="foo") assert llm.model_kwargs == {"foo": "bar"} diff --git a/libs/community/tests/unit_tests/llms/test_openai.py b/libs/community/tests/unit_tests/llms/test_openai.py index 3b1c4d8dfed23..73f6fad283483 100644 --- a/libs/community/tests/unit_tests/llms/test_openai.py +++ b/libs/community/tests/unit_tests/llms/test_openai.py @@ -1,12 +1,8 @@ -import os - import pytest from langchain_community.llms.openai import OpenAI from langchain_community.utils.openai import is_openai_v1 -os.environ["OPENAI_API_KEY"] = "foo" - def _openai_v1_installed() -> bool: try: @@ -17,15 +13,15 @@ def _openai_v1_installed() -> bool: @pytest.mark.requires("openai") def test_openai_model_param() -> None: - llm = OpenAI(model="foo") + llm = OpenAI(model="foo", openai_api_key="foo") assert llm.model_name == "foo" - llm = OpenAI(model_name="foo") + llm = OpenAI(model_name="foo", openai_api_key="foo") assert llm.model_name == "foo" @pytest.mark.requires("openai") def test_openai_model_kwargs() -> None: - llm = OpenAI(model_kwargs={"foo": "bar"}) + llm = OpenAI(model_kwargs={"foo": "bar"}, openai_api_key="foo") assert llm.model_kwargs == {"foo": "bar"} @@ -42,7 +38,7 @@ def test_openai_invalid_model_kwargs() -> None: @pytest.mark.requires("openai") def test_openai_incorrect_field() -> None: with pytest.warns(match="not default parameter"): - llm = OpenAI(foo="bar") + llm = OpenAI(foo="bar", openai_api_key="foo") assert llm.model_kwargs == {"foo": "bar"} From d903fa313e338ed1474bc2473222989815ad1740 Mon Sep 17 00:00:00 2001 From: Leonid Ganeline Date: Wed, 7 Feb 2024 19:09:34 -0800 Subject: [PATCH 25/83] docs: titles fix (#17206) Several notebooks have Title != file name. That results in corrupted sorting in Navbar (ToC). - Fixed titles and file names. - Changed text formats to the consistent form - Redirected renamed files in the `Vercel.json` --- ...nb => alibabacloud_pai_eas_endpoint.ipynb} | 16 +-- .../{watsonxllm.ipynb => ibm_watsonx.ipynb} | 10 +- ...{hanavector.ipynb => sap_hanavector.ipynb} | 105 ++++++++++-------- .../vectorstores/thirdai_neuraldb.ipynb | 32 ++++-- docs/vercel.json | 12 ++ 5 files changed, 109 insertions(+), 66 deletions(-) rename docs/docs/integrations/llms/{pai_eas_endpoint.ipynb => alibabacloud_pai_eas_endpoint.ipynb} (62%) rename docs/docs/integrations/llms/{watsonxllm.ipynb => ibm_watsonx.ipynb} (96%) rename docs/docs/integrations/vectorstores/{hanavector.ipynb => sap_hanavector.ipynb} (92%) diff --git a/docs/docs/integrations/llms/pai_eas_endpoint.ipynb b/docs/docs/integrations/llms/alibabacloud_pai_eas_endpoint.ipynb similarity index 62% rename from docs/docs/integrations/llms/pai_eas_endpoint.ipynb rename to docs/docs/integrations/llms/alibabacloud_pai_eas_endpoint.ipynb index 6fd85b7d58f65..db4d8d588ac68 100644 --- a/docs/docs/integrations/llms/pai_eas_endpoint.ipynb +++ b/docs/docs/integrations/llms/alibabacloud_pai_eas_endpoint.ipynb @@ -4,8 +4,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# AliCloud PAI EAS\n", - "Machine Learning Platform for AI of Alibaba Cloud is a machine learning or deep learning engineering platform intended for enterprises and developers. It provides easy-to-use, cost-effective, high-performance, and easy-to-scale plug-ins that can be applied to various industry scenarios. With over 140 built-in optimization algorithms, Machine Learning Platform for AI provides whole-process AI engineering capabilities including data labeling (PAI-iTAG), model building (PAI-Designer and PAI-DSW), model training (PAI-DLC), compilation optimization, and inference deployment (PAI-EAS). PAI-EAS supports different types of hardware resources, including CPUs and GPUs, and features high throughput and low latency. It allows you to deploy large-scale complex models with a few clicks and perform elastic scale-ins and scale-outs in real time. It also provides a comprehensive O&M and monitoring system." + "# Alibaba Cloud PAI EAS\n", + "\n", + ">[Machine Learning Platform for AI of Alibaba Cloud](https://www.alibabacloud.com/help/en/pai) is a machine learning or deep learning engineering platform intended for enterprises and developers. It provides easy-to-use, cost-effective, high-performance, and easy-to-scale plug-ins that can be applied to various industry scenarios. With over 140 built-in optimization algorithms, `Machine Learning Platform for AI` provides whole-process AI engineering capabilities including data labeling (`PAI-iTAG`), model building (`PAI-Designer` and `PAI-DSW`), model training (`PAI-DLC`), compilation optimization, and inference deployment (`PAI-EAS`). `PAI-EAS` supports different types of hardware resources, including CPUs and GPUs, and features high throughput and low latency. It allows you to deploy large-scale complex models with a few clicks and perform elastic scale-ins and scale-outs in real time. It also provides a comprehensive O&M and monitoring system." ] }, { @@ -29,7 +30,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "One who want to use eas llms must set up eas service first. When the eas service is launched, eas_service_rul and eas_service token can be got. Users can refer to https://www.alibabacloud.com/help/en/pai/user-guide/service-deployment/ for more information," + "One who wants to use EAS LLMs must set up EAS service first. When the EAS service is launched, `EAS_SERVICE_URL` and `EAS_SERVICE_TOKEN` can be obtained. Users can refer to https://www.alibabacloud.com/help/en/pai/user-guide/service-deployment/ for more information," ] }, { @@ -74,7 +75,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -88,10 +89,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.11" - }, - "orig_nbformat": 4 + "version": "3.10.12" + } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/docs/docs/integrations/llms/watsonxllm.ipynb b/docs/docs/integrations/llms/ibm_watsonx.ipynb similarity index 96% rename from docs/docs/integrations/llms/watsonxllm.ipynb rename to docs/docs/integrations/llms/ibm_watsonx.ipynb index f0b142cf96d46..32ecdc34fc3e0 100644 --- a/docs/docs/integrations/llms/watsonxllm.ipynb +++ b/docs/docs/integrations/llms/ibm_watsonx.ipynb @@ -7,8 +7,9 @@ "source": [ "# IBM watsonx.ai\n", "\n", - "[WatsonxLLM](https://ibm.github.io/watsonx-ai-python-sdk/fm_extensions.html#langchain) is a wrapper for IBM [watsonx.ai](https://www.ibm.com/products/watsonx-ai) foundation models.\n", - "This example shows how to communicate with watsonx.ai models using LangChain." + ">[WatsonxLLM](https://ibm.github.io/watsonx-ai-python-sdk/fm_extensions.html#langchain) is a wrapper for IBM [watsonx.ai](https://www.ibm.com/products/watsonx-ai) foundation models.\n", + "\n", + "This example shows how to communicate with `watsonx.ai` models using `LangChain`." ] }, { @@ -16,6 +17,8 @@ "id": "ea35b2b7", "metadata": {}, "source": [ + "## Setting up\n", + "\n", "Install the package [`ibm-watsonx-ai`](https://ibm.github.io/watsonx-ai-python-sdk/install.html)." ] }, @@ -60,6 +63,7 @@ "metadata": {}, "source": [ "## Load the model\n", + "\n", "You might need to adjust model `parameters` for different models or tasks. For details, refer to [documentation](https://ibm.github.io/watsonx-ai-python-sdk/fm_model.html#metanames.GenTextParamsMetaNames)." ] }, @@ -328,7 +332,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/docs/docs/integrations/vectorstores/hanavector.ipynb b/docs/docs/integrations/vectorstores/sap_hanavector.ipynb similarity index 92% rename from docs/docs/integrations/vectorstores/hanavector.ipynb rename to docs/docs/integrations/vectorstores/sap_hanavector.ipynb index 0cc9f61d31d11..63fe3add655ff 100644 --- a/docs/docs/integrations/vectorstores/hanavector.ipynb +++ b/docs/docs/integrations/vectorstores/sap_hanavector.ipynb @@ -6,13 +6,15 @@ "source": [ "# SAP HANA Cloud Vector Engine\n", "\n", - ">SAP HANA Cloud Vector Engine is a vector store fully integrated into the SAP HANA Cloud database." + ">[SAP HANA Cloud Vector Engine](https://www.sap.com/events/teched/news-guide/ai.html#article8) is a vector store fully integrated into the `SAP HANA Cloud` database." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "## Setting up\n", + "\n", "Installation of the HANA database driver." ] }, @@ -32,7 +34,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To use `OpenAIEmbeddings` so we use the OpenAI API Key." + "To use `OpenAIEmbeddings` we use the OpenAI API Key." ] }, { @@ -55,63 +57,70 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Load the sample document \"state_of_the_union.txt\" and create chunks from it." + "Create a database connection to a HANA Cloud instance" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": { "ExecuteTime": { - "end_time": "2023-09-09T08:02:25.452472Z", - "start_time": "2023-09-09T08:02:25.441563Z" + "end_time": "2023-09-09T08:02:28.174088Z", + "start_time": "2023-09-09T08:02:28.162698Z" } }, "outputs": [], "source": [ - "from langchain.docstore.document import Document\n", - "from langchain.text_splitter import CharacterTextSplitter\n", - "from langchain_community.document_loaders import TextLoader\n", - "from langchain_community.vectorstores.hanavector import HanaDB\n", - "from langchain_openai import OpenAIEmbeddings\n", - "\n", - "text_documents = TextLoader(\"../../modules/state_of_the_union.txt\").load()\n", - "text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)\n", - "text_chunks = text_splitter.split_documents(text_documents)\n", - "print(f\"Number of document chunks: {len(text_chunks)}\")\n", + "from hdbcli import dbapi\n", "\n", - "embeddings = OpenAIEmbeddings()" + "# Use connection settings from the environment\n", + "connection = dbapi.connect(\n", + " address=os.environ.get(\"HANA_DB_ADDRESS\"),\n", + " port=os.environ.get(\"HANA_DB_PORT\"),\n", + " user=os.environ.get(\"HANA_DB_USER\"),\n", + " password=os.environ.get(\"HANA_DB_PASSWORD\"),\n", + " autocommit=True,\n", + " sslValidateCertificate=False,\n", + ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Create a database connection to a HANA Cloud instance" + "## Example" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the sample document \"state_of_the_union.txt\" and create chunks from it." ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": { "ExecuteTime": { - "end_time": "2023-09-09T08:02:28.174088Z", - "start_time": "2023-09-09T08:02:28.162698Z" + "end_time": "2023-09-09T08:02:25.452472Z", + "start_time": "2023-09-09T08:02:25.441563Z" } }, "outputs": [], "source": [ - "from hdbcli import dbapi\n", + "from langchain.docstore.document import Document\n", + "from langchain.text_splitter import CharacterTextSplitter\n", + "from langchain_community.document_loaders import TextLoader\n", + "from langchain_community.vectorstores.hanavector import HanaDB\n", + "from langchain_openai import OpenAIEmbeddings\n", "\n", - "# Use connection settings from the environment\n", - "connection = dbapi.connect(\n", - " address=os.environ.get(\"HANA_DB_ADDRESS\"),\n", - " port=os.environ.get(\"HANA_DB_PORT\"),\n", - " user=os.environ.get(\"HANA_DB_USER\"),\n", - " password=os.environ.get(\"HANA_DB_PASSWORD\"),\n", - " autocommit=True,\n", - " sslValidateCertificate=False,\n", - ")" + "text_documents = TextLoader(\"../../modules/state_of_the_union.txt\").load()\n", + "text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)\n", + "text_chunks = text_splitter.split_documents(text_documents)\n", + "print(f\"Number of document chunks: {len(text_chunks)}\")\n", + "\n", + "embeddings = OpenAIEmbeddings()" ] }, { @@ -161,7 +170,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Perform a query to get the two best matching document chunks from the ones that we added in the previous step.\n", + "Perform a query to get the two best-matching document chunks from the ones that we added in the previous step.\n", "By default \"Cosine Similarity\" is used for the search." ] }, @@ -211,12 +220,15 @@ { "cell_type": "markdown", "metadata": { - "collapsed": false + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } }, "source": [ - "Maximal Marginal Relevance Search (MMR)\n", + "## Maximal Marginal Relevance Search (MMR)\n", "\n", - "Maximal marginal relevance optimizes for similarity to query AND diversity among selected documents. First 20 (fetch_k) items will be retrieved from the DB. The MMR algorithm will then find the best 2 (k) matches." + "`Maximal marginal relevance` optimizes for similarity to query AND diversity among selected documents. The first 20 (fetch_k) items will be retrieved from the DB. The MMR algorithm will then find the best 2 (k) matches." ] }, { @@ -227,7 +239,10 @@ "end_time": "2023-09-09T08:05:23.276819Z", "start_time": "2023-09-09T08:05:21.972256Z" }, - "collapsed": false + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } }, "outputs": [], "source": [ @@ -346,7 +361,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Using a VectorStore as a retriever in chains for retrieval augmented generation (RAG)\n" + "## Using a VectorStore as a retriever in chains for retrieval augmented generation (RAG)" ] }, { @@ -505,7 +520,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Standard tables vs. \"custom\" tables with vector data" + "## Standard tables vs. \"custom\" tables with vector data" ] }, { @@ -513,9 +528,9 @@ "metadata": {}, "source": [ "As default behaviour, the table for the embeddings is created with 3 columns\n", - "* A column \"VEC_TEXT\", which contains the text of the Document\n", - "* A column \"VEC_METADATA\", which contains the metadata of the Document\n", - "* A column \"VEC_VECTOR\", which contains the embeddings-vector of the document's text" + "* A column `VEC_TEXT`, which contains the text of the Document\n", + "* A column `VEC_METADATA`, which contains the metadata of the Document\n", + "* A column `VEC_VECTOR`, which contains the embeddings-vector of the document's text" ] }, { @@ -594,11 +609,11 @@ "metadata": {}, "source": [ "Custom tables must have at least three columns that match the semantics of a standard table\n", - "* A column with type \"NCLOB\" or \"NVARCHAR\" for the text/context of the embeddings\n", - "* A column with type \"NCLOB\" or \"NVARCHAR\" for the metadata \n", + "* A column with type `NCLOB` or `NVARCHAR` for the text/context of the embeddings\n", + "* A column with type `NCLOB` or `NVARCHAR` for the metadata \n", "* A column with type REAL_VECTOR for the embedding vector\n", "\n", - "The table can contain additional columns. When new Documents are inserted to the table, these addtional columns must allow NULL values." + "The table can contain additional columns. When new Documents are inserted into the table, these additional columns must allow NULL values." ] }, { @@ -654,7 +669,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Add another document and perform a similarity search on the custom table" + "Add another document and perform a similarity search on the custom table." ] }, { diff --git a/docs/docs/integrations/vectorstores/thirdai_neuraldb.ipynb b/docs/docs/integrations/vectorstores/thirdai_neuraldb.ipynb index f1f2461076eea..137e501897cf1 100644 --- a/docs/docs/integrations/vectorstores/thirdai_neuraldb.ipynb +++ b/docs/docs/integrations/vectorstores/thirdai_neuraldb.ipynb @@ -4,16 +4,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# **NeuralDB**\n", - "NeuralDB is a CPU-friendly and fine-tunable vector store developed by ThirdAI.\n", + "# ThirdAI NeuralDB\n", + "\n", + ">[NeuralDB](https://www.thirdai.com/neuraldb-enterprise/) is a CPU-friendly and fine-tunable vector store developed by [ThirdAI](https://www.thirdai.com/).\n", + "\n", + "## Initialization\n", "\n", - "### **Initialization**\n", "There are three initialization methods:\n", "- From Scratch: Basic model\n", "- From Bazaar: Download a pretrained base model from our model bazaar for better performance\n", "- From Checkpoint: Load a model that was previously saved\n", "\n", - "For all of the following initialization methods, the `thirdai_key` parameter can be ommitted if the `THIRDAI_KEY` environment variable is set.\n", + "For all of the following initialization methods, the `thirdai_key` parameter can be omitted if the `THIRDAI_KEY` environment variable is set.\n", "\n", "ThirdAI API keys can be obtained at https://www.thirdai.com/try-bolt/" ] @@ -55,7 +57,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Inserting document sources**" + "## Inserting document sources" ] }, { @@ -96,7 +98,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Similarity search**\n", + "## Similarity search\n", + "\n", "To query the vectorstore, you can use the standard LangChain vectorstore method `similarity_search`, which returns a list of LangChain Document objects. Each document object represents a chunk of text from the indexed files. For example, it may contain a paragraph from one of the indexed PDF files. In addition to the text, the document's metadata field contains information such as the document's ID, the source of this document (which file it came from), and the score of the document." ] }, @@ -114,7 +117,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Fine tuning**\n", + "## Fine tuning\n", + "\n", "NeuralDBVectorStore can be fine-tuned to user behavior and domain-specific knowledge. It can be fine-tuned in two ways:\n", "1. Association: the vectorstore associates a source phrase with a target phrase. When the vectorstore sees the source phrase, it will also consider results that are relevant to the target phrase.\n", "2. Upvoting: the vectorstore upweights the score of a document for a specific query. This is useful when you want to fine-tune the vectorstore to user behavior. For example, if a user searches \"how is a car manufactured\" and likes the returned document with id 52, then we can upvote the document with id 52 for the query \"how is a car manufactured\"." @@ -146,15 +150,23 @@ ], "metadata": { "kernelspec": { - "display_name": "langchain", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.10.0" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/docs/vercel.json b/docs/vercel.json index 3e6b4a78f3a05..fe74510af2b88 100644 --- a/docs/vercel.json +++ b/docs/vercel.json @@ -1,5 +1,17 @@ { "redirects": [ + { + "source": "/docs/integrations/llms/watsonxllm", + "destination": "/docs/integrations/llms/ibm_watsonx" + }, + { + "source": "/docs/integrations/llms/pai_eas_endpoint", + "destination": "/docs/integrations/llms/alibabacloud_pai_eas_endpoint" + }, + { + "source": "/docs/integrations/vectorstores/hanavector", + "destination": "/docs/integrations/vectorstores/sap_hanavector" + }, { "source": "/docs/use_cases/qa_structured/sql", "destination": "/docs/use_cases/sql/" From 7e4b676d534b2a63a00706d7fcb6cef204f289f2 Mon Sep 17 00:00:00 2001 From: Tomaz Bratanic Date: Thu, 8 Feb 2024 04:16:14 +0100 Subject: [PATCH 26/83] community[patch]: Better error propagation for neo4jgraph (#17190) There are other errors that could happen when refreshing the schema, so we want to propagate specific errors for more clarity --- .../langchain_community/graphs/neo4j_graph.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/community/langchain_community/graphs/neo4j_graph.py b/libs/community/langchain_community/graphs/neo4j_graph.py index 125fd96b151c5..9df427e38c721 100644 --- a/libs/community/langchain_community/graphs/neo4j_graph.py +++ b/libs/community/langchain_community/graphs/neo4j_graph.py @@ -133,12 +133,14 @@ def __init__( # Set schema try: self.refresh_schema() - except neo4j.exceptions.ClientError: - raise ValueError( - "Could not use APOC procedures. " - "Please ensure the APOC plugin is installed in Neo4j and that " - "'apoc.meta.data()' is allowed in Neo4j configuration " - ) + except neo4j.exceptions.ClientError as e: + if e.code == "Neo.ClientError.Procedure.ProcedureNotFound": + raise ValueError( + "Could not use APOC procedures. " + "Please ensure the APOC plugin is installed in Neo4j and that " + "'apoc.meta.data()' is allowed in Neo4j configuration " + ) + raise e @property def get_schema(self) -> str: From 780e84ae79b4c9d958110c3a5e89d5e31e457361 Mon Sep 17 00:00:00 2001 From: Eugene Yurtsev Date: Wed, 7 Feb 2024 22:23:43 -0500 Subject: [PATCH 27/83] community[minor]: SQLDatabase Add fetch mode `cursor`, query parameters, query by selectable, expose execution options, and documentation (#17191) - **Description:** Improve `SQLDatabase` adapter component to promote code re-use, see [suggestion](https://github.com/langchain-ai/langchain/pull/16246#pullrequestreview-1846590962). - **Needed by:** GH-16246 - **Addressed to:** @baskaryan, @cbornet ## Details - Add `cursor` fetch mode - Accept SQL query parameters - Accept both `str` and SQLAlchemy selectables as query expression - Expose `execution_options` - Documentation page (notebook) about `SQLDatabase` [^1] See [About SQLDatabase](https://github.com/langchain-ai/langchain/blob/c1c7b763/docs/docs/integrations/tools/sql_database.ipynb). [^1]: Apparently there hasn't been any yet? --------- Co-authored-by: Andreas Motl --- .../integrations/tools/sql_database.ipynb | 440 ++++++++++++++++++ .../tools/sql_database/tool.py | 6 +- .../utilities/sql_database.py | 102 +++- .../langchain_experimental/sql/base.py | 2 +- .../langchain_experimental/sql/vector_sql.py | 1 + .../tests/unit_tests/test_sql_database.py | 75 ++- 6 files changed, 600 insertions(+), 26 deletions(-) create mode 100644 docs/docs/integrations/tools/sql_database.ipynb diff --git a/docs/docs/integrations/tools/sql_database.ipynb b/docs/docs/integrations/tools/sql_database.ipynb new file mode 100644 index 0000000000000..eec9027e60597 --- /dev/null +++ b/docs/docs/integrations/tools/sql_database.ipynb @@ -0,0 +1,440 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# SQL Database\n", + "\n", + "::: {.callout-note}\n", + "The `SQLDatabase` adapter utility is a wrapper around a database connection.\n", + "\n", + "For talking to SQL databases, it uses the [SQLAlchemy] Core API .\n", + ":::\n", + "\n", + "\n", + "This notebook shows how to use the utility to access an SQLite database.\n", + "It uses the example [Chinook Database], and demonstrates those features:\n", + "\n", + "- Query using SQL\n", + "- Query using SQLAlchemy selectable\n", + "- Fetch modes `cursor`, `all`, and `one`\n", + "- Bind query parameters\n", + "\n", + "[Chinook Database]: https://github.com/lerocha/chinook-database\n", + "[SQLAlchemy]: https://www.sqlalchemy.org/\n", + "\n", + "\n", + "You can use the `Tool` or `@tool` decorator to create a tool from this utility.\n", + "\n", + "\n", + "::: {.callout-caution}\n", + "If creating a tool from the SQLDatbase utility and combining it with an LLM or exposing it to an end user\n", + "remember to follow good security practices.\n", + "\n", + "See security information: https://python.langchain.com/docs/security\n", + ":::" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [], + "source": [ + "!wget 'https://github.com/lerocha/chinook-database/releases/download/v1.4.2/Chinook_Sqlite.sql'" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1|AC/DC\r\n", + "2|Accept\r\n", + "3|Aerosmith\r\n", + "4|Alanis Morissette\r\n", + "5|Alice In Chains\r\n", + "6|Antônio Carlos Jobim\r\n", + "7|Apocalyptica\r\n", + "8|Audioslave\r\n", + "9|BackBeat\r\n", + "10|Billy Cobham\r\n", + "11|Black Label Society\r\n", + "12|Black Sabbath\r\n" + ] + } + ], + "source": [ + "!sqlite3 -bail -cmd '.read Chinook_Sqlite.sql' -cmd 'SELECT * FROM Artist LIMIT 12;' -cmd '.quit'" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "!sqlite3 -bail -cmd '.read Chinook_Sqlite.sql' -cmd '.save Chinook.db' -cmd '.quit'" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Initialize Database" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "import sqlalchemy as sa\n", + "from langchain.sql_database import SQLDatabase\n", + "\n", + "db = SQLDatabase.from_uri(\"sqlite:///Chinook.db\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Query as cursor\n", + "\n", + "The fetch mode `cursor` returns results as SQLAlchemy's\n", + "`CursorResult` instance." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[{'ArtistId': 1, 'Name': 'AC/DC'},\n", + " {'ArtistId': 2, 'Name': 'Accept'},\n", + " {'ArtistId': 3, 'Name': 'Aerosmith'},\n", + " {'ArtistId': 4, 'Name': 'Alanis Morissette'},\n", + " {'ArtistId': 5, 'Name': 'Alice In Chains'},\n", + " {'ArtistId': 6, 'Name': 'Antônio Carlos Jobim'},\n", + " {'ArtistId': 7, 'Name': 'Apocalyptica'},\n", + " {'ArtistId': 8, 'Name': 'Audioslave'},\n", + " {'ArtistId': 9, 'Name': 'BackBeat'},\n", + " {'ArtistId': 10, 'Name': 'Billy Cobham'},\n", + " {'ArtistId': 11, 'Name': 'Black Label Society'},\n", + " {'ArtistId': 12, 'Name': 'Black Sabbath'}]\n" + ] + } + ], + "source": [ + "result = db.run(\"SELECT * FROM Artist LIMIT 12;\", fetch=\"cursor\")\n", + "print(type(result))\n", + "pprint(list(result.mappings()))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Query as string payload\n", + "\n", + "The fetch modes `all` and `one` return results in string format." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[(1, 'AC/DC'), (2, 'Accept'), (3, 'Aerosmith'), (4, 'Alanis Morissette'), (5, 'Alice In Chains'), (6, 'Antônio Carlos Jobim'), (7, 'Apocalyptica'), (8, 'Audioslave'), (9, 'BackBeat'), (10, 'Billy Cobham'), (11, 'Black Label Society'), (12, 'Black Sabbath')]\n" + ] + } + ], + "source": [ + "result = db.run(\"SELECT * FROM Artist LIMIT 12;\", fetch=\"all\")\n", + "print(type(result))\n", + "print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[(1, 'AC/DC')]\n" + ] + } + ], + "source": [ + "result = db.run(\"SELECT * FROM Artist LIMIT 12;\", fetch=\"one\")\n", + "print(type(result))\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Query with parameters\n", + "\n", + "In order to bind query parameters, use the optional `parameters` argument." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'ArtistId': 35, 'Name': 'Pedro Luís & A Parede'},\n", + " {'ArtistId': 115, 'Name': 'Page & Plant'},\n", + " {'ArtistId': 116, 'Name': 'Passengers'},\n", + " {'ArtistId': 117, 'Name': \"Paul D'Ianno\"},\n", + " {'ArtistId': 118, 'Name': 'Pearl Jam'},\n", + " {'ArtistId': 119, 'Name': 'Peter Tosh'},\n", + " {'ArtistId': 120, 'Name': 'Pink Floyd'},\n", + " {'ArtistId': 121, 'Name': 'Planet Hemp'},\n", + " {'ArtistId': 186, 'Name': 'Pedro Luís E A Parede'},\n", + " {'ArtistId': 256, 'Name': 'Philharmonia Orchestra & Sir Neville Marriner'},\n", + " {'ArtistId': 275, 'Name': 'Philip Glass Ensemble'}]\n" + ] + } + ], + "source": [ + "result = db.run(\n", + " \"SELECT * FROM Artist WHERE Name LIKE :search;\",\n", + " parameters={\"search\": \"p%\"},\n", + " fetch=\"cursor\",\n", + ")\n", + "pprint(list(result.mappings()))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Query with SQLAlchemy selectable\n", + "\n", + "Other than plain-text SQL statements, the adapter also accepts SQLAlchemy selectables." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'ArtistId': 35, 'Name': 'Pedro Luís & A Parede'},\n", + " {'ArtistId': 115, 'Name': 'Page & Plant'},\n", + " {'ArtistId': 116, 'Name': 'Passengers'},\n", + " {'ArtistId': 117, 'Name': \"Paul D'Ianno\"},\n", + " {'ArtistId': 118, 'Name': 'Pearl Jam'},\n", + " {'ArtistId': 119, 'Name': 'Peter Tosh'},\n", + " {'ArtistId': 120, 'Name': 'Pink Floyd'},\n", + " {'ArtistId': 121, 'Name': 'Planet Hemp'},\n", + " {'ArtistId': 186, 'Name': 'Pedro Luís E A Parede'},\n", + " {'ArtistId': 256, 'Name': 'Philharmonia Orchestra & Sir Neville Marriner'},\n", + " {'ArtistId': 275, 'Name': 'Philip Glass Ensemble'}]\n" + ] + } + ], + "source": [ + "# In order to build a selectable on SA's Core API, you need a table definition.\n", + "metadata = sa.MetaData()\n", + "artist = sa.Table(\n", + " \"Artist\",\n", + " metadata,\n", + " sa.Column(\"ArtistId\", sa.INTEGER, primary_key=True),\n", + " sa.Column(\"Name\", sa.TEXT),\n", + ")\n", + "\n", + "# Build a selectable with the same semantics of the recent query.\n", + "query = sa.select(artist).where(artist.c.Name.like(\"p%\"))\n", + "result = db.run(query, fetch=\"cursor\")\n", + "pprint(list(result.mappings()))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "## Query with execution options\n", + "\n", + "It is possible to augment the statement invocation with custom execution options.\n", + "For example, when applying a schema name translation, subsequent statements will\n", + "fail, because they try to hit a non-existing table." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "ename": "OperationalError", + "evalue": "(sqlite3.OperationalError) no such table: bar.Artist\n[SQL: SELECT bar.\"Artist\".\"ArtistId\", bar.\"Artist\".\"Name\" \nFROM bar.\"Artist\" \nWHERE bar.\"Artist\".\"Name\" LIKE ?]\n[parameters: ('p%',)]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1969\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[0;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[1;32m 1968\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m evt_handled:\n\u001b[0;32m-> 1969\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdo_execute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1970\u001b[0m \u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[1;32m 1971\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1973\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_has_events \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine\u001b[38;5;241m.\u001b[39m_has_events:\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py:922\u001b[0m, in \u001b[0;36mDefaultDialect.do_execute\u001b[0;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[1;32m 921\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdo_execute\u001b[39m(\u001b[38;5;28mself\u001b[39m, cursor, statement, parameters, context\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[0;32m--> 922\u001b[0m cursor\u001b[38;5;241m.\u001b[39mexecute(statement, parameters)\n", + "\u001b[0;31mOperationalError\u001b[0m: no such table: bar.Artist", + "\nThe above exception was the direct cause of the following exception:\n", + "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[6], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Build a selectable with the same semantics of the recent query.\u001b[39;00m\n\u001b[1;32m 2\u001b[0m query \u001b[38;5;241m=\u001b[39m sa\u001b[38;5;241m.\u001b[39mselect(artist)\u001b[38;5;241m.\u001b[39mwhere(artist\u001b[38;5;241m.\u001b[39mc\u001b[38;5;241m.\u001b[39mName\u001b[38;5;241m.\u001b[39mlike(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mp\u001b[39m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124m\"\u001b[39m))\n\u001b[0;32m----> 3\u001b[0m \u001b[43mdb\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfetch\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mresult\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mschema_translate_map\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mbar\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m}\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/libs/community/langchain_community/utilities/sql_database.py:484\u001b[0m, in \u001b[0;36mSQLDatabase.run\u001b[0;34m(self, command, fetch, parameters, execution_options, include_columns)\u001b[0m\n\u001b[1;32m 471\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrun\u001b[39m(\n\u001b[1;32m 472\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 473\u001b[0m command: Union[\u001b[38;5;28mstr\u001b[39m, Executable],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 477\u001b[0m include_columns: \u001b[38;5;28mbool\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m,\n\u001b[1;32m 478\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[\u001b[38;5;28mstr\u001b[39m, Result]:\n\u001b[1;32m 479\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Execute a SQL command and return a string representing the results.\u001b[39;00m\n\u001b[1;32m 480\u001b[0m \n\u001b[1;32m 481\u001b[0m \u001b[38;5;124;03m If the statement returns rows, a string of the results is returned.\u001b[39;00m\n\u001b[1;32m 482\u001b[0m \u001b[38;5;124;03m If the statement returns no rows, an empty string is returned.\u001b[39;00m\n\u001b[1;32m 483\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 484\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 485\u001b[0m \u001b[43m \u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfetch\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexecution_options\u001b[49m\n\u001b[1;32m 486\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 488\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m fetch \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m 489\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/libs/community/langchain_community/utilities/sql_database.py:450\u001b[0m, in \u001b[0;36mSQLDatabase._execute\u001b[0;34m(self, command, fetch, parameters, execution_options)\u001b[0m\n\u001b[1;32m 448\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 449\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mQuery expression has unknown type: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(command)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 450\u001b[0m cursor \u001b[38;5;241m=\u001b[39m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 451\u001b[0m \u001b[43m \u001b[49m\u001b[43mcommand\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 452\u001b[0m \u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 453\u001b[0m \u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mexecution_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 454\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 456\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m cursor\u001b[38;5;241m.\u001b[39mreturns_rows:\n\u001b[1;32m 457\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m fetch \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mall\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1416\u001b[0m, in \u001b[0;36mConnection.execute\u001b[0;34m(self, statement, parameters, execution_options)\u001b[0m\n\u001b[1;32m 1414\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exc\u001b[38;5;241m.\u001b[39mObjectNotExecutableError(statement) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m 1415\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1416\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mmeth\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1417\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1418\u001b[0m \u001b[43m \u001b[49m\u001b[43mdistilled_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1419\u001b[0m \u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mNO_OPTIONS\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1420\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py:516\u001b[0m, in \u001b[0;36mClauseElement._execute_on_connection\u001b[0;34m(self, connection, distilled_params, execution_options)\u001b[0m\n\u001b[1;32m 514\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m TYPE_CHECKING:\n\u001b[1;32m 515\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28mself\u001b[39m, Executable)\n\u001b[0;32m--> 516\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mconnection\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_clauseelement\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 517\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdistilled_params\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\n\u001b[1;32m 518\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 519\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 520\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m exc\u001b[38;5;241m.\u001b[39mObjectNotExecutableError(\u001b[38;5;28mself\u001b[39m)\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1639\u001b[0m, in \u001b[0;36mConnection._execute_clauseelement\u001b[0;34m(self, elem, distilled_parameters, execution_options)\u001b[0m\n\u001b[1;32m 1627\u001b[0m compiled_cache: Optional[CompiledCacheType] \u001b[38;5;241m=\u001b[39m execution_options\u001b[38;5;241m.\u001b[39mget(\n\u001b[1;32m 1628\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcompiled_cache\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine\u001b[38;5;241m.\u001b[39m_compiled_cache\n\u001b[1;32m 1629\u001b[0m )\n\u001b[1;32m 1631\u001b[0m compiled_sql, extracted_params, cache_hit \u001b[38;5;241m=\u001b[39m elem\u001b[38;5;241m.\u001b[39m_compile_w_cache(\n\u001b[1;32m 1632\u001b[0m dialect\u001b[38;5;241m=\u001b[39mdialect,\n\u001b[1;32m 1633\u001b[0m compiled_cache\u001b[38;5;241m=\u001b[39mcompiled_cache,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1637\u001b[0m linting\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdialect\u001b[38;5;241m.\u001b[39mcompiler_linting \u001b[38;5;241m|\u001b[39m compiler\u001b[38;5;241m.\u001b[39mWARN_LINTING,\n\u001b[1;32m 1638\u001b[0m )\n\u001b[0;32m-> 1639\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_context\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1640\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1641\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecution_ctx_cls\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_compiled\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1642\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompiled_sql\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1643\u001b[0m \u001b[43m \u001b[49m\u001b[43mdistilled_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1644\u001b[0m \u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1645\u001b[0m \u001b[43m \u001b[49m\u001b[43mcompiled_sql\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1646\u001b[0m \u001b[43m \u001b[49m\u001b[43mdistilled_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1647\u001b[0m \u001b[43m \u001b[49m\u001b[43melem\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1648\u001b[0m \u001b[43m \u001b[49m\u001b[43mextracted_params\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1649\u001b[0m \u001b[43m \u001b[49m\u001b[43mcache_hit\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcache_hit\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1650\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1651\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m has_events:\n\u001b[1;32m 1652\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdispatch\u001b[38;5;241m.\u001b[39mafter_execute(\n\u001b[1;32m 1653\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 1654\u001b[0m elem,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1658\u001b[0m ret,\n\u001b[1;32m 1659\u001b[0m )\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1848\u001b[0m, in \u001b[0;36mConnection._execute_context\u001b[0;34m(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)\u001b[0m\n\u001b[1;32m 1843\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_exec_insertmany_context(\n\u001b[1;32m 1844\u001b[0m dialect,\n\u001b[1;32m 1845\u001b[0m context,\n\u001b[1;32m 1846\u001b[0m )\n\u001b[1;32m 1847\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1848\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_exec_single_context\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1849\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\n\u001b[1;32m 1850\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1988\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[0;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[1;32m 1985\u001b[0m result \u001b[38;5;241m=\u001b[39m context\u001b[38;5;241m.\u001b[39m_setup_result_proxy()\n\u001b[1;32m 1987\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[0;32m-> 1988\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_handle_dbapi_exception\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1989\u001b[0m \u001b[43m \u001b[49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[1;32m 1990\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1992\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:2343\u001b[0m, in \u001b[0;36mConnection._handle_dbapi_exception\u001b[0;34m(self, e, statement, parameters, cursor, context, is_sub_exec)\u001b[0m\n\u001b[1;32m 2341\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m should_wrap:\n\u001b[1;32m 2342\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m sqlalchemy_exception \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m-> 2343\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m sqlalchemy_exception\u001b[38;5;241m.\u001b[39mwith_traceback(exc_info[\u001b[38;5;241m2\u001b[39m]) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n\u001b[1;32m 2344\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 2345\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m exc_info[\u001b[38;5;241m1\u001b[39m] \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1969\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[0;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[1;32m 1967\u001b[0m \u001b[38;5;28;01mbreak\u001b[39;00m\n\u001b[1;32m 1968\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m evt_handled:\n\u001b[0;32m-> 1969\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdo_execute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1970\u001b[0m \u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[1;32m 1971\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1973\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_has_events \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine\u001b[38;5;241m.\u001b[39m_has_events:\n\u001b[1;32m 1974\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdispatch\u001b[38;5;241m.\u001b[39mafter_cursor_execute(\n\u001b[1;32m 1975\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 1976\u001b[0m cursor,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1980\u001b[0m context\u001b[38;5;241m.\u001b[39mexecutemany,\n\u001b[1;32m 1981\u001b[0m )\n", + "File \u001b[0;32m~/dev/crate/ecosystem/langchain/.venv/lib/python3.11/site-packages/sqlalchemy/engine/default.py:922\u001b[0m, in \u001b[0;36mDefaultDialect.do_execute\u001b[0;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[1;32m 921\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdo_execute\u001b[39m(\u001b[38;5;28mself\u001b[39m, cursor, statement, parameters, context\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[0;32m--> 922\u001b[0m cursor\u001b[38;5;241m.\u001b[39mexecute(statement, parameters)\n", + "\u001b[0;31mOperationalError\u001b[0m: (sqlite3.OperationalError) no such table: bar.Artist\n[SQL: SELECT bar.\"Artist\".\"ArtistId\", bar.\"Artist\".\"Name\" \nFROM bar.\"Artist\" \nWHERE bar.\"Artist\".\"Name\" LIKE ?]\n[parameters: ('p%',)]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)" + ] + } + ], + "source": [ + "query = sa.select(artist).where(artist.c.Name.like(\"p%\"))\n", + "db.run(query, fetch=\"cursor\", execution_options={\"schema_translate_map\": {None: \"bar\"}})" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/libs/community/langchain_community/tools/sql_database/tool.py b/libs/community/langchain_community/tools/sql_database/tool.py index 850cecb45107b..4c7fe4726a055 100644 --- a/libs/community/langchain_community/tools/sql_database/tool.py +++ b/libs/community/langchain_community/tools/sql_database/tool.py @@ -1,6 +1,8 @@ # flake8: noqa """Tools for interacting with a SQL database.""" -from typing import Any, Dict, Optional, Type +from typing import Any, Dict, Optional, Sequence, Type, Union + +from sqlalchemy import Result from langchain_core.pydantic_v1 import BaseModel, Field, root_validator @@ -42,7 +44,7 @@ def _run( self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None, - ) -> str: + ) -> Union[str, Sequence[Dict[str, Any]], Result[Any]]: """Execute the query, return the results or an error message.""" return self.db.run_no_throw(query) diff --git a/libs/community/langchain_community/utilities/sql_database.py b/libs/community/langchain_community/utilities/sql_database.py index 298b8ca7e224c..087ac44bc112f 100644 --- a/libs/community/langchain_community/utilities/sql_database.py +++ b/libs/community/langchain_community/utilities/sql_database.py @@ -1,12 +1,21 @@ """SQLAlchemy wrapper around a database.""" from __future__ import annotations -from typing import Any, Dict, Iterable, List, Literal, Optional, Sequence +from typing import Any, Dict, Iterable, List, Literal, Optional, Sequence, Union import sqlalchemy from langchain_core._api import deprecated from langchain_core.utils import get_from_env -from sqlalchemy import MetaData, Table, create_engine, inspect, select, text +from sqlalchemy import ( + Executable, + MetaData, + Result, + Table, + create_engine, + inspect, + select, + text, +) from sqlalchemy.engine import Engine from sqlalchemy.exc import ProgrammingError, SQLAlchemyError from sqlalchemy.schema import CreateTable @@ -373,67 +382,113 @@ def _get_sample_rows(self, table: Table) -> str: def _execute( self, - command: str, - fetch: Literal["all", "one"] = "all", - ) -> Sequence[Dict[str, Any]]: + command: Union[str, Executable], + fetch: Literal["all", "one", "cursor"] = "all", + *, + parameters: Optional[Dict[str, Any]] = None, + execution_options: Optional[Dict[str, Any]] = None, + ) -> Union[Sequence[Dict[str, Any]], Result]: """ Executes SQL command through underlying engine. If the statement returns no rows, an empty list is returned. """ + parameters = parameters or {} + execution_options = execution_options or {} with self._engine.begin() as connection: # type: Connection # type: ignore[name-defined] if self._schema is not None: if self.dialect == "snowflake": connection.exec_driver_sql( - "ALTER SESSION SET search_path = %s", (self._schema,) + "ALTER SESSION SET search_path = %s", + (self._schema,), + execution_options=execution_options, ) elif self.dialect == "bigquery": - connection.exec_driver_sql("SET @@dataset_id=?", (self._schema,)) + connection.exec_driver_sql( + "SET @@dataset_id=?", + (self._schema,), + execution_options=execution_options, + ) elif self.dialect == "mssql": pass elif self.dialect == "trino": - connection.exec_driver_sql("USE ?", (self._schema,)) + connection.exec_driver_sql( + "USE ?", + (self._schema,), + execution_options=execution_options, + ) elif self.dialect == "duckdb": # Unclear which parameterized argument syntax duckdb supports. # The docs for the duckdb client say they support multiple, # but `duckdb_engine` seemed to struggle with all of them: # https://github.com/Mause/duckdb_engine/issues/796 - connection.exec_driver_sql(f"SET search_path TO {self._schema}") + connection.exec_driver_sql( + f"SET search_path TO {self._schema}", + execution_options=execution_options, + ) elif self.dialect == "oracle": connection.exec_driver_sql( - f"ALTER SESSION SET CURRENT_SCHEMA = {self._schema}" + f"ALTER SESSION SET CURRENT_SCHEMA = {self._schema}", + execution_options=execution_options, ) elif self.dialect == "sqlany": # If anybody using Sybase SQL anywhere database then it should not # go to else condition. It should be same as mssql. pass elif self.dialect == "postgresql": # postgresql - connection.exec_driver_sql("SET search_path TO %s", (self._schema,)) + connection.exec_driver_sql( + "SET search_path TO %s", + (self._schema,), + execution_options=execution_options, + ) + + if isinstance(command, str): + command = text(command) + elif isinstance(command, Executable): + pass + else: + raise TypeError(f"Query expression has unknown type: {type(command)}") + cursor = connection.execute( + command, + parameters, + execution_options=execution_options, + ) - cursor = connection.execute(text(command)) if cursor.returns_rows: if fetch == "all": result = [x._asdict() for x in cursor.fetchall()] elif fetch == "one": first_result = cursor.fetchone() result = [] if first_result is None else [first_result._asdict()] + elif fetch == "cursor": + return cursor else: - raise ValueError("Fetch parameter must be either 'one' or 'all'") + raise ValueError( + "Fetch parameter must be either 'one', 'all', or 'cursor'" + ) return result return [] def run( self, - command: str, - fetch: Literal["all", "one"] = "all", + command: Union[str, Executable], + fetch: Literal["all", "one", "cursor"] = "all", include_columns: bool = False, - ) -> str: + *, + parameters: Optional[Dict[str, Any]] = None, + execution_options: Optional[Dict[str, Any]] = None, + ) -> Union[str, Sequence[Dict[str, Any]], Result[Any]]: """Execute a SQL command and return a string representing the results. If the statement returns rows, a string of the results is returned. If the statement returns no rows, an empty string is returned. """ - result = self._execute(command, fetch) + result = self._execute( + command, fetch, parameters=parameters, execution_options=execution_options + ) + + if fetch == "cursor": + return result res = [ { @@ -472,7 +527,10 @@ def run_no_throw( command: str, fetch: Literal["all", "one"] = "all", include_columns: bool = False, - ) -> str: + *, + parameters: Optional[Dict[str, Any]] = None, + execution_options: Optional[Dict[str, Any]] = None, + ) -> Union[str, Sequence[Dict[str, Any]], Result[Any]]: """Execute a SQL command and return a string representing the results. If the statement returns rows, a string of the results is returned. @@ -481,7 +539,13 @@ def run_no_throw( If the statement throws an error, the error message is returned. """ try: - return self.run(command, fetch, include_columns) + return self.run( + command, + fetch, + parameters=parameters, + execution_options=execution_options, + include_columns=include_columns, + ) except SQLAlchemyError as e: """Format the error message""" return f"Error: {e}" diff --git a/libs/experimental/langchain_experimental/sql/base.py b/libs/experimental/langchain_experimental/sql/base.py index 1785598e36ae2..b6de5e67c9d45 100644 --- a/libs/experimental/langchain_experimental/sql/base.py +++ b/libs/experimental/langchain_experimental/sql/base.py @@ -173,7 +173,7 @@ def _call( sql_cmd = checked_sql_command _run_manager.on_text("\nSQLResult: ", verbose=self.verbose) - _run_manager.on_text(result, color="yellow", verbose=self.verbose) + _run_manager.on_text(str(result), color="yellow", verbose=self.verbose) # If return direct, we just set the final result equal to # the result of the sql query result, otherwise try to get a human readable # final answer diff --git a/libs/experimental/langchain_experimental/sql/vector_sql.py b/libs/experimental/langchain_experimental/sql/vector_sql.py index 1b0db95904416..a21a6bae8682e 100644 --- a/libs/experimental/langchain_experimental/sql/vector_sql.py +++ b/libs/experimental/langchain_experimental/sql/vector_sql.py @@ -78,6 +78,7 @@ def parse(self, text: str) -> str: def get_result_from_sqldb(db: SQLDatabase, cmd: str) -> Sequence[Dict[str, Any]]: result = db._execute(cmd, fetch="all") + assert isinstance(result, Sequence) return result diff --git a/libs/langchain/tests/unit_tests/test_sql_database.py b/libs/langchain/tests/unit_tests/test_sql_database.py index fea54e74c2548..c593faae8e821 100644 --- a/libs/langchain/tests/unit_tests/test_sql_database.py +++ b/libs/langchain/tests/unit_tests/test_sql_database.py @@ -1,16 +1,19 @@ -# flake8: noqa=E501 +# flake8: noqa: E501 """Test SQL database wrapper.""" - +import pytest +import sqlalchemy as sa from langchain_community.utilities.sql_database import SQLDatabase, truncate_word from sqlalchemy import ( Column, Integer, MetaData, + Result, String, Table, Text, create_engine, insert, + select, ) metadata_obj = MetaData() @@ -108,8 +111,8 @@ def test_table_info_w_sample_rows() -> None: assert sorted(output.split()) == sorted(expected_output.split()) -def test_sql_database_run() -> None: - """Test that commands can be run successfully and returned in correct format.""" +def test_sql_database_run_fetch_all() -> None: + """Verify running SQL expressions returning results as strings.""" engine = create_engine("sqlite:///:memory:") metadata_obj.create_all(engine) stmt = insert(user).values( @@ -131,6 +134,52 @@ def test_sql_database_run() -> None: assert full_output == expected_full_output +def test_sql_database_run_fetch_result() -> None: + """Verify running SQL expressions returning results as SQLAlchemy `Result` instances.""" + engine = create_engine("sqlite:///:memory:") + metadata_obj.create_all(engine) + stmt = insert(user).values(user_id=17, user_name="hwchase") + with engine.begin() as conn: + conn.execute(stmt) + db = SQLDatabase(engine) + command = "select user_id, user_name, user_bio from user where user_id = 17" + + result = db.run(command, fetch="cursor", include_columns=True) + expected = [{"user_id": 17, "user_name": "hwchase", "user_bio": None}] + assert isinstance(result, Result) + assert result.mappings().fetchall() == expected + + +def test_sql_database_run_with_parameters() -> None: + """Verify running SQL expressions with query parameters.""" + engine = create_engine("sqlite:///:memory:") + metadata_obj.create_all(engine) + stmt = insert(user).values(user_id=17, user_name="hwchase") + with engine.begin() as conn: + conn.execute(stmt) + db = SQLDatabase(engine) + command = "select user_id, user_name, user_bio from user where user_id = :user_id" + + full_output = db.run(command, parameters={"user_id": 17}, include_columns=True) + expected_full_output = "[{'user_id': 17, 'user_name': 'hwchase', 'user_bio': None}]" + assert full_output == expected_full_output + + +def test_sql_database_run_sqlalchemy_selectable() -> None: + """Verify running SQL expressions using SQLAlchemy selectable.""" + engine = create_engine("sqlite:///:memory:") + metadata_obj.create_all(engine) + stmt = insert(user).values(user_id=17, user_name="hwchase") + with engine.begin() as conn: + conn.execute(stmt) + db = SQLDatabase(engine) + command = select(user).where(user.c.user_id == 17) + + full_output = db.run(command, include_columns=True) + expected_full_output = "[{'user_id': 17, 'user_name': 'hwchase', 'user_bio': None}]" + assert full_output == expected_full_output + + def test_sql_database_run_update() -> None: """Test commands which return no rows return an empty string.""" engine = create_engine("sqlite:///:memory:") @@ -145,6 +194,24 @@ def test_sql_database_run_update() -> None: assert output == expected_output +def test_sql_database_schema_translate_map() -> None: + """Verify using statement-specific execution options.""" + + engine = create_engine("sqlite:///:memory:") + db = SQLDatabase(engine) + + # Define query using SQLAlchemy selectable. + command = select(user).where(user.c.user_id == 17) + + # Define statement-specific execution options. + execution_options = {"schema_translate_map": {None: "bar"}} + + # Verify the schema translation is applied. + with pytest.raises(sa.exc.OperationalError) as ex: + db.run(command, execution_options=execution_options, fetch="cursor") + assert ex.match("no such table: bar.user") + + def test_truncate_word() -> None: assert truncate_word("Hello World", length=5) == "He..." assert truncate_word("Hello World", length=0) == "Hello World" From 4e3ed7f043ce0f7ee14cd96c8fd7b820a61979d3 Mon Sep 17 00:00:00 2001 From: Bassem Yacoube <125713079+AI-Bassem@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:25:52 -0800 Subject: [PATCH 28/83] community[patch]: octoai embeddings bug fix (#17216) fixes a bug in octoa_embeddings provider --- .../langchain_community/embeddings/octoai_embeddings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/community/langchain_community/embeddings/octoai_embeddings.py b/libs/community/langchain_community/embeddings/octoai_embeddings.py index a93fa4e03ad18..f006a437a4ee3 100644 --- a/libs/community/langchain_community/embeddings/octoai_embeddings.py +++ b/libs/community/langchain_community/embeddings/octoai_embeddings.py @@ -80,7 +80,7 @@ def _compute_embeddings( json_data = resp_json["data"] for item in json_data: if "embedding" in item: - embedding.append(item["embedding"]) + embedding = item["embedding"] except Exception as e: raise ValueError(f"Error raised by the inference endpoint: {e}") from e From 7f55c957900e6cd4693e6943dc2bb47b6f60d504 Mon Sep 17 00:00:00 2001 From: sana-google <135305956+sana-google@users.noreply.github.com> Date: Thu, 8 Feb 2024 03:26:10 +0000 Subject: [PATCH 29/83] docs: add missing link to Quickstart (#17085) Replace this entire comment with: - **Description:** Added missing link for Quickstart in Model IO documentation, - **Issue:** N/A, - **Dependencies:** N/A, - **Twitter handle:** N/A Co-authored-by: Eugene Yurtsev --- docs/docs/modules/model_io/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/modules/model_io/index.mdx b/docs/docs/modules/model_io/index.mdx index eeb94b485056f..a5cf4e81fd49c 100644 --- a/docs/docs/modules/model_io/index.mdx +++ b/docs/docs/modules/model_io/index.mdx @@ -17,7 +17,7 @@ A conceptual explanation of messages, prompts, LLMs vs ChatModels, and output pa ## [Quickstart](/docs/modules/model_io/quick_start) -Covers the basics of getting started working with different types of models. You should walk through [this section] if you want to get an overview of the functionality. +Covers the basics of getting started working with different types of models. You should walk through [this section](/docs/modules/model_io/quick_start) if you want to get an overview of the functionality. ## [Prompts](/docs/modules/model_io/prompts/) From 00a09e1b7117f3bde14a44748510fcccc95f9de5 Mon Sep 17 00:00:00 2001 From: Bagatur <22008038+baskaryan@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:52:42 -0800 Subject: [PATCH 30/83] docs: use PromptTemplate.from_template (#17218) Ran ```python import glob import re def update_prompt(x): return re.sub( r"(?P\b)PromptTemplate\(template=(?P