diff --git a/examples/chat_with_ai/main.py b/examples/chat_with_ai/main.py index e9be81c0e..9021a6bf7 100755 --- a/examples/chat_with_ai/main.py +++ b/examples/chat_with_ai/main.py @@ -9,7 +9,7 @@ @ui.page('/') def main(): - llm = ChatOpenAI(model_name='gpt-3.5-turbo', streaming=True, openai_api_key=OPENAI_API_KEY) + llm = ChatOpenAI(model_name='gpt-4o-mini', streaming=True, openai_api_key=OPENAI_API_KEY) async def send() -> None: question = text.value diff --git a/examples/openai_assistant/main.py b/examples/openai_assistant/main.py new file mode 100755 index 000000000..0d0709e9b --- /dev/null +++ b/examples/openai_assistant/main.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +from openai import AsyncOpenAI +from openai.types.beta.assistant_stream_event import ThreadMessageInProgress +from openai.types.beta.threads import MessageDeltaEvent, TextDeltaBlock + +from nicegui import ui + +client = AsyncOpenAI(api_key='provide your OpenAI API key here') + + +@ui.page('/') +async def main(): + assistant = await client.beta.assistants.create( + name='NiceGUI Assistant', + instructions=''' + You are a personal assistant for NiceGUI developers. + Your sole focus is to help with questions about the NiceGUI framework. + You are precise and concise. + Stay on the topic. + Very short answers are preferred, but always be friendly and polite. + ''', + tools=[{'type': 'code_interpreter'}], + model='gpt-4o-mini', + ) + + thread = await client.beta.threads.create() + + async def send() -> None: + response.content = '' + spinner = ui.spinner(size='5em', type='comment').classes('mx-auto') + await client.beta.threads.messages.create( + thread_id=thread.id, + role='user', + content=question.value, + ) + stream = await client.beta.threads.runs.create( + assistant_id=assistant.id, + thread_id=thread.id, + stream=True, + ) + async for chunk in stream: + if isinstance(chunk, ThreadMessageInProgress): + spinner.delete() + # NOTE: the stream contains a lot of different types so we need to filter out the ones we don't need + if not isinstance(chunk.data, MessageDeltaEvent) or not chunk.data.delta.content: + continue + content = chunk.data.delta.content[0] + if not isinstance(content, TextDeltaBlock) or content.text is None or content.text.value is None: + continue + response.content += content.text.value + + with ui.column().classes('mx-auto w-full max-w-xl my-16'): + ui.label('NiceGUI Assistant').classes('text-2xl font-bold mx-auto') + question = ui.input(value='Why does NiceGUI use async/await?') \ + .classes('w-full self-center mt-4').props('hint="Ask your question" dense') \ + .on('keydown.enter', send) + response = ui.markdown().classes('mx-4 mt-2') + ui.timer(0, send, once=True) # NOTE: we send the prepared demo question immediately + +ui.run() diff --git a/examples/openai_assistant/requirements.txt b/examples/openai_assistant/requirements.txt new file mode 100644 index 000000000..c172a027b --- /dev/null +++ b/examples/openai_assistant/requirements.txt @@ -0,0 +1 @@ +openai==1.58.1 diff --git a/website/examples.py b/website/examples.py index a95aec98f..263ee41d5 100644 --- a/website/examples.py +++ b/website/examples.py @@ -69,4 +69,5 @@ def __post_init__(self) -> None: Example('NGINX HTTPS', 'Use NGINX to serve a NiceGUI app with HTTPS'), Example('Node Module Integration', 'Use NPM to add dependencies to a NiceGUI app'), Example('Signature Pad', 'A custom element based on [signature_pad](https://www.npmjs.com/package/signature_pad'), + Example('OpenAI Assistant', "Using OpenAI's Assistant API with async/await"), ]