Show details for query tokens (#1392)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from string import Template
|
||||
@@ -92,6 +93,7 @@ class BaseLlmConfig(BaseConfig):
|
||||
top_p: float = 1,
|
||||
stream: bool = False,
|
||||
online: bool = False,
|
||||
token_usage: bool = False,
|
||||
deployment_name: Optional[str] = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
where: dict[str, Any] = None,
|
||||
@@ -135,6 +137,8 @@ class BaseLlmConfig(BaseConfig):
|
||||
:type stream: bool, optional
|
||||
:param online: Controls whether to use internet for answering query, defaults to False
|
||||
:type online: bool, optional
|
||||
:param token_usage: Controls whether to return token usage in response, defaults to False
|
||||
:type token_usage: bool, optional
|
||||
:param deployment_name: t.b.a., defaults to None
|
||||
:type deployment_name: Optional[str], optional
|
||||
:param system_prompt: System prompt string, defaults to None
|
||||
@@ -180,6 +184,8 @@ class BaseLlmConfig(BaseConfig):
|
||||
self.max_tokens = max_tokens
|
||||
self.model = model
|
||||
self.top_p = top_p
|
||||
self.online = online
|
||||
self.token_usage = token_usage
|
||||
self.deployment_name = deployment_name
|
||||
self.system_prompt = system_prompt
|
||||
self.query_type = query_type
|
||||
@@ -197,6 +203,10 @@ class BaseLlmConfig(BaseConfig):
|
||||
self.online = online
|
||||
self.api_version = api_version
|
||||
|
||||
if token_usage:
|
||||
f = open("model_prices_and_context_window.json")
|
||||
self.model_pricing_map = json.load(f)
|
||||
|
||||
if isinstance(prompt, str):
|
||||
prompt = Template(prompt)
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ from typing import Any, Optional, Union
|
||||
from dotenv import load_dotenv
|
||||
from langchain.docstore.document import Document
|
||||
|
||||
from embedchain.cache import (adapt, get_gptcache_session,
|
||||
gptcache_data_convert,
|
||||
gptcache_update_cache_callback)
|
||||
from embedchain.cache import adapt, get_gptcache_session, gptcache_data_convert, gptcache_update_cache_callback
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config import AddConfig, BaseLlmConfig, ChunkerConfig
|
||||
from embedchain.config.base_app_config import BaseAppConfig
|
||||
@@ -18,8 +16,7 @@ from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.helpers.json_serializable import JSONSerializable
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.models.data_type import (DataType, DirectDataType,
|
||||
IndirectDataType, SpecialDataType)
|
||||
from embedchain.models.data_type import DataType, DirectDataType, IndirectDataType, SpecialDataType
|
||||
from embedchain.utils.misc import detect_datatype, is_valid_json_string
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
@@ -478,7 +475,7 @@ class EmbedChain(JSONSerializable):
|
||||
where: Optional[dict] = None,
|
||||
citations: bool = False,
|
||||
**kwargs: dict[str, Any],
|
||||
) -> Union[tuple[str, list[tuple[str, dict]]], str]:
|
||||
) -> Union[tuple[str, list[tuple[str, dict]]], str, dict[str, Any]]:
|
||||
"""
|
||||
Queries the vector database based on the given input query.
|
||||
Gets relevant doc based on the query and then passes it to an
|
||||
@@ -501,7 +498,9 @@ class EmbedChain(JSONSerializable):
|
||||
:type kwargs: dict[str, Any]
|
||||
:return: The answer to the query, with citations if the citation flag is True
|
||||
or the dry run result
|
||||
:rtype: str, if citations is False, otherwise tuple[str, list[tuple[str,str,str]]]
|
||||
:rtype: str, if citations is False and token_usage is False, otherwise if citations is true then
|
||||
tuple[str, list[tuple[str,str,str]]] and if token_usage is true then
|
||||
tuple[str, list[tuple[str,str,str]], dict[str, Any]]
|
||||
"""
|
||||
contexts = self._retrieve_from_database(
|
||||
input_query=input_query, config=config, where=where, citations=citations, **kwargs
|
||||
@@ -524,17 +523,29 @@ class EmbedChain(JSONSerializable):
|
||||
dry_run=dry_run,
|
||||
)
|
||||
else:
|
||||
answer = self.llm.query(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
if self.llm.config.token_usage:
|
||||
answer, token_info = self.llm.query(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
else:
|
||||
answer = self.llm.query(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
|
||||
# Send anonymous telemetry
|
||||
self.telemetry.capture(event_name="query", properties=self._telemetry_props)
|
||||
|
||||
if citations:
|
||||
if self.llm.config.token_usage:
|
||||
return {"answer": answer, "contexts": contexts, "usage": token_info}
|
||||
return answer, contexts
|
||||
else:
|
||||
return answer
|
||||
if self.llm.config.token_usage:
|
||||
return {"answer": answer, "usage": token_info}
|
||||
|
||||
logger.warning(
|
||||
"Starting from v0.1.125 the return type of query method will be changed to tuple containing `answer`."
|
||||
)
|
||||
return answer
|
||||
|
||||
def chat(
|
||||
self,
|
||||
@@ -545,7 +556,7 @@ class EmbedChain(JSONSerializable):
|
||||
where: Optional[dict[str, str]] = None,
|
||||
citations: bool = False,
|
||||
**kwargs: dict[str, Any],
|
||||
) -> Union[tuple[str, list[tuple[str, dict]]], str]:
|
||||
) -> Union[tuple[str, list[tuple[str, dict]]], str, dict[str, Any]]:
|
||||
"""
|
||||
Queries the vector database on the given input query.
|
||||
Gets relevant doc based on the query and then passes it to an
|
||||
@@ -572,7 +583,9 @@ class EmbedChain(JSONSerializable):
|
||||
:type kwargs: dict[str, Any]
|
||||
:return: The answer to the query, with citations if the citation flag is True
|
||||
or the dry run result
|
||||
:rtype: str, if citations is False, otherwise tuple[str, list[tuple[str,str,str]]]
|
||||
:rtype: str, if citations is False and token_usage is False, otherwise if citations is true then
|
||||
tuple[str, list[tuple[str,str,str]]] and if token_usage is true then
|
||||
tuple[str, list[tuple[str,str,str]], dict[str, Any]]
|
||||
"""
|
||||
contexts = self._retrieve_from_database(
|
||||
input_query=input_query, config=config, where=where, citations=citations, **kwargs
|
||||
@@ -600,9 +613,14 @@ class EmbedChain(JSONSerializable):
|
||||
)
|
||||
else:
|
||||
logger.debug("Cache disabled. Running chat without cache.")
|
||||
answer = self.llm.chat(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
if self.llm.config.token_usage:
|
||||
answer, token_info = self.llm.query(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
else:
|
||||
answer = self.llm.query(
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
|
||||
# add conversation in memory
|
||||
self.llm.add_history(self.config.id, input_query, answer, session_id=session_id)
|
||||
@@ -611,9 +629,16 @@ class EmbedChain(JSONSerializable):
|
||||
self.telemetry.capture(event_name="chat", properties=self._telemetry_props)
|
||||
|
||||
if citations:
|
||||
if self.llm.config.token_usage:
|
||||
return {"answer": answer, "contexts": contexts, "usage": token_info}
|
||||
return answer, contexts
|
||||
else:
|
||||
return answer
|
||||
if self.llm.config.token_usage:
|
||||
return {"answer": answer, "usage": token_info}
|
||||
|
||||
logger.warning(
|
||||
"Starting from v0.1.125 the return type of query method will be changed to tuple containing `answer`."
|
||||
)
|
||||
return answer
|
||||
|
||||
def search(self, query, num_documents=3, where=None, raw_filter=None, namespace=None):
|
||||
"""
|
||||
|
||||
@@ -9,10 +9,10 @@ class GPT4AllEmbedder(BaseEmbedder):
|
||||
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
||||
super().__init__(config=config)
|
||||
|
||||
from langchain.embeddings import \
|
||||
GPT4AllEmbeddings as LangchainGPT4AllEmbeddings
|
||||
from langchain_community.embeddings import GPT4AllEmbeddings as LangchainGPT4AllEmbeddings
|
||||
|
||||
embeddings = LangchainGPT4AllEmbeddings()
|
||||
model_name = self.config.model or "all-MiniLM-L6-v2-f16.gguf"
|
||||
embeddings = LangchainGPT4AllEmbeddings(model_name=model_name)
|
||||
embedding_fn = BaseEmbedder._langchain_default_concept(embeddings)
|
||||
self.set_embedding_fn(embedding_fn=embedding_fn)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
try:
|
||||
from langchain_anthropic import ChatAnthropic
|
||||
@@ -21,8 +21,27 @@ class AnthropicLlm(BaseLlm):
|
||||
if not self.config.api_key and "ANTHROPIC_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the ANTHROPIC_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
return AnthropicLlm._get_answer(prompt=prompt, config=self.config)
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "anthropic/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["input_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["output_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["input_tokens"],
|
||||
"completion_tokens": token_info["output_tokens"],
|
||||
"total_tokens": token_info["input_tokens"] + token_info["output_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
@@ -34,4 +53,7 @@ class AnthropicLlm(BaseLlm):
|
||||
|
||||
messages = BaseLlm._get_messages(prompt, system_prompt=config.system_prompt)
|
||||
|
||||
return chat(messages).content
|
||||
chat_response = chat.invoke(messages)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -164,7 +164,7 @@ class BaseLlm(JSONSerializable):
|
||||
return search.run(input_query)
|
||||
|
||||
@staticmethod
|
||||
def _stream_response(answer: Any) -> Generator[Any, Any, None]:
|
||||
def _stream_response(answer: Any, token_info: Optional[dict[str, Any]] = None) -> Generator[Any, Any, None]:
|
||||
"""Generator to be used as streaming response
|
||||
|
||||
:param answer: Answer chunk from llm
|
||||
@@ -177,6 +177,8 @@ class BaseLlm(JSONSerializable):
|
||||
streamed_answer = streamed_answer + chunk
|
||||
yield chunk
|
||||
logger.info(f"Answer: {streamed_answer}")
|
||||
if token_info:
|
||||
logger.info(f"Token Info: {token_info}")
|
||||
|
||||
def query(self, input_query: str, contexts: list[str], config: BaseLlmConfig = None, dry_run=False):
|
||||
"""
|
||||
@@ -219,11 +221,18 @@ class BaseLlm(JSONSerializable):
|
||||
if dry_run:
|
||||
return prompt
|
||||
|
||||
answer = self.get_answer_from_llm(prompt)
|
||||
if self.config.token_usage:
|
||||
answer, token_info = self.get_answer_from_llm(prompt)
|
||||
else:
|
||||
answer = self.get_answer_from_llm(prompt)
|
||||
if isinstance(answer, str):
|
||||
logger.info(f"Answer: {answer}")
|
||||
if self.config.token_usage:
|
||||
return answer, token_info
|
||||
return answer
|
||||
else:
|
||||
if self.config.token_usage:
|
||||
return self._stream_response(answer, token_info)
|
||||
return self._stream_response(answer)
|
||||
finally:
|
||||
if config:
|
||||
@@ -276,13 +285,13 @@ class BaseLlm(JSONSerializable):
|
||||
if dry_run:
|
||||
return prompt
|
||||
|
||||
answer = self.get_answer_from_llm(prompt)
|
||||
answer, token_info = self.get_answer_from_llm(prompt)
|
||||
if isinstance(answer, str):
|
||||
logger.info(f"Answer: {answer}")
|
||||
return answer
|
||||
return answer, token_info
|
||||
else:
|
||||
# this is a streamed response and needs to be handled differently.
|
||||
return self._stream_response(answer)
|
||||
return self._stream_response(answer, token_info)
|
||||
finally:
|
||||
if config:
|
||||
# Restore previous config
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import importlib
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from langchain_community.llms.cohere import Cohere
|
||||
from langchain_cohere import ChatCohere
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.helpers.json_serializable import register_deserializable
|
||||
@@ -17,27 +17,50 @@ class CohereLlm(BaseLlm):
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError(
|
||||
"The required dependencies for Cohere are not installed."
|
||||
'Please install with `pip install --upgrade "embedchain[cohere]"`'
|
||||
"Please install with `pip install langchain_cohere==1.16.0`"
|
||||
) from None
|
||||
|
||||
super().__init__(config=config)
|
||||
if not self.config.api_key and "COHERE_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the COHERE_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.system_prompt:
|
||||
raise ValueError("CohereLlm does not support `system_prompt`")
|
||||
return CohereLlm._get_answer(prompt=prompt, config=self.config)
|
||||
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "cohere/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["input_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["output_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["input_tokens"],
|
||||
"completion_tokens": token_info["output_tokens"],
|
||||
"total_tokens": token_info["input_tokens"] + token_info["output_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
api_key = config.api_key or os.getenv("COHERE_API_KEY")
|
||||
llm = Cohere(
|
||||
cohere_api_key=api_key,
|
||||
model=config.model,
|
||||
max_tokens=config.max_tokens,
|
||||
temperature=config.temperature,
|
||||
p=config.top_p,
|
||||
)
|
||||
api_key = config.api_key or os.environ["COHERE_API_KEY"]
|
||||
kwargs = {
|
||||
"model_name": config.model or "command-r",
|
||||
"temperature": config.temperature,
|
||||
"max_tokens": config.max_tokens,
|
||||
"together_api_key": api_key,
|
||||
}
|
||||
|
||||
return llm.invoke(prompt)
|
||||
chat = ChatCohere(**kwargs)
|
||||
chat_response = chat.invoke(prompt)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_count"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||
from langchain.schema import HumanMessage, SystemMessage
|
||||
@@ -22,9 +22,27 @@ class GroqLlm(BaseLlm):
|
||||
if not self.config.api_key and "GROQ_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the GROQ_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt) -> str:
|
||||
response = self._get_answer(prompt, self.config)
|
||||
return response
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "groq/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["prompt_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["completion_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["prompt_tokens"],
|
||||
"completion_tokens": token_info["completion_tokens"],
|
||||
"total_tokens": token_info["prompt_tokens"] + token_info["completion_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
def _get_answer(self, prompt: str, config: BaseLlmConfig) -> str:
|
||||
messages = []
|
||||
@@ -42,4 +60,8 @@ class GroqLlm(BaseLlm):
|
||||
chat = ChatGroq(**kwargs, streaming=config.stream, callbacks=callbacks, api_key=api_key)
|
||||
else:
|
||||
chat = ChatGroq(**kwargs)
|
||||
return chat.invoke(messages).content
|
||||
|
||||
chat_response = chat.invoke(prompt)
|
||||
if self.config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.helpers.json_serializable import register_deserializable
|
||||
@@ -13,8 +13,27 @@ class MistralAILlm(BaseLlm):
|
||||
if not self.config.api_key and "MISTRAL_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the MISTRAL_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
return MistralAILlm._get_answer(prompt=prompt, config=self.config)
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "mistralai/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["prompt_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["completion_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["prompt_tokens"],
|
||||
"completion_tokens": token_info["completion_tokens"],
|
||||
"total_tokens": token_info["prompt_tokens"] + token_info["completion_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig):
|
||||
@@ -47,6 +66,7 @@ class MistralAILlm(BaseLlm):
|
||||
answer += chunk.content
|
||||
return answer
|
||||
else:
|
||||
response = client.invoke(**kwargs, input=messages)
|
||||
answer = response.content
|
||||
return answer
|
||||
chat_response = client.invoke(**kwargs, input=messages)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from collections.abc import Iterable
|
||||
from typing import Optional, Union
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from langchain.callbacks.manager import CallbackManager
|
||||
from langchain.callbacks.stdout import StdOutCallbackHandler
|
||||
@@ -25,8 +25,27 @@ class NvidiaLlm(BaseLlm):
|
||||
if not self.config.api_key and "NVIDIA_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the NVIDIA_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
return self._get_answer(prompt=prompt, config=self.config)
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "nvidia/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["input_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["output_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["input_tokens"],
|
||||
"completion_tokens": token_info["output_tokens"],
|
||||
"total_tokens": token_info["input_tokens"] + token_info["output_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> Union[str, Iterable]:
|
||||
@@ -43,4 +62,7 @@ class NvidiaLlm(BaseLlm):
|
||||
if labels:
|
||||
params["labels"] = labels
|
||||
llm = ChatNVIDIA(**params, callback_manager=CallbackManager(callback_manager))
|
||||
return llm.invoke(prompt).content if labels is None else llm.invoke(prompt, labels=labels).content
|
||||
chat_response = llm.invoke(prompt) if labels is None else llm.invoke(prompt, labels=labels)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -23,9 +23,28 @@ class OpenAILlm(BaseLlm):
|
||||
self.tools = tools
|
||||
super().__init__(config=config)
|
||||
|
||||
def get_llm_model_answer(self, prompt) -> str:
|
||||
response = self._get_answer(prompt, self.config)
|
||||
return response
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "openai/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["prompt_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["completion_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["prompt_tokens"],
|
||||
"completion_tokens": token_info["completion_tokens"],
|
||||
"total_tokens": token_info["prompt_tokens"] + token_info["completion_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
def _get_answer(self, prompt: str, config: BaseLlmConfig) -> str:
|
||||
messages = []
|
||||
@@ -66,7 +85,10 @@ class OpenAILlm(BaseLlm):
|
||||
if self.tools:
|
||||
return self._query_function_call(chat, self.tools, messages)
|
||||
|
||||
return chat.invoke(messages).content
|
||||
chat_response = chat.invoke(messages)
|
||||
if self.config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
def _query_function_call(
|
||||
self,
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import importlib
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from langchain_community.llms import Together
|
||||
try:
|
||||
from langchain_together import ChatTogether
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Please install the langchain_together package by running `pip install langchain_together==0.1.3`."
|
||||
)
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.helpers.json_serializable import register_deserializable
|
||||
@@ -24,20 +29,43 @@ class TogetherLlm(BaseLlm):
|
||||
if not self.config.api_key and "TOGETHER_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the TOGETHER_API_KEY environment variable or pass it in the config.")
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.system_prompt:
|
||||
raise ValueError("TogetherLlm does not support `system_prompt`")
|
||||
return TogetherLlm._get_answer(prompt=prompt, config=self.config)
|
||||
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "together/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["prompt_tokens"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info["completion_tokens"]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["prompt_tokens"],
|
||||
"completion_tokens": token_info["completion_tokens"],
|
||||
"total_tokens": token_info["prompt_tokens"] + token_info["completion_tokens"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
api_key = config.api_key or os.getenv("TOGETHER_API_KEY")
|
||||
llm = Together(
|
||||
together_api_key=api_key,
|
||||
model=config.model,
|
||||
max_tokens=config.max_tokens,
|
||||
temperature=config.temperature,
|
||||
top_p=config.top_p,
|
||||
)
|
||||
api_key = config.api_key or os.environ["TOGETHER_API_KEY"]
|
||||
kwargs = {
|
||||
"model_name": config.model or "mixtral-8x7b-32768",
|
||||
"temperature": config.temperature,
|
||||
"max_tokens": config.max_tokens,
|
||||
"together_api_key": api_key,
|
||||
}
|
||||
|
||||
return llm.invoke(prompt)
|
||||
chat = ChatTogether(**kwargs)
|
||||
chat_response = chat.invoke(prompt)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["token_usage"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import importlib
|
||||
import logging
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||
from langchain_google_vertexai import ChatVertexAI
|
||||
@@ -24,16 +24,35 @@ class VertexAILlm(BaseLlm):
|
||||
) from None
|
||||
super().__init__(config=config)
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
return VertexAILlm._get_answer(prompt=prompt, config=self.config)
|
||||
def get_llm_model_answer(self, prompt) -> tuple[str, Optional[dict[str, Any]]]:
|
||||
if self.config.token_usage:
|
||||
response, token_info = self._get_answer(prompt, self.config)
|
||||
model_name = "vertexai/" + self.config.model
|
||||
if model_name not in self.config.model_pricing_map:
|
||||
raise ValueError(
|
||||
f"Model {model_name} not found in `model_prices_and_context_window.json`. \
|
||||
You can disable token usage by setting `token_usage` to False."
|
||||
)
|
||||
total_cost = (
|
||||
self.config.model_pricing_map[model_name]["input_cost_per_token"] * token_info["prompt_token_count"]
|
||||
) + self.config.model_pricing_map[model_name]["output_cost_per_token"] * token_info[
|
||||
"candidates_token_count"
|
||||
]
|
||||
response_token_info = {
|
||||
"prompt_tokens": token_info["prompt_token_count"],
|
||||
"completion_tokens": token_info["candidates_token_count"],
|
||||
"total_tokens": token_info["prompt_token_count"] + token_info["candidates_token_count"],
|
||||
"total_cost": round(total_cost, 10),
|
||||
"cost_currency": "USD",
|
||||
}
|
||||
return response, response_token_info
|
||||
return self._get_answer(prompt, self.config)
|
||||
|
||||
@staticmethod
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
if config.top_p and config.top_p != 1:
|
||||
logger.warning("Config option `top_p` is not supported by this model.")
|
||||
|
||||
messages = BaseLlm._get_messages(prompt, system_prompt=config.system_prompt)
|
||||
|
||||
if config.stream:
|
||||
callbacks = config.callbacks if config.callbacks else [StreamingStdOutCallbackHandler()]
|
||||
llm = ChatVertexAI(
|
||||
@@ -42,4 +61,8 @@ class VertexAILlm(BaseLlm):
|
||||
else:
|
||||
llm = ChatVertexAI(temperature=config.temperature, model=config.model)
|
||||
|
||||
return llm.invoke(messages).content
|
||||
messages = VertexAILlm._get_messages(prompt)
|
||||
chat_response = llm.invoke(messages)
|
||||
if config.token_usage:
|
||||
return chat_response.content, chat_response.response_metadata["usage_metadata"]
|
||||
return chat_response.content
|
||||
|
||||
@@ -428,6 +428,7 @@ def validate_config(config_data):
|
||||
Optional("top_p"): Or(float, int),
|
||||
Optional("stream"): bool,
|
||||
Optional("online"): bool,
|
||||
Optional("token_usage"): bool,
|
||||
Optional("template"): str,
|
||||
Optional("prompt"): str,
|
||||
Optional("system_prompt"): str,
|
||||
|
||||
Reference in New Issue
Block a user