OpenAI

import ast
import inspect
import json
import os
from inspect import Parameter

from openai import OpenAI
from pydantic import create_model
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
aussie_sys = """
    You are an Aussie LLM that uses Aussie slang and analogies whenever possible.
    """


chat_completion = client.chat.completions.create(
    model="gpt-3.5-turbo-1106",
    messages=[
        {"role": "system", "content": aussie_sys},
        {"role": "user", "content": "What is money?"},
    ],
)
print(chat_completion.choices[0].message.content)
Well, money is like the oil in the engine of an old Holden ute. It keeps things running smoothly. It's the dosh you use to buy snags for a Barbie, or to shout your mates a few coldies at the pub. Money is what you earn from working hard, and it's what you use to pay your bills and have a good time. Without money, you're as useful as a broken dunny in the bush, mate.
chat_completion.usage
CompletionUsage(completion_tokens=94, prompt_tokens=34, total_tokens=128)
def calculate_price(model: str, chat_completion) -> str:
    input_tokens = chat_completion.usage.prompt_tokens
    output_tokens = chat_completion.usage.completion_tokens

    if model == "gpt-3.5-turbo-1106":
        input_price = 0.0010 / 1000
        output_price = 0.0020 / 1000

    input_cost = input_price * input_tokens
    output_cost = output_price * output_tokens

    return f"${input_cost + output_cost}"
calculate_price("gpt-3.5-turbo-1106", chat_completion)
'$0.00022199999999999998'

Function Calling

def askgpt(user, system=None, model="gpt-3.5-turbo", **kwargs):
    msgs = []
    if system:
        msgs.append({"role": "system", "content": system})
    msgs.append({"role": "user", "content": user})
    return client.chat.completions.create(model=model, messages=msgs, **kwargs)
def sums(a: int, b: int = 1):
    "Adds a + b"
    return a + b
def run(code):
    tree = ast.parse(code)
    last_node = tree.body[-1] if tree.body else None

    # If the last node is an expression, modify the AST to capture the result
    if isinstance(last_node, ast.Expr):
        tgts = [ast.Name(id="_result", ctx=ast.Store())]
        assign = ast.Assign(targets=tgts, value=last_node.value)
        tree.body[-1] = ast.fix_missing_locations(assign)

    ns = {}
    exec(compile(tree, filename="<ast>", mode="exec"), ns)
    return ns.get("_result", None)


def python(code: str):
    "Return result of executing `code` using python. If execution not permitted, returns `#FAIL#`"
    go = input(f"Proceed with execution?\n```\n{code}\n```\n")
    if go.lower() != "y":
        return "#FAIL#"
    return run(code)
def schema(f):
    kw = {
        n: (o.annotation, ... if o.default == Parameter.empty else o.default)
        for n, o in inspect.signature(f).parameters.items()
    }
    s = create_model(f"Input for `{f.__name__}`", **kw).model_json_schema()
    return dict(name=f.__name__, description=f.__doc__, parameters=s)
schema(sums)
{'name': 'sums',
 'description': 'Adds a + b',
 'parameters': {'properties': {'a': {'title': 'A', 'type': 'integer'},
   'b': {'default': 1, 'title': 'B', 'type': 'integer'}},
  'required': ['a'],
  'title': 'Input for `sums`',
  'type': 'object'}}
c = askgpt(
    "Use the `sum` function to solve this: What is 6+3?",
    system="You must use the `sum` function instead of adding yourself.",
    functions=[schema(sums)],
)
c
ChatCompletion(id='chatcmpl-8fmz35qBq4bV1VOi2FWuzLtJPeSDm', choices=[Choice(finish_reason='function_call', index=0, logprobs=None, message=ChatCompletionMessage(content=None, role='assistant', function_call=FunctionCall(arguments='{\n  "a": 6,\n  "b": 3\n}', name='sums'), tool_calls=None))], created=1704970433, model='gpt-3.5-turbo-0613', object='chat.completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=22, prompt_tokens=83, total_tokens=105))
m = c.choices[0].message
m
ChatCompletionMessage(content=None, role='assistant', function_call=FunctionCall(arguments='{\n  "a": 6,\n  "b": 3\n}', name='sums'), tool_calls=None)
m.function_call.arguments
'{\n  "a": 6,\n  "b": 3\n}'
funcs_ok = {"sums", "python"}


def call_func(c):
    fc = c.choices[0].message.function_call
    if fc.name not in funcs_ok:
        return print(f"Not allowed: {fc.name}")
    f = globals()[fc.name]
    return f(**json.loads(fc.arguments))
call_func(c)
9
run(
    """
a=1
b=2
a+b
"""
)
3
c = askgpt(
    "What is 12 factorial?",
    system="Use python for any required computations.",
    functions=[schema(python)],
)
call_func(c)
479001600