streamlit-nightly 1.53.2.dev20260128__py3-none-any.whl → 1.53.2.dev20260202__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.
- streamlit/commands/execution_control.py +2 -2
- streamlit/config.py +3 -2
- streamlit/config_util.py +63 -8
- streamlit/delta_generator.py +2 -0
- streamlit/elements/deck_gl_json_chart.py +5 -1
- streamlit/elements/lib/built_in_chart_utils.py +24 -4
- streamlit/elements/lib/color_util.py +20 -1
- streamlit/elements/lib/column_types.py +6 -2
- streamlit/elements/lib/utils.py +6 -6
- streamlit/elements/markdown.py +0 -1
- streamlit/elements/metric.py +2 -1
- streamlit/elements/vega_charts.py +24 -4
- streamlit/elements/widgets/button_group.py +6 -276
- streamlit/elements/widgets/feedback.py +322 -0
- streamlit/elements/widgets/number_input.py +2 -1
- streamlit/elements/widgets/slider.py +2 -1
- streamlit/material_icon_names.py +1 -1
- streamlit/proto/Alert_pb2.py +2 -3
- streamlit/proto/AppPage_pb2.py +2 -3
- streamlit/proto/ArrowData_pb2.py +2 -3
- streamlit/proto/ArrowNamedDataSet_pb2.py +2 -3
- streamlit/proto/ArrowVegaLiteChart_pb2.py +2 -3
- streamlit/proto/Arrow_pb2.py +11 -18
- streamlit/proto/Arrow_pb2.pyi +1 -42
- streamlit/proto/AudioInput_pb2.py +5 -6
- streamlit/proto/AudioInput_pb2.pyi +3 -3
- streamlit/proto/Audio_pb2.py +3 -4
- streamlit/proto/AuthRedirect_pb2.py +2 -3
- streamlit/proto/AutoRerun_pb2.py +2 -3
- streamlit/proto/BackMsg_pb2.py +2 -3
- streamlit/proto/BackMsg_pb2.pyi +2 -10
- streamlit/proto/Balloons_pb2.py +2 -3
- streamlit/proto/Balloons_pb2.pyi +0 -2
- streamlit/proto/BidiComponent_pb2.py +2 -3
- streamlit/proto/Block_pb2.py +36 -43
- streamlit/proto/Block_pb2.pyi +3 -48
- streamlit/proto/ButtonGroup_pb2.py +11 -14
- streamlit/proto/ButtonGroup_pb2.pyi +6 -41
- streamlit/proto/ButtonLikeIconPosition_pb2.py +2 -3
- streamlit/proto/Button_pb2.py +3 -6
- streamlit/proto/Button_pb2.pyi +1 -18
- streamlit/proto/CameraInput_pb2.py +5 -6
- streamlit/proto/CameraInput_pb2.pyi +3 -3
- streamlit/proto/ChatInput_pb2.py +5 -8
- streamlit/proto/ChatInput_pb2.pyi +1 -17
- streamlit/proto/Checkbox_pb2.py +7 -8
- streamlit/proto/Checkbox_pb2.pyi +3 -3
- streamlit/proto/ClientState_pb2.py +2 -3
- streamlit/proto/Code_pb2.py +3 -6
- streamlit/proto/Code_pb2.pyi +1 -18
- streamlit/proto/ColorPicker_pb2.py +5 -6
- streamlit/proto/ColorPicker_pb2.pyi +3 -3
- streamlit/proto/Common_pb2.py +7 -8
- streamlit/proto/Common_pb2.pyi +2 -10
- streamlit/proto/Components_pb2.py +2 -3
- streamlit/proto/DateInput_pb2.py +5 -6
- streamlit/proto/DateInput_pb2.pyi +3 -3
- streamlit/proto/DateTimeInput_pb2.py +5 -6
- streamlit/proto/DateTimeInput_pb2.pyi +3 -3
- streamlit/proto/DeckGlJsonChart_pb2.py +5 -12
- streamlit/proto/DeckGlJsonChart_pb2.pyi +1 -54
- streamlit/proto/Delta_pb2.py +4 -6
- streamlit/proto/Delta_pb2.pyi +5 -14
- streamlit/proto/DocString_pb2.py +2 -3
- streamlit/proto/DownloadButton_pb2.py +2 -3
- streamlit/proto/Element_pb2.py +5 -8
- streamlit/proto/Element_pb2.pyi +9 -29
- streamlit/proto/Empty_pb2.py +2 -3
- streamlit/proto/Exception_pb2.py +2 -3
- streamlit/proto/Favicon_pb2.py +2 -3
- streamlit/proto/Feedback_pb2.py +28 -0
- streamlit/proto/Feedback_pb2.pyi +93 -0
- streamlit/proto/FileUploader_pb2.py +5 -6
- streamlit/proto/FileUploader_pb2.pyi +3 -3
- streamlit/proto/ForwardMsg_pb2.py +12 -18
- streamlit/proto/ForwardMsg_pb2.pyi +4 -48
- streamlit/proto/GapSize_pb2.py +2 -3
- streamlit/proto/GitInfo_pb2.py +2 -3
- streamlit/proto/GraphVizChart_pb2.py +3 -6
- streamlit/proto/GraphVizChart_pb2.pyi +1 -18
- streamlit/proto/Heading_pb2.py +2 -3
- streamlit/proto/HeightConfig_pb2.py +2 -3
- streamlit/proto/Html_pb2.py +2 -3
- streamlit/proto/IFrame_pb2.py +4 -11
- streamlit/proto/IFrame_pb2.pyi +1 -42
- streamlit/proto/Image_pb2.py +5 -8
- streamlit/proto/Image_pb2.pyi +2 -25
- streamlit/proto/Json_pb2.py +2 -3
- streamlit/proto/LabelVisibility_pb2.py +28 -0
- streamlit/proto/{LabelVisibilityMessage_pb2.pyi → LabelVisibility_pb2.pyi} +14 -14
- streamlit/proto/LinkButton_pb2.py +2 -3
- streamlit/proto/Logo_pb2.py +2 -3
- streamlit/proto/Markdown_pb2.py +5 -6
- streamlit/proto/Markdown_pb2.pyi +1 -5
- streamlit/proto/Metric_pb2.py +11 -12
- streamlit/proto/Metric_pb2.pyi +3 -3
- streamlit/proto/MetricsEvent_pb2.py +2 -3
- streamlit/proto/MultiSelect_pb2.py +5 -8
- streamlit/proto/MultiSelect_pb2.pyi +4 -14
- streamlit/proto/Navigation_pb2.py +2 -3
- streamlit/proto/NewSession_pb2.py +39 -28
- streamlit/proto/NewSession_pb2.pyi +44 -20
- streamlit/proto/NumberInput_pb2.py +7 -8
- streamlit/proto/NumberInput_pb2.pyi +3 -3
- streamlit/proto/PageConfig_pb2.py +2 -3
- streamlit/proto/PageInfo_pb2.py +2 -3
- streamlit/proto/PageLink_pb2.py +2 -3
- streamlit/proto/PageNotFound_pb2.py +2 -3
- streamlit/proto/PageProfile_pb2.py +2 -3
- streamlit/proto/ParentMessage_pb2.py +2 -3
- streamlit/proto/PlotlyChart_pb2.py +5 -10
- streamlit/proto/PlotlyChart_pb2.pyi +1 -58
- streamlit/proto/Progress_pb2.py +2 -3
- streamlit/proto/Radio_pb2.py +5 -8
- streamlit/proto/Radio_pb2.pyi +5 -22
- streamlit/proto/RootContainer_pb2.py +2 -3
- streamlit/proto/Selectbox_pb2.py +5 -8
- streamlit/proto/Selectbox_pb2.pyi +5 -25
- streamlit/proto/SessionEvent_pb2.py +2 -3
- streamlit/proto/SessionStatus_pb2.py +2 -3
- streamlit/proto/Skeleton_pb2.py +2 -3
- streamlit/proto/Slider_pb2.py +9 -10
- streamlit/proto/Slider_pb2.pyi +3 -3
- streamlit/proto/Snow_pb2.py +2 -3
- streamlit/proto/Snow_pb2.pyi +0 -2
- streamlit/proto/Space_pb2.py +2 -3
- streamlit/proto/Spinner_pb2.py +2 -3
- streamlit/proto/TextAlignmentConfig_pb2.py +2 -3
- streamlit/proto/TextArea_pb2.py +5 -8
- streamlit/proto/TextArea_pb2.pyi +4 -21
- streamlit/proto/TextInput_pb2.py +7 -8
- streamlit/proto/TextInput_pb2.pyi +3 -3
- streamlit/proto/Text_pb2.py +2 -3
- streamlit/proto/TimeInput_pb2.py +5 -6
- streamlit/proto/TimeInput_pb2.pyi +3 -3
- streamlit/proto/Toast_pb2.py +2 -3
- streamlit/proto/Transient_pb2.py +2 -3
- streamlit/proto/Video_pb2.py +3 -4
- streamlit/proto/WidgetStates_pb2.py +2 -3
- streamlit/proto/WidthConfig_pb2.py +2 -3
- streamlit/proto/openmetrics_data_model_pb2.py +2 -3
- streamlit/runtime/runtime.py +0 -4
- streamlit/static/index.html +2 -2
- streamlit/static/manifest.json +327 -312
- streamlit/static/static/css/{index.BUP6fTcR.css → index.C8MrxwGF.css} +1 -1
- streamlit/static/static/js/{ErrorOutline.esm.D71F8ziR.js → ErrorOutline.esm.CLuz0rSD.js} +1 -1
- streamlit/static/static/js/{FileDownload.esm.yTkppsJy.js → FileDownload.esm.CO68LcnZ.js} +1 -1
- streamlit/static/static/js/{FileHelper.hUOqtbwa.js → FileHelper.DAXgY6Ug.js} +1 -1
- streamlit/static/static/js/{FormClearHelper.DN8D_YXO.js → FormClearHelper.zxJ53Nym.js} +1 -1
- streamlit/static/static/js/{InputInstructions.DbssY6d4.js → InputInstructions.CCbg8esE.js} +1 -1
- streamlit/static/static/js/{Particles.BznyVdfo.js → Particles.BJw0A-zv.js} +1 -1
- streamlit/static/static/js/{ProgressBar.C5uBOtcx.js → ProgressBar.BrrHeAEh.js} +2 -2
- streamlit/static/static/js/{StreamlitSyntaxHighlighter.Nf1895x-.js → StreamlitSyntaxHighlighter.DvPLy3zk.js} +1 -1
- streamlit/static/static/js/{TableChart.esm.DHKzVs3a.js → TableChart.esm.BawvAi5p.js} +1 -1
- streamlit/static/static/js/{Toolbar.CQsWYXer.js → Toolbar.CbpscbNb.js} +1 -1
- streamlit/static/static/js/{WidgetLabelHelpIconInline.6xCU76OE.js → WidgetLabelHelpIconInline.DA4S2HFP.js} +1 -1
- streamlit/static/static/js/{base-input.Cs-E6S71.js → base-input.BKKl2eBF.js} +4 -4
- streamlit/static/static/js/{checkbox.OTGupu18.js → checkbox.CB43AKV4.js} +1 -1
- streamlit/static/static/js/{createDownloadLinkElement.DnBEQQbK.js → createDownloadLinkElement.jVwF96ey.js} +1 -1
- streamlit/static/static/js/data-grid-overlay-editor.CxQizSv7.js +1 -0
- streamlit/static/static/js/{downloader.K0GUNeuj.js → downloader.CKlIgsy5.js} +1 -1
- streamlit/static/static/js/{embed.o8HvK3mH.js → embed.BhRb_2n8.js} +1 -1
- streamlit/static/static/js/{es6.BHy5pqTP.js → es6.DPyfPmWm.js} +2 -2
- streamlit/static/static/js/formatNumber.DtfMnnPx.js +1 -0
- streamlit/static/static/js/{iconPosition.2YynQUxu.js → iconPosition.DkZAlu_k.js} +1 -1
- streamlit/static/static/js/{iframeResizer.contentWindow.D5h3hQuU.js → iframeResizer.contentWindow.l5sQWLra.js} +1 -1
- streamlit/static/static/js/{index.BZ-GJVxB.js → index.465nmxtO.js} +2 -2
- streamlit/static/static/js/{index.BPdmXoYW.js → index.6J1N4is3.js} +1 -1
- streamlit/static/static/js/{index.Bfo1cXfC.js → index.AZ9T4EqJ.js} +1 -1
- streamlit/static/static/js/{index.cfuZ69LI.js → index.BAK0CG1Q.js} +1 -1
- streamlit/static/static/js/{index.5zqfJ-in.js → index.BLD3tJ2C.js} +1 -1
- streamlit/static/static/js/{index.CxWzt6oi.js → index.BUlT_mOL.js} +3 -3
- streamlit/static/static/js/{index.DxGXuhh6.js → index.Bc_FQ4Wb.js} +1 -1
- streamlit/static/static/js/{index.DJfMW0Gy.js → index.BpCj2-sQ.js} +1 -1
- streamlit/static/static/js/{index.DLUSo6de.js → index.BzO83wKm.js} +1 -1
- streamlit/static/static/js/index.CAoX2tlo.js +2 -0
- streamlit/static/static/js/{index.CwtpGPHA.js → index.CBbYMKZp.js} +1 -1
- streamlit/static/static/js/{index.Bgf49D1Z.js → index.CL7it7tU.js} +222 -222
- streamlit/static/static/js/{index.DxfYCrPp.js → index.CL_icBXS.js} +1 -1
- streamlit/static/static/js/index.C_19KWNs.js +2 -0
- streamlit/static/static/js/index.CaU3Uv_L.js +1 -0
- streamlit/static/static/js/{index.Dh3PJIlq.js → index.Ccye_uLl.js} +1 -1
- streamlit/static/static/js/{index.C65jHNhe.js → index.CiS4giQ2.js} +1 -1
- streamlit/static/static/js/{index.hlAfdSqC.js → index.Ck64OQhV.js} +1 -1
- streamlit/static/static/js/{index.HmRK3HyC.js → index.CmbqbRMZ.js} +1 -1
- streamlit/static/static/js/{index.8MlRyIxN.js → index.CsEZTo6L.js} +2 -2
- streamlit/static/static/js/{index.DVRCyxMp.js → index.CsIENsKH.js} +1 -1
- streamlit/static/static/js/{index.Bqmx23jK.js → index.Cwg8nWw5.js} +1 -1
- streamlit/static/static/js/{index.CZf7Go1Z.js → index.D83azq2w.js} +1 -1
- streamlit/static/static/js/{index.CUkhn-vu.js → index.DDr-BLbJ.js} +1 -1
- streamlit/static/static/js/{index.iUV9rb8C.js → index.DKoJr0Se.js} +1 -1
- streamlit/static/static/js/{index.C2EoeVjP.js → index.DL_ywOgf.js} +2 -2
- streamlit/static/static/js/{index.q0ceUXt6.js → index.DR6V0uBJ.js} +1 -1
- streamlit/static/static/js/index.DZOGT9vX.js +1 -0
- streamlit/static/static/js/{index.BtuskCwg.js → index.Dac9Jib-.js} +1 -1
- streamlit/static/static/js/{index.6c-qDsD7.js → index.DiBeetOH.js} +1 -1
- streamlit/static/static/js/{index.DlgcEr0f.js → index.DjuMEZ6m.js} +1 -1
- streamlit/static/static/js/{index.DBPWUJsj.js → index.DmWUXdjc.js} +54 -54
- streamlit/static/static/js/{index.DL_yE83J.js → index.DpSc4e1j.js} +2 -2
- streamlit/static/static/js/{index.CgVv04GM.js → index.DzdPUxsx.js} +2 -2
- streamlit/static/static/js/{index.BtRWcqZV.js → index.FioS1Y9m.js} +1 -1
- streamlit/static/static/js/{index.BfMPq234.js → index.L9pOjBEn.js} +3 -3
- streamlit/static/static/js/{index.TjMWsKSH.js → index.LjqoQCm5.js} +3 -3
- streamlit/static/static/js/index.OizPL4jg.js +1 -0
- streamlit/static/static/js/{index.Cb03y5I8.js → index.Q2t_iBn0.js} +1 -1
- streamlit/static/static/js/index.WIMtx3m0.js +2 -0
- streamlit/static/static/js/index.Y9wPTZIf.js +1 -0
- streamlit/static/static/js/{index.COh5V_89.js → index.YutgmD9x.js} +2 -2
- streamlit/static/static/js/{index.BIqcOZ_u.js → index.b_f-McZ5.js} +1 -1
- streamlit/static/static/js/{index.BzTVI_BY.js → index.e6Ry6-Ft.js} +1 -1
- streamlit/static/static/js/index.hnu9U-5g.js +1 -0
- streamlit/static/static/js/{index.C6wyTXhz.js → index.rvbQETlC.js} +1 -1
- streamlit/static/static/js/index.w7yKy9fh.js +6 -0
- streamlit/static/static/js/{index.C7wst9Tm.js → index.y0h42OXL.js} +1 -1
- streamlit/static/static/js/{index.aCorc3Yt.js → index.y5HxPwg9.js} +48 -48
- streamlit/static/static/js/{index.CX0KdFyR.js → index.yHLCvUGh.js} +1 -1
- streamlit/static/static/js/{input.CXGIJ7D6.js → input.CAtwSQ27.js} +1 -1
- streamlit/static/static/js/{main.CCVkbuxC.js → main.VeMVx6VI.js} +1 -1
- streamlit/static/static/js/{memory.CNbnYs2A.js → memory.CxS_lIUn.js} +1 -1
- streamlit/static/static/js/number-overlay-editor.CoqRgZW_.js +9 -0
- streamlit/static/static/js/{pandasStylerUtils.CFSReOTm.js → pandasStylerUtils.DGWgd5sM.js} +1 -1
- streamlit/static/static/js/{sandbox.Bld0L3us.js → sandbox.2mSqEau0.js} +1 -1
- streamlit/static/static/js/sprintfjs.CsoVVZ9k.js +1 -0
- streamlit/static/static/js/{styled-components.BoUHK6TA.js → styled-components.BShfh7J8.js} +1 -1
- streamlit/static/static/js/{throttle.ByDFm7WV.js → throttle.Fq1DQK4p.js} +1 -1
- streamlit/static/static/js/{timepicker.CN6CUZEL.js → timepicker.DmyY-qtn.js} +1 -1
- streamlit/static/static/js/{toConsumableArray.DwMycSpg.js → toConsumableArray.Dvd9AIqV.js} +1 -1
- streamlit/static/static/js/uniqueId.CCajdEK8.js +1 -0
- streamlit/static/static/js/{useBasicWidgetState.Bg0ZMUt5.js → useBasicWidgetState.COLQ5AFB.js} +1 -1
- streamlit/static/static/js/{useIntlLocale.DgBUDcPA.js → useIntlLocale.kdIj0ego.js} +1 -1
- streamlit/static/static/js/{useTextInputAutoExpand.DDBezxks.js → useTextInputAutoExpand.DkuG1C1S.js} +1 -1
- streamlit/static/static/js/{useUpdateUiValue.Df1h6fXC.js → useUpdateUiValue.-UI_JsjT.js} +1 -1
- streamlit/static/static/js/{useWaveformController.DbWw5MEk.js → useWaveformController.C5PTwL6I.js} +1 -1
- streamlit/static/static/js/{withCalculatedWidth.YaK0HIIP.js → withCalculatedWidth.BREyS0pJ.js} +1 -1
- streamlit/static/static/js/{withFullScreenWrapper.CcWCKoY8.js → withFullScreenWrapper.DYDiEOrW.js} +1 -1
- streamlit/static/static/media/MaterialSymbols-Rounded.CnH1S47a.woff2 +0 -0
- streamlit/testing/v1/app_test.py +21 -5
- streamlit/testing/v1/element_tree.py +81 -4
- streamlit/web/server/server.py +0 -1
- streamlit/web/server/starlette/starlette_app.py +0 -1
- {streamlit_nightly-1.53.2.dev20260128.dist-info → streamlit_nightly-1.53.2.dev20260202.dist-info}/METADATA +10 -25
- {streamlit_nightly-1.53.2.dev20260128.dist-info → streamlit_nightly-1.53.2.dev20260202.dist-info}/RECORD +245 -252
- streamlit/proto/BokehChart_pb2.py +0 -27
- streamlit/proto/BokehChart_pb2.pyi +0 -56
- streamlit/proto/DataFrame_pb2.py +0 -56
- streamlit/proto/DataFrame_pb2.pyi +0 -430
- streamlit/proto/LabelVisibilityMessage_pb2.py +0 -29
- streamlit/proto/NamedDataSet_pb2.py +0 -28
- streamlit/proto/NamedDataSet_pb2.pyi +0 -67
- streamlit/proto/PagesChanged_pb2.py +0 -28
- streamlit/proto/PagesChanged_pb2.pyi +0 -55
- streamlit/proto/VegaLiteChart_pb2.py +0 -29
- streamlit/proto/VegaLiteChart_pb2.pyi +0 -79
- streamlit/static/static/js/data-grid-overlay-editor.COiiMi5r.js +0 -1
- streamlit/static/static/js/formatNumber.BK7h0k2z.js +0 -1
- streamlit/static/static/js/index.BBTKOM0z.js +0 -6
- streamlit/static/static/js/index.CSPY26T2.js +0 -1
- streamlit/static/static/js/index.CYhhEdja.js +0 -1
- streamlit/static/static/js/index.CdsyTabv.js +0 -1
- streamlit/static/static/js/index.CjRU8O1O.js +0 -2
- streamlit/static/static/js/index.Dc5-tFdw.js +0 -2
- streamlit/static/static/js/index.DcngUOyD.js +0 -2
- streamlit/static/static/js/index.VwDKazgt.js +0 -1
- streamlit/static/static/js/number-overlay-editor.CvI6wkld.js +0 -9
- streamlit/static/static/js/sprintf.DpPCfzXw.js +0 -1
- streamlit/static/static/js/uniqueId.DcCWa2cf.js +0 -1
- streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
- streamlit_nightly-1.53.2.dev20260128.data/scripts/streamlit.cmd +0 -16
- {streamlit_nightly-1.53.2.dev20260128.dist-info → streamlit_nightly-1.53.2.dev20260202.dist-info}/WHEEL +0 -0
- {streamlit_nightly-1.53.2.dev20260128.dist-info → streamlit_nightly-1.53.2.dev20260202.dist-info}/entry_points.txt +0 -0
- {streamlit_nightly-1.53.2.dev20260128.dist-info → streamlit_nightly-1.53.2.dev20260202.dist-info}/top_level.txt +0 -0
|
@@ -19,7 +19,6 @@ from dataclasses import dataclass, field
|
|
|
19
19
|
from typing import (
|
|
20
20
|
TYPE_CHECKING,
|
|
21
21
|
Any,
|
|
22
|
-
Final,
|
|
23
22
|
Generic,
|
|
24
23
|
Literal,
|
|
25
24
|
TypeAlias,
|
|
@@ -28,7 +27,6 @@ from typing import (
|
|
|
28
27
|
overload,
|
|
29
28
|
)
|
|
30
29
|
|
|
31
|
-
from streamlit import config
|
|
32
30
|
from streamlit.elements.lib.form_utils import current_form_id
|
|
33
31
|
from streamlit.elements.lib.layout_utils import (
|
|
34
32
|
LayoutConfig,
|
|
@@ -76,20 +74,6 @@ if TYPE_CHECKING:
|
|
|
76
74
|
T = TypeVar("T")
|
|
77
75
|
V = TypeVar("V")
|
|
78
76
|
|
|
79
|
-
_THUMB_ICONS: Final = (":material/thumb_up:", ":material/thumb_down:")
|
|
80
|
-
_FACES_ICONS: Final = (
|
|
81
|
-
":material/sentiment_sad:",
|
|
82
|
-
":material/sentiment_dissatisfied:",
|
|
83
|
-
":material/sentiment_neutral:",
|
|
84
|
-
":material/sentiment_satisfied:",
|
|
85
|
-
":material/sentiment_very_satisfied:",
|
|
86
|
-
)
|
|
87
|
-
_NUMBER_STARS: Final = 5
|
|
88
|
-
_STAR_ICON: Final = ":material/star:"
|
|
89
|
-
# we don't have the filled-material icon library as a dependency. Hence, we have it here
|
|
90
|
-
# in base64 format and send it over the wire as an image.
|
|
91
|
-
_SELECTED_STAR_ICON: Final = ":material/star_filled:"
|
|
92
|
-
|
|
93
77
|
SelectionMode: TypeAlias = Literal["single", "multi"]
|
|
94
78
|
|
|
95
79
|
|
|
@@ -185,35 +169,6 @@ class ButtonGroupSerde(Generic[T]):
|
|
|
185
169
|
return self.serde.deserialize(ui_value)
|
|
186
170
|
|
|
187
171
|
|
|
188
|
-
def get_mapped_options(
|
|
189
|
-
feedback_option: Literal["thumbs", "faces", "stars"],
|
|
190
|
-
) -> tuple[list[ButtonGroupProto.Option], list[int]]:
|
|
191
|
-
# options object understandable by the web app
|
|
192
|
-
options: list[ButtonGroupProto.Option] = []
|
|
193
|
-
# we use the option index in the webapp communication to
|
|
194
|
-
# indicate which option is selected
|
|
195
|
-
options_indices: list[int] = []
|
|
196
|
-
|
|
197
|
-
if feedback_option == "thumbs":
|
|
198
|
-
# reversing the index mapping to have thumbs up first (but still with the higher
|
|
199
|
-
# index (=sentiment) in the list)
|
|
200
|
-
options_indices = list(reversed(range(len(_THUMB_ICONS))))
|
|
201
|
-
options = [ButtonGroupProto.Option(content_icon=icon) for icon in _THUMB_ICONS]
|
|
202
|
-
elif feedback_option == "faces":
|
|
203
|
-
options_indices = list(range(len(_FACES_ICONS)))
|
|
204
|
-
options = [ButtonGroupProto.Option(content_icon=icon) for icon in _FACES_ICONS]
|
|
205
|
-
elif feedback_option == "stars":
|
|
206
|
-
options_indices = list(range(_NUMBER_STARS))
|
|
207
|
-
options = [
|
|
208
|
-
ButtonGroupProto.Option(
|
|
209
|
-
content_icon=_STAR_ICON,
|
|
210
|
-
selected_content_icon=_SELECTED_STAR_ICON,
|
|
211
|
-
)
|
|
212
|
-
] * _NUMBER_STARS
|
|
213
|
-
|
|
214
|
-
return options, options_indices
|
|
215
|
-
|
|
216
|
-
|
|
217
172
|
def _build_proto(
|
|
218
173
|
widget_id: str,
|
|
219
174
|
formatted_options: Sequence[ButtonGroupProto.Option],
|
|
@@ -221,10 +176,7 @@ def _build_proto(
|
|
|
221
176
|
disabled: bool,
|
|
222
177
|
current_form_id: str,
|
|
223
178
|
click_mode: ButtonGroupProto.ClickMode.ValueType,
|
|
224
|
-
|
|
225
|
-
ButtonGroupProto.SelectionVisualization.ONLY_SELECTED
|
|
226
|
-
),
|
|
227
|
-
style: Literal["borderless", "pills", "segmented_control"] = "pills",
|
|
179
|
+
style: Literal["pills", "segmented_control"] = "pills",
|
|
228
180
|
label: str | None = None,
|
|
229
181
|
label_visibility: LabelVisibility = "visible",
|
|
230
182
|
help: str | None = None,
|
|
@@ -249,7 +201,6 @@ def _build_proto(
|
|
|
249
201
|
|
|
250
202
|
for formatted_option in formatted_options:
|
|
251
203
|
proto.options.append(formatted_option)
|
|
252
|
-
proto.selection_visualization = selection_visualization
|
|
253
204
|
return proto
|
|
254
205
|
|
|
255
206
|
|
|
@@ -263,219 +214,6 @@ def _maybe_raise_selection_mode_warning(selection_mode: SelectionMode) -> None:
|
|
|
263
214
|
|
|
264
215
|
|
|
265
216
|
class ButtonGroupMixin:
|
|
266
|
-
# These overloads are not documented in the docstring, at least not at this time, on
|
|
267
|
-
# the theory that most people won't know what it means. And the Literals here are a
|
|
268
|
-
# subclass of int anyway. Usually, we would make a type alias for
|
|
269
|
-
# Literal["thumbs", "faces", "stars"]; but, in this case, we don't use it in too
|
|
270
|
-
# many other places, and it's a more helpful autocomplete if we just enumerate the
|
|
271
|
-
# values explicitly, so a decision has been made to keep it as not an alias.
|
|
272
|
-
@overload
|
|
273
|
-
def feedback(
|
|
274
|
-
self,
|
|
275
|
-
options: Literal["thumbs"] = ...,
|
|
276
|
-
*,
|
|
277
|
-
key: Key | None = None,
|
|
278
|
-
default: int | None = None,
|
|
279
|
-
disabled: bool = False,
|
|
280
|
-
on_change: WidgetCallback | None = None,
|
|
281
|
-
args: WidgetArgs | None = None,
|
|
282
|
-
kwargs: WidgetKwargs | None = None,
|
|
283
|
-
width: Width = "content",
|
|
284
|
-
) -> Literal[0, 1] | None: ...
|
|
285
|
-
@overload
|
|
286
|
-
def feedback(
|
|
287
|
-
self,
|
|
288
|
-
options: Literal["faces", "stars"] = ...,
|
|
289
|
-
*,
|
|
290
|
-
key: Key | None = None,
|
|
291
|
-
default: int | None = None,
|
|
292
|
-
disabled: bool = False,
|
|
293
|
-
on_change: WidgetCallback | None = None,
|
|
294
|
-
args: WidgetArgs | None = None,
|
|
295
|
-
kwargs: WidgetKwargs | None = None,
|
|
296
|
-
width: Width = "content",
|
|
297
|
-
) -> Literal[0, 1, 2, 3, 4] | None: ...
|
|
298
|
-
@gather_metrics("feedback")
|
|
299
|
-
def feedback(
|
|
300
|
-
self,
|
|
301
|
-
options: Literal["thumbs", "faces", "stars"] = "thumbs",
|
|
302
|
-
*,
|
|
303
|
-
key: Key | None = None,
|
|
304
|
-
default: int | None = None,
|
|
305
|
-
disabled: bool = False,
|
|
306
|
-
on_change: WidgetCallback | None = None,
|
|
307
|
-
args: WidgetArgs | None = None,
|
|
308
|
-
kwargs: WidgetKwargs | None = None,
|
|
309
|
-
width: Width = "content",
|
|
310
|
-
) -> int | None:
|
|
311
|
-
"""Display a feedback widget.
|
|
312
|
-
|
|
313
|
-
A feedback widget is an icon-based button group available in three
|
|
314
|
-
styles, as described in ``options``. It is commonly used in chat and AI
|
|
315
|
-
apps to allow users to rate responses.
|
|
316
|
-
|
|
317
|
-
Parameters
|
|
318
|
-
----------
|
|
319
|
-
options : "thumbs", "faces", or "stars"
|
|
320
|
-
The feedback options displayed to the user. ``options`` can be one
|
|
321
|
-
of the following:
|
|
322
|
-
|
|
323
|
-
- ``"thumbs"`` (default): Streamlit displays a thumb-up and
|
|
324
|
-
thumb-down button group.
|
|
325
|
-
- ``"faces"``: Streamlit displays a row of five buttons with
|
|
326
|
-
facial expressions depicting increasing satisfaction from left to
|
|
327
|
-
right.
|
|
328
|
-
- ``"stars"``: Streamlit displays a row of star icons, allowing the
|
|
329
|
-
user to select a rating from one to five stars.
|
|
330
|
-
|
|
331
|
-
key : str or int
|
|
332
|
-
An optional string or integer to use as the unique key for the widget.
|
|
333
|
-
If this is omitted, a key will be generated for the widget
|
|
334
|
-
based on its content. No two widgets may have the same key.
|
|
335
|
-
|
|
336
|
-
default : int or None
|
|
337
|
-
Default feedback value. This must be consistent with the feedback
|
|
338
|
-
type in ``options``:
|
|
339
|
-
|
|
340
|
-
- 0 or 1 if ``options="thumbs"``.
|
|
341
|
-
- Between 0 and 4, inclusive, if ``options="faces"`` or
|
|
342
|
-
``options="stars"``.
|
|
343
|
-
|
|
344
|
-
disabled : bool
|
|
345
|
-
An optional boolean that disables the feedback widget if set
|
|
346
|
-
to ``True``. The default is ``False``.
|
|
347
|
-
|
|
348
|
-
on_change : callable
|
|
349
|
-
An optional callback invoked when this feedback widget's value
|
|
350
|
-
changes.
|
|
351
|
-
|
|
352
|
-
args : list or tuple
|
|
353
|
-
An optional list or tuple of args to pass to the callback.
|
|
354
|
-
|
|
355
|
-
kwargs : dict
|
|
356
|
-
An optional dict of kwargs to pass to the callback.
|
|
357
|
-
|
|
358
|
-
width : "content", "stretch", or int
|
|
359
|
-
The width of the feedback widget. This can be one of the following:
|
|
360
|
-
|
|
361
|
-
- ``"content"`` (default): The width of the widget matches the
|
|
362
|
-
width of its content, but doesn't exceed the width of the parent
|
|
363
|
-
container.
|
|
364
|
-
- ``"stretch"``: The width of the widget matches the width of the
|
|
365
|
-
parent container.
|
|
366
|
-
- An integer specifying the width in pixels: The widget has a
|
|
367
|
-
fixed width. If the specified width is greater than the width of
|
|
368
|
-
the parent container, the width of the widget matches the width
|
|
369
|
-
of the parent container.
|
|
370
|
-
|
|
371
|
-
Returns
|
|
372
|
-
-------
|
|
373
|
-
int or None
|
|
374
|
-
An integer indicating the user's selection, where ``0`` is the
|
|
375
|
-
lowest feedback. Higher values indicate more positive feedback.
|
|
376
|
-
If no option was selected, the widget returns ``None``.
|
|
377
|
-
|
|
378
|
-
- For ``options="thumbs"``, a return value of ``0`` indicates
|
|
379
|
-
thumbs-down, and ``1`` indicates thumbs-up.
|
|
380
|
-
- For ``options="faces"`` and ``options="stars"``, return values
|
|
381
|
-
range from ``0`` (least satisfied) to ``4`` (most satisfied).
|
|
382
|
-
|
|
383
|
-
Examples
|
|
384
|
-
--------
|
|
385
|
-
Display a feedback widget with stars, and show the selected sentiment:
|
|
386
|
-
|
|
387
|
-
>>> import streamlit as st
|
|
388
|
-
>>>
|
|
389
|
-
>>> sentiment_mapping = ["one", "two", "three", "four", "five"]
|
|
390
|
-
>>> selected = st.feedback("stars")
|
|
391
|
-
>>> if selected is not None:
|
|
392
|
-
>>> st.markdown(f"You selected {sentiment_mapping[selected]} star(s).")
|
|
393
|
-
|
|
394
|
-
.. output::
|
|
395
|
-
https://doc-feedback-stars.streamlit.app/
|
|
396
|
-
height: 200px
|
|
397
|
-
|
|
398
|
-
Display a feedback widget with thumbs, and show the selected sentiment:
|
|
399
|
-
|
|
400
|
-
>>> import streamlit as st
|
|
401
|
-
>>>
|
|
402
|
-
>>> sentiment_mapping = [":material/thumb_down:", ":material/thumb_up:"]
|
|
403
|
-
>>> selected = st.feedback("thumbs")
|
|
404
|
-
>>> if selected is not None:
|
|
405
|
-
>>> st.markdown(f"You selected: {sentiment_mapping[selected]}")
|
|
406
|
-
|
|
407
|
-
.. output::
|
|
408
|
-
https://doc-feedback-thumbs.streamlit.app/
|
|
409
|
-
height: 200px
|
|
410
|
-
|
|
411
|
-
"""
|
|
412
|
-
|
|
413
|
-
if options not in {"thumbs", "faces", "stars"}:
|
|
414
|
-
raise StreamlitAPIException(
|
|
415
|
-
"The options argument to st.feedback must be one of "
|
|
416
|
-
"['thumbs', 'faces', 'stars']. "
|
|
417
|
-
f"The argument passed was '{options}'."
|
|
418
|
-
)
|
|
419
|
-
transformed_options, options_indices = get_mapped_options(options)
|
|
420
|
-
|
|
421
|
-
if default is not None and (default < 0 or default >= len(transformed_options)):
|
|
422
|
-
raise StreamlitAPIException(
|
|
423
|
-
f"The default value in '{options}' must be a number between 0 and {len(transformed_options) - 1}."
|
|
424
|
-
f" The passed default value is {default}"
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
# Convert small pixel widths to "content" to prevent icon wrapping.
|
|
428
|
-
# Calculate threshold based on theme.baseFontSize to be responsive to
|
|
429
|
-
# custom themes. The calculation is based on icon buttons sized in rem:
|
|
430
|
-
# - Button size: ~1.5rem (icon 1.25rem + padding 0.125rem x 2)
|
|
431
|
-
# - Gap: 0.125rem between buttons
|
|
432
|
-
# - thumbs: 2 buttons + 1 gap = 3.125rem
|
|
433
|
-
# - faces/stars: 5 buttons + 4 gaps = 8rem
|
|
434
|
-
base_font_size = config.get_option("theme.baseFontSize") or 16
|
|
435
|
-
button_size_rem = 1.5
|
|
436
|
-
gap_size_rem = 0.125
|
|
437
|
-
|
|
438
|
-
if options == "thumbs":
|
|
439
|
-
# 2 buttons + 1 gap
|
|
440
|
-
min_width_rem = 2 * button_size_rem + gap_size_rem
|
|
441
|
-
else:
|
|
442
|
-
# 5 buttons + 4 gaps (faces or stars)
|
|
443
|
-
min_width_rem = 5 * button_size_rem + 4 * gap_size_rem
|
|
444
|
-
|
|
445
|
-
# Convert rem to pixels based on base font size, add 10% buffer
|
|
446
|
-
min_width_threshold = int(min_width_rem * base_font_size * 1.1)
|
|
447
|
-
|
|
448
|
-
if isinstance(width, int) and width < min_width_threshold:
|
|
449
|
-
width = "content"
|
|
450
|
-
|
|
451
|
-
_default: list[int] | None = (
|
|
452
|
-
[options_indices[default]] if default is not None else None
|
|
453
|
-
)
|
|
454
|
-
serde = _SingleSelectSerde[int](options_indices, default_value=_default)
|
|
455
|
-
|
|
456
|
-
selection_visualization = ButtonGroupProto.SelectionVisualization.ONLY_SELECTED
|
|
457
|
-
if options == "stars":
|
|
458
|
-
selection_visualization = (
|
|
459
|
-
ButtonGroupProto.SelectionVisualization.ALL_UP_TO_SELECTED
|
|
460
|
-
)
|
|
461
|
-
|
|
462
|
-
sentiment = self._button_group(
|
|
463
|
-
transformed_options,
|
|
464
|
-
default=_default,
|
|
465
|
-
key=key,
|
|
466
|
-
selection_mode="single",
|
|
467
|
-
disabled=disabled,
|
|
468
|
-
deserializer=serde.deserialize,
|
|
469
|
-
serializer=serde.serialize,
|
|
470
|
-
on_change=on_change,
|
|
471
|
-
args=args,
|
|
472
|
-
kwargs=kwargs,
|
|
473
|
-
selection_visualization=selection_visualization,
|
|
474
|
-
style="borderless",
|
|
475
|
-
width=width,
|
|
476
|
-
)
|
|
477
|
-
return sentiment.value
|
|
478
|
-
|
|
479
217
|
@overload
|
|
480
218
|
def pills(
|
|
481
219
|
self,
|
|
@@ -1023,18 +761,13 @@ class ButtonGroupMixin:
|
|
|
1023
761
|
default: list[int] | None = None,
|
|
1024
762
|
selection_mode: SelectionMode = "single",
|
|
1025
763
|
disabled: bool = False,
|
|
1026
|
-
style: Literal[
|
|
1027
|
-
"borderless", "pills", "segmented_control"
|
|
1028
|
-
] = "segmented_control",
|
|
764
|
+
style: Literal["pills", "segmented_control"] = "segmented_control",
|
|
1029
765
|
format_func: Callable[[V], ButtonGroupProto.Option] | None = None,
|
|
1030
766
|
deserializer: WidgetDeserializer[T],
|
|
1031
767
|
serializer: WidgetSerializer[T],
|
|
1032
768
|
on_change: WidgetCallback | None = None,
|
|
1033
769
|
args: WidgetArgs | None = None,
|
|
1034
770
|
kwargs: WidgetKwargs | None = None,
|
|
1035
|
-
selection_visualization: ButtonGroupProto.SelectionVisualization.ValueType = (
|
|
1036
|
-
ButtonGroupProto.SelectionVisualization.ONLY_SELECTED
|
|
1037
|
-
),
|
|
1038
771
|
label: str | None = None,
|
|
1039
772
|
label_visibility: LabelVisibility = "visible",
|
|
1040
773
|
help: str | None = None,
|
|
@@ -1062,9 +795,9 @@ class ButtonGroupMixin:
|
|
|
1062
795
|
"`selection_mode='single'`."
|
|
1063
796
|
)
|
|
1064
797
|
|
|
1065
|
-
if style not in {"
|
|
798
|
+
if style not in {"pills", "segmented_control"}:
|
|
1066
799
|
raise StreamlitAPIException(
|
|
1067
|
-
"The style argument must be one of ['
|
|
800
|
+
"The style argument must be one of ['pills', 'segmented_control']. "
|
|
1068
801
|
f"The argument passed was '{style}'."
|
|
1069
802
|
)
|
|
1070
803
|
|
|
@@ -1091,11 +824,9 @@ class ButtonGroupMixin:
|
|
|
1091
824
|
)
|
|
1092
825
|
|
|
1093
826
|
element_id = compute_and_register_element_id(
|
|
1094
|
-
|
|
1095
|
-
# "feedback" in errors
|
|
1096
|
-
"feedback" if style == "borderless" else style,
|
|
827
|
+
style,
|
|
1097
828
|
user_key=key,
|
|
1098
|
-
# Treat the provided key as the main identity for segmented_control
|
|
829
|
+
# Treat the provided key as the main identity for segmented_control and pills,
|
|
1099
830
|
# and only include kwargs that can invalidate the current selection.
|
|
1100
831
|
# We whitelist the formatted options and the click mode (single vs multi).
|
|
1101
832
|
key_as_main_identity={"options", "click_mode"},
|
|
@@ -1116,7 +847,6 @@ class ButtonGroupMixin:
|
|
|
1116
847
|
disabled,
|
|
1117
848
|
form_id,
|
|
1118
849
|
click_mode=parsed_selection_mode,
|
|
1119
|
-
selection_visualization=selection_visualization,
|
|
1120
850
|
style=style,
|
|
1121
851
|
label=label,
|
|
1122
852
|
label_visibility=label_visibility,
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2026)
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import (
|
|
18
|
+
TYPE_CHECKING,
|
|
19
|
+
Final,
|
|
20
|
+
Literal,
|
|
21
|
+
cast,
|
|
22
|
+
overload,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from streamlit.elements.lib.form_utils import current_form_id
|
|
26
|
+
from streamlit.elements.lib.layout_utils import (
|
|
27
|
+
LayoutConfig,
|
|
28
|
+
Width,
|
|
29
|
+
validate_width,
|
|
30
|
+
)
|
|
31
|
+
from streamlit.elements.lib.policies import check_widget_policies
|
|
32
|
+
from streamlit.elements.lib.utils import (
|
|
33
|
+
Key,
|
|
34
|
+
compute_and_register_element_id,
|
|
35
|
+
save_for_app_testing,
|
|
36
|
+
to_key,
|
|
37
|
+
)
|
|
38
|
+
from streamlit.errors import StreamlitAPIException
|
|
39
|
+
from streamlit.proto.Feedback_pb2 import Feedback as FeedbackProto
|
|
40
|
+
from streamlit.runtime.metrics_util import gather_metrics
|
|
41
|
+
from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
|
|
42
|
+
from streamlit.runtime.state import register_widget
|
|
43
|
+
|
|
44
|
+
if TYPE_CHECKING:
|
|
45
|
+
from streamlit.delta_generator import DeltaGenerator
|
|
46
|
+
from streamlit.runtime.state import (
|
|
47
|
+
WidgetArgs,
|
|
48
|
+
WidgetCallback,
|
|
49
|
+
WidgetKwargs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Number of options for each feedback type
|
|
54
|
+
_NUM_THUMBS_OPTIONS: Final = 2
|
|
55
|
+
_NUM_FACES_OPTIONS: Final = 5
|
|
56
|
+
_NUM_STARS_OPTIONS: Final = 5
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _get_num_options(feedback_type: Literal["thumbs", "faces", "stars"]) -> int:
|
|
60
|
+
"""Get the number of options for the given feedback type."""
|
|
61
|
+
if feedback_type == "thumbs":
|
|
62
|
+
return _NUM_THUMBS_OPTIONS
|
|
63
|
+
if feedback_type == "faces":
|
|
64
|
+
return _NUM_FACES_OPTIONS
|
|
65
|
+
return _NUM_STARS_OPTIONS
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _feedback_type_to_proto(
|
|
69
|
+
feedback_type: Literal["thumbs", "faces", "stars"],
|
|
70
|
+
) -> FeedbackProto.FeedbackType.ValueType:
|
|
71
|
+
"""Convert a feedback type string to the proto enum value."""
|
|
72
|
+
if feedback_type == "thumbs":
|
|
73
|
+
return FeedbackProto.FeedbackType.THUMBS
|
|
74
|
+
if feedback_type == "faces":
|
|
75
|
+
return FeedbackProto.FeedbackType.FACES
|
|
76
|
+
return FeedbackProto.FeedbackType.STARS
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FeedbackSerde:
|
|
80
|
+
"""Serializer/deserializer for feedback widget values.
|
|
81
|
+
|
|
82
|
+
Uses string as the wire format to distinguish three states:
|
|
83
|
+
- None (field not set): No UI interaction yet -> use default_value
|
|
84
|
+
- "" (empty string): User explicitly cleared -> return None
|
|
85
|
+
- "2" (string with value): User selected -> return int value
|
|
86
|
+
|
|
87
|
+
This allows clearing to work correctly even when a default is set.
|
|
88
|
+
The session state and return values are always int | None.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, default_value: int | None = None):
|
|
92
|
+
self.default_value = default_value
|
|
93
|
+
|
|
94
|
+
def serialize(self, value: int | None) -> str:
|
|
95
|
+
"""Serialize int value to string for wire format."""
|
|
96
|
+
return "" if value is None else str(value)
|
|
97
|
+
|
|
98
|
+
def deserialize(self, ui_value: str | None) -> int | None:
|
|
99
|
+
"""Deserialize string wire format back to int value."""
|
|
100
|
+
if ui_value is None:
|
|
101
|
+
return self.default_value # No UI interaction yet
|
|
102
|
+
if ui_value == "":
|
|
103
|
+
return None # User explicitly cleared
|
|
104
|
+
return int(ui_value) # User selected a value
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class FeedbackMixin:
|
|
108
|
+
@overload
|
|
109
|
+
def feedback(
|
|
110
|
+
self,
|
|
111
|
+
options: Literal["thumbs"] = ...,
|
|
112
|
+
*,
|
|
113
|
+
key: Key | None = None,
|
|
114
|
+
default: int | None = None,
|
|
115
|
+
disabled: bool = False,
|
|
116
|
+
on_change: WidgetCallback | None = None,
|
|
117
|
+
args: WidgetArgs | None = None,
|
|
118
|
+
kwargs: WidgetKwargs | None = None,
|
|
119
|
+
width: Width = "content",
|
|
120
|
+
) -> Literal[0, 1] | None: ...
|
|
121
|
+
|
|
122
|
+
@overload
|
|
123
|
+
def feedback(
|
|
124
|
+
self,
|
|
125
|
+
options: Literal["faces", "stars"] = ...,
|
|
126
|
+
*,
|
|
127
|
+
key: Key | None = None,
|
|
128
|
+
default: int | None = None,
|
|
129
|
+
disabled: bool = False,
|
|
130
|
+
on_change: WidgetCallback | None = None,
|
|
131
|
+
args: WidgetArgs | None = None,
|
|
132
|
+
kwargs: WidgetKwargs | None = None,
|
|
133
|
+
width: Width = "content",
|
|
134
|
+
) -> Literal[0, 1, 2, 3, 4] | None: ...
|
|
135
|
+
|
|
136
|
+
@gather_metrics("feedback")
|
|
137
|
+
def feedback(
|
|
138
|
+
self,
|
|
139
|
+
options: Literal["thumbs", "faces", "stars"] = "thumbs",
|
|
140
|
+
*,
|
|
141
|
+
key: Key | None = None,
|
|
142
|
+
default: int | None = None,
|
|
143
|
+
disabled: bool = False,
|
|
144
|
+
on_change: WidgetCallback | None = None,
|
|
145
|
+
args: WidgetArgs | None = None,
|
|
146
|
+
kwargs: WidgetKwargs | None = None,
|
|
147
|
+
width: Width = "content",
|
|
148
|
+
) -> int | None:
|
|
149
|
+
"""Display a feedback widget.
|
|
150
|
+
|
|
151
|
+
A feedback widget is an icon-based button group available in three
|
|
152
|
+
styles, as described in ``options``. It is commonly used in chat and AI
|
|
153
|
+
apps to allow users to rate responses.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
options : "thumbs", "faces", or "stars"
|
|
158
|
+
The feedback options displayed to the user. ``options`` can be one
|
|
159
|
+
of the following:
|
|
160
|
+
|
|
161
|
+
- ``"thumbs"`` (default): Streamlit displays a thumb-up and
|
|
162
|
+
thumb-down button group.
|
|
163
|
+
- ``"faces"``: Streamlit displays a row of five buttons with
|
|
164
|
+
facial expressions depicting increasing satisfaction from left to
|
|
165
|
+
right.
|
|
166
|
+
- ``"stars"``: Streamlit displays a row of star icons, allowing the
|
|
167
|
+
user to select a rating from one to five stars.
|
|
168
|
+
|
|
169
|
+
key : str or int
|
|
170
|
+
An optional string or integer to use as the unique key for the widget.
|
|
171
|
+
If this is omitted, a key will be generated for the widget
|
|
172
|
+
based on its content. No two widgets may have the same key.
|
|
173
|
+
|
|
174
|
+
default : int or None
|
|
175
|
+
Default feedback value. This must be consistent with the feedback
|
|
176
|
+
type in ``options``:
|
|
177
|
+
|
|
178
|
+
- 0 or 1 if ``options="thumbs"``.
|
|
179
|
+
- Between 0 and 4, inclusive, if ``options="faces"`` or
|
|
180
|
+
``options="stars"``.
|
|
181
|
+
|
|
182
|
+
disabled : bool
|
|
183
|
+
An optional boolean that disables the feedback widget if set
|
|
184
|
+
to ``True``. The default is ``False``.
|
|
185
|
+
|
|
186
|
+
on_change : callable
|
|
187
|
+
An optional callback invoked when this feedback widget's value
|
|
188
|
+
changes.
|
|
189
|
+
|
|
190
|
+
args : list or tuple
|
|
191
|
+
An optional list or tuple of args to pass to the callback.
|
|
192
|
+
|
|
193
|
+
kwargs : dict
|
|
194
|
+
An optional dict of kwargs to pass to the callback.
|
|
195
|
+
|
|
196
|
+
width : "content", "stretch", or int
|
|
197
|
+
The width of the feedback widget. This can be one of the following:
|
|
198
|
+
|
|
199
|
+
- ``"content"`` (default): The width of the widget matches the
|
|
200
|
+
width of its content, but doesn't exceed the width of the parent
|
|
201
|
+
container.
|
|
202
|
+
- ``"stretch"``: The width of the widget matches the width of the
|
|
203
|
+
parent container.
|
|
204
|
+
- An integer specifying the width in pixels: The widget has a
|
|
205
|
+
fixed width. If the specified width is greater than the width of
|
|
206
|
+
the parent container, the width of the widget matches the width
|
|
207
|
+
of the parent container.
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
-------
|
|
211
|
+
int or None
|
|
212
|
+
An integer indicating the user's selection, where ``0`` is the
|
|
213
|
+
lowest feedback. Higher values indicate more positive feedback.
|
|
214
|
+
If no option was selected, the widget returns ``None``.
|
|
215
|
+
|
|
216
|
+
- For ``options="thumbs"``, a return value of ``0`` indicates
|
|
217
|
+
thumbs-down, and ``1`` indicates thumbs-up.
|
|
218
|
+
- For ``options="faces"`` and ``options="stars"``, return values
|
|
219
|
+
range from ``0`` (least satisfied) to ``4`` (most satisfied).
|
|
220
|
+
|
|
221
|
+
Examples
|
|
222
|
+
--------
|
|
223
|
+
Display a feedback widget with stars, and show the selected sentiment:
|
|
224
|
+
|
|
225
|
+
>>> import streamlit as st
|
|
226
|
+
>>>
|
|
227
|
+
>>> sentiment_mapping = ["one", "two", "three", "four", "five"]
|
|
228
|
+
>>> selected = st.feedback("stars")
|
|
229
|
+
>>> if selected is not None:
|
|
230
|
+
>>> st.markdown(f"You selected {sentiment_mapping[selected]} star(s).")
|
|
231
|
+
|
|
232
|
+
.. output::
|
|
233
|
+
https://doc-feedback-stars.streamlit.app/
|
|
234
|
+
height: 200px
|
|
235
|
+
|
|
236
|
+
Display a feedback widget with thumbs, and show the selected sentiment:
|
|
237
|
+
|
|
238
|
+
>>> import streamlit as st
|
|
239
|
+
>>>
|
|
240
|
+
>>> sentiment_mapping = [":material/thumb_down:", ":material/thumb_up:"]
|
|
241
|
+
>>> selected = st.feedback("thumbs")
|
|
242
|
+
>>> if selected is not None:
|
|
243
|
+
>>> st.markdown(f"You selected: {sentiment_mapping[selected]}")
|
|
244
|
+
|
|
245
|
+
.. output::
|
|
246
|
+
https://doc-feedback-thumbs.streamlit.app/
|
|
247
|
+
height: 200px
|
|
248
|
+
|
|
249
|
+
"""
|
|
250
|
+
if options not in {"thumbs", "faces", "stars"}:
|
|
251
|
+
raise StreamlitAPIException(
|
|
252
|
+
"The options argument to st.feedback must be one of "
|
|
253
|
+
"['thumbs', 'faces', 'stars']. "
|
|
254
|
+
f"The argument passed was '{options}'."
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
num_options = _get_num_options(options)
|
|
258
|
+
|
|
259
|
+
if default is not None and (default < 0 or default >= num_options):
|
|
260
|
+
raise StreamlitAPIException(
|
|
261
|
+
f"The default value in '{options}' must be a number between 0 and {num_options - 1}."
|
|
262
|
+
f" The passed default value is {default}"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
key = to_key(key)
|
|
266
|
+
validate_width(width, allow_content=True)
|
|
267
|
+
layout_config = LayoutConfig(width=width)
|
|
268
|
+
|
|
269
|
+
check_widget_policies(self.dg, key, on_change, default_value=default)
|
|
270
|
+
|
|
271
|
+
ctx = get_script_run_ctx()
|
|
272
|
+
form_id = current_form_id(self.dg)
|
|
273
|
+
|
|
274
|
+
element_id = compute_and_register_element_id(
|
|
275
|
+
"feedback",
|
|
276
|
+
user_key=key,
|
|
277
|
+
key_as_main_identity={"options"},
|
|
278
|
+
dg=self.dg,
|
|
279
|
+
options=options,
|
|
280
|
+
default=default,
|
|
281
|
+
width=width,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
# Build the proto
|
|
285
|
+
proto = FeedbackProto()
|
|
286
|
+
proto.id = element_id
|
|
287
|
+
proto.type = _feedback_type_to_proto(options)
|
|
288
|
+
proto.disabled = disabled
|
|
289
|
+
proto.form_id = form_id
|
|
290
|
+
|
|
291
|
+
if default is not None:
|
|
292
|
+
proto.default = default
|
|
293
|
+
|
|
294
|
+
serde = FeedbackSerde(default_value=default)
|
|
295
|
+
|
|
296
|
+
widget_state = register_widget(
|
|
297
|
+
proto.id,
|
|
298
|
+
on_change_handler=on_change,
|
|
299
|
+
args=args,
|
|
300
|
+
kwargs=kwargs,
|
|
301
|
+
deserializer=serde.deserialize,
|
|
302
|
+
serializer=serde.serialize,
|
|
303
|
+
ctx=ctx,
|
|
304
|
+
value_type="string_value",
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
if widget_state.value_changed:
|
|
308
|
+
if widget_state.value is not None:
|
|
309
|
+
proto.value = widget_state.value
|
|
310
|
+
proto.set_value = True
|
|
311
|
+
|
|
312
|
+
if ctx:
|
|
313
|
+
save_for_app_testing(ctx, element_id, None)
|
|
314
|
+
|
|
315
|
+
self.dg._enqueue("feedback", proto, layout_config=layout_config)
|
|
316
|
+
|
|
317
|
+
return widget_state.value
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def dg(self) -> DeltaGenerator:
|
|
321
|
+
"""Get our DeltaGenerator."""
|
|
322
|
+
return cast("DeltaGenerator", self)
|
|
@@ -296,7 +296,8 @@ class NumberInputMixin:
|
|
|
296
296
|
<https://github.com/alexei/sprintf.js?tab=readme-ov-file#format-specification>`_.
|
|
297
297
|
|
|
298
298
|
For example, ``format="%0.1f"`` adjusts the displayed decimal
|
|
299
|
-
precision to only show one digit after the decimal.
|
|
299
|
+
precision to only show one digit after the decimal. Use ``,`` for
|
|
300
|
+
thousand separators (e.g. ``"%,d"`` yields ``"1,234"``).
|
|
300
301
|
|
|
301
302
|
key : str or int
|
|
302
303
|
An optional string or integer to use as the unique key for the widget.
|