diff --git a/README.md b/README.md index 8f4da7e9..9cd8b814 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,12 @@ from log10.load import log10 log10(openai) # all your openai calls are now logged ``` +For OpenAI v1, use `from log10.load import OpenAI` instead of `from openai import OpenAI` +```python +from log10.load import OpenAI +client = OpenAI() +``` Access your LLM data at [log10.io](https://log10.io) @@ -42,8 +47,12 @@ Log10 offers various integration methods, including a python LLM library wrapper Pick the one that works best for you. #### OpenAI -Use library wrapper `log10(openai)` as shown [above](#-what-is-this). -Full script [here](examples/logging/chatcompletion.py). +| log10 ver| openai v0 | openai v1 | +|----------|----------|----------| +| 0.4 | `load(openai)` ✅ | ❌ | +| 0.5 | `load(openai)` ✅ | `from log10.load import OpenAI` ✅ | + +**OpenAI v0** - Use library wrapper `log10(openai)`. Check out `examples/logging` in log10 version `0.4.6`. ```python import openai from log10.load import log10 @@ -52,12 +61,27 @@ log10(openai) # openai calls are now logged ``` -Use Log10 LLM abstraction. -Full script [here](examples/logging/llm_abstraction.py#6-#14). +**OpenAI v1** +> NOTE: We added OpenAI v1 API support in log10 `0.5.0` release. `load.log10(openai)` still works for openai v1. +```python +from log10.load import OpenAI +# from openai import OpenAI + +client = OpenAI() +completion = client.completions.create(model="curie", prompt="Once upon a time") +# All completions.create and chat.completions.create calls will be logged +``` +Full script [here](examples/logging/completion.py). + + +**Use Log10 LLM abstraction** + ```python from log10.openai import OpenAI + llm = OpenAI({"model": "gpt-3.5-turbo"}, log10_config=Log10Config()) ``` +openai v1+ lib required. Full script [here](examples/logging/llm_abstraction.py#6-#14). #### Anthropic Use library wrapper `log10(anthropic)`. @@ -74,6 +98,7 @@ Use Log10 LLM abstraction. Full script [here](examples/logging/llm_abstraction.py#16-#19). ```python from log10.anthropic import Anthropic + llm = Anthropic({"model": "claude-2"}, log10_config=Log10Config()) ``` @@ -85,12 +110,14 @@ Adding other providers is on the roadmap. **MosaicML** with LLM abstraction. Full script [here](/examples/logging/mosaicml_completion.py). ```python from log10.mosaicml import MosaicML + llm = MosaicML({"model": "llama2-70b-chat/v1"}, log10_config=Log10Config()) ``` **Together** with LLM abstraction. Full script [here](/examples/logging/together_completion.py). ```python from log10.together import Together + llm = Together({"model": "togethercomputer/llama-2-70b-chat"}, log10_config=Log10Config()) ``` @@ -137,7 +164,7 @@ And provide the following configuration in either a `.env` file, or as environme ### 🧠🔁 Readiness for RLHF & self hosting -Use your data and feedback from users to fine-tune custom models with RLHF with the option of building and deploying more reliable, accurate and efficient self-hosted models. +Use your data and feedback from users to fine-tune custom models with RLHF with the option of building and deploying more reliable, accurate and efficient self-hosted models. ### 👥🤝 Collaboration @@ -158,7 +185,7 @@ Create flexible groups to share and collaborate over all of the above features You can find and run examples under folder `examples`, e.g. run a logging example: ``` python examples/logging/chatcompletion.py -``` +``` Also you can run some end-to-end tests with [`xdocttest`](https://github.com/Erotemic/xdoctest) installed (`pip install xdoctest`). diff --git a/examples/README.md b/examples/README.md index 08b16064..8e36c35c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,6 +25,7 @@ Can be run on `OpenAI` or `Anthropic` ## Logging (and debugging) ### OpenAI +Requires openai >= "1.0.0" - `chatCompletion_async_vs_sync.py` Compare latencies when logging in async vs sync mode - `chatCompletion.py` Chat endpoint example diff --git a/examples/logging/chatcompletion.py b/examples/logging/chatcompletion.py index 70fbd8b3..521503c9 100644 --- a/examples/logging/chatcompletion.py +++ b/examples/logging/chatcompletion.py @@ -1,15 +1,9 @@ -import os +from log10.load import OpenAI -import openai -from log10.load import log10 +client = OpenAI() - -log10(openai) - -openai.api_key = os.getenv("OPENAI_API_KEY") - -completion = openai.ChatCompletion.create( +completion = client.chat.completions.create( model="gpt-3.5-turbo", messages=[ { diff --git a/examples/logging/chatcompletion_async_vs_sync.py b/examples/logging/chatcompletion_async_vs_sync.py deleted file mode 100644 index c52ffda8..00000000 --- a/examples/logging/chatcompletion_async_vs_sync.py +++ /dev/null @@ -1,70 +0,0 @@ -import sys - - -if "init_modules" in globals(): - # second or subsequent run: remove all but initially loaded modules - for m in list(sys.modules.keys()): - if m not in init_modules: - del sys.modules[m] -else: - # first run: find out which modules were initially loaded - init_modules = list(sys.modules.keys()) - -import os - -import openai - -from log10.load import log10, log10_session - - -openai.api_key = os.getenv("OPENAI_API_KEY") - -# Launch an async run -with log10_session(): - log10(openai, DEBUG_=True, USE_ASYNC_=True) - completion = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - { - "role": "system", - "content": "You are the most knowledgable Star Wars guru on the planet", - }, - { - "role": "user", - "content": "Write the time period of all the Star Wars movies and spinoffs?", - }, - ], - ) - print(completion.choices[0].message) - -# reload modules to prevent double calling openAI -if "init_modules" in globals(): - # second or subsequent run: remove all but initially loaded modules - for m in list(sys.modules.keys()): - if m not in init_modules: - del sys.modules[m] -else: - # first run: find out which modules were initially loaded - init_modules = list(sys.modules.keys()) - - -import openai # noqa - -# Compare to sync run - note there can be variability in the OpenAI calls -with log10_session(): - log10(openai, DEBUG_=True, USE_ASYNC_=False) - - completion = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - { - "role": "system", - "content": "You are the most knowledgable Star Wars guru on the planet", - }, - { - "role": "user", - "content": "Write the time period of all the Star Wars movies and spinoffs?", - }, - ], - ) - print(completion.choices[0].message) diff --git a/examples/logging/chatcompletion_sync.py b/examples/logging/chatcompletion_sync.py new file mode 100644 index 00000000..ffe97e30 --- /dev/null +++ b/examples/logging/chatcompletion_sync.py @@ -0,0 +1,27 @@ +from log10.load import OpenAI, log10_session + + +client = OpenAI() + +with log10_session(tags=["log10-io/examples"]): + completion = client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + { + "role": "user", + "content": "Hello?", + }, + ], + ) + print(completion.choices[0].message) + + completion = client.chat.completions.create( + model="gpt-3.5-turbo", + messages=[ + { + "role": "user", + "content": "Hello again, are you there?", + }, + ], + ) + print(completion.choices[0].message) diff --git a/examples/logging/completion.py b/examples/logging/completion.py index ff1c23fc..5007d118 100644 --- a/examples/logging/completion.py +++ b/examples/logging/completion.py @@ -1,15 +1,9 @@ -import os +from log10.load import OpenAI -import openai -from log10.load import log10 +client = OpenAI() - -log10(openai) - -openai.api_key = os.getenv("OPENAI_API_KEY") - -response = openai.Completion.create( +response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Write the names of all Star Wars movies and spinoffs along with the time periods in which they were set?", temperature=0, diff --git a/examples/logging/completion_simple.py b/examples/logging/completion_simple.py index beae1fbf..b293df2f 100644 --- a/examples/logging/completion_simple.py +++ b/examples/logging/completion_simple.py @@ -1,15 +1,9 @@ -import os +from log10.load import OpenAI -import openai -from log10.load import log10 +client = OpenAI() - -log10(openai, DEBUG_=True, USE_ASYNC_=False) - -openai.api_key = os.getenv("OPENAI_API_KEY") - -response = openai.Completion.create( +response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="What is 2+2?", temperature=0, diff --git a/examples/logging/get_url.py b/examples/logging/get_url.py index d72b7df5..1ef2cae8 100644 --- a/examples/logging/get_url.py +++ b/examples/logging/get_url.py @@ -1,21 +1,12 @@ -import os +from log10.load import OpenAI, log10_session -import openai -from langchain.llms import OpenAI -from log10.load import log10, log10_session - - -log10(openai) - -openai.api_key = os.getenv("OPENAI_API_KEY") - -llm = OpenAI(temperature=0.9, model_name="gpt-3.5-turbo-instruct") +client = OpenAI() with log10_session() as session: print(session.last_completion_url()) - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Why did the chicken cross the road?", temperature=0, @@ -27,7 +18,7 @@ print(session.last_completion_url()) - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Why did the cow cross the road?", temperature=0, @@ -42,7 +33,7 @@ with log10_session() as session: print(session.last_completion_url()) - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Why did the frog cross the road?", temperature=0, @@ -54,7 +45,7 @@ print(session.last_completion_url()) - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Why did the scorpion cross the road?", temperature=0, diff --git a/examples/logging/langchain_multiple_tools.py b/examples/logging/langchain_multiple_tools.py index 7be2a8cd..d38b9003 100644 --- a/examples/logging/langchain_multiple_tools.py +++ b/examples/logging/langchain_multiple_tools.py @@ -1,5 +1,3 @@ -import os - import openai from log10.load import log10 @@ -7,7 +5,6 @@ log10(openai) -openai.api_key = os.getenv("OPENAI_API_KEY") MAX_TOKENS = 512 TOOLS_DEFAULT_LIST = ["llm-math", "wikipedia"] diff --git a/examples/logging/langchain_qa.py b/examples/logging/langchain_qa.py index afe814d9..8cc027e9 100644 --- a/examples/logging/langchain_qa.py +++ b/examples/logging/langchain_qa.py @@ -1,5 +1,3 @@ -import os - import openai from log10.load import log10 @@ -7,8 +5,6 @@ log10(openai) -openai.api_key = os.getenv("OPENAI_API_KEY") - # Example from: https://python.langchain.com/en/latest/use_cases/question_answering.html # Download the state_of_the_union.txt here: https://raw.githubusercontent.com/hwchase17/langchain/master/docs/modules/state_of_the_union.txt # This example requires: pip install chromadb diff --git a/examples/logging/langchain_simple_sequential.py b/examples/logging/langchain_simple_sequential.py index b94f5abb..24bcf219 100644 --- a/examples/logging/langchain_simple_sequential.py +++ b/examples/logging/langchain_simple_sequential.py @@ -1,5 +1,3 @@ -import os - import openai from log10.load import log10 @@ -7,8 +5,6 @@ log10(openai) -openai.api_key = os.getenv("OPENAI_API_KEY") - from langchain.chains import LLMChain, SimpleSequentialChain from langchain.llms import OpenAI from langchain.prompts import PromptTemplate diff --git a/examples/logging/langchain_sqlagent.py b/examples/logging/langchain_sqlagent.py index 28a3583a..fa4c6a38 100644 --- a/examples/logging/langchain_sqlagent.py +++ b/examples/logging/langchain_sqlagent.py @@ -1,5 +1,4 @@ import datetime -import os import random import openai @@ -78,9 +77,6 @@ def generate_random_user(): session.close() -# Setup vars for Langchain -openai.api_key = os.getenv("OPENAI_API_KEY") - # Setup Langchain SQL agent db = SQLDatabase.from_uri("sqlite:///users.db") toolkit = SQLDatabaseToolkit(db=db) diff --git a/examples/logging/long_context_exception.py b/examples/logging/long_context_exception.py index d0253321..cff79206 100644 --- a/examples/logging/long_context_exception.py +++ b/examples/logging/long_context_exception.py @@ -1,17 +1,11 @@ -import os +from log10.load import OpenAI -import openai -from log10.load import log10 - - -log10(openai) - -openai.api_key = os.getenv("OPENAI_API_KEY") +client = OpenAI() text_to_repeat = "What is the meaning of life?" * 1000 -response = openai.Completion.create( +response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt=text_to_repeat, temperature=0, diff --git a/examples/logging/multiple_sessions.py b/examples/logging/multiple_sessions.py index d60f2192..fc61e2ef 100644 --- a/examples/logging/multiple_sessions.py +++ b/examples/logging/multiple_sessions.py @@ -1,5 +1,3 @@ -import os - import openai from langchain.chains import LLMChain, SimpleSequentialChain from langchain.llms import OpenAI @@ -10,8 +8,6 @@ log10(openai) -openai.api_key = os.getenv("OPENAI_API_KEY") - llm = OpenAI(temperature=0.9, model_name="gpt-3.5-turbo-instruct") diff --git a/examples/logging/tags_mixed.py b/examples/logging/tags_mixed.py index c46f5ae9..dfcae10a 100644 --- a/examples/logging/tags_mixed.py +++ b/examples/logging/tags_mixed.py @@ -6,8 +6,9 @@ log10(openai) +client = openai.OpenAI() with log10_session(tags=["foo", "bar"]): - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Where is the Eiffel Tower?", temperature=0, diff --git a/examples/logging/tags_openai.py b/examples/logging/tags_openai.py index c14de75e..4e5bac88 100644 --- a/examples/logging/tags_openai.py +++ b/examples/logging/tags_openai.py @@ -1,16 +1,8 @@ -import os +from log10.load import OpenAI, log10_session -import openai -from log10.load import log10, log10_session - - -log10(openai) - -openai.api_key = os.getenv("OPENAI_API_KEY") - - -response = openai.Completion.create( +client = OpenAI() +response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Where are the pyramids?", temperature=0, @@ -22,7 +14,7 @@ print(response) with log10_session(tags=["foo", "bar"]): - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Where is the Eiffel Tower?", temperature=0, @@ -34,7 +26,7 @@ print(response) with log10_session(tags=["bar", "baz"]): - response = openai.Completion.create( + response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Where is the statue of liberty?", temperature=0, @@ -45,7 +37,7 @@ ) print(response) -response = openai.Completion.create( +response = client.completions.create( model="gpt-3.5-turbo-instruct", prompt="Where is machu picchu?", temperature=0, diff --git a/log10/load.py b/log10/load.py index 31b5f072..475655be 100644 --- a/log10/load.py +++ b/log10/load.py @@ -1,6 +1,5 @@ import asyncio import functools -import inspect import json import logging import os @@ -9,12 +8,12 @@ import time import traceback from contextlib import contextmanager +from importlib.metadata import version -import backoff # for exponential backoff +import backoff import requests from dotenv import load_dotenv - -from log10.openai import RETRY_ERROR_TYPES as OPENAI_RETRY_ERROR_TYPES +from packaging.version import parse load_dotenv() @@ -42,9 +41,31 @@ target_service = "log10" # default to log10 -@backoff.on_exception(backoff.expo, OPENAI_RETRY_ERROR_TYPES) +def is_openai_v1() -> bool: + """Return whether OpenAI API is v1 or more.""" + _version = parse(version("openai")) + return _version.major >= 1 + + def func_with_backoff(func, *args, **kwargs): - return func(*args, **kwargs) + if func.__module__ != "openai" or is_openai_v1(): + return func(*args, **kwargs) + + import openai + + retry_errors = ( + openai.error.APIConnectionError, + openai.error.APIError, + openai.error.RateLimitError, + openai.error.ServiceUnavailableError, + openai.error.Timeout, + ) + + @backoff.on_exception(backoff.expo, retry_errors) + def _func_with_backoff(func, *args, **kwargs): + return func(*args, **kwargs) + + return _func_with_backoff(func, *args, **kwargs) # todo: should we do backoff as well? @@ -306,19 +327,25 @@ def wrapper(*args, **kwargs): from log10.anthropic import Anthropic response = Anthropic.prepare_response(kwargs["prompt"], output, "text") + kind = "completion" else: response = output + kind = "chat" if output.object == "chat.completion" else "completion" # in case the usage of load(openai) and langchain.ChatOpenAI if "api_key" in kwargs: kwargs.pop("api_key") + if hasattr(response, "model_dump_json"): + response = response.model_dump_json() + else: + response = json.dumps(response) log_row = { - "response": json.dumps(response), + "response": response, "status": "finished", "duration": int(duration * 1000), "stacktrace": json.dumps(stacktrace), - "kind": "completion", + "kind": kind, "orig_module": func.__module__, "orig_qualname": func.__qualname__, "request": json.dumps(kwargs), @@ -361,42 +388,35 @@ def set_sync_log_text(USE_ASYNC=True): def log10(module, DEBUG_=False, USE_ASYNC_=True): """Intercept and overload module for logging purposes + support both openai V0 and V1, and anthropic Keyword arguments: module -- the module to be intercepted (e.g. openai) DEBUG_ -- whether to show log10 related debug statements via python logging (default False) USE_ASYNC_ -- whether to run in async mode (default True) + Openai V0 example: Example: - >>> from log10.load import log10 + >>> from log10.load import log10 # xdoctest: +SKIP >>> import openai >>> log10(openai) - >>> response = openai.Completion.create( + >>> completion = openai.Completion.create( >>> model="gpt-3.5-turbo-instruct", >>> prompt="Once upon a time", >>> max_tokens=32, >>> ) - >>> print(response) + >>> print(completion) Example: - >>> from log10.load import log10 + >>> from log10.load import log10 # xdoctest: +SKIP >>> import openai >>> log10(openai) - >>> response = openai.ChatCompletion.create( + >>> completion = openai.ChatCompletion.create( >>> model="gpt-3.5-turbo", - >>> messages=[ - >>> { - >>> "role": "system", - >>> "content": "You are a Pingpong machine.", - >>> }, - >>> { - >>> "role": "user", - >>> "content": "Ping", - >>> }, - >>> ], + >>> messages=[{"role": "user", "content": "Hello world"}], >>> max_tokens=8, >>> ) - >>> print(response) + >>> print(completion) Example: >>> from log10.load import log10 @@ -467,24 +487,32 @@ def log10(module, DEBUG_=False, USE_ASYNC_=True): # elif inspect.isclass(method): # Handle nested classes # intercept_class_methods(method) - for name, attr in vars(module).items(): - if inspect.isclass(attr): - # OpenAI - if module.__name__ == "openai" and name in ["ChatCompletion", "Completion"]: - for method_name, method in vars(attr).items(): - if isinstance(method, classmethod): - original_method = method.__func__ - if original_method.__qualname__ in [ - "ChatCompletion.create", - "Completion.create", - ]: - decorated_method = intercepting_decorator(original_method) - setattr(attr, method_name, classmethod(decorated_method)) - # Anthropic if module.__name__ == "anthropic": - method = getattr(module.resources.completions.Completions, "create") attr = module.resources.completions.Completions + method = getattr(attr, "create") setattr(attr, "create", intercepting_decorator(method)) + elif module.__name__ == "openai": + openai_version = parse(version("openai")) + global OPENAI_V1 + OPENAI_V1 = openai_version >= parse("1.0.0") + + # support for sync completions + if OPENAI_V1: + attr = module.resources.completions.Completions + method = getattr(attr, "create") + setattr(attr, "create", intercepting_decorator(method)) + + attr = module.resources.chat.completions.Completions + method = getattr(attr, "create") + setattr(attr, "create", intercepting_decorator(method)) + else: + attr = module.api_resources.completion.Completion + method = getattr(attr, "create") + setattr(attr, "create", intercepting_decorator(method)) + + attr = module.api_resources.chat_completion.ChatCompletion + mothod = getattr(attr, "create") + setattr(attr, "create", intercepting_decorator(mothod)) # For future reference: # if callable(attr) and isinstance(attr, types.FunctionType): @@ -494,3 +522,37 @@ def log10(module, DEBUG_=False, USE_ASYNC_=True): # intercept_class_methods(attr) # # else: # uncomment if we want to include nested function support # # intercept_nested_functions(attr) + + +if is_openai_v1(): + import openai + from openai import OpenAI + + class OpenAI(OpenAI): + """ + Example: + >>> from log10.load import OpenAI + >>> client = OpenAI(tags=["load_v1_test"]) + >>> completion = client.completions.create(model='curie', prompt="Twice upon a time", max_tokens=32) + >>> print(completion) + + Example: + >>> from log10.load import OpenAI + >>> client = OpenAI(tags=["load_v1_test"]) + >>> completion = client.chat.completions.create( + >>> model="gpt-3.5-turbo", + >>> messages=[{"role": "user", "content": "Hello world"}], + >>> ) + >>> print(completion) + """ + + def __init__(self, *args, **kwargs): + # check if tags is passed in + if "tags" in kwargs: + global global_tags + global_tags = kwargs.pop("tags") + super().__init__(*args, **kwargs) + + if not getattr(openai, "_log10_patched", False): + log10(openai) + openai._log10_patched = True diff --git a/log10/openai.py b/log10/openai.py index 88b1f7fb..d30c8a06 100644 --- a/log10/openai.py +++ b/log10/openai.py @@ -1,46 +1,51 @@ import time from copy import deepcopy +from importlib.metadata import version from typing import List -# for exponential backoff -import backoff import openai -from openai import error +from packaging.version import parse from log10.llm import LLM, ChatCompletion, Kind, Message, TextCompletion -RETRY_ERROR_TYPES = ( - error.APIConnectionError, - error.APIError, - error.RateLimitError, - error.ServiceUnavailableError, - error.Timeout, -) +def is_openai_v1() -> bool: + """Return whether OpenAI API is v1 or more.""" + _version = parse(version("openai")) + return _version.major >= 1 class OpenAI(LLM): def __init__(self, hparams: dict = None, log10_config=None): + assert is_openai_v1(), "OpenAI API version must be >= 1.0.0 to use log10.OpenAI class" super().__init__(hparams, log10_config) + self._client = openai.OpenAI() - @backoff.on_exception(backoff.expo, RETRY_ERROR_TYPES) def chat(self, messages: List[Message], hparams: dict = None) -> ChatCompletion: + """ + Example: + >>> from log10.llm import Log10Config, Message + >>> from log10.openai import OpenAI + >>> llm = OpenAI({"model": "gpt-3.5-turbo"}, log10_config=Log10Config()) + >>> response = llm.chat([Message(role="user", content="Hello")]) + >>> print(response) + """ request = self.chat_request(messages, hparams) start_time = time.perf_counter() - completion = openai.ChatCompletion.create(**request) + completion = self._client.chat.completions.create(**request) self.completion_id = self.log_start(request, Kind.chat) response = ChatCompletion( - role=completion.choices[0]["message"]["role"], - content=completion.choices[0]["message"]["content"], + role=completion.choices[0].message.role, + content=completion.choices[0].message.content, response=completion, ) self.log_end( self.completion_id, - completion, + completion.model_dump(), time.perf_counter() - start_time, ) @@ -57,19 +62,26 @@ def chat_request(self, messages: List[Message], hparams: dict = None) -> dict: **merged_hparams, } - @backoff.on_exception(backoff.expo, RETRY_ERROR_TYPES) def text(self, prompt: str, hparams: dict = None) -> TextCompletion: + """ + Example: + >>> from log10.llm import Log10Config + >>> from log10.openai import OpenAI + >>> llm = OpenAI({"model": "gpt-3.5-turbo-instruct"}, log10_config=Log10Config()) + >>> response = llm.text("This is a test.") + >>> print(response) + """ request = self.text_request(prompt, hparams) start_time = time.perf_counter() completion_id = self.log_start(request, Kind.text) - completion = openai.Completion.create(**request) + completion = self._client.completions.create(**request) response = TextCompletion(text=completion.choices[0].text, response=completion) self.log_end( completion_id, - completion, + completion.model_dump(), time.perf_counter() - start_time, ) diff --git a/logging.md b/logging.md index e12e1ed0..9a6b6dea 100644 --- a/logging.md +++ b/logging.md @@ -23,6 +23,18 @@ from log10.load import log10 log10(openai) ``` +This works for both openai v0 and v1. + +For openai v1 only, the logging can be done like this: + +```python +from log10.load import OpenAI +# from openai import OpenAI + +client = OpenAI() +completion = client.completions.create(model='curie', prompt="Once upon a time") +# All completions.create and chat.completions.create calls will be logged +``` From that point on, all openai calls during the process execution will be logged. Please note that this only works for non-streaming calls at this time. @@ -125,6 +137,12 @@ with log10_session(tags=["foo", "bar"]): ``` +An addition way to add tag with openai v1 API: +```python +from log10.load import OpenAI +client = OpenAI(tags=["foo"]) +``` + ## LangChain logger If you want to use LLMs which are not natively supported by log10 yet, you can use the log10 logger / callback with langchain's llm abstraction: diff --git a/pyproject.toml b/pyproject.toml index ab9efb6a..1f65ee75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "log10-io" -version = "0.4.6" +version = "0.5.0" authors = ["log10 team"] license = "MIT" description = "Unified LLM data management" @@ -29,7 +29,7 @@ build = "^0.10.0" [tool.poetry.dependencies] python = ">=3.9,<4.0" langchain = "^0.0.303" -openai = "^0.28.1" +openai = "<2" requests = "^2.31.0" python-dotenv = "^1.0.0" google-cloud-bigquery = "^3.11.4" diff --git a/setup.py b/setup.py index 045754d1..60f810a3 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="Log10", - version="0.4.6", + version="0.5.0", description="Log10 LLM data management", author="Log10 team", author_email="team@log10.io",