main.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #!/usr/bin/env python3
  2. from openai import AsyncOpenAI
  3. from openai.types.beta.assistant_stream_event import ThreadMessageInProgress
  4. from openai.types.beta.threads import MessageDeltaEvent, TextDeltaBlock
  5. from nicegui import ui
  6. client = AsyncOpenAI(api_key='provide your OpenAI API key here')
  7. @ui.page('/')
  8. async def main():
  9. assistant = await client.beta.assistants.create(
  10. name='NiceGUI Assistant',
  11. instructions='''
  12. You are a personal assistant for NiceGUI developers.
  13. Your sole focus is to help with questions about the NiceGUI framework.
  14. You are precise and concise.
  15. Stay on the topic.
  16. Very short answers are preferred, but always be friendly and polite.
  17. ''',
  18. tools=[{'type': 'code_interpreter'}],
  19. model='gpt-4o-mini',
  20. )
  21. thread = await client.beta.threads.create()
  22. async def send() -> None:
  23. response.content = ''
  24. spinner = ui.spinner(size='5em', type='comment').classes('mx-auto')
  25. await client.beta.threads.messages.create(
  26. thread_id=thread.id,
  27. role='user',
  28. content=question.value,
  29. )
  30. stream = await client.beta.threads.runs.create(
  31. assistant_id=assistant.id,
  32. thread_id=thread.id,
  33. stream=True,
  34. )
  35. async for chunk in stream:
  36. if isinstance(chunk, ThreadMessageInProgress):
  37. spinner.delete()
  38. # NOTE: the stream contains a lot of different types so we need to filter out the ones we don't need
  39. if not isinstance(chunk.data, MessageDeltaEvent) or not chunk.data.delta.content:
  40. continue
  41. content = chunk.data.delta.content[0]
  42. if not isinstance(content, TextDeltaBlock) or content.text is None or content.text.value is None:
  43. continue
  44. response.content += content.text.value
  45. with ui.column().classes('mx-auto w-full max-w-xl my-16'):
  46. ui.label('NiceGUI Assistant').classes('text-2xl font-bold mx-auto')
  47. question = ui.input(value='Why does NiceGUI use async/await?') \
  48. .classes('w-full self-center mt-4').props('hint="Ask your question" dense') \
  49. .on('keydown.enter', send)
  50. response = ui.markdown().classes('mx-4 mt-2')
  51. ui.timer(0, send, once=True) # NOTE: we send the prepared demo question immediately
  52. ui.run()