Coder Social home page Coder Social logo

simpleaichat's Introduction

simpleaichat

from simpleaichat import AIChat

ai = AIChat(system="Write a fancy GitHub README based on the user-provided project name.")
ai("simpleaichat")

simpleaichat is a Python package for easily interfacing with chat apps like ChatGPT and GPT-4 with robust features and minimal code complexity. This tool has many features optimized for working with ChatGPT as fast and as cheap as possible, but still much more capable of modern AI tricks than most implementations:

  • Create and run chats with only a few lines of code!
  • Optimized workflows which minimize the amount of tokens used, reducing costs and latency.
  • Run multiple independent chats at once.
  • Minimal codebase: no code dives to figure out what's going on under the hood needed!
  • Chat streaming responses and the ability to use tools.
  • Async support, including for streaming and tools.
  • Ability to create more complex yet clear workflows if needed, such as Agents. (Demo soon!)
  • Coming soon: more chat model support (PaLM, Claude)!

Here's some fun, hackable examples on how simpleaichat works:

Installation

simpleaichat can be installed from PyPI:

pip3 install simpleaichat

Quick, Fun Demo

You can demo chat-apps very quickly with simpleaichat! First, you will need to get an OpenAI API key, and then with one line of code:

from simpleaichat import AIChat

AIChat(api_key="sk-...")

And with that, you'll be thrust directly into an interactive chat!

This AI chat will mimic the behavior of OpenAI's webapp, but on your local computer!

You can also pass the API key by storing it in an .env file with a OPENAI_API_KEY field in the working directory (recommended), or by setting the environment variable of OPENAI_API_KEY directly to the API key.

But what about creating your own custom conversations? That's where things get fun. Just input whatever person, place or thing, fictional or nonfictional, that you want to chat with!

AIChat("GLaDOS")  # assuming API key loaded via methods above

But that's not all! You can customize exactly how they behave too with additional commands!

AIChat("GLaDOS", "Speak in the style of a Seinfeld monologue")

AIChat("Ronald McDonald", "Speak using only emoji")

Need some socialization immediately? Once simpleaichat is installed, you can also start these chats directly from the command line!

simpleaichat
simpleaichat "GlaDOS"
simpleaichat "GLaDOS" "Speak in the style of a Seinfeld monologue"

Building AI-based Apps

The trick with working with new chat-based apps that wasn't readily available with earlier iterations of GPT-3 is the addition of the system prompt: a different class of prompt that guides the AI behavior throughout the entire conversation. In fact, the chat demos above are actually using system prompt tricks behind the scenes! OpenAI has also released an official guide for system prompt best practices to building AI apps.

For developers, you can instantiate a programmatic instance of AIChat by explicitly specifying a system prompt, or by disabling the console.

ai = AIChat(system="You are a helpful assistant.")
ai = AIChat(console=False)  # same as above

You can also pass in a model parameter, such as model="gpt-4" if you have access to GPT-4, or model="gpt-3.5-turbo-16k" for a larger-context-window ChatGPT.

You can then feed the new ai class with user input, and it will return and save the response from ChatGPT:

response = ai("What is the capital of California?")
print(response)
The capital of California is Sacramento.

Alternatively, you can stream responses by token with a generator if the text generation itself is too slow:

for chunk in ai.stream("What is the capital of California?", params={"max_tokens": 5}):
    response_td = chunk["response"]  # dict contains "delta" for the new token and "response"
    print(response_td)
The
The capital
The capital of
The capital of California
The capital of California is

Further calls to the ai object will continue the chat, automatically incorporating previous information from the conversation.

response = ai("When was it founded?")
print(response)
Sacramento was founded on February 27, 1850.

You can also save chat sessions (as CSV or JSON) and load them later. The API key is not saved so you will have to provide that when loading.

ai.save_session()  # CSV, will only save messages
ai.save_session(format="json", minify=True)  # JSON

ai.load_session("my.csv")
ai.load_session("my.json")

Functions

A large number of popular venture-capital-funded ChatGPT apps don't actually use the "chat" part of the model. Instead, they just use the system prompt/first user prompt as a form of natural language programming. You can emulate this behavior by passing a new system prompt when generating text, and not saving the resulting messages.

The AIChat class is a manager of chat sessions, which means you can have multiple independent chats or functions happening! The examples above use a default session, but you can create new ones by specifying a id when calling ai.

json = '{"title": "An array of integers.", "array": [-1, 0, 1]}'
functions = [
             "Format the user-provided JSON as YAML.",
             "Write a limerick based on the user-provided JSON.",
             "Translate the user-provided JSON from English to French."
            ]
params = {"temperature": 0.0, "max_tokens": 100}  # a temperature of 0.0 is deterministic

# We namespace the function by `id` so it doesn't affect other chats.
# Settings set during session creation will apply to all generations from the session,
# but you can change them per-generation, as is the case with the `system` prompt here.
ai = AIChat(id="function", params=params, save_messages=False)
for function in functions:
    output = ai(json, id="function", system=function)
    print(output)
title: "An array of integers."
array:
  - -1
  - 0
  - 1
An array of integers so neat,
With values that can't be beat,
From negative to positive one,
It's a range that's quite fun,
This JSON is really quite sweet!
{"titre": "Un tableau d'entiers.", "tableau": [-1, 0, 1]}

Newer versions of ChatGPT also support "function calling", but the real benefit of that feature is the ability for ChatGPT to support structured input and/or output, which now opens up a wide variety of applications! simpleaichat streamlines the workflow to allow you to just pass an input_schema and/or an output_schema.

You can construct a schema using a pydantic BaseModel.

from pydantic import BaseModel, Field

ai = AIChat(
    console=False,
    save_messages=False,  # with schema I/O, messages are never saved
    model="gpt-3.5-turbo-0613",
    params={"temperature": 0.0},
)

class get_event_metadata(BaseModel):
    """Event information"""

    description: str = Field(description="Description of event")
    city: str = Field(description="City where event occured")
    year: int = Field(description="Year when event occured")
    month: str = Field(description="Month when event occured")

# returns a dict, with keys ordered as in the schema
ai("First iPhone announcement", output_schema=get_event_metadata)
{'description': 'The first iPhone was announced by Apple Inc.',
 'city': 'San Francisco',
 'year': 2007,
 'month': 'January'}

See the TTRPG Generator Notebook for a more elaborate demonstration of schema capabilities.

Tools

One of the most recent aspects of interacting with ChatGPT is the ability for the model to use "tools." As popularized by LangChain, tools allow the model to decide when to use custom functions, which can extend beyond just the chat AI itself, for example retrieving recent information from the internet not present in the chat AI's training data. This workflow is analogous to ChatGPT Plugins.

Parsing the model output to invoke tools typically requires a number of shennanigans, but simpleaichat uses a neat trick to make it fast and reliable! Additionally, the specified tools return a context for ChatGPT to draw from for its final response, and tools you specify can return a dictionary which you can also populate with arbitrary metadata for debugging and postprocessing. Each generation returns a dictionary with the response and the tool function used, which can be used to set up workflows akin to LangChain-style Agents, e.g. recursively feed input to the model until it determines it does not need to use any more tools.

You will need to specify functions with docstrings which provide hints for the AI to select them:

from simpleaichat.utils import wikipedia_search, wikipedia_search_lookup

# This uses the Wikipedia Search API.
# Results from it are nondeterministic, your mileage will vary.
def search(query):
    """Search the internet."""
    wiki_matches = wikipedia_search(query, n=3)
    return {"context": ", ".join(wiki_matches), "titles": wiki_matches}

def lookup(query):
    """Lookup more information about a topic."""
    page = wikipedia_search_lookup(query, sentences=3)
    return page

params = {"temperature": 0.0, "max_tokens": 100}
ai = AIChat(params=params, console=False)

ai("San Francisco tourist attractions", tools=[search, lookup])
{'context': "Fisherman's Wharf, San Francisco, Tourist attractions in the United States, Lombard Street (San Francisco)",
 'titles': ["Fisherman's Wharf, San Francisco",
  'Tourist attractions in the United States',
  'Lombard Street (San Francisco)'],
 'tool': 'search',
 'response': "There are many popular tourist attractions in San Francisco, including Fisherman's Wharf and Lombard Street. Fisherman's Wharf is a bustling waterfront area known for its seafood restaurants, souvenir shops, and sea lion sightings. Lombard Street, on the other hand, is a famous winding street with eight hairpin turns that attract visitors from all over the world. Both of these attractions are must-sees for anyone visiting San Francisco."}
ai("Lombard Street?", tools=[search, lookup])
{'context': 'Lombard Street is an east–west street in San Francisco, California that is famous for a steep, one-block section with eight hairpin turns. Stretching from The Presidio east to The Embarcadero (with a gap on Telegraph Hill), most of the street\'s western segment is a major thoroughfare designated as part of U.S. Route 101. The famous one-block section, claimed to be "the crookedest street in the world", is located along the eastern segment in the Russian Hill neighborhood.',
 'tool': 'lookup',
 'response': 'Lombard Street is a famous street in San Francisco, California known for its steep, one-block section with eight hairpin turns. It stretches from The Presidio to The Embarcadero, with a gap on Telegraph Hill. The western segment of the street is a major thoroughfare designated as part of U.S. Route 101, while the famous one-block section, claimed to be "the crookedest street in the world", is located along the eastern segment in the Russian Hill'}
ai("Thanks for your help!", tools=[search, lookup])
{'response': "You're welcome! If you have any more questions or need further assistance, feel free to ask.",
 'tool': None}

Miscellaneous Notes

  • Like gpt-2-simple before it, the primary motivation behind releasing simpleaichat is to both democratize access to ChatGPT even more and also offer more transparency for non-engineers into how Chat AI-based apps work under the hood given the disproportionate amount of media misinformation about their capabilities. This is inspired by real-world experience from my work with BuzzFeed in the domain, where after spending a long time working with the popular LangChain, a more-simple implementation was both much easier to maintain and resulted in much better generations. I began focusing development on simpleaichat after reading a Hacker News thread filled with many similar complaints, indicating value for an easier-to-use interface for modern AI tricks.
    • simpleaichat very intentionally avoids coupling features with common use cases where possible (e.g. Tools) in order to avoid software lock-in due to the difficulty implementing anything not explicitly mentioned in the project's documentation. The philosophy behind simpleaichat is to provide good demos, and let the user's creativity and business needs take priority instead of having to fit a round peg into a square hole like with LangChain.
    • simpleaichat makes it easier to interface with Chat AIs, but it does not attempt to solve common technical and ethical problems inherent to large language models trained on the internet, including prompt injection and unintended plagiarism. The user should exercise good judgment when implementing simpleaichat. Use cases of simpleaichat which go against OpenAI's usage policies (including jailbreaking) will not be endorsed.
    • simpleaichat intentionally does not use the "Agent" logical metaphor for tool workflows because it's become an AI hype buzzword heavily divorced from its origins. If needed be, you can emulate the Agent workflow with a while loop without much additional code, plus with the additional benefit of much more flexibility such as debugging.
  • The session manager implements some sensible security defaults, such as using UUIDs as session ids by default, storing authentication information in a way to minimize unintentional leakage, and type enforcement via Pydantic. Your end-user application should still be aware of potential security issues, however.
  • Although OpenAI's documentation says that system prompts are less effective than a user prompt constructed in a similar manner, in my experience it still does perform better for maintaining rules/a persona.
  • Many examples of popular prompts use more conversational prompts, while the example prompts here use more consise and imperative prompts. This aspect of prompt engineering is still evolving, but in my experience commands do better with ChatGPT and with greater token efficieny. That's also why simpleaichat allows users to specify system prompts (and explicitly highlights what the default use) instead of relying on historical best practices.
  • Token counts for async is not supported as OpenAI doesn't return token counts when streaming responses. In general, there may be some desync in token counts and usage for various use cases; I'm working on categorizing them.
  • Outside of the explicit examples, none of this README uses AI-generated text. The introduction code example is just a joke, but it was too good of a real-world use case!

Roadmap

  • PaLM Chat (Bard) and Anthropic Claude support
  • More fun/feature-filled CLI chat app based on Textual
  • Simple example of using simpleaichat in a webapp
  • Simple of example of using simpleaichat in a stateless manner (e.g. AWS Lambda functions)

Maintainer/Creator

Max Woolf (@minimaxir)

Max's open-source projects are supported by his Patreon and GitHub Sponsors. If you found this project helpful, any monetary contributions to the Patreon are appreciated and will be put to good creative use.

License

MIT

simpleaichat's People

Contributors

adammarples avatar arne-cl avatar dmwyatt avatar eltociear avatar havef avatar keyboardant avatar minimaxir avatar player1537 avatar redraw avatar vokturz avatar zeitderforschung avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simpleaichat's Issues

Discrepancy in Schema Building Compared to OpenAI's Examples

Our current implementation for building schemas differs from the approach used in OpenAI's examples (see the "Basic concepts" section). Notably, our schema properties include a "title" field and potentially "items".

For example, in examples/notebooks/schema_ttrpg.ipynb, Event.schema()["properties"] yields:

{
    "type": {
        "title": "Type",
        "description": "Whether the event is a scene setting or a conversation by an NPC",
        "enum": [
            "setting",
            "conversation"
        ],
        "type": "string"
    },
    "data": {
        "title": "Data",
        "description": "Event data",
        "anyOf": [
            {
                "$ref": "#/definitions/Dialogue"
            },
            {
                "$ref": "#/definitions/Setting"
            }
        ]
    }
}

and write_ttrpg_story.schema()["properties"] is:

{
    "events": {
        "title": "Events",
        "description": "All events in a TTRPG campaign.",
        "type": "array",
        "items": {
            "$ref": "#/definitions/Event"
        }
    }
}

`ai.get_session().messages` is ambiguous

>>> ai = AIChat(api_key=OPENAI_API_KEY, console=False, params={"temperature": 0, "max_tokens": 100})
>>> ai("Hi")
>>> ai("Write me a poem over 4 lines.")
>>> ai.get_session().messages
[Hi,
 Hello! How can I assist you today?,
 Write me a poem over 4 lines.,
 Sure, here's a short poem for you:
 
 The sun sets in the west,
 As the birds fly to their nest,
 The world slows down to rest,
 And dreams come to manifest.]

Comparing to ai.get_session().dict()["messages"]:

[{'role': 'user',
  'content': 'Hi',
  'received_at': datetime.datetime(2023, 6, 20, 21, 59, 46, 826026, tzinfo=datetime.timezone.utc),
  'prompt_length': None,
  'completion_length': None,
  'total_length': None},
 {'role': 'assistant',
  'content': 'Hello! How can I assist you today?',
  'received_at': datetime.datetime(2023, 6, 20, 21, 59, 47, 774669, tzinfo=datetime.timezone.utc),
  'prompt_length': 20,
  'completion_length': 9,
  'total_length': 29},
 {'role': 'user',
  'content': 'Write me a poem over 4 lines.',
  'received_at': datetime.datetime(2023, 6, 20, 22, 0, 14, 373825, tzinfo=datetime.timezone.utc),
  'prompt_length': None,
  'completion_length': None,
  'total_length': None},
 {'role': 'assistant',
  'content': "Sure, here's a short poem for you:\n\nThe sun sets in the west,\nAs the birds fly to their nest,\nThe world slows down to rest,\nAnd dreams come to manifest.",
  'received_at': datetime.datetime(2023, 6, 20, 22, 0, 16, 531229, tzinfo=datetime.timezone.utc),
  'prompt_length': 48,
  'completion_length': 38,
  'total_length': 86}]

Would it be safer to rename messages to _messages to communicate you shouldn't access it directly?

System messages

Hi - great job building this.

I notice that messages doesn't include system message.
Would it be better to include system prompt in the messages to mirror Open AI's approach with messages?

message1 = ChatMessage(role="system", content="You are a helpful assistant.")

This may be handy in a couple of use cases:

  1. When we modify message history and system prompt we get consistent API for both
  2. When system prompt is injected mid-conversation (not documented by Open AI and not currently possible in this library?)

`AIChat` doesn't save messages if provided with an `output_schema` (despite setting `save_messages=True`)

and I'm able to reproduce the issue. Here's an example:

from simpleaichat import AIChat
from pydantic import BaseModel, Field
from typing import Literal

params = {
    "temperature": 0,
    "max_tokens": 100,
    "top_p": 1,
    "frequency_penalty": 0,
    "presence_penalty": 0,
}
ai = AIChat(api_key=api_key, console=False, model="gpt-3.5-turbo-0613", params=params, save_messages=True)

class get_weather(BaseModel):
    """
    Get the weather for a city.
    """
    city: str = Field(default="New York", title="City", description="City to get weather for")
    units: Literal["imperial", "metric"] = Field(default="metric", title="Units", description="Units of measurement")

response_structured = ai("What's the weather like in New York?", output_schema=get_weather)

Then, ai.get_session().messages == []. 🥲

(Note: This issue is with the latest commit, d8f04a5c0414356337beb0c392236ee48c38b865)

Too many line breaks in Jupyter Lab / Notebook

Printing every object line by line seems to be the default behaviour of the rich console, because the JupyterMixin in rich uses IPython.display which is not suited for the streaming use case.

image

The behaviour can be fixed with force_jupyter=False:

def interactive_console(self, character: str = None, prime: bool = True) -> None:
    console = Console(highlight=False, force_jupyter=False)
image

Improve documentation on tools a bit

The documentation on tools is currently a bit too obtuse for me. I'm left with some questions:

What happens when the model decides to use a tool? Does that function get called? With what, the entire query, or something else? Is this process repeated multiple times, or is it just a once-off? What does the second call have as inputs? Just the context?

Maybe I need a better example, but what I'm thinking of is a sort of functiony "smart home" helper, where you tell the AI to return a function to be called, such as toggle_lights("bedroom", "on").

Are these tools meant to enhance the context of the AI instead? Maybe that should be mentioned in the docs. I just can't grok it at all right now, because I'm not sure of the intended use case that tools are looking to solve.

Roles on Messages

Hi , I have a prompt that have been defined as SYSTEM , USER and ASSISTANCE roles .
In the OpenAI playground any alteration of the content for each role, give undesired results .
Was not able to find how to configure roles in this library
May you help me ?

Nice job !

Invalid keyword: 'options' in call to model_dump_json

In simpleaichat.py line 224, in the str() method, I was getting an error:

  File "/Users/liam/.virtualenvs/comedybot/lib/python3.10/site-packages/simpleaichat/simpleaichat.py", line 220, in __str__
    return self.default_session.model_dump_json(
TypeError: BaseModel.model_dump_json() got an unexpected keyword argument 'option'
def __str__(self) -> str: 
        if self.default_session:
            return self.default_session.model_dump_json(
                exclude={"api_key", "api_url"},
                exclude_none=True,
                option=orjson.OPT_INDENT_2,
            )

I couldn't find any version of Pydantic that had a 'option' keyword argument for the model_dump_json method.
So, I replaced it with indent=2 and that works.

Preserve OpenAI's response order

In the schema_ttrpg.ipynb example, it's mentioned that "orjson.dumps preserves field order from the ChatGPT API". This order preservation could be beneficial for certain use-cases, where the order of fields could carry meaningful information or improve readability.

Considering this, I propose that we replace pydantic.BaseModel with a subclass that inherits from it but also ensures that field order is preserved by default. This change would ensure that field order is preserved without needing to rely on orjson.dumps.

To implement this, we could consider using collections.OrderedDict in our subclass to store model attributes.

Rate limiting

I asked about this on HN:

"
Since this is async, can it automatically handle provided rate limits and batch queries appropriately?
Seems like everyone has to roll their own on this and it’s much nicer to have smooth tooling for it."

You wrote:

"
The underlying library for both sync and async is httpx (https://www.python-httpx.org/) which may be limited from the HTTP Client perspective but it may be possible to add rate limiting at a Session level.
"

I would consider this a high-priority feature for anything that can handle multiple prompts asynchronously. Particularly because I have many tasks like: Retrieve embeddings for these 3M items

Perhaps consider integrating optionally with GPTCache which does natively handle rate limits.

orjson.JSONDecodeError: Input is a zero-length, empty document: line 1 column 1 (char 0)

I tried to use simpleaichat but received error from the title. I installed simpleaichat in new virtual env and ran it in Python prompt.

Full traceback:

>>> AIChat(api_key="sk-***")
ChatGPT: Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "***/venv/lib/python3.9/site-packages/simpleaichat/simpleaichat.py", line 64, in __init__
    self.interactive_console(character=character, prime=prime)
  File "***/venv/lib/python3.9/site-packages/simpleaichat/simpleaichat.py", line 207, in interactive_console
    for chunk in sess.stream("Hello!", self.client):
  File "***/venv/lib/python3.9/site-packages/simpleaichat/chatgpt.py", line 147, in stream
    chunk_dict = orjson.loads(chunk)
orjson.JSONDecodeError: Input is a zero-length, empty document: line 1 column 1 (char 0

It happens also if I give it any argument like "Ronald McDonald" or similar.


Environment:
macOS Ventura 13.0.1
Python 3.9
Api key for ChatGPT Plus.

ImportError

Hey! Nice work, but I get this error for some reason.

Error:
ImportError: cannot import name 'AIChat' from partially initialized module 'simpleaichat' (most likely due to a circular import)

I used the first code from github page:
from simpleaichat import AIChat

AIChat(api_key="...") # inserted my api-key here
ai = AIChat(system="Write a fancy GitHub README based on the user-provided project name.")
ai("simpleaichat")

Before that I installed: pip3 install simpleaichat

Does it support it caching?

Hi, very nice library ,especially it is light. Does it support caching, so that the api calls can be reduced? just like Gpt-cache or else

JSONDecodeError - OpenAI API response is not json compliant

Hello, many thanks for the library

OpenAI sometimes returns response that is not json compliant

  • Adding trailing comma
  • Double quoting without backslashes
  • Not closing bracket such xxx."\n}'

Tested with gpt-3.5-turbo-0613

When using pydantic model as output_schema (inspired from the example notebook), orjson.loads fails.
Unfortunately, it's a bit unpredictable and cannot write a reproducible example.
Any advice?

Many thanks

Not an issue, just an example

I saw you had a to-do item for a practical example of using simpleaichat in a stateless manner (e.g. AWS Lambda functions). I wondered if I might humbly offer up my Google Chat chatbot that can hold a coherent conversation now thanks to your wonderful library. Thanks for developing this, I found it randomly in the trending feed and it solved a problem I happened to be having at that very moment.

https://github.com/RAHB-REALTORS-Association/chat2gpt

Add debugging option

Can you add a debugging option where one can easily see prompts going and coming back from LLM or tools?

Redo all examples for gpt-3.5-turbo-0613

Unfortunately the output is different enough such that I have to redo everything, which is annoying!

This only needs to be done by the time the default API shifts, June 27th.

Max tools > 9

Hi,
Found this library through your post, and I just wanted to say a great job at hitting it on the nail!

Reading the docs (https://github.com/minimaxir/simpleaichat/blob/db19d26250cdee7db8acb52027632083e83aeb28/PROMPTS.md?plain=1#L59C1-L59C185):

- The call sets `{"max_tokens": 1}` so it will only output one number (hence there is a hard limit of 9 tools), which makes it more cost and speed efficient than other implementations.

I couldn't help but point out that the tokenization scheme in gpt-3.5-turbo encodes the first 999 numbers as single tokens. Therefore, up to 999 tools should be possible using "max_tokens":1. It would just mean that you'd need to deal differently with the logit bias since the tokens for n > 9 are indeed not sequential. So the trick below wouldn't work:

logit_bias = {str(k): logit_bias_weight for k in range(15, 15 + len(tools) + 1)}
)

Feel free to close this.

Finetuned ChatGPT support

Due to my galaxy-brain implementation of checking for GPT-3 support, simpleaichat might work out of the box with a finetuned model. (there will be no finetuning support in simpleaichat itself)

Still need to test it though.

Using Code for User-Driven Data Collection - Handling Non-Responses & Clarifications

Hey, I'm currently exploring the capabilities of your code base and I'm interested in using it for a data collection task. Specifically, I'm looking to ask users a set of predefined questions and then collect their responses.

However, I have a requirement that may be a bit complex to implement with a simple loop. I want to ensure that the system is robust enough to handle cases where users may not immediately respond to a question, or may request further clarification before they feel comfortable providing an answer.

A straightforward loop might interpret these situations as valid inputs, which is something I'd like to avoid.

Is there a way within the current framework to manage this kind of scenario? Is there built-in functionality for managing non-responses or requests for clarification, or would I need to add this myself?

I appreciate any guidance you can provide on this matter.

For context, I've previously implemented this using OpenAI Function calls, but I'm curious to see if I can replicate this functionality with simpleaichat.

Best regards,

ConnectError

Hello ! You are so cool, but I get this error for some reason.

Error:
httpx.ConnectError: TLS/SSL connection has been closed (EOF) (_ssl.c:1131)

console script interactive chat doesn't support args

The function for the interactive chat console script doesn't support passing arguments.

def interactive_chat(character=None, character_command=None, prime=True):

I don't think console scripts allow passing kwargs directly to the function. I think sys.argv or argparse is required.

pip install fails with "no module dateutil" in fresh virtual environment

$ conda create -n simple-ai python && conda activate simple-ai
...
$ pip install simpleaichat
...
$ python
Python 3.11.3 (main, Apr 19 2023, 23:54:32) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import simpleaichat
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../site-packages/simpleaichat/__init__.py", line 1, in <module>
    from .simpleaichat import AIChat, AsyncAIChat
  File "/.../site-packages/simpleaichat/simpleaichat.py", line 3, in <module>
    import dateutil
ModuleNotFoundError: No module named 'dateutil'

Build-in tenacity

Consider implementing tenacity fallbacks as in OpenAI's example to avoid such failures (when sending multiple requests):

KeyError: "No AI generation: {'error': {'message': 'That model is currently overloaded with other requests. You can retry your request, or contact us through our help center at help.openai.com if the error persists. (Please include the request ID c7dddc8edaadb3d6ab49204671f84edf in your message.)', 'type': 'server_error', 'param': None, 'code': None}}"

[feature req]parameter n support

Great lib, Thanks, Max!

Btw, I find it don't support parameter n:
https://github.com/minimaxir/simpleaichat/blob/main/simpleaichat/chatgpt.py#L111

https://platform.openai.com/docs/api-reference/chat/create#chat/create-n

n Defaults to 1
How many chat completion choices to generate for each input message.

This parameter can improve diversity and make it easier for users to observe multiple results at once, and I think this parameter is somewhat underestimated.

LLMs tend to answer questions in an expert tone, will be very easy to give a single authoritative answer, and this parameter adds variety, and it would be great if it had this parameter. But it's not clear how to add this feature so as not to break the existing structure...

gpt-4-plugins equivalent

Hi,

Might be a silly question but would there be a way to get advantage of already existing gpt-4 plugins ? Or are they all completely closed source ?

As tools are here to mimic their behaviour, are there some guidelines about how to add the best integration possible with external APIs ?

Prioritize passed parameter over env variable

Basically
instead of this
gpt_api_key = os.getenv("OPENAI_API_KEY") or kwargs.get("api_key")

this

gpt_api_key = kwargs.get("api_key") or os.getenv("OPENAI_API_KEY")

Params are more specific than env variable, and this behaviour was unexpected (to me)

Usage stats for streaming response.

I think a simple solution could be to wait until the last chunk arrived and then calculate the usage with the prompt and response strings as shown here: https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
    """Return the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        print("Warning: model not found. Using cl100k_base encoding.")
        encoding = tiktoken.get_encoding("cl100k_base")
    if model in {
        "gpt-3.5-turbo-0613",
        "gpt-3.5-turbo-16k-0613",
        "gpt-4-0314",
        "gpt-4-32k-0314",
        "gpt-4-0613",
        "gpt-4-32k-0613",
        }:
        tokens_per_message = 3
        tokens_per_name = 1
    elif model == "gpt-3.5-turbo-0301":
        tokens_per_message = 4  # every message follows <|start|>{role/name}\n{content}<|end|>\n
        tokens_per_name = -1  # if there's a name, the role is omitted
    elif "gpt-3.5-turbo" in model:
        print("Warning: gpt-3.5-turbo may update over time. Returning num tokens assuming gpt-3.5-turbo-0613.")
        return num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613")
    elif "gpt-4" in model:
        print("Warning: gpt-4 may update over time. Returning num tokens assuming gpt-4-0613.")
        return num_tokens_from_messages(messages, model="gpt-4-0613")
    else:
        raise NotImplementedError(
            f"""num_tokens_from_messages() is not implemented for model {model}. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens."""
        )
    num_tokens = 0
    for message in messages:
        num_tokens += tokens_per_message
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += tokens_per_name
    num_tokens += 3  # every reply is primed with <|start|>assistant<|message|>
    return num_tokens

Needs to be extended to include the prompt to get the full usage object.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.