fsoft-ai-center commited on
Commit
441a978
·
verified ·
1 Parent(s): 403d4a6

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +288 -288
  2. logo.png +2 -2
app.py CHANGED
@@ -1,289 +1,289 @@
1
- import io
2
- import os
3
- import base64
4
- import librosa
5
- import numpy as np
6
- from io import BytesIO
7
- import streamlit as st
8
- from pydub import AudioSegment
9
- import matplotlib.pyplot as plt
10
- from scipy.io.wavfile import write
11
- from src.denoise import denoise
12
- from myrecorder import recorder
13
-
14
-
15
- SR = 16000
16
- CONTAINER_HEIGHT = 345
17
-
18
-
19
- def np_audio_to_bytesio(np_audio, np_audio_sr):
20
- _bytes = bytes()
21
- byte_io = io.BytesIO(_bytes)
22
- write(byte_io, np_audio_sr, np_audio)
23
- bytes_audio = byte_io.read()
24
- return bytes_audio
25
-
26
-
27
- def autoplay_audio(audio: str):
28
- audio_base64 = base64.b64encode(audio).decode('utf-8')
29
- audio_tag = f'<audio autoplay="true" src="data:audio/wav;base64,{audio_base64}">'
30
- st.markdown(audio_tag, unsafe_allow_html=True)
31
-
32
-
33
- def load_noisy_speech(root=os.path.join(os.getcwd(), 'noisy_speech')):
34
- noisy_speech_paths = {'EN':{}, 'JA': {}}
35
- noisy_speech_names = os.listdir(root)
36
- for name in noisy_speech_names:
37
- splt = name.split('_')
38
- lang, snr = splt[0].upper(), int(splt[1][:2])
39
- noisy_speech_paths[lang][snr] = os.path.join(root, name)
40
-
41
- en_keys = list(noisy_speech_paths['EN'].keys())
42
- en_keys.sort()
43
- en_keys.reverse()
44
- noisy_speech_paths['EN'] = {f'{key}dB': noisy_speech_paths['EN'][key] for key in en_keys}
45
-
46
- ja_keys = list(noisy_speech_paths['JA'].keys())
47
- ja_keys.sort()
48
- ja_keys.reverse()
49
- noisy_speech_paths['JA'] = {f'{key}dB': noisy_speech_paths['JA'][key] for key in ja_keys}
50
-
51
- return noisy_speech_paths
52
-
53
-
54
- def load_wav(wav_path):
55
- wav_22k, sr = librosa.load(wav_path)
56
- wav_16k = librosa.resample(wav_22k, orig_sr=sr, target_sr=SR)
57
- return wav_22k, wav_16k
58
-
59
-
60
- def wav_to_spec(wav, sr):
61
- if sr == 16000:
62
- wav = librosa.resample(wav, orig_sr=sr, target_sr=22050)
63
- spec = np.abs(librosa.stft(wav))
64
- spec = librosa.amplitude_to_db(spec, ref=np.max)
65
- return spec
66
-
67
-
68
- def export_spec_to_buffer(spec):
69
- plt.clf()
70
- plt.rcParams['figure.figsize'] = (16, 3.6)
71
- plt.rc('axes', labelsize=15)
72
- plt.rc('xtick', labelsize=15)
73
- plt.rc('ytick', labelsize=15)
74
- librosa.display.specshow(spec, y_axis='log', x_axis='time')
75
- img_buffer = BytesIO()
76
- img_buffer.truncate(0) # Remove all contents
77
- img_buffer.seek(0) # Reset the pointer to the start
78
- plt.savefig(img_buffer, format='JPEG', bbox_inches='tight', pad_inches=0)
79
- plt.close('all')
80
- return img_buffer
81
-
82
-
83
- def process_recorded_wav_bytes(wav_bytes, sr):
84
- file = BytesIO(wav_bytes)
85
- audio = AudioSegment.from_file(file=file, format='wav')
86
- audio = audio.set_sample_width(2)
87
- audio = audio.set_channels(1)
88
- audio_22k = audio.set_frame_rate(sr)
89
- audio_16k = audio.set_frame_rate(SR)
90
- audio_22k = np.array(audio_22k.get_array_of_samples(), dtype=np.float32)
91
- audio_16k = np.array(audio_16k.get_array_of_samples(), dtype=np.float32)
92
- return audio_22k, audio_16k
93
-
94
-
95
- def main():
96
-
97
- st.set_page_config(
98
- page_title="speech-denoising-app",
99
- layout="wide"
100
- )
101
-
102
- logo_space, title_space, _, tooltip_space = st.columns([2.03, 5, 1, 0.75], gap="small")
103
-
104
- with logo_space:
105
- st.write(
106
- """
107
- <div style="display: flex; justify-content: left;">
108
- <b><span style="text-align: center; color: #101414; font-size: 10px">FPT Corporation</span></b>
109
- </div>
110
- """,
111
- unsafe_allow_html=True
112
- )
113
- st.image('logo.png', width=48)
114
-
115
- with title_space:
116
- st.image('title.png', width=640)
117
-
118
- with tooltip_space:
119
- st.markdown(
120
- """
121
- <style>
122
- .tooltip {
123
- position: relative;
124
- display: inline-block;
125
- cursor: pointer;
126
- background-color: rgba(0, 76, 153, 1); /* Blue button color */
127
- padding: 10px;
128
- border-radius: 50%;
129
- font-size: 16px;
130
- font-weight: bold;
131
- width: 40px;
132
- height: 40px;
133
- text-align: center;
134
- line-height: 20px;
135
- color: white; /* Text color */
136
- box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
137
- }
138
-
139
- .tooltip .tooltiptext {
140
- visibility: hidden;
141
- width: 300px; /* Adjust width for readability */
142
- background-color: #333; /* Dark background for contrast */
143
- color: #fff;
144
- text-align: left; /* Align text to the left */
145
- border-radius: 8px;
146
- padding: 15px; /* Add padding for spacing */
147
- position: absolute;
148
- z-index: 1;
149
- top: 150%; /* Position below the button */
150
- left: 50%;
151
- transform: translateX(-50%);
152
- opacity: 0;
153
- transition: opacity 0.3s;
154
- font-size: 14px;
155
- line-height: 1.8; /* Adjust line height for readability */
156
- white-space: normal; /* Allow wrapping of text */
157
- }
158
-
159
- .tooltip:hover .tooltiptext {
160
- visibility: visible;
161
- opacity: 1;
162
- }
163
- </style>
164
- """,
165
- unsafe_allow_html=True,
166
- )
167
-
168
- st.markdown(
169
- """
170
- <div class="tooltip">
171
-
172
- <span class="tooltiptext">
173
- <strong>Steps:</strong><br>
174
- 1) Denoise your own speech: Click <em>Start recording</em>, then <em>Stop recording</em> when you are finished.<br>
175
- 2) Click <em>"Denoise"</em> and wait for a few seconds.<br>
176
- 3) Both the original audio and denoised audio will be available for playback.<br><br>
177
- <strong>Note:</strong> Playing "noise" on your device while recording your speech to emulate speaking in a noisy environment will not work as intended. To do this emulation more realistically, play the noise on a different device (such as your phone) while recording your speech.
178
- </span>
179
- </div>
180
- """,
181
- unsafe_allow_html=True,
182
- )
183
-
184
- tab1, tab2 = st.tabs(["📂Denoise our samples speech", "🎙️Denoise your own speech"])
185
-
186
- with tab1:
187
- noisy_speech_files = load_noisy_speech()
188
-
189
- input_space_tab1, output_space_tab1 = st.columns([1, 1], gap="medium")
190
- _, _, _, compute_space_tab1= st.columns([0.7, 1, 1, 1], gap="small")
191
-
192
- with compute_space_tab1:
193
- compute_tab1 = st.button('Denoise', key='denoise_tab1')
194
-
195
- with input_space_tab1.container(height=CONTAINER_HEIGHT, border=True):
196
- lang_select_space, snr_select_space = st.columns([1, 1], gap="small")
197
- with lang_select_space:
198
- language_select = st.selectbox("Language", list(noisy_speech_files.keys()))
199
- with snr_select_space:
200
- if language_select:
201
- snr_select = st.selectbox("SNR Level", list(noisy_speech_files[language_select].keys()))
202
-
203
- audio_path_tab1 = noisy_speech_files[language_select][snr_select]
204
- noisy_wav_22k_tab1, noisy_wav_tab1 = load_wav(audio_path_tab1)
205
- noisy_spec_tab1 = wav_to_spec(noisy_wav_22k_tab1, sr=22050)
206
- noisy_spec_buff_tab1 = export_spec_to_buffer(noisy_spec_tab1)
207
-
208
- st.audio(audio_path_tab1, format="wav")
209
- st.image(image=noisy_spec_buff_tab1)
210
-
211
- with output_space_tab1.container(height=CONTAINER_HEIGHT, border=True):
212
- st.write(
213
- """
214
- <div style="display: flex; justify-content: center;">
215
- <b><span style="text-align: center; color: #808080; font-size: 51.5px">Output</span></b>
216
- </div>
217
- """,
218
- unsafe_allow_html=True
219
- )
220
- if noisy_wav_tab1.any() and compute_tab1:
221
- with st.spinner("Denoising..."):
222
- denoised_wav_tab1 = denoise(noisy_wav_tab1)
223
- st.audio(denoised_wav_tab1, sample_rate=SR, format="audio/wav")
224
- denoised_spec_tab1 = wav_to_spec(denoised_wav_tab1, sr=SR)
225
- denoised_spec_buff_tab1 = export_spec_to_buffer(denoised_spec_tab1)
226
- st.image(image=denoised_spec_buff_tab1)
227
-
228
- with tab2:
229
- input_space_tab2, output_space_tab2 = st.columns([1, 1], gap="medium")
230
- _, record_space, _, compute_space_tab2 = st.columns([0.7, 1, 1, 1], gap="small")
231
-
232
- with record_space:
233
- record = recorder(
234
- start_prompt="Start Recording",
235
- stop_prompt="Stop Recording",
236
- just_once=False,
237
- use_container_width=False,
238
- format="wav",
239
- callback=None,
240
- args=(),
241
- kwargs={},
242
- key="tab2_recorder"
243
- )
244
-
245
- with compute_space_tab2:
246
- compute_tab2 = st.button('Denoise', key='denoise_tab2')
247
-
248
- noisy_wav_tab2 = np.array([])
249
- with input_space_tab2.container(height=CONTAINER_HEIGHT, border=True):
250
- st.write(
251
- """
252
- <div style="display: flex; justify-content: center;">
253
- <b><span style="text-align: center; color: #808080; font-size: 51.5px">Input</span></b>
254
- </div>
255
- """,
256
- unsafe_allow_html=True
257
- )
258
-
259
- if record:
260
- wav_bytes_record = record['bytes']
261
- sr = record['sample_rate']
262
- noisy_wav_22k_tab2, noisy_wav_tab2 = process_recorded_wav_bytes(wav_bytes_record, sr=22050)
263
- noisy_spec_tab2 = wav_to_spec(noisy_wav_22k_tab2, sr=22050)
264
- noisy_spec_buff_tab2 = export_spec_to_buffer(noisy_spec_tab2)
265
-
266
- st.audio(wav_bytes_record, format="wav")
267
- st.image(image=noisy_spec_buff_tab2)
268
-
269
- with output_space_tab2.container(height=CONTAINER_HEIGHT, border=True):
270
- st.write(
271
- """
272
- <div style="display: flex; justify-content: center;">
273
- <b><span style="text-align: center; color: #808080; font-size: 51.5px">Output</span></b>
274
- </div>
275
- """,
276
- unsafe_allow_html=True
277
- )
278
- if noisy_wav_tab2.any() and compute_tab2:
279
- with st.spinner("Denoising..."):
280
- denoised_wav_tab2 = denoise(noisy_wav_tab2)
281
- st.audio(denoised_wav_tab2, sample_rate=SR, format="audio/wav")
282
- denoised_spec_tab2 = wav_to_spec(denoised_wav_tab2, sr=SR)
283
- denoised_spec_buff_tab2 = export_spec_to_buffer(denoised_spec_tab2)
284
- st.image(image=denoised_spec_buff_tab2)
285
- record = None
286
-
287
-
288
- if __name__ == '__main__':
289
  main()
 
1
+ import io
2
+ import os
3
+ import base64
4
+ import librosa
5
+ import numpy as np
6
+ from io import BytesIO
7
+ import streamlit as st
8
+ from pydub import AudioSegment
9
+ import matplotlib.pyplot as plt
10
+ from scipy.io.wavfile import write
11
+ from src.denoise import denoise
12
+ from myrecorder import recorder
13
+
14
+
15
+ SR = 16000
16
+ CONTAINER_HEIGHT = 340
17
+
18
+
19
+ def np_audio_to_bytesio(np_audio, np_audio_sr):
20
+ _bytes = bytes()
21
+ byte_io = io.BytesIO(_bytes)
22
+ write(byte_io, np_audio_sr, np_audio)
23
+ bytes_audio = byte_io.read()
24
+ return bytes_audio
25
+
26
+
27
+ def autoplay_audio(audio: str):
28
+ audio_base64 = base64.b64encode(audio).decode('utf-8')
29
+ audio_tag = f'<audio autoplay="true" src="data:audio/wav;base64,{audio_base64}">'
30
+ st.markdown(audio_tag, unsafe_allow_html=True)
31
+
32
+
33
+ def load_noisy_speech(root=os.path.join(os.getcwd(), 'noisy_speech')):
34
+ noisy_speech_paths = {'EN':{}, 'JA': {}}
35
+ noisy_speech_names = os.listdir(root)
36
+ for name in noisy_speech_names:
37
+ splt = name.split('_')
38
+ lang, snr = splt[0].upper(), int(splt[1][:2])
39
+ noisy_speech_paths[lang][snr] = os.path.join(root, name)
40
+
41
+ en_keys = list(noisy_speech_paths['EN'].keys())
42
+ en_keys.sort()
43
+ en_keys.reverse()
44
+ noisy_speech_paths['EN'] = {f'{key}dB': noisy_speech_paths['EN'][key] for key in en_keys}
45
+
46
+ ja_keys = list(noisy_speech_paths['JA'].keys())
47
+ ja_keys.sort()
48
+ ja_keys.reverse()
49
+ noisy_speech_paths['JA'] = {f'{key}dB': noisy_speech_paths['JA'][key] for key in ja_keys}
50
+
51
+ return noisy_speech_paths
52
+
53
+
54
+ def load_wav(wav_path):
55
+ wav_22k, sr = librosa.load(wav_path)
56
+ wav_16k = librosa.resample(wav_22k, orig_sr=sr, target_sr=SR)
57
+ return wav_22k, wav_16k
58
+
59
+
60
+ def wav_to_spec(wav, sr):
61
+ if sr == 16000:
62
+ wav = librosa.resample(wav, orig_sr=sr, target_sr=22050)
63
+ spec = np.abs(librosa.stft(wav))
64
+ spec = librosa.amplitude_to_db(spec, ref=np.max)
65
+ return spec
66
+
67
+
68
+ def export_spec_to_buffer(spec):
69
+ plt.clf()
70
+ plt.rcParams['figure.figsize'] = (16, 3.6)
71
+ plt.rc('axes', labelsize=15)
72
+ plt.rc('xtick', labelsize=15)
73
+ plt.rc('ytick', labelsize=15)
74
+ librosa.display.specshow(spec, y_axis='linear', x_axis='time')
75
+ img_buffer = BytesIO()
76
+ img_buffer.truncate(0) # Remove all contents
77
+ img_buffer.seek(0) # Reset the pointer to the start
78
+ plt.savefig(img_buffer, format='JPEG', bbox_inches='tight', pad_inches=0)
79
+ plt.close('all')
80
+ return img_buffer
81
+
82
+
83
+ def process_recorded_wav_bytes(wav_bytes, sr):
84
+ file = BytesIO(wav_bytes)
85
+ audio = AudioSegment.from_file(file=file, format='wav')
86
+ audio = audio.set_sample_width(2)
87
+ audio = audio.set_channels(1)
88
+ audio_22k = audio.set_frame_rate(sr)
89
+ audio_16k = audio.set_frame_rate(SR)
90
+ audio_22k = np.array(audio_22k.get_array_of_samples(), dtype=np.float32)
91
+ audio_16k = np.array(audio_16k.get_array_of_samples(), dtype=np.float32)
92
+ return audio_22k, audio_16k
93
+
94
+
95
+ def main():
96
+
97
+ st.set_page_config(
98
+ page_title="speech-denoising-app",
99
+ layout="wide"
100
+ )
101
+
102
+ logo_space, title_space, _, tooltip_space = st.columns([2.03, 5, 1, 0.75], gap="small")
103
+
104
+ with logo_space:
105
+ st.write(
106
+ """
107
+ <div style="display: flex; justify-content: left;">
108
+ <b><span style="text-align: center; color: #101414; font-size: 10px">FPT Corporation</span></b>
109
+ </div>
110
+ """,
111
+ unsafe_allow_html=True
112
+ )
113
+ st.image('logo.png', width=48)
114
+
115
+ with title_space:
116
+ st.image('title.png', width=640)
117
+
118
+ with tooltip_space:
119
+ st.markdown(
120
+ """
121
+ <style>
122
+ .tooltip {
123
+ position: relative;
124
+ display: inline-block;
125
+ cursor: pointer;
126
+ background-color: rgba(0, 76, 153, 1); /* Blue button color */
127
+ padding: 10px;
128
+ border-radius: 50%;
129
+ font-size: 16px;
130
+ font-weight: bold;
131
+ width: 40px;
132
+ height: 40px;
133
+ text-align: center;
134
+ line-height: 20px;
135
+ color: white; /* Text color */
136
+ box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
137
+ }
138
+
139
+ .tooltip .tooltiptext {
140
+ visibility: hidden;
141
+ width: 300px; /* Adjust width for readability */
142
+ background-color: #333; /* Dark background for contrast */
143
+ color: #fff;
144
+ text-align: left; /* Align text to the left */
145
+ border-radius: 8px;
146
+ padding: 15px; /* Add padding for spacing */
147
+ position: absolute;
148
+ z-index: 1;
149
+ top: 150%; /* Position below the button */
150
+ left: 50%;
151
+ transform: translateX(-50%);
152
+ opacity: 0;
153
+ transition: opacity 0.3s;
154
+ font-size: 14px;
155
+ line-height: 1.8; /* Adjust line height for readability */
156
+ white-space: normal; /* Allow wrapping of text */
157
+ }
158
+
159
+ .tooltip:hover .tooltiptext {
160
+ visibility: visible;
161
+ opacity: 1;
162
+ }
163
+ </style>
164
+ """,
165
+ unsafe_allow_html=True,
166
+ )
167
+
168
+ st.markdown(
169
+ """
170
+ <div class="tooltip">
171
+
172
+ <span class="tooltiptext">
173
+ <strong>Steps:</strong><br>
174
+ 1) Denoise your own speech: Click <em>Start recording</em>, then <em>Stop recording</em> when you are finished.<br>
175
+ 2) Click <em>"Denoise"</em> and wait for a few seconds.<br>
176
+ 3) Both the original audio and denoised audio will be available for playback.<br><br>
177
+ <strong>Note:</strong> Playing "noise" on your device while recording your speech to emulate speaking in a noisy environment will not work as intended. To do this emulation more realistically, play the noise on a different device (such as your phone) while recording your speech.
178
+ </span>
179
+ </div>
180
+ """,
181
+ unsafe_allow_html=True,
182
+ )
183
+
184
+ tab1, tab2 = st.tabs(["📂Denoise our samples speech", "🎙️Denoise your own speech"])
185
+
186
+ with tab1:
187
+ noisy_speech_files = load_noisy_speech()
188
+
189
+ input_space_tab1, output_space_tab1 = st.columns([1, 1], gap="medium")
190
+ _, _, _, compute_space_tab1= st.columns([0.7, 1, 1, 1], gap="small")
191
+
192
+ with compute_space_tab1:
193
+ compute_tab1 = st.button('Denoise', key='denoise_tab1')
194
+
195
+ with input_space_tab1.container(height=CONTAINER_HEIGHT, border=True):
196
+ lang_select_space, snr_select_space = st.columns([1, 1], gap="small")
197
+ with lang_select_space:
198
+ language_select = st.selectbox("Language", list(noisy_speech_files.keys()))
199
+ with snr_select_space:
200
+ if language_select:
201
+ snr_select = st.selectbox("SNR Level", list(noisy_speech_files[language_select].keys()))
202
+
203
+ audio_path_tab1 = noisy_speech_files[language_select][snr_select]
204
+ noisy_wav_22k_tab1, noisy_wav_tab1 = load_wav(audio_path_tab1)
205
+ noisy_spec_tab1 = wav_to_spec(noisy_wav_22k_tab1, sr=22050)
206
+ noisy_spec_buff_tab1 = export_spec_to_buffer(noisy_spec_tab1)
207
+
208
+ st.audio(audio_path_tab1, format="wav")
209
+ st.image(image=noisy_spec_buff_tab1)
210
+
211
+ with output_space_tab1.container(height=CONTAINER_HEIGHT, border=True):
212
+ st.write(
213
+ """
214
+ <div style="display: flex; justify-content: center;">
215
+ <b><span style="text-align: center; color: #808080; font-size: 51.5px">Output</span></b>
216
+ </div>
217
+ """,
218
+ unsafe_allow_html=True
219
+ )
220
+ if noisy_wav_tab1.any() and compute_tab1:
221
+ with st.spinner("Denoising..."):
222
+ denoised_wav_tab1 = denoise(noisy_wav_tab1)
223
+ st.audio(denoised_wav_tab1, sample_rate=SR, format="audio/wav")
224
+ denoised_spec_tab1 = wav_to_spec(denoised_wav_tab1, sr=SR)
225
+ denoised_spec_buff_tab1 = export_spec_to_buffer(denoised_spec_tab1)
226
+ st.image(image=denoised_spec_buff_tab1)
227
+
228
+ with tab2:
229
+ input_space_tab2, output_space_tab2 = st.columns([1, 1], gap="medium")
230
+ _, record_space, _, compute_space_tab2 = st.columns([0.7, 1, 1, 1], gap="small")
231
+
232
+ with record_space:
233
+ record = recorder(
234
+ start_prompt="Start Recording",
235
+ stop_prompt="Stop Recording",
236
+ just_once=False,
237
+ use_container_width=False,
238
+ format="wav",
239
+ callback=None,
240
+ args=(),
241
+ kwargs={},
242
+ key="tab2_recorder"
243
+ )
244
+
245
+ with compute_space_tab2:
246
+ compute_tab2 = st.button('Denoise', key='denoise_tab2')
247
+
248
+ noisy_wav_tab2 = np.array([])
249
+ with input_space_tab2.container(height=CONTAINER_HEIGHT, border=True):
250
+ st.write(
251
+ """
252
+ <div style="display: flex; justify-content: center;">
253
+ <b><span style="text-align: center; color: #808080; font-size: 51.5px">Input</span></b>
254
+ </div>
255
+ """,
256
+ unsafe_allow_html=True
257
+ )
258
+
259
+ if record:
260
+ wav_bytes_record = record['bytes']
261
+ sr = record['sample_rate']
262
+ noisy_wav_22k_tab2, noisy_wav_tab2 = process_recorded_wav_bytes(wav_bytes_record, sr=22050)
263
+ noisy_spec_tab2 = wav_to_spec(noisy_wav_22k_tab2, sr=22050)
264
+ noisy_spec_buff_tab2 = export_spec_to_buffer(noisy_spec_tab2)
265
+
266
+ st.audio(wav_bytes_record, format="wav")
267
+ st.image(image=noisy_spec_buff_tab2)
268
+
269
+ with output_space_tab2.container(height=CONTAINER_HEIGHT, border=True):
270
+ st.write(
271
+ """
272
+ <div style="display: flex; justify-content: center;">
273
+ <b><span style="text-align: center; color: #808080; font-size: 51.5px">Output</span></b>
274
+ </div>
275
+ """,
276
+ unsafe_allow_html=True
277
+ )
278
+ if noisy_wav_tab2.any() and compute_tab2:
279
+ with st.spinner("Denoising..."):
280
+ denoised_wav_tab2 = denoise(noisy_wav_tab2)
281
+ st.audio(denoised_wav_tab2, sample_rate=SR, format="audio/wav")
282
+ denoised_spec_tab2 = wav_to_spec(denoised_wav_tab2, sr=SR)
283
+ denoised_spec_buff_tab2 = export_spec_to_buffer(denoised_spec_tab2)
284
+ st.image(image=denoised_spec_buff_tab2)
285
+ record = None
286
+
287
+
288
+ if __name__ == '__main__':
289
  main()
logo.png CHANGED

Git LFS Details

  • SHA256: beeb8a9707775981c208c3aedd9541b9023888f2c32afaa772172ae65237be8b
  • Pointer size: 131 Bytes
  • Size of remote file: 111 kB

Git LFS Details

  • SHA256: b1b3e6cc0d730f176f21cfcd3fbe67b422232acc79141303e0db1f609d10c002
  • Pointer size: 131 Bytes
  • Size of remote file: 142 kB