Skip to content

Commit 9da5920

Browse files
Merge branch 'zauberzeug:main' into main
2 parents 1b565df + d17b61b commit 9da5920

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2225
-1764
lines changed

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM --platform=linux/amd64 python:3.9
1+
FROM python:3.9
22

33
ENV POETRY_VERSION=2.1.2 \
44
POETRY_NO_INTERACTION=1 \

.github/workflows/test.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,7 @@ jobs:
4444
- name: install dependencies
4545
run: |
4646
set -x
47-
poetry install --all-extras
48-
# install packages to run the examples
49-
poetry run pip install opencv-python opencv-contrib-python-headless httpx isort replicate langchain openai simpy tortoise-orm
50-
poetry run pip install -r tests/requirements.txt
51-
# try fix issue with importlib_resources
52-
poetry run pip install importlib-resources
47+
poetry install --all-extras --with dev
5348
- name: setup chromedriver
5449
uses: nanasess/[email protected]
5550
- name: pytest
@@ -61,8 +56,18 @@ jobs:
6156
name: screenshots-${{ matrix.python }}
6257
path: screenshots/*.failed.png
6358
retention-days: 14
59+
- name: install test startup dependencies
60+
run: |
61+
set -x
62+
# install packages to run the examples
63+
poetry run pip install opencv-python opencv-contrib-python-headless httpx isort replicate openai simpy tortoise-orm
6464
- name: test startup
6565
run: poetry run ./test_startup.sh
66+
- name: restore dependencies for effective caching
67+
if: always()
68+
run: |
69+
set -x
70+
poetry install --all-extras --with dev
6671
6772
slack:
6873
needs:

examples/chat_with_ai/log_callback_handler.py

Lines changed: 0 additions & 48 deletions
This file was deleted.

examples/chat_with_ai/main.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
#!/usr/bin/env python3
22
from html_sanitizer import Sanitizer
33
from langchain_openai import ChatOpenAI
4-
from log_callback_handler import NiceGuiLogElementCallbackHandler
54

65
from nicegui import ui
76

87
OPENAI_API_KEY = 'not-set' # TODO: set your OpenAI API key here
98

109

11-
@ui.page('/')
12-
def main():
10+
def root():
1311
llm = ChatOpenAI(model_name='gpt-4o-mini', streaming=True, openai_api_key=OPENAI_API_KEY)
1412

1513
async def send() -> None:
@@ -22,27 +20,15 @@ async def send() -> None:
2220
spinner = ui.spinner(type='dots')
2321

2422
response = ''
25-
async for chunk in llm.astream(question, config={'callbacks': [NiceGuiLogElementCallbackHandler(log)]}):
23+
async for chunk in llm.astream(question):
2624
response += chunk.content
2725
response_message.clear()
2826
with response_message:
2927
ui.html(response, sanitize=Sanitizer().sanitize)
3028
ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)')
3129
message_container.remove(spinner)
3230

33-
ui.add_css(r'a:link, a:visited {color: inherit !important; text-decoration: none; font-weight: 500}')
34-
35-
# the queries below are used to expand the contend down to the footer (content can then use flex-grow to expand)
36-
ui.query('.q-page').classes('flex')
37-
ui.query('.nicegui-content').classes('w-full')
38-
39-
with ui.tabs().classes('w-full') as tabs:
40-
chat_tab = ui.tab('Chat')
41-
logs_tab = ui.tab('Logs')
42-
with ui.tab_panels(tabs, value=chat_tab).classes('w-full max-w-2xl mx-auto flex-grow items-stretch'):
43-
message_container = ui.tab_panel(chat_tab).classes('items-stretch')
44-
with ui.tab_panel(logs_tab):
45-
log = ui.log().classes('w-full h-full')
31+
message_container = ui.column().classes('w-full max-w-2xl mx-auto flex-grow items-stretch')
4632

4733
with ui.footer().classes('bg-white'), ui.column().classes('w-full max-w-3xl mx-auto my-6'):
4834
with ui.row().classes('w-full no-wrap items-center'):
@@ -51,7 +37,8 @@ async def send() -> None:
5137
text = ui.input(placeholder=placeholder).props('rounded outlined input-class=mx-3') \
5238
.classes('w-full self-center').on('keydown.enter', send)
5339
ui.markdown('simple chat app built with [NiceGUI](https://nicegui.io)') \
54-
.classes('text-xs self-end mr-8 m-[-1em] text-primary')
40+
.classes('text-xs self-end mr-8 m-[-1em] text-primary') \
41+
.classes('[&_a]:text-inherit [&_a]:no-underline [&_a]:font-medium')
5542

5643

57-
ui.run(title='Chat with GPT-3 (example)')
44+
ui.run(root, title='Chat with GPT-4o-mini')
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
html-sanitizer>=2.6.0
2-
langchain>=0.2
3-
langchain-community
4-
langchain_openai
2+
langchain_openai>=0.3
53
nicegui>=3.0

examples/openai_assistant/main.py

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,48 @@
11
#!/usr/bin/env python3
22
from openai import AsyncOpenAI
3-
from openai.types.beta.assistant_stream_event import ThreadMessageInProgress
4-
from openai.types.beta.threads import MessageDeltaEvent, TextDeltaBlock
53

64
from nicegui import ui
75

86
client = AsyncOpenAI(api_key='provide your OpenAI API key here')
97

108

11-
@ui.page('/')
12-
async def main():
13-
assistant = await client.beta.assistants.create(
14-
name='NiceGUI Assistant',
15-
instructions='''
16-
You are a personal assistant for NiceGUI developers.
17-
Your sole focus is to help with questions about the NiceGUI framework.
18-
You are precise and concise.
19-
Stay on the topic.
20-
Very short answers are preferred, but always be friendly and polite.
21-
''',
22-
tools=[{'type': 'code_interpreter'}],
23-
model='gpt-4o-mini',
24-
)
25-
26-
thread = await client.beta.threads.create()
9+
async def root():
10+
messages = []
2711

2812
async def send() -> None:
13+
messages.append({'role': 'user', 'content': question.value})
14+
2915
response.content = ''
3016
spinner = ui.spinner(size='5em', type='comment').classes('mx-auto')
31-
await client.beta.threads.messages.create(
32-
thread_id=thread.id,
33-
role='user',
34-
content=question.value,
35-
)
36-
stream = await client.beta.threads.runs.create(
37-
assistant_id=assistant.id,
38-
thread_id=thread.id,
17+
18+
stream = await client.chat.completions.create(
19+
model='gpt-4o-mini',
20+
messages=[
21+
{
22+
'role': 'system',
23+
'content': '''
24+
You are a personal assistant for NiceGUI developers.
25+
Your sole focus is to help with questions about the NiceGUI framework.
26+
You are precise and concise.
27+
Stay on the topic.
28+
Very short answers are preferred, but always be friendly and polite.
29+
''',
30+
},
31+
*messages,
32+
],
3933
stream=True,
4034
)
35+
36+
spinner.delete()
37+
assistant_message = ''
38+
4139
async for chunk in stream:
42-
if isinstance(chunk, ThreadMessageInProgress):
43-
spinner.delete()
44-
# NOTE: the stream contains a lot of different types so we need to filter out the ones we don't need
45-
if not isinstance(chunk.data, MessageDeltaEvent) or not chunk.data.delta.content:
46-
continue
47-
content = chunk.data.delta.content[0]
48-
if not isinstance(content, TextDeltaBlock) or content.text is None or content.text.value is None:
49-
continue
50-
response.content += content.text.value
40+
if chunk.choices and chunk.choices[0].delta.content:
41+
content = chunk.choices[0].delta.content
42+
assistant_message += content
43+
response.content += content
44+
45+
messages.append({'role': 'assistant', 'content': assistant_message})
5146

5247
with ui.column().classes('mx-auto w-full max-w-xl my-16'):
5348
ui.label('NiceGUI Assistant').classes('text-2xl font-bold mx-auto')
@@ -57,4 +52,4 @@ async def send() -> None:
5752
response = ui.markdown().classes('mx-4 mt-2')
5853
ui.timer(0, send, once=True) # NOTE: we send the prepared demo question immediately
5954

60-
ui.run()
55+
ui.run(root=root)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
nicegui>=3.0
2-
openai==1.58.1
2+
openai>=2.3.0

examples/svg_clock/main.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ def build_svg() -> str:
1010
Original was borrowed from https://de.m.wikipedia.org/wiki/Datei:Station_Clock.svg.
1111
"""
1212
now = datetime.now()
13+
seconds_angle = now.second / 60 * 360
14+
minutes_angle = now.minute / 60 * 360 + seconds_angle / 60
15+
hours_angle = now.hour / 12 * 360 + minutes_angle / 12
1316
return f'''
1417
<svg width="800" height="800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
1518
<circle cx="400" cy="400" r="400" fill="#fff"/>
@@ -30,13 +33,13 @@ def build_svg() -> str:
3033
</g>
3134
<use transform="rotate(90 400 400)" xlink:href="#d"/>
3235
</g>
33-
<g transform="rotate({250 + now.hour / 12 * 360} 400 400)">
36+
<g transform="rotate({250 + hours_angle} 400 400)">
3437
<path d="m334.31 357.65-12.068 33.669 283.94 100.8 23.565-10.394-13.332-24.325z"/>
3538
</g>
36-
<g transform="rotate({117 + now.minute / 60 * 360} 400 400)">
39+
<g transform="rotate({117 + minutes_angle} 400 400)">
3740
<path d="m480.73 344.98 11.019 21.459-382.37 199.37-18.243-7.2122 4.768-19.029z"/>
3841
</g>
39-
<g transform="rotate({169 + now.second / 60 * 360} 400 400)">
42+
<g transform="rotate({169 + seconds_angle} 400 400)">
4043
<path d="m410.21 301.98-43.314 242.68a41.963 41.963 0 0 0-2.8605-0.091 41.963 41.963 0 0 0-41.865 42.059 41.963 41.963 0 0 0 30.073 40.144l-18.417 103.18 1.9709 3.9629 3.2997-2.9496 21.156-102.65a41.963 41.963 0 0 0 3.9771 0.1799 41.963 41.963 0 0 0 41.865-42.059 41.963 41.963 0 0 0-29.003-39.815l49.762-241.44zm-42.448 265.56a19.336 19.336 0 0 1 15.703 18.948 19.336 19.336 0 0 1-19.291 19.38 19.336 19.336 0 0 1-19.38-19.291 19.336 19.336 0 0 1 19.291-19.38 19.336 19.336 0 0 1 3.6752 0.3426z" fill="#a40000"/>
4144
</g>
4245
</svg>

examples/zeromq/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ In addition to the normal NiceGUI dependencies, the zmq library must be installe
1515
### Running the publisher
1616

1717
The publisher is a simple Python script that sends random data to a ZeroMQ socket.
18-
To run it, simply execute the following command:
18+
To run the publisher in the background, simply execute the following command:
1919

2020
```bash
21-
python zmq-server.py
21+
python zmq-server.py &
2222
```
2323

2424
### Running the NiceGUI server
@@ -35,3 +35,9 @@ python main.py
3535
Once both the publisher and GUI server are running, you will see an updating plot on the UI.
3636

3737
![plot](images/plot.png)
38+
39+
To kill zmq-server.py running in the background, execute the following command after main.py ends.
40+
41+
```bash
42+
kill -9 %%
43+
```

nicegui/elements/aggrid/aggrid.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ export default {
7474
return runMethod(this.api.getRowNode(row_id), name, args);
7575
},
7676
handle_event(type, args) {
77-
if (type === "gridSizeChanged" && this.auto_size_columns) {
78-
this.api.sizeColumnsToFit();
79-
}
8077
this.$emit(type, {
8178
value: args.value,
8279
oldValue: args.oldValue,
@@ -114,6 +111,5 @@ export default {
114111
props: {
115112
options: Object,
116113
html_columns: Array,
117-
auto_size_columns: Boolean,
118114
},
119115
};

0 commit comments

Comments
 (0)