Yehor Smoliakov commited on
Commit
bcaad24
·
1 Parent(s): 265c245
.gitattributes CHANGED
@@ -1,35 +1,6 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ sample_1.wav filter=lfs diff=lfs merge=lfs -text
2
+ sample_2.wav filter=lfs diff=lfs merge=lfs -text
3
+ sample_3.wav filter=lfs diff=lfs merge=lfs -text
4
+ sample_4.wav filter=lfs diff=lfs merge=lfs -text
5
+ sample_5.wav filter=lfs diff=lfs merge=lfs -text
6
+ sample_6.wav filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .idea/
2
+ .venv/
3
+ .ruff_cache/
4
+
5
+ flagged/
README.md CHANGED
@@ -1,7 +1,7 @@
1
  ---
2
- title: St Hubert Uk Demo
3
- emoji: 🌍
4
- colorFrom: pink
5
  colorTo: gray
6
  sdk: streamlit
7
  sdk_version: 1.37.1
@@ -10,4 +10,21 @@ pinned: false
10
  license: mit
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Streamlit: Speech-to-Text for Ukrainian (HuBERT)
3
+ emoji: 🎙️
4
+ colorFrom: blue
5
  colorTo: gray
6
  sdk: streamlit
7
  sdk_version: 1.37.1
 
10
  license: mit
11
  ---
12
 
13
+ ## Install
14
+
15
+ ```shell
16
+ uv venv --python 3.12
17
+
18
+ source .venv/bin/activate
19
+
20
+ uv pip install -r requirements.txt
21
+
22
+ # in development mode
23
+ uv pip install -r requirements-dev.txt
24
+ ```
25
+
26
+ ## Run
27
+
28
+ ```shell
29
+ python app.py
30
+ ```
app.py ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys
2
+ import time
3
+
4
+ from importlib.metadata import version
5
+
6
+ from os import remove
7
+ from os.path import exists
8
+
9
+ import numpy as np
10
+
11
+ import torch
12
+ import torchaudio
13
+ import torchaudio.transforms as T
14
+
15
+ import streamlit as st
16
+
17
+ from streamlit.runtime.uploaded_file_manager import UploadedFile
18
+ from transformers import HubertForCTC, Wav2Vec2Processor
19
+
20
+
21
+ # Config
22
+ model_name = "Yehor/hubert-uk"
23
+
24
+ torchaudio_backend = "soundfile"
25
+
26
+ min_duration = 0.5
27
+ max_duration = 60
28
+
29
+ concurrency_limit = 5
30
+ use_torch_compile = False
31
+
32
+ # Torch
33
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
34
+ torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
35
+
36
+ # Load the model
37
+ asr_model = HubertForCTC.from_pretrained(
38
+ model_name, torch_dtype=torch_dtype, device_map=device
39
+ )
40
+ processor = Wav2Vec2Processor.from_pretrained(model_name)
41
+
42
+ if use_torch_compile:
43
+ asr_model = torch.compile(asr_model)
44
+
45
+ # Elements
46
+ examples = [
47
+ "example_1.wav",
48
+ "example_2.wav",
49
+ "example_3.wav",
50
+ "example_4.wav",
51
+ "example_5.wav",
52
+ "example_6.wav",
53
+ ]
54
+
55
+ examples_table = """
56
+ | File | Text |
57
+ | ------------- | ------------- |
58
+ | `example_1.wav` | тема про яку не люблять говорити офіційні джерела у генштабі і міноборони це хімічна зброя окупанти вже тривалий час використовують хімічну зброю заборонену |
59
+ | `example_2.wav` | всіма конвенціями якщо спочатку це були гранати з дронів то тепер фіксують випадки застосування |
60
+ | `example_3.wav` | хімічних снарядів причому склад отруйної речовони різний а отже й наслідки для наших військових теж різні |
61
+ | `example_4.wav` | використовує на фронті все що має і хімічна зброя не вийняток тож з чим маємо справу розбиралася марія моганисян |
62
+ | `example_5.wav` | двох тисяч випадків застосування росіянами боєприпасів споряджених небезпечними хімічними речовинами |
63
+ | `example_6.wav` | на всі писані норми марія моганисян олександр моторний спецкор марафон єдині новини |
64
+ """.strip()
65
+
66
+ authors_table = """
67
+ ## Authors
68
+
69
+ Follow them in social networks and **contact** if you need any help or have any questions:
70
+
71
+ | <img src="https://avatars.githubusercontent.com/u/7875085?v=4" width="100"> <br> **Yehor Smoliakov** |
72
+ |------------------------------------------------------------------------------------------------------|
73
+ | https://t.me/smlkw in Telegram |
74
+ | https://x.com/yehor_smoliakov at X |
75
+ | https://github.com/egorsmkv at GitHub |
76
+ | https://huggingface.co/Yehor at Hugging Face |
77
+ | or use [email protected] |
78
+ """.strip()
79
+
80
+ description_head = f"""
81
+ ## Overview
82
+
83
+ This space uses https://huggingface.co/Yehor/hubert-uk model to recognize audio files.
84
+
85
+ > Due to resource limitations, audio duration **must not** exceed **{max_duration}** seconds.
86
+ """.strip()
87
+
88
+ description_foot = f"""
89
+ ## Community
90
+
91
+ - **Discord**: https://discord.gg/yVAjkBgmt4
92
+ - Speech Recognition: https://t.me/speech_recognition_uk
93
+ - Speech Synthesis: https://t.me/speech_synthesis_uk
94
+
95
+ ## More
96
+
97
+ Check out other ASR models: https://github.com/egorsmkv/speech-recognition-uk
98
+
99
+ {authors_table}
100
+ """.strip()
101
+
102
+ transcription_value = """
103
+ Recognized text will appear here.
104
+
105
+ Choose **an example file** below the Recognize button, upload **your audio file**, or use **the microphone** to record own voice.
106
+ """.strip()
107
+
108
+ tech_env = f"""
109
+ #### Environment
110
+
111
+ - Python: {sys.version}
112
+ - Torch device: {device}
113
+ - Torch dtype: {torch_dtype}
114
+ - Use torch.compile: {use_torch_compile}
115
+ """.strip()
116
+
117
+ tech_libraries = f"""
118
+ #### Libraries
119
+
120
+ - torch: {version('torch')}
121
+ - torchaudio: {version('torchaudio')}
122
+ - transformers: {version('transformers')}
123
+ - accelerate: {version('accelerate')}
124
+ - streamlit: {version('streamlit')}
125
+ """.strip()
126
+
127
+
128
+ # UploadedFile
129
+ def inference(uploaded_file: UploadedFile):
130
+ audio_path = uploaded_file.file_id + '.wav'
131
+
132
+ with open(audio_path, 'wb') as f:
133
+ f.write(uploaded_file.getvalue())
134
+
135
+ if not audio_path:
136
+ st.error("Please upload an audio file.")
137
+ return
138
+
139
+ st.info("Starting recognition")
140
+
141
+ meta = torchaudio.info(audio_path, backend=torchaudio_backend)
142
+ duration = meta.num_frames / meta.sample_rate
143
+
144
+ if duration < min_duration:
145
+ st.error(
146
+ f"The duration of the file is less than {min_duration} seconds, it is {round(duration, 2)} seconds."
147
+ )
148
+ return
149
+ if duration > max_duration:
150
+ st.error(f"The duration of the file exceeds {max_duration} seconds.")
151
+ return
152
+
153
+ paths = [
154
+ audio_path,
155
+ ]
156
+
157
+ results = []
158
+
159
+ for path in paths:
160
+ t0 = time.time()
161
+
162
+ meta = torchaudio.info(audio_path, backend=torchaudio_backend)
163
+ audio_duration = meta.num_frames / meta.sample_rate
164
+
165
+ audio_input, sr = torchaudio.load(path, backend=torchaudio_backend)
166
+
167
+ if meta.num_channels > 1:
168
+ audio_input = torch.mean(audio_input, dim=0, keepdim=True)
169
+
170
+ if meta.sample_rate != 16_000:
171
+ resampler = T.Resample(sr, 16_000, dtype=audio_input.dtype)
172
+ audio_input = resampler(audio_input)
173
+
174
+ audio_input = audio_input.squeeze(0).numpy()
175
+
176
+ inputs = processor(
177
+ [audio_input], sampling_rate=16_000, padding=True
178
+ ).input_values
179
+ features = torch.tensor(np.array(inputs), dtype=torch_dtype).to(device)
180
+
181
+ with torch.inference_mode():
182
+ logits = asr_model(features).logits
183
+
184
+ predicted_ids = torch.argmax(logits, dim=-1)
185
+ predictions = processor.batch_decode(predicted_ids)
186
+
187
+ if not predictions:
188
+ predictions = "-"
189
+
190
+ elapsed_time = round(time.time() - t0, 2)
191
+ rtf = round(elapsed_time / audio_duration, 4)
192
+ audio_duration = round(audio_duration, 2)
193
+
194
+ results.append(
195
+ {
196
+ "path": path.split("/")[-1],
197
+ "transcription": "\n".join(predictions),
198
+ "audio_duration": audio_duration,
199
+ "rtf": rtf,
200
+ }
201
+ )
202
+
203
+ st.info("Finished!")
204
+
205
+ result_texts = []
206
+
207
+ for result in results:
208
+ result_texts.append(f'**{result["path"]}**')
209
+ result_texts.append("\n\n")
210
+ result_texts.append(f'> {result["transcription"]}')
211
+ result_texts.append("\n\n")
212
+ result_texts.append(f'**Audio duration**: {result["audio_duration"]}')
213
+ result_texts.append("\n")
214
+ result_texts.append(f'**Real-Time Factor**: {result["rtf"]}')
215
+
216
+ if exists(audio_path):
217
+ remove(audio_path)
218
+
219
+ return "\n".join(result_texts)
220
+
221
+
222
+ st.title("Speech-to-Text for Ukrainian using HuBERT")
223
+ st.markdown(description_head)
224
+
225
+ st.markdown("## Usage")
226
+
227
+ audio_file = st.file_uploader("Upload an audio file", type=["wav"])
228
+
229
+ if st.button("Recognize"):
230
+ if audio_file is not None:
231
+ transcription = inference(audio_file)
232
+ st.markdown(transcription)
233
+ else:
234
+ st.error("Please upload an audio file.")
235
+
236
+ st.markdown("### Examples")
237
+ st.markdown(examples_table)
238
+
239
+ st.markdown(description_foot, unsafe_allow_html=True)
240
+
241
+ st.markdown("### Environment")
242
+ st.markdown(tech_env)
243
+ st.markdown(tech_libraries)
example_1.wav ADDED
Binary file (273 kB). View file
 
example_2.wav ADDED
Binary file (200 kB). View file
 
example_3.wav ADDED
Binary file (193 kB). View file
 
example_4.wav ADDED
Binary file (241 kB). View file
 
example_5.wav ADDED
Binary file (193 kB). View file
 
example_6.wav ADDED
Binary file (186 kB). View file
 
requirements-dev.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ruff
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+
3
+ torch
4
+ torchaudio
5
+
6
+ soundfile
7
+
8
+ setuptools
9
+
10
+ transformers
11
+ accelerate
streamlit_config/config.toml ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [global]
2
+
3
+ # By default, Streamlit displays a warning when a user sets both a widget
4
+ # default value in the function defining the widget and a widget value via
5
+ # the widget's key in `st.session_state`.
6
+
7
+ # If you'd like to turn off this warning, set this to True.
8
+
9
+ # Default: false
10
+ # disableWidgetStateDuplicationWarning = false
11
+
12
+ # If True, will show a warning when you run a Streamlit-enabled script
13
+ # via "python my_script.py".
14
+
15
+ # Default: true
16
+ # showWarningOnDirectExecution = true
17
+
18
+
19
+ [logger]
20
+
21
+ # Level of logging: 'error', 'warning', 'info', or 'debug'.
22
+
23
+ # Default: 'info'
24
+ level = "error"
25
+
26
+ # String format for logging messages. If logger.datetimeFormat is set,
27
+ # logger messages will default to `%(asctime)s.%(msecs)03d %(message)s`. See
28
+ # [Python's documentation](https://docs.python.org/2.6/library/logging.html#formatter-objects)
29
+ # for available attributes.
30
+
31
+ # Default: "%(asctime)s %(message)s"
32
+ # messageFormat = "%(asctime)s %(message)s"
33
+
34
+
35
+ [client]
36
+
37
+ # Controls whether uncaught app exceptions and deprecation warnings
38
+ # are displayed in the browser. By default, this is set to True and
39
+ # Streamlit displays app exceptions and associated tracebacks, and
40
+ # deprecation warnings, in the browser.
41
+
42
+ # If set to False, deprecation warnings and full exception messages
43
+ # will print to the console only. Exceptions will still display in the
44
+ # browser with a generic error message. For now, the exception type and
45
+ # traceback show in the browser also, but they will be removed in the
46
+ # future.
47
+
48
+ # Default: true
49
+ # showErrorDetails = true
50
+
51
+ # Change the visibility of items in the toolbar, options menu,
52
+ # and settings dialog (top right of the app).
53
+
54
+ # Allowed values:
55
+ # * "auto" : Show the developer options if the app is accessed through
56
+ # localhost or through Streamlit Community Cloud as a developer.
57
+ # Hide them otherwise.
58
+ # * "developer" : Show the developer options.
59
+ # * "viewer" : Hide the developer options.
60
+ # * "minimal" : Show only options set externally (e.g. through
61
+ # Streamlit Community Cloud) or through st.set_page_config.
62
+ # If there are no options left, hide the menu.
63
+
64
+ # Default: "auto"
65
+ # toolbarMode = "auto"
66
+
67
+ # Controls whether to display the default sidebar page navigation in a
68
+ # multi-page app. This only applies when app's pages are defined by the
69
+ # `pages/` directory.
70
+
71
+ # Default: true
72
+ # showSidebarNavigation = true
73
+
74
+
75
+ [runner]
76
+
77
+ # Allows you to type a variable or string by itself in a single line of
78
+ # Python code to write it to the app.
79
+
80
+ # Default: true
81
+ # magicEnabled = true
82
+
83
+ # Handle script rerun requests immediately, rather than waiting for script
84
+ # execution to reach a yield point. This makes Streamlit much more
85
+ # responsive to user interaction, but it can lead to race conditions in
86
+ # apps that mutate session_state data outside of explicit session_state
87
+ # assignment statements.
88
+
89
+ # Default: true
90
+ fastReruns = false
91
+
92
+ # Raise an exception after adding unserializable data to Session State.
93
+ # Some execution environments may require serializing all data in Session
94
+ # State, so it may be useful to detect incompatibility during development,
95
+ # or when the execution environment will stop supporting it in the future.
96
+
97
+ # Default: false
98
+ # enforceSerializableSessionState = false
99
+
100
+ # Adjust how certain 'options' widgets like radio, selectbox, and
101
+ # multiselect coerce Enum members when the Enum class gets
102
+ # re-defined during a script re-run.
103
+
104
+ # Allowed values:
105
+ # * "off": Disables Enum coercion.
106
+ # * "nameOnly": Enum classes can be coerced if their member names match.
107
+ # * "nameAndValue": Enum classes can be coerced if their member names AND
108
+ # member values match.
109
+
110
+ # Default: "nameOnly"
111
+ # enumCoercion = "nameOnly"
112
+
113
+
114
+ [server]
115
+
116
+ # List of folders that should not be watched for changes.
117
+
118
+ # Relative paths will be taken as relative to the current working directory.
119
+
120
+ # Example: ['/home/user1/env', 'relative/path/to/folder']
121
+
122
+ # Default: []
123
+ # folderWatchBlacklist = []
124
+
125
+ # Change the type of file watcher used by Streamlit, or turn it off
126
+ # completely.
127
+
128
+ # Allowed values:
129
+ # * "auto" : Streamlit will attempt to use the watchdog module, and
130
+ # falls back to polling if watchdog is not available.
131
+ # * "watchdog" : Force Streamlit to use the watchdog module.
132
+ # * "poll" : Force Streamlit to always use polling.
133
+ # * "none" : Streamlit will not watch files.
134
+
135
+ # Default: "auto"
136
+ # fileWatcherType = "auto"
137
+
138
+ # Symmetric key used to produce signed cookies. If deploying on multiple replicas, this should
139
+ # be set to the same value across all replicas to ensure they all share the same secret.
140
+
141
+ # Default: randomly generated secret key.
142
+ # cookieSecret = "2efe79ee95dc08b35058032186268c9b1147069c04dc332bad9048e3284c6934"
143
+
144
+ # If false, will attempt to open a browser window on start.
145
+
146
+ # Default: false unless (1) we are on a Linux box where DISPLAY is unset, or
147
+ # (2) we are running in the Streamlit Atom plugin.
148
+ # headless = false
149
+
150
+ # Automatically rerun script when the file is modified on disk.
151
+
152
+ # Default: false
153
+ # runOnSave = false
154
+
155
+ # The address where the server will listen for client and browser
156
+ # connections. Use this if you want to bind the server to a specific address.
157
+ # If set, the server will only be accessible from this address, and not from
158
+ # any aliases (like localhost).
159
+
160
+ # Default: (unset)
161
+ # address =
162
+
163
+ # The port where the server will listen for browser connections.
164
+
165
+ # Don't use port 3000 which is reserved for internal development.
166
+
167
+ # Default: 8501
168
+ # port = 8501
169
+
170
+ # The base path for the URL where Streamlit should be served from.
171
+
172
+ # Default: ""
173
+ # baseUrlPath = ""
174
+
175
+ # Enables support for Cross-Origin Resource Sharing (CORS) protection, for added security.
176
+
177
+ # Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and
178
+ # `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
179
+
180
+ # Default: true
181
+ # enableCORS = true
182
+
183
+ # Enables support for Cross-Site Request Forgery (XSRF) protection, for added security.
184
+
185
+ # Due to conflicts between CORS and XSRF, if `server.enableXsrfProtection` is on and
186
+ # `server.enableCORS` is off at the same time, we will prioritize `server.enableXsrfProtection`.
187
+
188
+ # Default: true
189
+ # enableXsrfProtection = true
190
+
191
+ # Max size, in megabytes, for files uploaded with the file_uploader.
192
+
193
+ # Default: 200
194
+ # maxUploadSize = 200
195
+
196
+ # Max size, in megabytes, of messages that can be sent via the WebSocket connection.
197
+
198
+ # Default: 200
199
+ # maxMessageSize = 200
200
+
201
+ # Enables support for websocket compression.
202
+
203
+ # Default: false
204
+ # enableWebsocketCompression = false
205
+
206
+ # Enable serving files from a `static` directory in the running app's directory.
207
+
208
+ # Default: false
209
+ # enableStaticServing = false
210
+
211
+ # Server certificate file for connecting via HTTPS.
212
+ # Must be set at the same time as "server.sslKeyFile".
213
+
214
+ # ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
215
+ # sslCertFile =
216
+
217
+ # Cryptographic key file for connecting via HTTPS.
218
+ # Must be set at the same time as "server.sslCertFile".
219
+
220
+ # ['DO NOT USE THIS OPTION IN A PRODUCTION ENVIRONMENT. It has not gone through security audits or performance tests. For the production environment, we recommend performing SSL termination by the load balancer or the reverse proxy.']
221
+ # sslKeyFile =
222
+
223
+
224
+ [browser]
225
+
226
+ # Internet address where users should point their browsers in order to
227
+ # connect to the app. Can be IP address or DNS name and path.
228
+
229
+ # This is used to:
230
+ # - Set the correct URL for CORS and XSRF protection purposes.
231
+ # - Show the URL on the terminal
232
+ # - Open the browser
233
+
234
+ # Default: "localhost"
235
+ # serverAddress = "localhost"
236
+
237
+ # Whether to send usage statistics to Streamlit.
238
+
239
+ # Default: true
240
+ # gatherUsageStats = true
241
+
242
+ # Port where users should point their browsers in order to connect to the
243
+ # app.
244
+
245
+ # This is used to:
246
+ # - Set the correct URL for XSRF protection purposes.
247
+ # - Show the URL on the terminal (part of `streamlit run`).
248
+ # - Open the browser automatically (part of `streamlit run`).
249
+
250
+ # This option is for advanced use cases. To change the port of your app, use
251
+ # `server.Port` instead. Don't use port 3000 which is reserved for internal
252
+ # development.
253
+
254
+ # Default: whatever value is set in server.port.
255
+ # serverPort = 8501
256
+
257
+
258
+ [mapbox]
259
+
260
+ # Configure Streamlit to use a custom Mapbox
261
+ # token for elements like st.pydeck_chart and st.map.
262
+ # To get a token for yourself, create an account at
263
+ # https://mapbox.com. It's free (for moderate usage levels)!
264
+
265
+ # Default: ""
266
+ # token = ""
267
+
268
+
269
+ [theme]
270
+
271
+ # The preset Streamlit theme that your custom theme inherits from.
272
+ # One of "light" or "dark".
273
+ # base =
274
+
275
+ # Primary accent color for interactive elements.
276
+ # primaryColor =
277
+
278
+ # Background color for the main content area.
279
+ # backgroundColor =
280
+
281
+ # Background color used for the sidebar and most interactive widgets.
282
+ # secondaryBackgroundColor =
283
+
284
+ # Color used for almost all text.
285
+ # textColor =
286
+
287
+ # Font family for all text in the app, except code blocks. One of "sans serif",
288
+ # "serif", or "monospace".
289
+ # font =
290
+