Skip to content

Commit

Permalink
Merge branch 'master' into jacob/hotfix
Browse files Browse the repository at this point in the history
  • Loading branch information
efriis committed Dec 6, 2023
2 parents 5a1fd1a + 0dea8cc commit e1649cf
Show file tree
Hide file tree
Showing 13 changed files with 204 additions and 59 deletions.
2 changes: 1 addition & 1 deletion docs/docs/integrations/adapters/openai-old.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"source": [
"# OpenAI Adapter(Old)\n",
"\n",
"**Please ensure OpenAI library is less than 1.0.0; otherwise, refer to the newer doc [OpenAI Adapter](./openai.ipynb).**\n",
"**Please ensure OpenAI library is less than 1.0.0; otherwise, refer to the newer doc [OpenAI Adapter](./openai).**\n",
"\n",
"A lot of people get started with OpenAI but want to explore other models. LangChain's integrations with many model providers make this easy to do so. While LangChain has it's own message and model APIs, we've also made it as easy as possible to explore other models by exposing an adapter to adapt LangChain models to the OpenAI api.\n",
"\n",
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/integrations/adapters/openai.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"source": [
"# OpenAI Adapter\n",
"\n",
"**Please ensure OpenAI library is version 1.0.0 or higher; otherwise, refer to the older doc [OpenAI Adapter(Old)](./openai-old.ipynb).**\n",
"**Please ensure OpenAI library is version 1.0.0 or higher; otherwise, refer to the older doc [OpenAI Adapter(Old)](./openai-old).**\n",
"\n",
"A lot of people get started with OpenAI but want to explore other models. LangChain's integrations with many model providers make this easy to do so. While LangChain has it's own message and model APIs, we've also made it as easy as possible to explore other models by exposing an adapter to adapt LangChain models to the OpenAI api.\n",
"\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ supported functions:
- `delete_doc_by_texts`


For a more detailed walk through of the Alibaba Cloud OpenSearch wrapper, see [this notebook](../modules/indexes/vectorstores/examples/alibabacloud_opensearch.ipynb)
For a more detailed walk through of the Alibaba Cloud OpenSearch wrapper, see [this notebook](/docs/integrations/vectorstores/alibabacloud_opensearch)

If you encounter any problems during use, please feel free to contact [[email protected]]([email protected]) , and we will do our best to provide you with assistance and support.

2 changes: 1 addition & 1 deletion docs/docs/integrations/providers/dataforseo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The DataForSEO utility wraps the API. To import this utility, use:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper
```

For a detailed walkthrough of this wrapper, see [this notebook](/docs/integrations/tools/dataforseo.ipynb).
For a detailed walkthrough of this wrapper, see [this notebook](/docs/integrations/tools/dataforseo).

### Tool

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/integrations/providers/jina.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ embeddings = JinaEmbeddings(jina_api_key='jina_**', model_name='jina-embeddings-

You can check the list of available models from [here](https://jina.ai/embeddings/)

For a more detailed walkthrough of this, see [this notebook](/docs/integrations/text_embedding/jina.ipynb)
For a more detailed walkthrough of this, see [this notebook](/docs/integrations/text_embedding/jina)
2 changes: 1 addition & 1 deletion docs/docs/integrations/providers/vearch.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Vearch Python SDK enables vearch to use locally. Vearch python sdk can be instal

# Vectorstore

Vearch also can used as vectorstore. Most detalis in [this notebook](docs/modules/indexes/vectorstores/examples/vearch.ipynb)
Vearch also can used as vectorstore. Most detalis in [this notebook](/docs/integrations/vectorstores/vearch)

```python
from langchain.vectorstores import Vearch
Expand Down
5 changes: 3 additions & 2 deletions libs/core/langchain_core/runnables/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ class RunnableWithMessageHistory(RunnableBindingBase):
from typing import Optional
from langchain_core.chat_models import ChatAnthropic
from langchain_core.memory.chat_message_histories import RedisChatMessageHistory
from langchain.chat_models import ChatAnthropic
from langchain.memory.chat_message_histories import RedisChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
Expand Down
31 changes: 18 additions & 13 deletions libs/langchain/langchain/chat_models/baidu_qianfan_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
SystemMessage,
)
from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult
from langchain_core.pydantic_v1 import Field, root_validator
from langchain_core.pydantic_v1 import Field, SecretStr, root_validator
from langchain_core.utils import convert_to_secret_str

from langchain.callbacks.manager import (
AsyncCallbackManagerForLLMRun,
Expand Down Expand Up @@ -88,8 +89,8 @@ class QianfanChatEndpoint(BaseChatModel):

client: Any

qianfan_ak: Optional[str] = None
qianfan_sk: Optional[str] = None
qianfan_ak: Optional[SecretStr] = None
qianfan_sk: Optional[SecretStr] = None

streaming: Optional[bool] = False
"""Whether to stream the results or not."""
Expand Down Expand Up @@ -118,19 +119,23 @@ class QianfanChatEndpoint(BaseChatModel):

@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
values["qianfan_ak"] = get_from_dict_or_env(
values,
"qianfan_ak",
"QIANFAN_AK",
values["qianfan_ak"] = convert_to_secret_str(
get_from_dict_or_env(
values,
"qianfan_ak",
"QIANFAN_AK",
)
)
values["qianfan_sk"] = get_from_dict_or_env(
values,
"qianfan_sk",
"QIANFAN_SK",
values["qianfan_sk"] = convert_to_secret_str(
get_from_dict_or_env(
values,
"qianfan_sk",
"QIANFAN_SK",
)
)
params = {
"ak": values["qianfan_ak"],
"sk": values["qianfan_sk"],
"ak": values["qianfan_ak"].get_secret_value(),
"sk": values["qianfan_sk"].get_secret_value(),
"model": values["model"],
"stream": values["streaming"],
}
Expand Down
23 changes: 13 additions & 10 deletions libs/langchain/langchain/llms/cerebriumai.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import logging
from typing import Any, Dict, List, Mapping, Optional
from typing import Any, Dict, List, Mapping, Optional, cast

import requests
from langchain_core.pydantic_v1 import Extra, Field, root_validator
from langchain_core.pydantic_v1 import Extra, Field, SecretStr, root_validator

from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain.llms.base import LLM
from langchain.llms.utils import enforce_stop_tokens
from langchain.utils import get_from_dict_or_env
from langchain.utils import convert_to_secret_str, get_from_dict_or_env

logger = logging.getLogger(__name__)


class CerebriumAI(LLM):
"""CerebriumAI large language models.
To use, you should have the ``cerebrium`` python package installed, and the
environment variable ``CEREBRIUMAI_API_KEY`` set with your API key.
To use, you should have the ``cerebrium`` python package installed.
You should also have the environment variable ``CEREBRIUMAI_API_KEY``
set with your API key or pass it as a named argument in the constructor.
Any parameters that are valid to be passed to the call can be passed
in, even if not explicitly saved on this class.
Expand All @@ -25,7 +26,7 @@ class CerebriumAI(LLM):
.. code-block:: python
from langchain.llms import CerebriumAI
cerebrium = CerebriumAI(endpoint_url="")
cerebrium = CerebriumAI(endpoint_url="", cerebriumai_api_key="my-api-key")
"""

Expand All @@ -36,7 +37,7 @@ class CerebriumAI(LLM):
"""Holds any model parameters valid for `create` call not
explicitly specified."""

cerebriumai_api_key: Optional[str] = None
cerebriumai_api_key: Optional[SecretStr] = None

class Config:
"""Configuration for this pydantic config."""
Expand Down Expand Up @@ -64,8 +65,8 @@ def build_extra(cls, values: Dict[str, Any]) -> Dict[str, Any]:
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate that api key and python package exists in environment."""
cerebriumai_api_key = get_from_dict_or_env(
values, "cerebriumai_api_key", "CEREBRIUMAI_API_KEY"
cerebriumai_api_key = convert_to_secret_str(
get_from_dict_or_env(values, "cerebriumai_api_key", "CEREBRIUMAI_API_KEY")
)
values["cerebriumai_api_key"] = cerebriumai_api_key
return values
Expand All @@ -91,7 +92,9 @@ def _call(
**kwargs: Any,
) -> str:
headers: Dict = {
"Authorization": self.cerebriumai_api_key,
"Authorization": cast(
SecretStr, self.cerebriumai_api_key
).get_secret_value(),
"Content-Type": "application/json",
}
params = self.model_kwargs or {}
Expand Down
106 changes: 78 additions & 28 deletions libs/langchain/langchain/vectorstores/qdrant.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ class Qdrant(VectorStore):
qdrant = Qdrant(client, collection_name, embedding_function)
"""

CONTENT_KEY = "page_content"
METADATA_KEY = "metadata"
CONTENT_KEY = ["page_content"]
METADATA_KEY = ["metadata"]
VECTOR_NAME = None

def __init__(
self,
client: Any,
collection_name: str,
embeddings: Optional[Embeddings] = None,
content_payload_key: str = CONTENT_KEY,
metadata_payload_key: str = METADATA_KEY,
content_payload_key: Union[list, str] = CONTENT_KEY,
metadata_payload_key: Union[list, str] = METADATA_KEY,
distance_strategy: str = "COSINE",
vector_name: Optional[str] = VECTOR_NAME,
embedding_function: Optional[Callable] = None, # deprecated
Expand All @@ -112,6 +112,12 @@ def __init__(
f"got {type(client)}"
)

if isinstance(content_payload_key, str): # Ensuring Backward compatibility
content_payload_key = [content_payload_key]

if isinstance(metadata_payload_key, str): # Ensuring Backward compatibility
metadata_payload_key = [metadata_payload_key]

if embeddings is None and embedding_function is None:
raise ValueError(
"`embeddings` value can't be None. Pass `Embeddings` instance."
Expand All @@ -127,8 +133,14 @@ def __init__(
self._embeddings_function = embedding_function
self.client: qdrant_client.QdrantClient = client
self.collection_name = collection_name
self.content_payload_key = content_payload_key or self.CONTENT_KEY
self.metadata_payload_key = metadata_payload_key or self.METADATA_KEY
self.content_payload_key = (
content_payload_key if content_payload_key is not None else self.CONTENT_KEY
)
self.metadata_payload_key = (
metadata_payload_key
if metadata_payload_key is not None
else self.METADATA_KEY
)
self.vector_name = vector_name or self.VECTOR_NAME

if embedding_function is not None:
Expand Down Expand Up @@ -1178,8 +1190,8 @@ def from_texts(
path: Optional[str] = None,
collection_name: Optional[str] = None,
distance_func: str = "Cosine",
content_payload_key: str = CONTENT_KEY,
metadata_payload_key: str = METADATA_KEY,
content_payload_key: List[str] = CONTENT_KEY,
metadata_payload_key: List[str] = METADATA_KEY,
vector_name: Optional[str] = VECTOR_NAME,
batch_size: int = 64,
shard_number: Optional[int] = None,
Expand Down Expand Up @@ -1354,8 +1366,8 @@ async def afrom_texts(
path: Optional[str] = None,
collection_name: Optional[str] = None,
distance_func: str = "Cosine",
content_payload_key: str = CONTENT_KEY,
metadata_payload_key: str = METADATA_KEY,
content_payload_key: List[str] = CONTENT_KEY,
metadata_payload_key: List[str] = METADATA_KEY,
vector_name: Optional[str] = VECTOR_NAME,
batch_size: int = 64,
shard_number: Optional[int] = None,
Expand Down Expand Up @@ -1527,8 +1539,8 @@ def construct_instance(
path: Optional[str] = None,
collection_name: Optional[str] = None,
distance_func: str = "Cosine",
content_payload_key: str = CONTENT_KEY,
metadata_payload_key: str = METADATA_KEY,
content_payload_key: List[str] = CONTENT_KEY,
metadata_payload_key: List[str] = METADATA_KEY,
vector_name: Optional[str] = VECTOR_NAME,
shard_number: Optional[int] = None,
replication_factor: Optional[int] = None,
Expand Down Expand Up @@ -1691,8 +1703,8 @@ async def aconstruct_instance(
path: Optional[str] = None,
collection_name: Optional[str] = None,
distance_func: str = "Cosine",
content_payload_key: str = CONTENT_KEY,
metadata_payload_key: str = METADATA_KEY,
content_payload_key: List[str] = CONTENT_KEY,
metadata_payload_key: List[str] = METADATA_KEY,
vector_name: Optional[str] = VECTOR_NAME,
shard_number: Optional[int] = None,
replication_factor: Optional[int] = None,
Expand Down Expand Up @@ -1888,11 +1900,11 @@ def _similarity_search_with_relevance_scores(

@classmethod
def _build_payloads(
cls,
cls: Type[Qdrant],
texts: Iterable[str],
metadatas: Optional[List[dict]],
content_payload_key: str,
metadata_payload_key: str,
content_payload_key: list[str],
metadata_payload_key: list[str],
) -> List[dict]:
payloads = []
for i, text in enumerate(texts):
Expand All @@ -1913,29 +1925,67 @@ def _build_payloads(

@classmethod
def _document_from_scored_point(
cls,
cls: Type[Qdrant],
scored_point: Any,
content_payload_key: str,
metadata_payload_key: str,
content_payload_key: list[str],
metadata_payload_key: list[str],
) -> Document:
return Document(
page_content=scored_point.payload.get(content_payload_key),
metadata=scored_point.payload.get(metadata_payload_key) or {},
payload = scored_point.payload
return Qdrant._document_from_payload(
payload=payload,
content_payload_key=content_payload_key,
metadata_payload_key=metadata_payload_key,
)

@classmethod
def _document_from_scored_point_grpc(
cls,
cls: Type[Qdrant],
scored_point: Any,
content_payload_key: str,
metadata_payload_key: str,
content_payload_key: list[str],
metadata_payload_key: list[str],
) -> Document:
from qdrant_client.conversions.conversion import grpc_to_payload

payload = grpc_to_payload(scored_point.payload)
return Qdrant._document_from_payload(
payload=payload,
content_payload_key=content_payload_key,
metadata_payload_key=metadata_payload_key,
)

@classmethod
def _document_from_payload(
cls: Type[Qdrant],
payload: Any,
content_payload_key: list[str],
metadata_payload_key: list[str],
) -> Document:
if len(content_payload_key) == 1:
content = payload.get(
content_payload_key
) # Ensuring backward compatibility
elif len(content_payload_key) > 1:
content = {
content_key: payload.get(content_key)
for content_key in content_payload_key
}
content = str(content) # Ensuring str type output
else:
content = ""
if len(metadata_payload_key) == 1:
metadata = payload.get(
metadata_payload_key
) # Ensuring backward compatibility
elif len(metadata_payload_key) > 1:
metadata = {
metadata_key: payload.get(metadata_key)
for metadata_key in metadata_payload_key
}
else:
metadata = {}
return Document(
page_content=payload[content_payload_key],
metadata=payload.get(metadata_payload_key) or {},
page_content=content,
metadata=metadata,
)

def _build_condition(self, key: str, value: Any) -> List[rest.FieldCondition]:
Expand Down
Loading

0 comments on commit e1649cf

Please sign in to comment.