solara 1.24.0__py2.py3-none-any.whl → 1.25.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solara/__init__.py +1 -1
- solara/__main__.py +4 -1
- solara/cache.py +9 -4
- solara/checks.py +9 -4
- solara/lab/components/__init__.py +1 -0
- solara/lab/components/chat.py +203 -0
- solara/minisettings.py +1 -1
- solara/server/assets/style.css +1545 -0
- solara/server/flask.py +1 -1
- solara/server/kernel.py +3 -3
- solara/server/patch.py +2 -0
- solara/server/reload.py +1 -1
- solara/server/server.py +58 -0
- solara/server/settings.py +1 -0
- solara/server/starlette.py +32 -13
- solara/server/static/solara_bootstrap.py +1 -1
- solara/server/telemetry.py +8 -3
- solara/server/templates/loader-plain.html +1 -1
- solara/server/templates/loader-solara.html +1 -1
- solara/server/templates/solara.html.j2 +20 -25
- solara/util.py +15 -2
- solara/website/components/notebook.py +44 -1
- solara/website/pages/__init__.py +3 -0
- solara/website/pages/api/__init__.py +1 -0
- solara/website/pages/api/chat.py +109 -0
- solara/website/pages/apps/jupyter-dashboard-1.py +116 -0
- solara/website/pages/apps/scatter.py +4 -4
- solara/website/pages/doc_use_download.py +1 -1
- solara/website/pages/docs/content/04-tutorial/00-overview.md +1 -0
- solara/website/pages/docs/content/04-tutorial/60-jupyter-dashboard-part1.py +18 -1
- solara/website/pages/docs/content/04-tutorial/_jupyter_dashboard_1.ipynb +607 -14
- solara/website/pages/docs/content/10-howto/ipywidget_libraries.md +1 -1
- solara/website/pages/docs/content/95-changelog.md +31 -0
- solara/website/pages/examples/ai/chatbot.py +96 -0
- solara/website/public/success.html +16 -7
- solara/website/templates/index.html.j2 +16 -15
- {solara-1.24.0.dist-info → solara-1.25.1.dist-info}/METADATA +9 -8
- {solara-1.24.0.dist-info → solara-1.25.1.dist-info}/RECORD +43 -40
- {solara-1.24.0.dist-info → solara-1.25.1.dist-info}/WHEEL +1 -1
- solara/server/assets/index.css +0 -14480
- {solara-1.24.0.data → solara-1.25.1.data}/data/prefix/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -0
- {solara-1.24.0.data → solara-1.25.1.data}/data/prefix/etc/jupyter/jupyter_server_config.d/solara.json +0 -0
- {solara-1.24.0.dist-info → solara-1.25.1.dist-info}/entry_points.txt +0 -0
- {solara-1.24.0.dist-info → solara-1.25.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# Chat Components
|
|
3
|
+
|
|
4
|
+
These are the components available in Solara to build chat interfaces.
|
|
5
|
+
Although they can be used together to create a pre-built chat interface, inserting custom components is also possible.
|
|
6
|
+
For an example of how to use a custom message component, see the bottom of the page.
|
|
7
|
+
|
|
8
|
+
Also check out the [Chatbot](/examples/ai/chatbot) example.
|
|
9
|
+
|
|
10
|
+
# ChatBox
|
|
11
|
+
"""
|
|
12
|
+
import solara
|
|
13
|
+
from solara.website.utils import apidoc
|
|
14
|
+
|
|
15
|
+
from . import NoPage
|
|
16
|
+
|
|
17
|
+
title = "Chat Components"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__doc__ += apidoc(solara.lab.components.chat.ChatBox.f) # type: ignore
|
|
21
|
+
__doc__ += "# ChatInput"
|
|
22
|
+
__doc__ += apidoc(solara.lab.components.chat.ChatInput.f) # type: ignore
|
|
23
|
+
__doc__ += "# ChatMessage"
|
|
24
|
+
__doc__ += apidoc(solara.lab.components.chat.ChatMessage.f) # type: ignore
|
|
25
|
+
__doc__ += """## Different Message Styles
|
|
26
|
+
|
|
27
|
+
The `ChatMessage` component has a few different styles available. These are shown below.
|
|
28
|
+
|
|
29
|
+
```solara
|
|
30
|
+
import solara
|
|
31
|
+
|
|
32
|
+
@solara.component
|
|
33
|
+
def Page():
|
|
34
|
+
with solara.Column():
|
|
35
|
+
solara.lab.ChatMessage(["Default"])
|
|
36
|
+
solara.lab.ChatMessage(["`color`"], color="#ff991f")
|
|
37
|
+
solara.lab.ChatMessage(["`avatar_background_color`"], avatar_background_color="success")
|
|
38
|
+
solara.lab.ChatMessage(["`border_radius='20px'`"], border_radius="20px")
|
|
39
|
+
solara.lab.ChatMessage(["`notch=True`"], notch=True)
|
|
40
|
+
```
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
__doc__ += """
|
|
44
|
+
# A Basic Example
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
```solara
|
|
48
|
+
import solara
|
|
49
|
+
|
|
50
|
+
messages = solara.use_reactive([])
|
|
51
|
+
name = solara.use_reactive("User")
|
|
52
|
+
|
|
53
|
+
def send(new_message):
|
|
54
|
+
messages.set([
|
|
55
|
+
*messages.value,
|
|
56
|
+
{"user": True, "name": name.value, "message": new_message,},
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
@solara.component
|
|
60
|
+
def Page():
|
|
61
|
+
solara.InputText("username", value=name)
|
|
62
|
+
with solara.Column(style={"min-height": "50vh"}):
|
|
63
|
+
with solara.lab.ChatBox():
|
|
64
|
+
for item in messages.value:
|
|
65
|
+
with solara.lab.ChatMessage(
|
|
66
|
+
user=item["user"],
|
|
67
|
+
name=item["name"],
|
|
68
|
+
):
|
|
69
|
+
solara.Markdown(item["message"])
|
|
70
|
+
solara.lab.ChatInput(send_callback=send)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
# A Custom Message Component
|
|
74
|
+
|
|
75
|
+
```solara
|
|
76
|
+
import solara
|
|
77
|
+
|
|
78
|
+
messages = solara.use_reactive([])
|
|
79
|
+
|
|
80
|
+
def send(new_message):
|
|
81
|
+
messages.set([
|
|
82
|
+
*messages.value,
|
|
83
|
+
{"name": "User", "message": new_message},
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
@solara.component
|
|
87
|
+
def CustomMessage(
|
|
88
|
+
message,
|
|
89
|
+
name = "User",
|
|
90
|
+
):
|
|
91
|
+
with solara.Column(gap=0):
|
|
92
|
+
with solara.Row():
|
|
93
|
+
solara.Markdown(f"**{name}**: {message}")
|
|
94
|
+
solara.v.Divider(style_="margin: 0;")
|
|
95
|
+
|
|
96
|
+
@solara.component
|
|
97
|
+
def Page():
|
|
98
|
+
with solara.Column(style={"min-height": "50vh"}):
|
|
99
|
+
with solara.lab.ChatBox():
|
|
100
|
+
for item in messages.value:
|
|
101
|
+
CustomMessage(
|
|
102
|
+
message=item["message"],
|
|
103
|
+
name=item["name"],
|
|
104
|
+
)
|
|
105
|
+
solara.lab.ChatInput(send_callback=send)
|
|
106
|
+
```
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
Page = NoPage
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import folium
|
|
4
|
+
import folium.plugins
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
import solara
|
|
9
|
+
|
|
10
|
+
districts = solara.reactive(
|
|
11
|
+
["Bayview", "Northern"],
|
|
12
|
+
)
|
|
13
|
+
categories = solara.reactive(["Vandalism", "Assault", "Robbery"])
|
|
14
|
+
limit = solara.reactive(100)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
ROOT = Path(solara.__file__).parent / "website" / "pages" / "docs" / "content" / "04-tutorial"
|
|
18
|
+
path = ROOT / Path("SF_crime_sample.csv.gz")
|
|
19
|
+
url = "https://raw.githubusercontent.com/widgetti/solara/master/solara/website/pages/docs/content/04-tutorial/SF_crime_sample.csv"
|
|
20
|
+
|
|
21
|
+
if path.exists():
|
|
22
|
+
df_crime = pd.read_csv(path)
|
|
23
|
+
else:
|
|
24
|
+
df_crime = pd.read_csv(url)
|
|
25
|
+
|
|
26
|
+
df_crime
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
df_crime["Category"] = df_crime["Category"].str.title()
|
|
30
|
+
df_crime["PdDistrict"] = df_crime["PdDistrict"].str.title()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def crime_filter(df, district_values, category_values):
|
|
34
|
+
df_dist = df.loc[df["PdDistrict"].isin(district_values)]
|
|
35
|
+
df_category = df_dist.loc[df_dist["Category"].isin(category_values)]
|
|
36
|
+
return df_category
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def crime_charts(df):
|
|
40
|
+
cat_unique = df["Category"].value_counts()
|
|
41
|
+
cat_unique = cat_unique.reset_index()
|
|
42
|
+
|
|
43
|
+
dist_unique = df["PdDistrict"].value_counts()
|
|
44
|
+
dist_unique = dist_unique.reset_index()
|
|
45
|
+
|
|
46
|
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(20, 10))
|
|
47
|
+
|
|
48
|
+
ax1.bar(cat_unique["Category"], cat_unique["count"])
|
|
49
|
+
ax1.set_title("Amount of Criminal Case Based on Category")
|
|
50
|
+
ax2.bar(dist_unique["PdDistrict"], dist_unique["count"])
|
|
51
|
+
ax2.set_title("Amount of Criminal Case in Selected District")
|
|
52
|
+
|
|
53
|
+
# this does not work on solara yet: https://github.com/widgetti/solara/issues/399
|
|
54
|
+
# display(fig)
|
|
55
|
+
# plt.close(fig)
|
|
56
|
+
solara.FigureMatplotlib(fig)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def crime_map(df):
|
|
60
|
+
latitude = 37.77
|
|
61
|
+
longitude = -122.42
|
|
62
|
+
|
|
63
|
+
sanfran_map = folium.Map(location=[latitude, longitude], zoom_start=12)
|
|
64
|
+
|
|
65
|
+
incidents = folium.plugins.MarkerCluster().add_to(sanfran_map)
|
|
66
|
+
|
|
67
|
+
# loop through the dataframe and add each data point to the mark cluster
|
|
68
|
+
for (
|
|
69
|
+
lat,
|
|
70
|
+
lng,
|
|
71
|
+
label,
|
|
72
|
+
) in zip(df.Y, df.X, df.Category):
|
|
73
|
+
folium.Marker(
|
|
74
|
+
location=[lat, lng],
|
|
75
|
+
icon=None,
|
|
76
|
+
popup=label,
|
|
77
|
+
).add_to(incidents)
|
|
78
|
+
|
|
79
|
+
# show map
|
|
80
|
+
solara.display(sanfran_map)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@solara.component
|
|
84
|
+
def View():
|
|
85
|
+
dff = crime_filter(df_crime, districts.value, categories.value)
|
|
86
|
+
row_count = len(dff)
|
|
87
|
+
if row_count > limit.value:
|
|
88
|
+
solara.Warning(f"Only showing the first {limit.value} of {row_count:,} crimes on map")
|
|
89
|
+
with solara.Column(style={"max-height": "400px"}):
|
|
90
|
+
crime_map(dff.iloc[: limit.value])
|
|
91
|
+
if row_count > 0:
|
|
92
|
+
crime_charts(dff)
|
|
93
|
+
else:
|
|
94
|
+
solara.Warning("You filtered out all the data, no charts shown")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@solara.component
|
|
98
|
+
def Controls():
|
|
99
|
+
solara.SelectMultiple("District", all_values=[str(k) for k in df_crime["PdDistrict"].unique().tolist()], values=districts) # type: ignore
|
|
100
|
+
solara.SelectMultiple("Category", all_values=[str(k) for k in df_crime["Category"].unique().tolist()], values=categories) # type: ignore
|
|
101
|
+
solara.Text("Maximum number of rows to show on map")
|
|
102
|
+
solara.SliderInt("", value=limit, min=1, max=1000)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@solara.component
|
|
106
|
+
def Page():
|
|
107
|
+
with solara.Sidebar():
|
|
108
|
+
Controls()
|
|
109
|
+
View()
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# only needed on the solara website itself
|
|
113
|
+
@solara.component
|
|
114
|
+
def Layout(children):
|
|
115
|
+
route, routes = solara.use_route()
|
|
116
|
+
return solara.AppLayout(children=children)
|
|
@@ -28,10 +28,10 @@ class State:
|
|
|
28
28
|
|
|
29
29
|
@staticmethod
|
|
30
30
|
def load_sample():
|
|
31
|
-
State.x.value =
|
|
32
|
-
State.y.value =
|
|
33
|
-
State.size.value =
|
|
34
|
-
State.color.value =
|
|
31
|
+
State.x.value = "gdpPercap"
|
|
32
|
+
State.y.value = "lifeExp"
|
|
33
|
+
State.size.value = "pop"
|
|
34
|
+
State.color.value = "continent"
|
|
35
35
|
State.logx.value = True
|
|
36
36
|
State.df.value = df_sample
|
|
37
37
|
|
|
@@ -20,7 +20,7 @@ def DownloadFile(file_path=file_path, url=url, expected_size=expected_size, on_d
|
|
|
20
20
|
status = "Done 🎉"
|
|
21
21
|
else:
|
|
22
22
|
MEGABYTES = 2.0**20.0
|
|
23
|
-
status = "Downloading
|
|
23
|
+
status = "Downloading {}... ({:6.2f}/{:6.2f} MB)".format(file_path, downloaded_size / MEGABYTES, expected_size / MEGABYTES)
|
|
24
24
|
# status = "hi"
|
|
25
25
|
# return MarkdownIt(f'{status}')
|
|
26
26
|
assert download.progress is not None
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Instead of having one tutorial, we have tutorials for different audiences.
|
|
4
4
|
|
|
5
|
+
* [Jupyter Dashboard](/docs/tutorial/jupyter-dashboard-part1): Learn to create a dashboard in the Jupyter notebook.
|
|
5
6
|
* [Data science](/docs/tutorial/data-science): In this tutorial, we will introduce Solara from the perspective of a data scientist or when you are thinking of using Solara for a data science app.
|
|
6
7
|
* [Web app](/docs/tutorial/web-app): You are not a data scientist, but you are interested in using Solara to create a web app using Pure Python.
|
|
7
8
|
* [IPywidgets user](/docs/tutorial/ipywidgets): If you are already using [ipywidgets](/docs/understanding/ipywidgets) you will learn how to use the [Solara server](/docs/understanding/solara-server) to render your regular ipywidget applications.
|
|
@@ -32,9 +32,26 @@ def Page():
|
|
|
32
32
|
]
|
|
33
33
|
solara.Meta(name="keywords", content=", ".join(tags))
|
|
34
34
|
|
|
35
|
-
Notebook(
|
|
35
|
+
Notebook(
|
|
36
|
+
Path(HERE / "_jupyter_dashboard_1.ipynb"),
|
|
37
|
+
show_last_expressions=True,
|
|
38
|
+
execute=False,
|
|
39
|
+
outputs={
|
|
40
|
+
"a7d17a84": None, # empty output (7)
|
|
41
|
+
"82f1d2f7": solara.Image("https://github.com/widgetti/solara/assets/1765949/e844acdb-c77d-4df4-ba4c-a629f92f18a3"), # map (11)
|
|
42
|
+
"3e7ea361": None, # (13)
|
|
43
|
+
"56055643": solara.Image("https://github.com/widgetti/solara/assets/1765949/daaa3a46-61f5-431f-8003-b42b5915da4b"), # View (15)
|
|
44
|
+
"c78010ec": solara.Image("https://github.com/widgetti/solara/assets/1765949/2f4daf0f-b7d8-4f70-b04a-c27542cffdb0"), # Page (20)
|
|
45
|
+
"18290364": solara.Image("https://github.com/widgetti/solara/assets/1765949/a691d9f1-f07b-4e06-b21b-20980476ad64"), # Controls
|
|
46
|
+
"0ca68fe8": None,
|
|
47
|
+
"fef5d187": None,
|
|
48
|
+
"af686391": solara.Image("https://github.com/widgetti/solara/assets/1765949/f0075ad1-808d-458c-8797-e460ce4dc06d"), # Full app
|
|
49
|
+
},
|
|
50
|
+
)
|
|
36
51
|
solara.Markdown(
|
|
37
52
|
"""
|
|
53
|
+
Explore this app live at [solara.dev](/apps/jupyter-dashboard-1).
|
|
54
|
+
|
|
38
55
|
Don’t miss the next tutorial and stay updated with the latest techniques and insights by subscribing to our newsletter.
|
|
39
56
|
"""
|
|
40
57
|
)
|