|
@@ -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()
|