Tonic commited on
Commit
31a7207
1 Parent(s): 03dd384

testing 123

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Dockerfile +8 -0
  2. README (2).md +61 -0
  3. README.qmd +92 -0
  4. assets/1221-135766-0002.wav +0 -0
  5. assets/mel_filters.npz +3 -0
  6. build-dolphin-2_6-phi-2.sh +26 -0
  7. build-mistral.sh +18 -0
  8. build-models.sh +7 -0
  9. build-phi-2.sh +25 -0
  10. build-whisper.sh +33 -0
  11. build.sh +21 -0
  12. docker/Dockerfile +8 -0
  13. docker/base-image/Dockerfile +14 -0
  14. docker/base-image/install-deps.sh +54 -0
  15. docker/base-image/install-trt-llm.sh +16 -0
  16. docker/build.sh +21 -0
  17. docker/publish.sh +4 -0
  18. docker/scripts/build-dolphin-2_6-phi-2.sh +26 -0
  19. docker/scripts/build-mistral.sh +18 -0
  20. docker/scripts/build-models.sh +7 -0
  21. docker/scripts/build-phi-2.sh +25 -0
  22. docker/scripts/build-whisper.sh +33 -0
  23. docker/scripts/run-whisperfusion.sh +16 -0
  24. docker/scripts/setup-whisperfusion.sh +27 -0
  25. docker/scripts/setup.sh +6 -0
  26. examples/chatbot/html/css/all.min.css +5 -0
  27. examples/chatbot/html/css/style.css +437 -0
  28. examples/chatbot/html/img/0.png +0 -0
  29. examples/chatbot/html/img/1.png +0 -0
  30. examples/chatbot/html/img/2.png +0 -0
  31. examples/chatbot/html/img/COL-logo.png +0 -0
  32. examples/chatbot/html/img/Collabora_Logo.svg +0 -0
  33. examples/chatbot/html/img/Phi.svg +14 -0
  34. examples/chatbot/html/img/microphone-hover.png +0 -0
  35. examples/chatbot/html/img/microphone-white.png +0 -0
  36. examples/chatbot/html/img/microphone.png +0 -0
  37. examples/chatbot/html/img/pause.png +0 -0
  38. examples/chatbot/html/img/record.png +0 -0
  39. examples/chatbot/html/img/stop.png +0 -0
  40. examples/chatbot/html/index.html +52 -0
  41. examples/chatbot/html/js/audio-processor.js +31 -0
  42. examples/chatbot/html/js/main.js +340 -0
  43. examples/chatbot/html/static/0.mp3 +0 -0
  44. examples/chatbot/html/static/1.mp3 +0 -0
  45. examples/chatbot/html/static/10.mp3 +0 -0
  46. examples/chatbot/html/static/2.mp3 +0 -0
  47. examples/chatbot/html/static/3.mp3 +0 -0
  48. examples/chatbot/html/static/4.mp3 +0 -0
  49. examples/chatbot/html/static/5.mp3 +0 -0
  50. examples/chatbot/html/static/6.mp3 +0 -0
Dockerfile ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ FROM ghcr.io/collabora/whisperfusion-base:latest as base
2
+
3
+ WORKDIR /root
4
+ COPY scripts/setup-whisperfusion.sh scripts/run-whisperfusion.sh scratch-space/models /root/
5
+ RUN ./setup-whisperfusion.sh
6
+
7
+ CMD ./run-whisperfusion.sh
8
+
README (2).md ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # WhisperFusion
2
+
3
+ <h2 align="center">
4
+ <a href="https://www.youtube.com/watch?v=_PnaP0AQJnk"><img
5
+ src="https://img.youtube.com/vi/_PnaP0AQJnk/0.jpg" style="background-color:rgba(0,0,0,0);" height=300 alt="WhisperFusion"></a>
6
+ <br><br>Seamless conversations with AI (with ultra-low latency)<br><br>
7
+ </h2>
8
+
9
+ Welcome to WhisperFusion. WhisperFusion builds upon the capabilities of
10
+ the [WhisperLive](https://github.com/collabora/WhisperLive) and
11
+ [WhisperSpeech](https://github.com/collabora/WhisperSpeech) by
12
+ integrating Mistral, a Large Language Model (LLM), on top of the
13
+ real-time speech-to-text pipeline. Both LLM and
14
+ Whisper are optimized to run efficiently as TensorRT engines, maximizing
15
+ performance and real-time processing capabilities. While WhiperSpeech is
16
+ optimized with torch.compile.
17
+
18
+ ## Features
19
+
20
+ - **Real-Time Speech-to-Text**: Utilizes OpenAI WhisperLive to convert
21
+ spoken language into text in real-time.
22
+
23
+ - **Large Language Model Integration**: Adds Mistral, a Large Language
24
+ Model, to enhance the understanding and context of the transcribed
25
+ text.
26
+
27
+ - **TensorRT Optimization**: Both LLM and Whisper are optimized to
28
+ run as TensorRT engines, ensuring high-performance and low-latency
29
+ processing.
30
+ - **torch.compile**: WhisperSpeech uses torch.compile to speed up
31
+ inference which makes PyTorch code run faster by JIT-compiling PyTorch
32
+ code into optimized kernels.
33
+
34
+ ## Getting Started
35
+ - We provide a pre-built TensorRT-LLM docker container that has both whisper and
36
+ phi converted to TensorRT engines and WhisperSpeech model is pre-downloaded to
37
+ quickly start interacting with WhisperFusion.
38
+ ```bash
39
+ docker run --gpus all --shm-size 64G -p 6006:6006 -p 8888:8888 -it ghcr.io/collabora/whisperfusion:latest
40
+ ```
41
+
42
+ - Start Web GUI
43
+ ```bash
44
+ cd examples/chatbot/html
45
+ python -m http.server
46
+ ```
47
+
48
+ ## Build Docker Image
49
+ - We provide the docker image for cuda-architecures 89 and 90. If you have a GPU
50
+ with a different cuda architecture. For e.g. to build for RTX 3090 with cuda-
51
+ architecture 86
52
+ ```bash
53
+ bash build.sh 86-real
54
+ ```
55
+ This should build the `ghcr.io/collabora/whisperfusion:latest` for RTX 3090.
56
+
57
+ ## Contact Us
58
+
59
+ For questions or issues, please open an issue. Contact us at:
60
+ marcus.edel@collabora.com, jpc@collabora.com,
61
+ vineet.suryan@collabora.com
README.qmd ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ format: gfm
3
+ execute:
4
+ echo: false
5
+ output: asis
6
+ ---
7
+
8
+ ```{python}
9
+ #| include: false
10
+ def include_file(fname):
11
+ with open(fname) as f:
12
+ print(f'''
13
+ :::{{.callout-note}}
14
+ These steps are included in `{fname}`
15
+ :::
16
+ ''')
17
+ code = False
18
+ for l in f:
19
+ if l.startswith('#!'):
20
+ continue
21
+ if l.startswith('## '):
22
+ if code: print("```"); code=False
23
+ print(l[3:])
24
+ elif l.strip():
25
+ if not code: print("```bash"); code=True
26
+ print(l.rstrip())
27
+ if code: print("```")
28
+ ```
29
+
30
+ # WhisperFusion
31
+
32
+ <h2 align="center">
33
+ <a href="https://www.youtube.com/watch?v=_PnaP0AQJnk"><img
34
+ src="https://img.youtube.com/vi/_PnaP0AQJnk/0.jpg" style="background-color:rgba(0,0,0,0);" height=300 alt="WhisperFusion"></a>
35
+ <br><br>Doing math with WhisperFusion: Ultra-low latency conversations with an AI chatbot<br><br>
36
+ </h2>
37
+
38
+ Welcome to WhisperFusion. WhisperFusion builds upon the capabilities of the [WhisperLive](https://github.com/collabora/WhisperLive) and [WhisperSpeech](https://github.com/collabora/WhisperSpeech) by integrating Mistral, a Large Language Model (LLM), on top of the real-time speech-to-text pipeline. WhisperLive relies on OpenAI Whisper, a powerful automatic speech recognition (ASR) system. Both Mistral and Whisper are optimized to run efficiently as TensorRT engines, maximizing performance and real-time processing capabilities.
39
+
40
+ ## Features
41
+ - **Real-Time Speech-to-Text**: Utilizes OpenAI WhisperLive to convert spoken language into text in real-time.
42
+
43
+ - **Large Language Model Integration**: Adds Mistral, a Large Language Model, to enhance the understanding and context of the transcribed text.
44
+
45
+ - **TensorRT Optimization**: Both Mistral and Whisper are optimized to run as TensorRT engines, ensuring high-performance and low-latency processing.
46
+
47
+ ## Prerequisites
48
+ Install [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM/blob/main/docs/source/installation.md) to build Whisper and Mistral TensorRT engines. The README builds a docker image for TensorRT-LLM.
49
+ Instead of building a docker image, we can also refer to the README and the [Dockerfile.multi](https://github.com/NVIDIA/TensorRT-LLM/blob/main/docker/Dockerfile.multi) to install the required packages in the base pytroch docker image. Just make sure to use the correct base image as mentioned in the dockerfile and everything should go nice and smooth.
50
+
51
+ ### Build Whisper TensorRT Engine
52
+
53
+ ```{python}
54
+ include_file('docker/scripts/build-whisper.sh')
55
+ ```
56
+
57
+ ### Build Mistral TensorRT Engine
58
+
59
+ ```{python}
60
+ include_file('docker/scripts/build-mistral.sh')
61
+ ```
62
+
63
+ ### Build Phi TensorRT Engine
64
+
65
+ ```{python}
66
+ include_file('docker/scripts/build-phi-2.sh')
67
+ ```
68
+
69
+ ## Build WhisperFusion
70
+
71
+ ```{python}
72
+ include_file('docker/scripts/setup-whisperfusion.sh')
73
+ ```
74
+
75
+ ### Run WhisperFusion with Whisper and Mistral/Phi-2
76
+
77
+ Take the folder path for Whisper TensorRT model, folder_path and tokenizer_path for Mistral/Phi-2 TensorRT from the build phase. If a huggingface model is used to build mistral/phi-2 then just use the huggingface repo name as the tokenizer path.
78
+
79
+ ```{python}
80
+ include_file('docker/scripts/run-whisperfusion.sh')
81
+ ```
82
+
83
+ - On the client side clone the repo, install the requirements and execute `run_client.py`
84
+ ```bash
85
+ cd WhisperFusion
86
+ pip install -r requirements.txt
87
+ python3 run_client.py
88
+ ```
89
+
90
+ ## Contact Us
91
+ For questions or issues, please open an issue.
92
+ Contact us at: marcus.edel@collabora.com, jpc@collabora.com, vineet.suryan@collabora.com
assets/1221-135766-0002.wav ADDED
Binary file (154 kB). View file
 
assets/mel_filters.npz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7450ae70723a5ef9d341e3cee628c7cb0177f36ce42c44b7ed2bf3325f0f6d4c
3
+ size 4271
build-dolphin-2_6-phi-2.sh ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Note: Phi is only available in main branch and hasnt been released yet. So, make sure to build TensorRT-LLM from main branch.
4
+
5
+ cd /root/TensorRT-LLM-examples/phi
6
+
7
+ ## Build TensorRT for [Dolphin Phi Finetuned](https://huggingface.co/cognitivecomputations/dolphin-2_6-phi-2) ChatML format with `fp16`
8
+
9
+ git lfs install
10
+ phi_path=$(huggingface-cli download --repo-type model cognitivecomputations/dolphin-2_6-phi-2)
11
+ name=dolphin-2_6-phi-2
12
+ python3 build.py --dtype=float16 \
13
+ --log_level=verbose \
14
+ --use_gpt_attention_plugin float16 \
15
+ --use_gemm_plugin float16 \
16
+ --max_batch_size=1 \
17
+ --max_input_len=1024 \
18
+ --max_output_len=1024 \
19
+ --output_dir=$name \
20
+ --model_dir="$phi_path" >&1 | tee build.log
21
+
22
+ dest=/root/scratch-space/models
23
+ mkdir -p "$dest/$name/tokenizer"
24
+ cp -r "$name" "$dest"
25
+ (cd "$phi_path" && cp config.json tokenizer_config.json vocab.json merges.txt "$dest/$name/tokenizer")
26
+ cp -r "$phi_path" "$dest/phi-orig-model"
build-mistral.sh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ cd /root/TensorRT-LLM-examples/llama
4
+
5
+ ## Build TensorRT for Mistral with `fp16`
6
+
7
+ python build.py --model_dir teknium/OpenHermes-2.5-Mistral-7B \
8
+ --dtype float16 \
9
+ --remove_input_padding \
10
+ --use_gpt_attention_plugin float16 \
11
+ --enable_context_fmha \
12
+ --use_gemm_plugin float16 \
13
+ --output_dir ./tmp/mistral/7B/trt_engines/fp16/1-gpu/ \
14
+ --max_input_len 5000 \
15
+ --max_batch_size 1
16
+
17
+ mkdir -p /root/scratch-space/models
18
+ cp -r tmp/mistral/7B/trt_engines/fp16/1-gpu /root/scratch-space/models/mistral
build-models.sh ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ test -f /etc/shinit_v2 && source /etc/shinit_v2
4
+
5
+ ./build-whisper.sh
6
+ # ./build-mistral.sh
7
+ ./build-dolphin-2_6-phi-2.sh
build-phi-2.sh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Note: Phi is only available in main branch and hasnt been released yet. So, make sure to build TensorRT-LLM from main branch.
4
+
5
+ cd /root/TensorRT-LLM-examples/phi
6
+
7
+ ## Build TensorRT for Phi-2 with `fp16`
8
+
9
+ git lfs install
10
+ phi_path=$(huggingface-cli download --repo-type model --revision 834565c23f9b28b96ccbeabe614dd906b6db551a microsoft/phi-2)
11
+ python3 build.py --dtype=float16 \
12
+ --log_level=verbose \
13
+ --use_gpt_attention_plugin float16 \
14
+ --use_gemm_plugin float16 \
15
+ --max_batch_size=16 \
16
+ --max_input_len=1024 \
17
+ --max_output_len=1024 \
18
+ --output_dir=phi-2 \
19
+ --model_dir="$phi_path" >&1 | tee build.log
20
+
21
+ dest=/root/scratch-space/models
22
+ mkdir -p "$dest/phi-2/tokenizer"
23
+ cp -r phi-2 "$dest"
24
+ (cd "$phi_path" && cp config.json tokenizer_config.json vocab.json merges.txt "$dest/phi-2/tokenizer")
25
+ cp -r "$phi_path" "$dest/phi-orig-model"
build-whisper.sh ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Change working dir to the [whisper example dir](https://github.com/NVIDIA/TensorRT-LLM/tree/main/examples/whisper) in TensorRT-LLM.
4
+ cd /root/TensorRT-LLM-examples/whisper
5
+
6
+ ## Currently, by default TensorRT-LLM only supports `large-v2` and `large-v3`. In this repo, we use `small.en`.
7
+ ## Download the required assets
8
+
9
+ # the sound filter definitions
10
+ wget --directory-prefix=assets https://raw.githubusercontent.com/openai/whisper/main/whisper/assets/mel_filters.npz
11
+ # the small.en model weights
12
+ wget --directory-prefix=assets https://openaipublic.azureedge.net/main/whisper/models/f953ad0fd29cacd07d5a9eda5624af0f6bcf2258be67c92b79389873d91e0872/small.en.pt
13
+
14
+ ## We have to patch the script to add support for out model size (`small.en`):
15
+ patch <<EOF
16
+ --- build.py.old 2024-01-17 17:47:47.508545842 +0100
17
+ +++ build.py 2024-01-17 17:47:41.404941926 +0100
18
+ @@ -58,6 +58,7 @@
19
+ choices=[
20
+ "large-v3",
21
+ "large-v2",
22
+ + "small.en",
23
+ ])
24
+ parser.add_argument('--quantize_dir', type=str, default="quantize/1-gpu")
25
+ parser.add_argument('--dtype',
26
+ EOF
27
+
28
+ ## Finally we can build the TensorRT engine for the `small.en` Whisper model:
29
+ pip install -r requirements.txt
30
+ python3 build.py --output_dir whisper_small_en --use_gpt_attention_plugin --use_gemm_plugin --use_layernorm_plugin --use_bert_attention_plugin --model_name small.en
31
+
32
+ mkdir -p /root/scratch-space/models
33
+ cp -r whisper_small_en /root/scratch-space/models
build.sh ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ if [ -n "$1" ]; then
4
+ CUDA_ARCH="$1"
5
+ BASE_IMAGE_BUILD_ARG="--build-arg CUDA_ARCH=$CUDA_ARCH"
6
+ else
7
+ BASE_IMAGE_BUILD_ARG=""
8
+ fi
9
+
10
+ [ -n "$VERBOSE" ] && ARGS="--progress plain"
11
+
12
+ (
13
+ cd base-image &&
14
+ docker build $ARGS $BASE_IMAGE_BUILD_ARG -t ghcr.io/collabora/whisperfusion-base:latest .
15
+ )
16
+
17
+ mkdir -p scratch-space
18
+ cp -r scripts/build-* scratch-space
19
+ docker run --gpus all --shm-size 64G -v "$PWD"/scratch-space:/root/scratch-space -w /root/scratch-space -it ghcr.io/collabora/whisperfusion-base:latest ./build-models.sh
20
+
21
+ docker build $ARGS -t ghcr.io/collabora/whisperfusion:latest .
docker/Dockerfile ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ FROM ghcr.io/collabora/whisperfusion-base:latest as base
2
+
3
+ WORKDIR /root
4
+ COPY scripts/setup-whisperfusion.sh scripts/run-whisperfusion.sh scratch-space/models /root/
5
+ RUN ./setup-whisperfusion.sh
6
+
7
+ CMD ./run-whisperfusion.sh
8
+
docker/base-image/Dockerfile ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ARG BASE_IMAGE=nvcr.io/nvidia/pytorch
2
+ #ARG BASE_TAG=23.10-py3
3
+ ARG BASE_IMAGE=nvcr.io/nvidia/cuda
4
+ ARG BASE_TAG=12.2.2-devel-ubuntu22.04
5
+
6
+ FROM ${BASE_IMAGE}:${BASE_TAG} as base
7
+ ARG CUDA_ARCH
8
+ WORKDIR /root
9
+ COPY install-deps.sh /root
10
+ ENV CUDA_ARCH=${CUDA_ARCH}
11
+ RUN bash install-deps.sh && rm install-deps.sh
12
+
13
+ COPY install-trt-llm.sh /root
14
+ RUN bash install-trt-llm.sh && rm install-trt-llm.sh
docker/base-image/install-deps.sh ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ apt-get update && apt-get -y install git git-lfs
4
+ git clone --depth=1 -b cuda12.2 https://github.com/makaveli10/TensorRT-LLM.git
5
+ cd TensorRT-LLM
6
+ git checkout main
7
+ git submodule update --init --recursive
8
+ git lfs install
9
+ git lfs pull
10
+
11
+ # do not reinstall CUDA (our base image provides the same exact versions)
12
+ patch -p1 <<EOF
13
+ diff --git a/docker/common/install_tensorrt.sh b/docker/common/install_tensorrt.sh
14
+ index 2dcb0a6..3a27e03 100644
15
+ --- a/docker/common/install_tensorrt.sh
16
+ +++ b/docker/common/install_tensorrt.sh
17
+ @@ -35,19 +35,7 @@ install_ubuntu_requirements() {
18
+ dpkg -i cuda-keyring_1.0-1_all.deb
19
+
20
+ apt-get update
21
+ - if [[ $(apt list --installed | grep libcudnn8) ]]; then
22
+ - apt-get remove --purge -y libcudnn8*
23
+ - fi
24
+ - if [[ $(apt list --installed | grep libnccl) ]]; then
25
+ - apt-get remove --purge -y --allow-change-held-packages libnccl*
26
+ - fi
27
+ - if [[ $(apt list --installed | grep libcublas) ]]; then
28
+ - apt-get remove --purge -y --allow-change-held-packages libcublas*
29
+ - fi
30
+ - CUBLAS_CUDA_VERSION=$(echo $CUDA_VER | sed 's/\./-/g')
31
+ apt-get install -y --no-install-recommends libcudnn8=${CUDNN_VER} libcudnn8-dev=${CUDNN_VER}
32
+ - apt-get install -y --no-install-recommends libnccl2=${NCCL_VER} libnccl-dev=${NCCL_VER}
33
+ - apt-get install -y --no-install-recommends libcublas-${CUBLAS_CUDA_VERSION}=${CUBLAS_VER} libcublas-dev-${CUBLAS_CUDA_VERSION}=${CUBLAS_VER}
34
+ apt-get clean
35
+ rm -rf /var/lib/apt/lists/*
36
+ }
37
+ EOF
38
+
39
+ cd docker/common/
40
+ export BASH_ENV=${BASH_ENV:-/etc/bash.bashrc}
41
+ export ENV=${ENV:-/etc/shinit_v2}
42
+ bash install_base.sh
43
+ bash install_cmake.sh
44
+ source $ENV
45
+ bash install_ccache.sh
46
+ # later on TensorRT-LLM will force reinstall this version anyways
47
+ pip3 install --extra-index-url https://download.pytorch.org/whl/cu121 torch
48
+ bash install_tensorrt.sh
49
+ bash install_polygraphy.sh
50
+ source $ENV
51
+
52
+ cd /root/TensorRT-LLM/docker/common/
53
+ bash install_mpi4py.sh
54
+ source $ENV
docker/base-image/install-trt-llm.sh ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ export ENV=${ENV:-/etc/shinit_v2}
4
+ source $ENV
5
+
6
+ CUDA_ARCH="${CUDA_ARCH:-89-real;90-real}"
7
+
8
+ cd /root/TensorRT-LLM
9
+ python3 scripts/build_wheel.py --clean --cuda_architectures "$CUDA_ARCH" --trt_root /usr/local/tensorrt
10
+ pip install build/tensorrt_llm-0.7.1-cp310-cp310-linux_x86_64.whl
11
+ mv examples ../TensorRT-LLM-examples
12
+ cd ..
13
+
14
+ rm -rf TensorRT-LLM
15
+ # we don't need static libraries and they take a lot of space
16
+ (cd /usr && find . -name '*static.a' | grep -v cudart_static | xargs rm -f)
docker/build.sh ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ if [ -n "$1" ]; then
4
+ CUDA_ARCH="$1"
5
+ BASE_IMAGE_BUILD_ARG="--build-arg CUDA_ARCH=$CUDA_ARCH"
6
+ else
7
+ BASE_IMAGE_BUILD_ARG=""
8
+ fi
9
+
10
+ [ -n "$VERBOSE" ] && ARGS="--progress plain"
11
+
12
+ (
13
+ cd base-image &&
14
+ docker build $ARGS $BASE_IMAGE_BUILD_ARG -t ghcr.io/collabora/whisperfusion-base:latest .
15
+ )
16
+
17
+ mkdir -p scratch-space
18
+ cp -r scripts/build-* scratch-space
19
+ docker run --gpus all --shm-size 64G -v "$PWD"/scratch-space:/root/scratch-space -w /root/scratch-space -it ghcr.io/collabora/whisperfusion-base:latest ./build-models.sh
20
+
21
+ docker build $ARGS -t ghcr.io/collabora/whisperfusion:latest .
docker/publish.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ docker push ghcr.io/collabora/whisperfusion-base:latest
4
+ docker push ghcr.io/collabora/whisperfusion:latest
docker/scripts/build-dolphin-2_6-phi-2.sh ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Note: Phi is only available in main branch and hasnt been released yet. So, make sure to build TensorRT-LLM from main branch.
4
+
5
+ cd /root/TensorRT-LLM-examples/phi
6
+
7
+ ## Build TensorRT for [Dolphin Phi Finetuned](https://huggingface.co/cognitivecomputations/dolphin-2_6-phi-2) ChatML format with `fp16`
8
+
9
+ git lfs install
10
+ phi_path=$(huggingface-cli download --repo-type model cognitivecomputations/dolphin-2_6-phi-2)
11
+ name=dolphin-2_6-phi-2
12
+ python3 build.py --dtype=float16 \
13
+ --log_level=verbose \
14
+ --use_gpt_attention_plugin float16 \
15
+ --use_gemm_plugin float16 \
16
+ --max_batch_size=1 \
17
+ --max_input_len=1024 \
18
+ --max_output_len=1024 \
19
+ --output_dir=$name \
20
+ --model_dir="$phi_path" >&1 | tee build.log
21
+
22
+ dest=/root/scratch-space/models
23
+ mkdir -p "$dest/$name/tokenizer"
24
+ cp -r "$name" "$dest"
25
+ (cd "$phi_path" && cp config.json tokenizer_config.json vocab.json merges.txt "$dest/$name/tokenizer")
26
+ cp -r "$phi_path" "$dest/phi-orig-model"
docker/scripts/build-mistral.sh ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ cd /root/TensorRT-LLM-examples/llama
4
+
5
+ ## Build TensorRT for Mistral with `fp16`
6
+
7
+ python build.py --model_dir teknium/OpenHermes-2.5-Mistral-7B \
8
+ --dtype float16 \
9
+ --remove_input_padding \
10
+ --use_gpt_attention_plugin float16 \
11
+ --enable_context_fmha \
12
+ --use_gemm_plugin float16 \
13
+ --output_dir ./tmp/mistral/7B/trt_engines/fp16/1-gpu/ \
14
+ --max_input_len 5000 \
15
+ --max_batch_size 1
16
+
17
+ mkdir -p /root/scratch-space/models
18
+ cp -r tmp/mistral/7B/trt_engines/fp16/1-gpu /root/scratch-space/models/mistral
docker/scripts/build-models.sh ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ test -f /etc/shinit_v2 && source /etc/shinit_v2
4
+
5
+ ./build-whisper.sh
6
+ # ./build-mistral.sh
7
+ ./build-dolphin-2_6-phi-2.sh
docker/scripts/build-phi-2.sh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Note: Phi is only available in main branch and hasnt been released yet. So, make sure to build TensorRT-LLM from main branch.
4
+
5
+ cd /root/TensorRT-LLM-examples/phi
6
+
7
+ ## Build TensorRT for Phi-2 with `fp16`
8
+
9
+ git lfs install
10
+ phi_path=$(huggingface-cli download --repo-type model --revision 834565c23f9b28b96ccbeabe614dd906b6db551a microsoft/phi-2)
11
+ python3 build.py --dtype=float16 \
12
+ --log_level=verbose \
13
+ --use_gpt_attention_plugin float16 \
14
+ --use_gemm_plugin float16 \
15
+ --max_batch_size=16 \
16
+ --max_input_len=1024 \
17
+ --max_output_len=1024 \
18
+ --output_dir=phi-2 \
19
+ --model_dir="$phi_path" >&1 | tee build.log
20
+
21
+ dest=/root/scratch-space/models
22
+ mkdir -p "$dest/phi-2/tokenizer"
23
+ cp -r phi-2 "$dest"
24
+ (cd "$phi_path" && cp config.json tokenizer_config.json vocab.json merges.txt "$dest/phi-2/tokenizer")
25
+ cp -r "$phi_path" "$dest/phi-orig-model"
docker/scripts/build-whisper.sh ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Change working dir to the [whisper example dir](https://github.com/NVIDIA/TensorRT-LLM/tree/main/examples/whisper) in TensorRT-LLM.
4
+ cd /root/TensorRT-LLM-examples/whisper
5
+
6
+ ## Currently, by default TensorRT-LLM only supports `large-v2` and `large-v3`. In this repo, we use `small.en`.
7
+ ## Download the required assets
8
+
9
+ # the sound filter definitions
10
+ wget --directory-prefix=assets https://raw.githubusercontent.com/openai/whisper/main/whisper/assets/mel_filters.npz
11
+ # the small.en model weights
12
+ wget --directory-prefix=assets https://openaipublic.azureedge.net/main/whisper/models/f953ad0fd29cacd07d5a9eda5624af0f6bcf2258be67c92b79389873d91e0872/small.en.pt
13
+
14
+ ## We have to patch the script to add support for out model size (`small.en`):
15
+ patch <<EOF
16
+ --- build.py.old 2024-01-17 17:47:47.508545842 +0100
17
+ +++ build.py 2024-01-17 17:47:41.404941926 +0100
18
+ @@ -58,6 +58,7 @@
19
+ choices=[
20
+ "large-v3",
21
+ "large-v2",
22
+ + "small.en",
23
+ ])
24
+ parser.add_argument('--quantize_dir', type=str, default="quantize/1-gpu")
25
+ parser.add_argument('--dtype',
26
+ EOF
27
+
28
+ ## Finally we can build the TensorRT engine for the `small.en` Whisper model:
29
+ pip install -r requirements.txt
30
+ python3 build.py --output_dir whisper_small_en --use_gpt_attention_plugin --use_gemm_plugin --use_layernorm_plugin --use_bert_attention_plugin --model_name small.en
31
+
32
+ mkdir -p /root/scratch-space/models
33
+ cp -r whisper_small_en /root/scratch-space/models
docker/scripts/run-whisperfusion.sh ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ test -f /etc/shinit_v2 && source /etc/shinit_v2
4
+
5
+ cd WhisperFusion
6
+ if [ "$1" != "mistral" ]; then
7
+ exec python3 main.py --phi \
8
+ --whisper_tensorrt_path /root/whisper_small_en \
9
+ --phi_tensorrt_path /root/dolphin-2_6-phi-2 \
10
+ --phi_tokenizer_path /root/dolphin-2_6-phi-2/tokenizer
11
+ else
12
+ exec python3 main.py --mistral \
13
+ --whisper_tensorrt_path /root/models/whisper_small_en \
14
+ --mistral_tensorrt_path /root/models/mistral \
15
+ --mistral_tokenizer_path teknium/OpenHermes-2.5-Mistral-7B
16
+ fi
docker/scripts/setup-whisperfusion.sh ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ## Clone this repo and install requirements
4
+ [ -d "WhisperFusion" ] || git clone https://github.com/collabora/WhisperFusion.git
5
+
6
+ cd WhisperFusion
7
+ apt update
8
+ apt install ffmpeg portaudio19-dev -y
9
+
10
+ ## Install torchaudio matching the PyTorch from the base image
11
+ pip install --extra-index-url https://download.pytorch.org/whl/cu121 torchaudio
12
+
13
+ ## Install all the other dependencies normally
14
+ pip install -r requirements.txt
15
+
16
+ ## force update huggingface_hub (tokenizers 0.14.1 spuriously require and ancient <=0.18 version)
17
+ pip install -U huggingface_hub
18
+
19
+ huggingface-cli download collabora/whisperspeech t2s-small-en+pl.model s2a-q4-tiny-en+pl.model
20
+ huggingface-cli download charactr/vocos-encodec-24khz
21
+
22
+ mkdir -p /root/.cache/torch/hub/checkpoints/
23
+ curl -L -o /root/.cache/torch/hub/checkpoints/encodec_24khz-d7cc33bc.th https://dl.fbaipublicfiles.com/encodec/v0/encodec_24khz-d7cc33bc.th
24
+ mkdir -p /root/.cache/whisper-live/
25
+ curl -L -o /root/.cache/whisper-live/silero_vad.onnx https://github.com/snakers4/silero-vad/raw/master/files/silero_vad.onnx
26
+
27
+ python -c 'from transformers.utils.hub import move_cache; move_cache()'
docker/scripts/setup.sh ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ #!/bin/bash -e
2
+
3
+ ./setup-whisper.sh
4
+ #./setup-mistral.sh
5
+ ./setup-phi-2.sh
6
+ ./setup-whisperfusion.sh
examples/chatbot/html/css/all.min.css ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ /*!
2
+ * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4
+ */
5
+ .fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-bacteria:before{content:"\e059"}.fa-bacterium:before{content:"\e05a"}.fa-bahai:before{content:"\f666"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-box-tissue:before{content:"\e05b"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caravan:before{content:"\f8ff"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-alt:before{content:"\f422"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-disease:before{content:"\f7fa"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-alt:before{content:"\f424"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-faucet:before{content:"\e005"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-medical:before{content:"\e05c"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-holding-water:before{content:"\f4c1"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-sparkles:before{content:"\e05d"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-hands-wash:before{content:"\e05e"}.fa-handshake:before{content:"\f2b5"}.fa-handshake-alt-slash:before{content:"\e05f"}.fa-handshake-slash:before{content:"\e060"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-cowboy:before{content:"\f8c0"}.fa-hat-cowboy-side:before{content:"\f8c1"}.fa-hat-wizard:before{content:"\f6e8"}.fa-hdd:before{content:"\f0a0"}.fa-head-side-cough:before{content:"\e061"}.fa-head-side-cough-slash:before{content:"\e062"}.fa-head-side-mask:before{content:"\e063"}.fa-head-side-virus:before{content:"\e064"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hive:before{content:"\e07f"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hospital-user:before{content:"\f80d"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-house-user:before{content:"\e065"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-ideal:before{content:"\e013"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-innosoft:before{content:"\e080"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-house:before{content:"\e066"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lungs:before{content:"\f604"}.fa-lungs-virus:before{content:"\e067"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microblog:before{content:"\e01a"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse:before{content:"\f8cc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-arrows:before{content:"\e068"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-perbyte:before{content:"\e083"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-plane-slash:before{content:"\e069"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pump-medical:before{content:"\e06a"}.fa-pump-soap:before{content:"\e06b"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-record-vinyl:before{content:"\f8d9"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-rust:before{content:"\e07a"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-shield-virus:before{content:"\e06c"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopify:before{content:"\e057"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sink:before{content:"\e06d"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-soap:before{content:"\e06e"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-stopwatch-20:before{content:"\e06f"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-store-alt-slash:before{content:"\e070"}.fa-store-slash:before{content:"\e071"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swift:before{content:"\f8e1"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-tiktok:before{content:"\e07b"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toilet-paper-slash:before{content:"\e072"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-trailer:before{content:"\e041"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-uncharted:before{content:"\e084"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-users-slash:before{content:"\e073"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-vest:before{content:"\e085"}.fa-vest-patches:before{content:"\e086"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-virus:before{content:"\e074"}.fa-virus-slash:before{content:"\e075"}.fa-viruses:before{content:"\e076"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-watchman-monitoring:before{content:"\e087"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.fab,.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900}
examples/chatbot/html/css/style.css ADDED
@@ -0,0 +1,437 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Import Google font - Poppins */
2
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap');
3
+ *{
4
+ /* margin: 0px;
5
+ padding: 0px; */
6
+ box-sizing: border-box;
7
+ font-family: "Poppins", sans-serif;
8
+ }
9
+ html, body {
10
+ height: 100%;
11
+ }
12
+
13
+ html {
14
+ display: table;
15
+ /* margin: auto; */
16
+ }
17
+
18
+
19
+ body{
20
+ /* display: flex; */
21
+ align-items: center;
22
+ /* justify-content: center; */
23
+ min-height: 100vh;
24
+ background: #EBECF2;
25
+
26
+ display: table-cell;
27
+ vertical-align: middle;
28
+
29
+ margin: 0 !important;
30
+ padding: 0 !important;
31
+
32
+
33
+
34
+ }
35
+
36
+
37
+ .avatar-container {
38
+ text-align: left;
39
+ display: grid;
40
+ grid-template-columns: auto auto 1fr;
41
+ grid-gap: 0px;
42
+ padding-left:0px;
43
+ padding-top: 2px;
44
+ margin-top: 10px;
45
+ }
46
+
47
+ .text-container {
48
+ text-align: left;
49
+ display: grid;
50
+ grid-template-columns: auto 1fr;
51
+ grid-gap: 0px;
52
+ padding-left:0px;
53
+ padding-top: 8px;
54
+ }
55
+
56
+ .llm-timing-container {
57
+ text-align: left;
58
+ display: grid;
59
+ grid-template-columns: auto auto 1fr;
60
+ grid-gap: 4px;
61
+ padding-left:0px;
62
+ padding-top: 8px;
63
+ font-size: 12px;
64
+ }
65
+
66
+ .transcription-timing-container {
67
+ text-align: left;
68
+ display: grid;
69
+ grid-template-columns: auto auto 1fr;
70
+ grid-gap: 4px;
71
+ padding-left:0px;
72
+ padding-top: 8px;
73
+ font-size: 12px;
74
+ }
75
+
76
+ .whisperspeech-timing-container {
77
+ text-align: left;
78
+ display: grid;
79
+ grid-template-columns: auto 1fr;
80
+ grid-gap: 4px;
81
+ padding-left:0px;
82
+ padding-top: 8px;
83
+ font-size: 12px;
84
+ }
85
+
86
+ .whisperspeech-audio-container {
87
+ text-align: left;
88
+ display: grid;
89
+ grid-template-columns: 1fr auto 1fr;
90
+ grid-gap: 4px;
91
+ padding-left:0px;
92
+ padding-top: 8px;
93
+ font-size: 12px;
94
+ }
95
+
96
+ .control-container {
97
+ text-align: left;
98
+ display: grid;
99
+ grid-template-columns: auto auto 20px auto auto auto 1fr;
100
+ grid-gap: 4px;
101
+ padding-left:0px;
102
+ font-size: 12px;
103
+ }
104
+
105
+
106
+ .avatar {
107
+ border-radius: 50%;
108
+ width: 24px;
109
+ float: left;
110
+ }
111
+
112
+ .avatar-name {
113
+ font-size:15px;
114
+ padding-left:4px;
115
+ padding-top:2px
116
+ }
117
+
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
129
+
130
+
131
+
132
+
133
+
134
+ ::selection{
135
+ color: #fff;
136
+ }
137
+ .wrapper{
138
+ width: 430px;
139
+ background: #fff;
140
+ border-radius: 5px;
141
+ padding: 30px;
142
+ box-shadow: 7px 7px 12px rgba(0,0,0,0.05);
143
+ }
144
+ .wrapper header{
145
+ /* color: #6990F2; */
146
+ font-size: 27px;
147
+ font-weight: 600;
148
+ text-align: center;
149
+ }
150
+ .wrapper form{
151
+ height: 167px;
152
+ display: flex;
153
+ cursor: pointer;
154
+ margin: 30px 0;
155
+ align-items: center;
156
+ justify-content: center;
157
+ flex-direction: column;
158
+ border-radius: 5px;
159
+ border: 2px dashed #6990F2;
160
+ background-color: #F7FBFF;
161
+ }
162
+ form :where(i, p){
163
+ /* color: #6990F2; */
164
+ }
165
+ form i{
166
+ font-size: 50px;
167
+ }
168
+ form p{
169
+ margin-top: 15px;
170
+ font-size: 16px;
171
+ }
172
+
173
+ .row {
174
+ border: 0.01em solid lightgray;
175
+ }
176
+
177
+ section .row{
178
+ margin-bottom: 10px;
179
+ background: #E9F0FF;
180
+ list-style: none;
181
+ padding: 15px 20px;
182
+ border-radius: 5px;
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: space-between;
186
+ }
187
+ section .row i{
188
+ /* color: #6990F2; */
189
+ font-size: 30px;
190
+ }
191
+ section .details span{
192
+ font-size: 14px;
193
+ }
194
+ .progress-area .row .content{
195
+ width: 100%;
196
+ margin-left: 15px;
197
+ }
198
+ .progress-area .details{
199
+ display: flex;
200
+ align-items: center;
201
+ margin-bottom: 7px;
202
+ justify-content: space-between;
203
+ }
204
+ .progress-area .content .progress-bar{
205
+ height: 6px;
206
+ width: 100%;
207
+ margin-bottom: 4px;
208
+ background: #fff;
209
+ border-radius: 30px;
210
+ }
211
+ .content .progress-bar .progress{
212
+ height: 100%;
213
+ width: 0%;
214
+ border-radius: inherit;
215
+ }
216
+ .uploaded-area{
217
+ max-height: 232px;
218
+ overflow-y: scroll;
219
+ }
220
+ .uploaded-area.onprogress{
221
+ max-height: 150px;
222
+ }
223
+ .uploaded-area::-webkit-scrollbar{
224
+ width: 0px;
225
+ }
226
+ .uploaded-area .row .content{
227
+ display: flex;
228
+ align-items: center;
229
+ }
230
+ .uploaded-area .row .details{
231
+ display: flex;
232
+ margin-left: 15px;
233
+ flex-direction: column;
234
+ }
235
+
236
+ .uploaded-area .row .details .size{
237
+ color: #404040;
238
+ font-size: 11px;
239
+ }
240
+ .uploaded-area i.fa-check{
241
+ font-size: 16px;
242
+ }
243
+
244
+
245
+ .upload-container-title {
246
+ text-align: left;
247
+ display: grid;
248
+ grid-template-columns: auto auto 1fr;
249
+ grid-gap: 6px;
250
+ padding-left:0px;
251
+ /* background-color: #F8F8F8; */
252
+ padding-top:0px;
253
+ font-weight: 400;
254
+ }
255
+
256
+ .name {
257
+ font-size: 12px;
258
+ text-align: left;
259
+ }
260
+
261
+
262
+ .process-container-chart {
263
+ text-align: left;
264
+ display: grid;
265
+ grid-template-columns: 50% 50%;
266
+ grid-gap: 6px;
267
+ padding-left:0px;
268
+ /* background-color: #F8F8F8; */
269
+ padding-top:0px;
270
+ font-weight: 400;
271
+ }
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+
281
+
282
+
283
+
284
+
285
+ .radial {
286
+ width: 16vh;
287
+ height: 16vh;
288
+ margin: auto;
289
+ position: relative;
290
+ }
291
+ .ring {
292
+ position: absolute;
293
+ top: 0%;
294
+ left: 0%;
295
+ transform: rotateZ(0);
296
+ width: 100%;
297
+ height: 100%;
298
+ color: hsl(40, 100%, 60%);
299
+ }
300
+ .ring:before {
301
+ pointer-events: none;
302
+ content: '';
303
+ border: 1.5vh solid hsla(40, 100%, 60%, 0.25);
304
+ border-radius: 60vh;
305
+ position: absolute;
306
+ top: 0;
307
+ bottom: 0;
308
+ left: 0;
309
+ right: 0;
310
+ }
311
+ .ring .label {
312
+ position: absolute;
313
+ width: 7em;
314
+ text-align: right;
315
+ font-size: 2.025vh;
316
+ font-weight: 300;
317
+ line-height: 1.5vh;
318
+ right: 50%;
319
+ transform: translate3d(-20%, 0, 0);
320
+ text-transform: uppercase;
321
+ letter-spacing: 0.5em;
322
+ z-index: 10;
323
+ color: transparent;
324
+ }
325
+ .dot {
326
+ width: 1.5vh;
327
+ height: 50%;
328
+ position: absolute;
329
+ top: 0;
330
+ left: 50%;
331
+ transform: rotateZ(0deg);
332
+ transform-origin: 0 100%;
333
+ transform-style: preserve-3d;
334
+ }
335
+ .dot:before {
336
+ content: '';
337
+ display: inline-block;
338
+ width: 5.4vh;
339
+ height: 1.5vh;
340
+ border-radius: 100%;
341
+ background: hsl(40, 100%, 60%);
342
+ transform: translate3d(-50%, 0, 0) scale(0);
343
+ opacity: 0;
344
+ transition: transform 0.6s, opacity 0.6s;
345
+ }
346
+ .dot.val:before {
347
+ transform: translate3d(-50%, 0, 0) scale(1);
348
+ opacity: 1;
349
+ }
350
+ .ring:nth-child(4) {
351
+ width: 10%;
352
+ height: 10%;
353
+ top: 45%;
354
+ left: 45%;
355
+ color: hsl(355, 100%, 60%);
356
+ -webkit-animation-delay: 0.75s;
357
+ animation-delay: 0.75s;
358
+ }
359
+ .ring:nth-child(4):before {
360
+ border-color: hsla(355, 100%, 60%, 0.25);
361
+ }
362
+ .ring:nth-child(4) .dot:before {
363
+ background: hsl(355, 100%, 60%);
364
+ }
365
+ .ring:nth-child(3) {
366
+ width: 40%;
367
+ height: 40%;
368
+ top: 30%;
369
+ left: 30%;
370
+ color: hsl(10, 100%, 60%);
371
+ -webkit-animation-delay: 0.5s;
372
+ animation-delay: 0.5s;
373
+ }
374
+ .ring:nth-child(3):before {
375
+ border-color: hsla(10, 100%, 60%, 0.25);
376
+ }
377
+ .ring:nth-child(3) .dot:before {
378
+ background: hsl(10, 100%, 60%);
379
+ }
380
+ .ring:nth-child(2) {
381
+ width: 70%;
382
+ height: 70%;
383
+ top: 15%;
384
+ left: 15%;
385
+ color: hsl(25, 100%, 60%);
386
+ -webkit-animation-delay: 0.25s;
387
+ animation-delay: 0.25s;
388
+ }
389
+ .ring:nth-child(2):before {
390
+ border-color: hsla(25, 100%, 60%, 0.25);
391
+ }
392
+ .ring:nth-child(2) .dot:before {
393
+ background: hsl(25, 100%, 60%);
394
+ }
395
+ @-webkit-keyframes spin {
396
+ to {
397
+ transform: rotateZ(1turn);
398
+ }
399
+ }
400
+ @keyframes spin {
401
+ to {
402
+ transform: rotateZ(1turn);
403
+ }
404
+ }
405
+ .slides {
406
+ opacity: 0.35;
407
+ margin: 5vh 0;
408
+ text-align: center;
409
+ }
410
+ .slides input {
411
+ display: inline-block;
412
+ }
413
+ *,
414
+ * :before,
415
+ * :after {
416
+ box-sizing: border-box;
417
+ -webkit-backface-visibility: hidden;
418
+ backface-visibility: hidden;
419
+ }
420
+
421
+ summary {
422
+ -webkit-touch-callout: none;
423
+ -webkit-user-select: none;
424
+ -khtml-user-select: none;
425
+ -moz-user-select: none;
426
+ -ms-user-select: none;
427
+ user-select: none;
428
+ }
429
+
430
+
431
+ .button-item {
432
+ cursor: pointer;
433
+ }
434
+
435
+ .audio-container {
436
+ margin-top:14px;
437
+ }
examples/chatbot/html/img/0.png ADDED
examples/chatbot/html/img/1.png ADDED
examples/chatbot/html/img/2.png ADDED
examples/chatbot/html/img/COL-logo.png ADDED
examples/chatbot/html/img/Collabora_Logo.svg ADDED
examples/chatbot/html/img/Phi.svg ADDED
examples/chatbot/html/img/microphone-hover.png ADDED
examples/chatbot/html/img/microphone-white.png ADDED
examples/chatbot/html/img/microphone.png ADDED
examples/chatbot/html/img/pause.png ADDED
examples/chatbot/html/img/record.png ADDED
examples/chatbot/html/img/stop.png ADDED
examples/chatbot/html/index.html ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Collabora - WhisperFusion: The Power of WhisperLive, LLM's, and WhisperSpeech</title>
7
+ <link rel="stylesheet" href="css/style.css">
8
+ <link rel="stylesheet" href="css/all.min.css"/>
9
+ </head>
10
+ <body>
11
+ <div style="background-color: white;width:100vw;margin-top:0;">
12
+ <div style="max-width: 500px; margin: 0 auto !important; float: none !important;padding-top:20px;padding-bottom:30px;font-family: 'Poppins', sans-serif;font-weight: 400;">
13
+ <div style="width:150px;padding-top:40px;display:flex;max-width: 500px;">
14
+ <img src="img/Collabora_Logo.svg" \>
15
+ </div>
16
+ <br>
17
+ <h3>WhisperFusion: The Power of WhisperLive, LLM's, and WhisperSpeech</h3>
18
+ <br>
19
+ <p>Using state-of-the-art natural language processing techniques, we implemented WhisperFusion a techonlogy demo that combines live transcriptions, LLM's and text-to-speech, in a low-latency pipeline. For more details about the demo, checkout <a style="color:#6990F2" href="https://github.com/collabora/WhisperFusion">https://github.com/collabora/WhisperFusion</a>.</p>
20
+ </div>
21
+ </div>
22
+ <center>
23
+ <div id="main-wrapper" class="message-wrapper" style="max-width: 500px;"></div>
24
+
25
+ <br><br>
26
+ <div id="control-container" class="control-container" style="width:500px;height:50px;background-color: #5C2983;border-radius: 20px;">
27
+ <div style="margin-top:10px;padding-left:20px">
28
+ <img class="button-item" onclick="startRecording()" onmouseleave='this.src="img/microphone.png"' onmouseover='this.src="img/microphone-hover.png"' style="width:20px;padding-top:4px" src="img/microphone-white.png" \>
29
+ </div>
30
+ <div style="margin-top:10px">
31
+ <img class="button-item" onclick="stopRecording()" id="recording-stop-btn" style="width:20px;display:none;padding-top:4px" src="img/stop.png" \>
32
+ </div>
33
+ <div>
34
+ <div id="instructions-text" style="width:440px;height:40px;border-radius: 14px;color:white;padding:4px;font-size:14px;text-align:center;padding-top:15px">Click the microphone to start</div>
35
+ </div>
36
+ <div style="margin-top:10px">
37
+ <img id="recording-dot" class="avatar" src="img/record.png" style="display:none;padding-top:2px" \>
38
+ </div>
39
+ <div id="recording-line" style="display:none;margin-top:20px;width:280px;height:4px;background-color: #6990F2;border-radius: 2px;padding-top:6px">
40
+ </div>
41
+ <div style="margin-top:2px;padding-left:10px;padding-top:0px">
42
+ <p id="recording-time" style="display:none;">00:00</p>
43
+ </div>
44
+ <div></div>
45
+ </div>
46
+ <br><br>
47
+ </center>
48
+
49
+ </body>
50
+
51
+ <script src="js/main.js"></script>
52
+ </html>
examples/chatbot/html/js/audio-processor.js ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class AudioStreamProcessor extends AudioWorkletProcessor {
2
+ constructor() {
3
+ super();
4
+ this.chunkSize = 4096;
5
+ this.buffer = new Float32Array(this.chunkSize);
6
+ this.bufferPointer = 0;
7
+ }
8
+
9
+ process(inputs, outputs, parameters) {
10
+ const input = inputs[0];
11
+ const output = outputs[0];
12
+
13
+ for (let i = 0; i < input[0].length; i++) {
14
+ this.buffer[this.bufferPointer++] = input[0][i];
15
+
16
+ if (this.bufferPointer >= this.chunkSize) {
17
+
18
+ this.port.postMessage(this.buffer);
19
+ this.bufferPointer = 0;
20
+ }
21
+ }
22
+
23
+ for (let channel = 0; channel < input.length; ++channel) {
24
+ output[channel].set(input[channel]);
25
+ }
26
+
27
+ return true;
28
+ }
29
+ }
30
+
31
+ registerProcessor("audio-stream-processor", AudioStreamProcessor);
examples/chatbot/html/js/main.js ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let websocket_uri = 'ws://localhost:6006';
2
+ let websocket_audio_uri = 'ws://localhost:8888';
3
+
4
+ let bufferSize = 4096,
5
+ AudioContext,
6
+ context,
7
+ processor,
8
+ input,
9
+ websocket;
10
+ var intervalFunction = null;
11
+ var recordingTime = 0;
12
+ var server_state = 0;
13
+ var websocket_audio = null;
14
+ let audioContext_tts = null;
15
+ var you_name = "Marcus"
16
+
17
+ var audioContext = null;
18
+ var audioWorkletNode = null;
19
+ var audio_state = 0;
20
+ var available_transcription_elements = 0;
21
+ var available_llm_elements = 0;
22
+ var available_audio_elements = 0;
23
+ var llm_outputs = [];
24
+ var new_transcription_element_state = true;
25
+ var audio_sources = [];
26
+ var audio_source = null;
27
+
28
+ initWebSocket();
29
+
30
+ const zeroPad = (num, places) => String(num).padStart(places, '0')
31
+
32
+ const generateUUID = () => {
33
+ let dt = new Date().getTime();
34
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
35
+ const r = (dt + Math.random() * 16) % 16 | 0;
36
+ dt = Math.floor(dt / 16);
37
+ return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
38
+ });
39
+ };
40
+
41
+ function recording_timer() {
42
+ recordingTime++;
43
+ document.getElementById("recording-time").innerHTML = zeroPad(parseInt(recordingTime / 60), 2) + ":" + zeroPad(parseInt(recordingTime % 60), 2) + "s";
44
+ }
45
+
46
+ const start_recording = async () => {
47
+ console.log(audioContext)
48
+ try {
49
+ if (audioContext) {
50
+
51
+ await audioContext.resume();
52
+
53
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
54
+
55
+ if (!audioContext) return;
56
+ console.log(audioContext?.state);
57
+
58
+ await audioContext.audioWorklet.addModule("js/audio-processor.js");
59
+
60
+ const source = audioContext.createMediaStreamSource(stream);
61
+ audioWorkletNode = new AudioWorkletNode(audioContext, "audio-stream-processor");
62
+
63
+ audioWorkletNode.port.onmessage = (event) => {
64
+ if (server_state != 1) {
65
+ console.log("server is not ready!!")
66
+ return;
67
+ }
68
+ const audioData = event.data;
69
+ if (websocket && websocket.readyState === WebSocket.OPEN && audio_state == 0) {
70
+ websocket.send(audioData.buffer);
71
+ console.log("send data")
72
+ }
73
+ };
74
+
75
+ source.connect(audioWorkletNode);
76
+ }
77
+ } catch (e) {
78
+ console.log("Error", e);
79
+ }
80
+ };
81
+
82
+ const handleStartRecording = async () => {
83
+ start_recording();
84
+ };
85
+
86
+ const startRecording = async () => {
87
+ document.getElementById("instructions-text").style.display = "none";
88
+ document.getElementById("control-container").style.backgroundColor = "white";
89
+
90
+ AudioContext = window.AudioContext || window.webkitAudioContext;
91
+ audioContext = new AudioContext({ latencyHint: 'interactive', sampleRate: 16000 });
92
+
93
+ audioContext_tts = new AudioContext({ sampleRate: 24000 });
94
+
95
+ document.getElementById("recording-stop-btn").style.display = "block";
96
+ document.getElementById("recording-dot").style.display = "block";
97
+ document.getElementById("recording-line").style.display = "block";
98
+ document.getElementById("recording-time").style.display = "block";
99
+
100
+ intervalFunction = setInterval(recording_timer, 1000);
101
+
102
+ await handleStartRecording();
103
+ };
104
+
105
+ function stopRecording() {
106
+ audio_state = 1;
107
+ clearInterval(intervalFunction);
108
+ }
109
+
110
+ function initWebSocket() {
111
+ websocket_audio = new WebSocket(websocket_audio_uri);
112
+ websocket_audio.binaryType = "arraybuffer";
113
+
114
+ websocket_audio.onopen = function() { }
115
+ websocket_audio.onclose = function(e) { }
116
+ websocket_audio.onmessage = function(e) {
117
+ available_audio_elements++;
118
+
119
+ let float32Array = new Float32Array(e.data);
120
+ let audioBuffer = audioContext_tts.createBuffer(1, float32Array.length, 24000);
121
+ audioBuffer.getChannelData(0).set(float32Array);
122
+
123
+ new_whisper_speech_audio_element("audio-" + available_audio_elements, Math.floor(audioBuffer.duration));
124
+
125
+ audio_sources.push(audioBuffer);
126
+
127
+ audio_source = audioContext_tts.createBufferSource();
128
+ audio_source.buffer = audioBuffer;
129
+ audio_source.connect(audioContext_tts.destination);
130
+ audio_source.start();
131
+
132
+ window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
133
+ }
134
+
135
+ websocket = new WebSocket(websocket_uri);
136
+ websocket.binaryType = "arraybuffer";
137
+
138
+ console.log("Websocket created.");
139
+
140
+ websocket.onopen = function() {
141
+ console.log("Connected to server.");
142
+
143
+ websocket.send(JSON.stringify({
144
+ uid: generateUUID(),
145
+ multilingual: false,
146
+ language: "en",
147
+ task: "transcribe"
148
+ }));
149
+ }
150
+
151
+ websocket.onclose = function(e) {
152
+ console.log("Connection closed (" + e.code + ").");
153
+ }
154
+
155
+ websocket.onmessage = function(e) {
156
+ var data = JSON.parse(e.data);
157
+
158
+ if ("message" in data) {
159
+ if (data["message"] == "SERVER_READY") {
160
+ server_state = 1;
161
+ }
162
+ } else if ("segments" in data) {
163
+ if (new_transcription_element_state) {
164
+ available_transcription_elements = available_transcription_elements + 1;
165
+
166
+ var img_src = "0.png";
167
+ if (you_name.toLowerCase() == "marcus") {
168
+ you_name = "Marcus";
169
+ img_src = "0.png";
170
+ } else if (you_name.toLowerCase() == "vineet") {
171
+ you_name = "Vineet";
172
+ img_src = "1.png";
173
+ } else if (you_name.toLowerCase() == "jakub") {
174
+ you_name = "Jakub";
175
+ img_src = "2.png";
176
+ }
177
+
178
+ new_transcription_element(you_name, img_src);
179
+ new_text_element("<p>" + data["segments"][0].text + "</p>", "transcription-" + available_transcription_elements);
180
+ new_transcription_element_state = false;
181
+ }
182
+ document.getElementById("transcription-" + available_transcription_elements).innerHTML = "<p>" + data["segments"][0].text + "</p>";
183
+
184
+ if (data["eos"] == true) {
185
+ new_transcription_element_state = true;
186
+ }
187
+ } else if ("llm_output" in data) {
188
+ new_transcription_element("Phi-2", "Phi.svg");
189
+ new_text_element("<p>" + data["llm_output"][0] + "</p>", "llm-" + available_transcription_elements);
190
+ }
191
+
192
+ window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
193
+ }
194
+ }
195
+
196
+ function new_transcription_element(speaker_name, speaker_avatar) {
197
+ var avatar_container = document.createElement("div");
198
+ avatar_container.className = "avatar-container";
199
+
200
+ var avatar_img = document.createElement("div");
201
+ avatar_img.innerHTML = "<img class='avatar' src='img/" + speaker_avatar + "' \>";
202
+
203
+ var avatar_name = document.createElement("div");
204
+ avatar_name.className = "avatar-name";
205
+ avatar_name.innerHTML = speaker_name;
206
+
207
+ var dummy_element = document.createElement("div");
208
+
209
+ avatar_container.appendChild(avatar_img);
210
+ avatar_container.appendChild(avatar_name);
211
+ avatar_container.appendChild(dummy_element);
212
+
213
+ document.getElementById("main-wrapper").appendChild(avatar_container);
214
+ }
215
+
216
+ function new_text_element(text, id) {
217
+ var text_container = document.createElement("div");
218
+ text_container.className = "text-container";
219
+ text_container.style.maxWidth = "500px";
220
+
221
+ var text_element = document.createElement("div");
222
+ text_element.id = id;
223
+ text_element.innerHTML = "<p>" + text + "</p>";
224
+
225
+ var dummy_element = document.createElement("div");
226
+
227
+ text_container.appendChild(text_element);
228
+ text_container.appendChild(dummy_element);
229
+
230
+ document.getElementById("main-wrapper").appendChild(text_container);
231
+ }
232
+
233
+ function new_transcription_time_element(time) {
234
+ var text_container = document.createElement("div");
235
+ text_container.className = "transcription-timing-container";
236
+ text_container.style.maxWidth = "500px";
237
+
238
+ var text_element = document.createElement("div");
239
+ text_element.innerHTML = "<span>WhisperLive - Transcription time: " + time + "ms</span>";
240
+
241
+ var dummy_element = document.createElement("div");
242
+
243
+ text_container.appendChild(text_element);
244
+ text_container.appendChild(dummy_element);
245
+
246
+ document.getElementById("main-wrapper").appendChild(text_container);
247
+ }
248
+
249
+ function new_llm_time_element(time) {
250
+ var text_container = document.createElement("div");
251
+ text_container.className = "llm-timing-container";
252
+ text_container.style.maxWidth = "500px";
253
+
254
+ var first_response_text_element = document.createElement("div");
255
+ first_response_text_element.innerHTML = "<span>Phi-2 first response time: " + time + "ms</span>";
256
+
257
+ var complete_response_text_element = document.createElement("div");
258
+ complete_response_text_element.innerHTML = "<span>Phi-2 complete response time: " + time + "ms</span>";
259
+
260
+ var dummy_element = document.createElement("div");
261
+
262
+ text_container.appendChild(first_response_text_element);
263
+ text_container.appendChild(complete_response_text_element);
264
+ text_container.appendChild(dummy_element);
265
+
266
+ document.getElementById("main-wrapper").appendChild(text_container);
267
+ }
268
+
269
+ function new_whisper_speech_audio_element(id, duration) {
270
+ var audio_container = document.createElement("div");
271
+ audio_container.className = "whisperspeech-audio-container";
272
+ audio_container.style.maxWidth = "500px";
273
+
274
+ var audio_div_element = document.createElement("div");
275
+ var audio_element = document.createElement("audio");
276
+ audio_element.style.paddingTop = "20px";
277
+
278
+ if (duration > 10)
279
+ duration = 10;
280
+ audio_element.src = "static/" + duration + ".mp3";
281
+
282
+ audio_element.id = id;
283
+ audio_element.onplay = function() {
284
+ console.log(this.id)
285
+ var id = this.id.split("-")[1] - 1;
286
+
287
+ if (audio_source) {
288
+ audio_source.disconnect();
289
+ }
290
+
291
+ audio_source = audioContext_tts.createBufferSource();
292
+ audio_source.buffer = audio_sources[id];
293
+ audio_source.connect(audioContext_tts.destination);
294
+ audio_source.start()
295
+ };
296
+ audio_element.onpause = function() {
297
+ this.currentTime = 0;
298
+ console.log(this.id)
299
+ var id = this.id.split("-")[1] - 1;
300
+ if (audio_source) {
301
+ audio_source.stop();
302
+ }
303
+ };
304
+ audio_element.controls = true;
305
+
306
+ audio_div_element.appendChild(audio_element);
307
+
308
+ var dummy_element_a = document.createElement("div");
309
+ var dummy_element_b = document.createElement("div");
310
+
311
+ audio_container.appendChild(dummy_element_a);
312
+ audio_container.appendChild(audio_div_element);
313
+ audio_container.appendChild(dummy_element_b);
314
+
315
+ document.getElementById("main-wrapper").appendChild(audio_container);
316
+ }
317
+
318
+ function new_whisper_speech_time_element(time) {
319
+ var text_container = document.createElement("div");
320
+ text_container.className = "whisperspeech-timing-container";
321
+ text_container.style.maxWidth = "500px";
322
+
323
+ var text_element = document.createElement("div");
324
+ text_element.innerHTML = "<span>WhisperSpeech response time: " + time + "ms</span>";
325
+
326
+ var dummy_element = document.createElement("div");
327
+
328
+ text_container.appendChild(text_element);
329
+ text_container.appendChild(dummy_element);
330
+
331
+ document.getElementById("main-wrapper").appendChild(text_container);
332
+ }
333
+
334
+ document.addEventListener('DOMContentLoaded', function() {
335
+ const queryString = window.location.search;
336
+ const urlParams = new URLSearchParams(queryString);
337
+ if (urlParams.has('name')) {
338
+ you_name = urlParams.get('name')
339
+ }
340
+ }, false);
examples/chatbot/html/static/0.mp3 ADDED
Binary file (227 Bytes). View file
 
examples/chatbot/html/static/1.mp3 ADDED
Binary file (4.39 kB). View file
 
examples/chatbot/html/static/10.mp3 ADDED
Binary file (36.2 kB). View file
 
examples/chatbot/html/static/2.mp3 ADDED
Binary file (8.34 kB). View file
 
examples/chatbot/html/static/3.mp3 ADDED
Binary file (12.3 kB). View file
 
examples/chatbot/html/static/4.mp3 ADDED
Binary file (16.3 kB). View file
 
examples/chatbot/html/static/5.mp3 ADDED
Binary file (20.3 kB). View file
 
examples/chatbot/html/static/6.mp3 ADDED
Binary file (24.3 kB). View file