Spaces:
Sleeping
Sleeping
adarshadda
commited on
Commit
•
b0dd51d
1
Parent(s):
d3fbd97
initial commit
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- Dockerfile +43 -0
- LICENSE +201 -0
- app/.DS_Store +0 -0
- app/__pycache__/app.cpython-311.pyc +0 -0
- app/__pycache__/emotion_data.cpython-311.pyc +0 -0
- app/app.py +148 -0
- app/emotion_data.py +170 -0
- app/modules/.DS_Store +0 -0
- app/modules/__init__.py +34 -0
- app/modules/__pycache__/__init__.cpython-310.pyc +0 -0
- app/modules/__pycache__/__init__.cpython-311.pyc +0 -0
- app/modules/__pycache__/__init__.cpython-312.pyc +0 -0
- app/modules/__pycache__/__init__.cpython-38.pyc +0 -0
- app/modules/__pycache__/__init__.cpython-39.pyc +0 -0
- app/modules/__pycache__/utils.cpython-310(1).pyc +0 -0
- app/modules/__pycache__/utils.cpython-310.pyc +0 -0
- app/modules/__pycache__/utils.cpython-311.pyc +0 -0
- app/modules/__pycache__/utils.cpython-312.pyc +0 -0
- app/modules/__pycache__/utils.cpython-38.pyc +0 -0
- app/modules/__pycache__/utils.cpython-39.pyc +0 -0
- app/modules/audio/__init__.py +18 -0
- app/modules/audio/__pycache__/__init__.cpython-38.pyc +0 -0
- app/modules/emotion/__init__.py +24 -0
- app/modules/emotion/__pycache__/__init__.cpython-310.pyc +0 -0
- app/modules/emotion/__pycache__/__init__.cpython-311.pyc +0 -0
- app/modules/emotion/__pycache__/__init__.cpython-312.pyc +0 -0
- app/modules/emotion/__pycache__/__init__.cpython-38.pyc +0 -0
- app/modules/emotion/__pycache__/__init__.cpython-39.pyc +0 -0
- app/modules/transcription/__init__.py +30 -0
- app/modules/transcription/__pycache__/__init__.cpython-311.pyc +0 -0
- app/modules/transcription/__pycache__/__init__.cpython-312.pyc +0 -0
- app/modules/transcription/__pycache__/__init__.cpython-38.pyc +0 -0
- app/modules/utils.py +20 -0
- app/static/audio_main.js +159 -0
- app/static/audio_to_text.css +135 -0
- app/static/audiodisplay.js +19 -0
- app/static/dem.css +53 -0
- app/static/demo.css +40 -0
- app/static/distract.js +165 -0
- app/static/distractandchange.css +29 -0
- app/static/energy.js +163 -0
- app/static/engage.js +165 -0
- app/static/footer.js +8 -0
- app/static/footer_file.css +48 -0
- app/static/header.js +8 -0
- app/static/header_file.css +77 -0
- app/static/login.css +39 -0
- app/static/main.css +109 -0
- app/static/main.js +202 -0
- app/static/recorder.js +99 -0
Dockerfile
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.8.10-slim
|
2 |
+
|
3 |
+
RUN export DEBIAN_FRONTEND=noninteractive \
|
4 |
+
&& apt-get -qq update \
|
5 |
+
&& apt install software-properties-common -y \
|
6 |
+
&& apt-get install build-essential -y \
|
7 |
+
&& python3 --version \
|
8 |
+
&& apt update \
|
9 |
+
&& apt install ffmpeg -y \
|
10 |
+
&& rm -rf /var/lib/apt/lists/* \
|
11 |
+
&& apt update \
|
12 |
+
&& apt install nginx -y
|
13 |
+
|
14 |
+
### Set up user with permissions
|
15 |
+
# Set up a new user named "user" with user ID 1000
|
16 |
+
RUN useradd -m -u 1000 user
|
17 |
+
|
18 |
+
# Switch to the "user" user
|
19 |
+
USER user
|
20 |
+
|
21 |
+
# Set home to the user's home directory
|
22 |
+
ENV HOME=/home/user \
|
23 |
+
PATH=/home/user/.local/bin:$PATH
|
24 |
+
|
25 |
+
# Set the working directory to the user's home directory
|
26 |
+
WORKDIR $HOME/app
|
27 |
+
|
28 |
+
### Set up app-specific content
|
29 |
+
COPY requirements.txt requirements.txt
|
30 |
+
RUN pip3 install -r requirements.txt
|
31 |
+
RUN pip3 install gunicorn
|
32 |
+
|
33 |
+
# Copy the current directory contents into the container at $HOME/app setting the owner to the user
|
34 |
+
COPY --chown=user app $HOME/app
|
35 |
+
|
36 |
+
### Update permissions for the app
|
37 |
+
USER root
|
38 |
+
RUN chmod 755 ~/app/*
|
39 |
+
USER user
|
40 |
+
|
41 |
+
# RUN python3 server.py
|
42 |
+
ENTRYPOINT ["python3", "app.py"]
|
43 |
+
# ENTRYPOINT ["gunicorn", "--timeout 600", "wsgi:app"]
|
LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Apache License
|
2 |
+
Version 2.0, January 2004
|
3 |
+
http://www.apache.org/licenses/
|
4 |
+
|
5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6 |
+
|
7 |
+
1. Definitions.
|
8 |
+
|
9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
11 |
+
|
12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13 |
+
the copyright owner that is granting the License.
|
14 |
+
|
15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
16 |
+
other entities that control, are controlled by, or are under common
|
17 |
+
control with that entity. For the purposes of this definition,
|
18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
19 |
+
direction or management of such entity, whether by contract or
|
20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22 |
+
|
23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24 |
+
exercising permissions granted by this License.
|
25 |
+
|
26 |
+
"Source" form shall mean the preferred form for making modifications,
|
27 |
+
including but not limited to software source code, documentation
|
28 |
+
source, and configuration files.
|
29 |
+
|
30 |
+
"Object" form shall mean any form resulting from mechanical
|
31 |
+
transformation or translation of a Source form, including but
|
32 |
+
not limited to compiled object code, generated documentation,
|
33 |
+
and conversions to other media types.
|
34 |
+
|
35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
36 |
+
Object form, made available under the License, as indicated by a
|
37 |
+
copyright notice that is included in or attached to the work
|
38 |
+
(an example is provided in the Appendix below).
|
39 |
+
|
40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41 |
+
form, that is based on (or derived from) the Work and for which the
|
42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
44 |
+
of this License, Derivative Works shall not include works that remain
|
45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46 |
+
the Work and Derivative Works thereof.
|
47 |
+
|
48 |
+
"Contribution" shall mean any work of authorship, including
|
49 |
+
the original version of the Work and any modifications or additions
|
50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
54 |
+
means any form of electronic, verbal, or written communication sent
|
55 |
+
to the Licensor or its representatives, including but not limited to
|
56 |
+
communication on electronic mailing lists, source code control systems,
|
57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
59 |
+
excluding communication that is conspicuously marked or otherwise
|
60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
61 |
+
|
62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
64 |
+
subsequently incorporated within the Work.
|
65 |
+
|
66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
71 |
+
Work and such Derivative Works in Source or Object form.
|
72 |
+
|
73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76 |
+
(except as stated in this section) patent license to make, have made,
|
77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78 |
+
where such license applies only to those patent claims licensable
|
79 |
+
by such Contributor that are necessarily infringed by their
|
80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
82 |
+
institute patent litigation against any entity (including a
|
83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84 |
+
or a Contribution incorporated within the Work constitutes direct
|
85 |
+
or contributory patent infringement, then any patent licenses
|
86 |
+
granted to You under this License for that Work shall terminate
|
87 |
+
as of the date such litigation is filed.
|
88 |
+
|
89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
90 |
+
Work or Derivative Works thereof in any medium, with or without
|
91 |
+
modifications, and in Source or Object form, provided that You
|
92 |
+
meet the following conditions:
|
93 |
+
|
94 |
+
(a) You must give any other recipients of the Work or
|
95 |
+
Derivative Works a copy of this License; and
|
96 |
+
|
97 |
+
(b) You must cause any modified files to carry prominent notices
|
98 |
+
stating that You changed the files; and
|
99 |
+
|
100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
101 |
+
that You distribute, all copyright, patent, trademark, and
|
102 |
+
attribution notices from the Source form of the Work,
|
103 |
+
excluding those notices that do not pertain to any part of
|
104 |
+
the Derivative Works; and
|
105 |
+
|
106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107 |
+
distribution, then any Derivative Works that You distribute must
|
108 |
+
include a readable copy of the attribution notices contained
|
109 |
+
within such NOTICE file, excluding those notices that do not
|
110 |
+
pertain to any part of the Derivative Works, in at least one
|
111 |
+
of the following places: within a NOTICE text file distributed
|
112 |
+
as part of the Derivative Works; within the Source form or
|
113 |
+
documentation, if provided along with the Derivative Works; or,
|
114 |
+
within a display generated by the Derivative Works, if and
|
115 |
+
wherever such third-party notices normally appear. The contents
|
116 |
+
of the NOTICE file are for informational purposes only and
|
117 |
+
do not modify the License. You may add Your own attribution
|
118 |
+
notices within Derivative Works that You distribute, alongside
|
119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
120 |
+
that such additional attribution notices cannot be construed
|
121 |
+
as modifying the License.
|
122 |
+
|
123 |
+
You may add Your own copyright statement to Your modifications and
|
124 |
+
may provide additional or different license terms and conditions
|
125 |
+
for use, reproduction, or distribution of Your modifications, or
|
126 |
+
for any such Derivative Works as a whole, provided Your use,
|
127 |
+
reproduction, and distribution of the Work otherwise complies with
|
128 |
+
the conditions stated in this License.
|
129 |
+
|
130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
132 |
+
by You to the Licensor shall be under the terms and conditions of
|
133 |
+
this License, without any additional terms or conditions.
|
134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135 |
+
the terms of any separate license agreement you may have executed
|
136 |
+
with Licensor regarding such Contributions.
|
137 |
+
|
138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
140 |
+
except as required for reasonable and customary use in describing the
|
141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
142 |
+
|
143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144 |
+
agreed to in writing, Licensor provides the Work (and each
|
145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147 |
+
implied, including, without limitation, any warranties or conditions
|
148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150 |
+
appropriateness of using or redistributing the Work and assume any
|
151 |
+
risks associated with Your exercise of permissions under this License.
|
152 |
+
|
153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
154 |
+
whether in tort (including negligence), contract, or otherwise,
|
155 |
+
unless required by applicable law (such as deliberate and grossly
|
156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157 |
+
liable to You for damages, including any direct, indirect, special,
|
158 |
+
incidental, or consequential damages of any character arising as a
|
159 |
+
result of this License or out of the use or inability to use the
|
160 |
+
Work (including but not limited to damages for loss of goodwill,
|
161 |
+
work stoppage, computer failure or malfunction, or any and all
|
162 |
+
other commercial damages or losses), even if such Contributor
|
163 |
+
has been advised of the possibility of such damages.
|
164 |
+
|
165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168 |
+
or other liability obligations and/or rights consistent with this
|
169 |
+
License. However, in accepting such obligations, You may act only
|
170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171 |
+
of any other Contributor, and only if You agree to indemnify,
|
172 |
+
defend, and hold each Contributor harmless for any liability
|
173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
174 |
+
of your accepting any such warranty or additional liability.
|
175 |
+
|
176 |
+
END OF TERMS AND CONDITIONS
|
177 |
+
|
178 |
+
APPENDIX: How to apply the Apache License to your work.
|
179 |
+
|
180 |
+
To apply the Apache License to your work, attach the following
|
181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182 |
+
replaced with your own identifying information. (Don't include
|
183 |
+
the brackets!) The text should be enclosed in the appropriate
|
184 |
+
comment syntax for the file format. We also recommend that a
|
185 |
+
file or class name and description of purpose be included on the
|
186 |
+
same "printed page" as the copyright notice for easier
|
187 |
+
identification within third-party archives.
|
188 |
+
|
189 |
+
Copyright [yyyy] [name of copyright owner]
|
190 |
+
|
191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192 |
+
you may not use this file except in compliance with the License.
|
193 |
+
You may obtain a copy of the License at
|
194 |
+
|
195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
196 |
+
|
197 |
+
Unless required by applicable law or agreed to in writing, software
|
198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200 |
+
See the License for the specific language governing permissions and
|
201 |
+
limitations under the License.
|
app/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
app/__pycache__/app.cpython-311.pyc
ADDED
Binary file (7 kB). View file
|
|
app/__pycache__/emotion_data.cpython-311.pyc
ADDED
Binary file (4.89 kB). View file
|
|
app/app.py
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import uuid
|
3 |
+
import logging
|
4 |
+
from flask import Flask, flash, render_template, request, jsonify, url_for
|
5 |
+
from flask.templating import TemplateNotFound
|
6 |
+
from flask_cors import CORS
|
7 |
+
#from modules import Module
|
8 |
+
|
9 |
+
#model = Module()
|
10 |
+
|
11 |
+
|
12 |
+
app = Flask(__name__)
|
13 |
+
CORS(app)
|
14 |
+
|
15 |
+
app.secret_key = "Testing"
|
16 |
+
app.config['STATIC_FOLDER'] = 'static'
|
17 |
+
|
18 |
+
emotion_categories = {
|
19 |
+
"admiration": "soothieanduplift",
|
20 |
+
"amusement": "soothieanduplift",
|
21 |
+
"anger": "distractandchange",
|
22 |
+
"annoyance": "distractandchange",
|
23 |
+
"approval": "soothieanduplift",
|
24 |
+
"caring": "soothieanduplift",
|
25 |
+
"confusion": "engageandexplore",
|
26 |
+
"curiosity": "engageandexplore",
|
27 |
+
"desire": "engageandexplore",
|
28 |
+
"disappointment": "reflectiveandunderstand",
|
29 |
+
"disapproval": "distractandchange",
|
30 |
+
"disgust": "distractandchange",
|
31 |
+
"embarrassment": "distractandchange",
|
32 |
+
"excitement": "energeticandmotivate",
|
33 |
+
"fear": "distractandchange",
|
34 |
+
"gratitude": "soothieanduplift",
|
35 |
+
"grief": "reflectiveandunderstand",
|
36 |
+
"joy": "energeticandmotivate",
|
37 |
+
"love": "soothieanduplift",
|
38 |
+
"nervousness": "distractandchange",
|
39 |
+
"optimism": "energeticandmotivate",
|
40 |
+
"pride": "energeticandmotivate",
|
41 |
+
"realization": "engageandexplore",
|
42 |
+
"relief": "soothieanduplift",
|
43 |
+
"remorse": "reflectiveandunderstand",
|
44 |
+
"sadness": "reflectiveandunderstand",
|
45 |
+
"surprise": "engageandexplore",
|
46 |
+
"neutral": "soothieanduplift"
|
47 |
+
}
|
48 |
+
|
49 |
+
@app.route('/')
|
50 |
+
def index():
|
51 |
+
return render_template('index.html')
|
52 |
+
|
53 |
+
@app.route('/audio_to_text/')
|
54 |
+
def audio_to_text():
|
55 |
+
return render_template('audio_to_text.html')
|
56 |
+
|
57 |
+
@app.route('/audio', methods=['POST', 'GET'])
|
58 |
+
def audio():
|
59 |
+
if request.method == 'POST':
|
60 |
+
try:
|
61 |
+
output_file = f"./tmp/{uuid.uuid4()}.wav"
|
62 |
+
open(output_file, 'wb').write(request.data)
|
63 |
+
text, emotion = model.predict(audio_path=output_file)
|
64 |
+
os.remove(output_file)
|
65 |
+
|
66 |
+
predicted_category = emotion_categories.get(emotion, "defaultcategory")
|
67 |
+
return jsonify({
|
68 |
+
"url": url_for(predicted_category, text=text, emotion=emotion)
|
69 |
+
})
|
70 |
+
print("Predicted Category:", predicted_category) # Print predicted category
|
71 |
+
print("Text:", text) # Print predicted text
|
72 |
+
print("Emotion:", emotion) # Print predicted emotion
|
73 |
+
logging.info("Predicted Category: %s", predicted_category)
|
74 |
+
logging.info("Text: %s", text)
|
75 |
+
logging.info("Emotion: %s", emotion)
|
76 |
+
return jsonify({"url": url_for(predicted_category)})
|
77 |
+
|
78 |
+
except (FileNotFoundError, TemplateNotFound) as e:
|
79 |
+
logging.error(e)
|
80 |
+
return jsonify({"error": "Template file not found."}), 404
|
81 |
+
|
82 |
+
except Exception as e:
|
83 |
+
logging.error(e)
|
84 |
+
return jsonify({"error": "An error occurred"}), 500
|
85 |
+
|
86 |
+
elif request.method == 'GET':
|
87 |
+
return jsonify({"message": "This route only accepts POST requests."}), 405
|
88 |
+
|
89 |
+
|
90 |
+
@app.route('/reflectiveandunderstand', methods=['GET'])
|
91 |
+
def reflectiveandunderstand():
|
92 |
+
text = request.args.get('text', '') # Get predicted text
|
93 |
+
emotion = request.args.get('emotion', '') # Get predicted emotion
|
94 |
+
if emotion in emotion_data:
|
95 |
+
emotionInfo = emotion_data[emotion]
|
96 |
+
return render_template('reflectiveandunderstand.html', text=text, emotion=emotion, emotionInfo=emotionInfo)
|
97 |
+
else:
|
98 |
+
return jsonify({"error": "Emotion not found"}), 404
|
99 |
+
|
100 |
+
@app.route('/distractandchange', methods=['GET'])
|
101 |
+
def distractandchange():
|
102 |
+
text = request.args.get('text', '') # Get predicted text
|
103 |
+
emotion = request.args.get('emotion', '') # Get predicted emotion
|
104 |
+
if emotion in emotion_data:
|
105 |
+
emotionInfo = emotion_data[emotion]
|
106 |
+
return render_template('distractandchange.html', text=text, emotion=emotion, emotionInfo=emotionInfo)
|
107 |
+
else:
|
108 |
+
return jsonify({"error": "Emotion not found"}), [email protected]('/energeticandmotivate', methods=['GET'])
|
109 |
+
|
110 |
+
def energeticandmotivate():
|
111 |
+
text = request.args.get('text', '') # Get predicted text
|
112 |
+
emotion = request.args.get('emotion', '') # Get predicted emotion
|
113 |
+
if emotion in emotion_data:
|
114 |
+
emotionInfo = emotion_data[emotion]
|
115 |
+
return render_template('energeticandmotivate.html', text=text, emotion=emotion, emotionInfo=emotionInfo)
|
116 |
+
else:
|
117 |
+
return jsonify({"error": "Emotion not found"}), [email protected]('/energeticandmotivate', methods=['GET'])
|
118 |
+
|
119 |
+
@app.route('/engageandexplore', methods=['GET'])
|
120 |
+
def engageandexplore():
|
121 |
+
text = request.args.get('text', '') # Get predicted text
|
122 |
+
emotion = request.args.get('emotion', '') # Get predicted emotion
|
123 |
+
if emotion in emotion_data:
|
124 |
+
emotionInfo = emotion_data[emotion]
|
125 |
+
return render_template('engageandexplore.html', text=text, emotion=emotion, emotionInfo=emotionInfo)
|
126 |
+
else:
|
127 |
+
return jsonify({"error": "Emotion not found"}), [email protected]('/energeticandmotivate', methods=['GET'])
|
128 |
+
|
129 |
+
# Add more routes as needed, mirroring your category names
|
130 |
+
@app.route('/soothieanduplift', methods=['GET'])
|
131 |
+
def soothieanduplift():
|
132 |
+
text = request.args.get('text', '') # Get predicted text
|
133 |
+
emotion = request.args.get('emotion', '') # Get predicted emotion
|
134 |
+
if emotion in emotion_data:
|
135 |
+
emotionInfo = emotion_data[emotion]
|
136 |
+
return render_template('soothieanduplift.html', text=text, emotion=emotion, emotionInfo=emotionInfo)
|
137 |
+
else:
|
138 |
+
return jsonify({"error": "Emotion not found"}), [email protected]('/energeticandmotivate', methods=['GET'])
|
139 |
+
|
140 |
+
# Add more routes as needed, mirroring your category names
|
141 |
+
|
142 |
+
|
143 |
+
|
144 |
+
if __name__ == "__main__":
|
145 |
+
# Configure logging for Hugging Face environment
|
146 |
+
logging.basicConfig(level=logging.DEBUG)
|
147 |
+
|
148 |
+
app.run(debug=True, port=7860, host='0.0.0.0')
|
app/emotion_data.py
ADDED
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
emotion_data = {
|
2 |
+
"admiration": {
|
3 |
+
'heading': "Time to appreciate the beauty around you!",
|
4 |
+
'info': "We've picked songs that uplift your mood and inspire feelings of wonder.",
|
5 |
+
'category': "soothieanduplift",
|
6 |
+
'class': "emotion-info emotion-heading"
|
7 |
+
},
|
8 |
+
"amusement": {
|
9 |
+
'heading': "Let's have some fun! Get ready to laugh and lighten up.",
|
10 |
+
'info': "This playlist features playful and lighthearted music to boost your mood.",
|
11 |
+
'category': "soothieanduplift",
|
12 |
+
'class': "emotion-info emotion-heading"
|
13 |
+
},
|
14 |
+
"anger": {
|
15 |
+
'heading': "Time to cool off!",
|
16 |
+
'info': "Here are some tracks to help you release anger and find peace.",
|
17 |
+
'category': "distractandchange",
|
18 |
+
'class': "emotion-info emotion-heading"
|
19 |
+
},
|
20 |
+
"annoyance": {
|
21 |
+
'heading': "Feeling annoyed? Let's turn it around!",
|
22 |
+
'info': "Listen to these tunes to shift your mood and find some relief.",
|
23 |
+
'category': "distractandchange",
|
24 |
+
'class': "emotion-info emotion-heading"
|
25 |
+
},
|
26 |
+
"approval": {
|
27 |
+
'heading': "Feel appreciated and acknowledged!",
|
28 |
+
'info': "Enjoy these tracks that celebrate approval and acceptance.",
|
29 |
+
'category': "soothieanduplift",
|
30 |
+
'class': "emotion-info emotion-heading"
|
31 |
+
},
|
32 |
+
"caring": {
|
33 |
+
'heading': "Embrace feelings of care and compassion.",
|
34 |
+
'info': "This playlist is all about fostering a sense of warmth and empathy.",
|
35 |
+
'category': "soothieanduplift",
|
36 |
+
'class': "emotion-info emotion-heading"
|
37 |
+
},
|
38 |
+
"confusion": {
|
39 |
+
'heading': "Embrace the confusion and explore!",
|
40 |
+
'info': "Dive into these tracks to embrace curiosity and explore new perspectives.",
|
41 |
+
'category': "engageandexplore",
|
42 |
+
'class': "emotion-info emotion-heading"
|
43 |
+
},
|
44 |
+
"curiosity": {
|
45 |
+
'heading': "Fuel your curiosity with these tunes!",
|
46 |
+
'info': "Feed your curiosity and thirst for knowledge with this eclectic playlist.",
|
47 |
+
'category': "engageandexplore",
|
48 |
+
'class': "emotion-info emotion-heading"
|
49 |
+
},
|
50 |
+
"desire": {
|
51 |
+
'heading': "Embrace your desires and passions!",
|
52 |
+
'info': "Indulge in these tracks that ignite feelings of longing and passion.",
|
53 |
+
'category': "engageandexplore",
|
54 |
+
'class': "emotion-info emotion-heading"
|
55 |
+
},
|
56 |
+
"disappointment": {
|
57 |
+
'heading': "Feeling disappointed? You're not alone.",
|
58 |
+
'info': "Reflect and understand with these songs that capture the essence of disappointment.",
|
59 |
+
'category': "reflectiveandunderstand",
|
60 |
+
'class': "emotion-info emotion-heading"
|
61 |
+
},
|
62 |
+
"disapproval": {
|
63 |
+
'heading': "Shake off disapproval and find your groove.",
|
64 |
+
'info': "Listen to these tunes to uplift your spirits and brush off negativity.",
|
65 |
+
'category': "distractandchange",
|
66 |
+
'class': "emotion-info emotion-heading"
|
67 |
+
},
|
68 |
+
"disgust": {
|
69 |
+
'heading': "Time to cleanse your palate!",
|
70 |
+
'info': "Find solace in these tracks that help you move past feelings of disgust.",
|
71 |
+
'category': "distractandchange",
|
72 |
+
'class': "emotion-info emotion-heading"
|
73 |
+
},
|
74 |
+
"embarrassment": {
|
75 |
+
'heading': "Embrace the embarrassment and move forward!",
|
76 |
+
'info': "Listen to these tunes to shake off embarrassment and regain confidence.",
|
77 |
+
'category': "distractandchange",
|
78 |
+
'class': "emotion-info emotion-heading"
|
79 |
+
},
|
80 |
+
"excitement": {
|
81 |
+
'heading': "Get ready to be pumped up!",
|
82 |
+
'info': "Feel the energy with these high-octane tracks that fuel excitement.",
|
83 |
+
'category': "energeticandmotivate",
|
84 |
+
'class': "emotion-info emotion-heading"
|
85 |
+
},
|
86 |
+
"fear": {
|
87 |
+
'heading': "Facing fear head-on!",
|
88 |
+
'info': "Conquer your fears with these empowering tracks that inspire courage.",
|
89 |
+
'category': "distractandchange",
|
90 |
+
'class': "emotion-info emotion-heading"
|
91 |
+
},
|
92 |
+
"gratitude": {
|
93 |
+
'heading': "Feel grateful and blessed!",
|
94 |
+
'info': "Express gratitude with these heartfelt tunes that inspire thankfulness.",
|
95 |
+
'category': "soothieanduplift",
|
96 |
+
'class': "emotion-info emotion-heading"
|
97 |
+
},
|
98 |
+
"grief": {
|
99 |
+
'heading': "Navigating through grief and loss.",
|
100 |
+
'info': "Reflect and understand with these poignant songs that capture the essence of grief.",
|
101 |
+
'category': "reflectiveandunderstand",
|
102 |
+
'class': "emotion-info emotion-heading"
|
103 |
+
},
|
104 |
+
"joy": {
|
105 |
+
'heading': "Let joy fill your heart!",
|
106 |
+
'info': "Experience pure bliss with these uplifting tracks that radiate joy.",
|
107 |
+
'category': "energeticandmotivate",
|
108 |
+
'class': "emotion-info emotion-heading"
|
109 |
+
},
|
110 |
+
"love": {
|
111 |
+
'heading': "Celebrate love in all its forms!",
|
112 |
+
'info': "Get lost in these romantic tunes that celebrate the beauty of love.",
|
113 |
+
'category': "soothieanduplift",
|
114 |
+
'class': "emotion-info emotion-heading"
|
115 |
+
},
|
116 |
+
"nervousness": {
|
117 |
+
'heading': "Embrace the nerves and stay strong!",
|
118 |
+
'info': "Find calmness and strength with these soothing tracks that ease nervousness.",
|
119 |
+
'category': "distractandchange",
|
120 |
+
'class': "emotion-info emotion-heading"
|
121 |
+
},
|
122 |
+
"optimism": {
|
123 |
+
'heading': "Stay positive and optimistic!",
|
124 |
+
'info': "Fuel your optimism with these uplifting tunes that inspire positivity.",
|
125 |
+
'category': "energeticandmotivate",
|
126 |
+
'class': "emotion-info emotion-heading"
|
127 |
+
},
|
128 |
+
"pride": {
|
129 |
+
'heading': "Feel proud of your achievements!",
|
130 |
+
'info': "Celebrate your accomplishments with these triumphant tunes that exude pride.",
|
131 |
+
'category': "energeticandmotivate",
|
132 |
+
'class': "emotion-info emotion-heading"
|
133 |
+
},
|
134 |
+
"realization": {
|
135 |
+
'heading': "Embrace newfound realizations!",
|
136 |
+
'info': "Explore new insights and perspectives with these thought-provoking tunes.",
|
137 |
+
'category': "engageandexplore",
|
138 |
+
'class': "emotion-info emotion-heading"
|
139 |
+
},
|
140 |
+
"relief": {
|
141 |
+
'heading': "Find relief and comfort!",
|
142 |
+
'info': "Experience a sense of relief and relaxation with these calming tracks.",
|
143 |
+
'category': "soothieanduplift",
|
144 |
+
'class': "emotion-info emotion-heading"
|
145 |
+
},
|
146 |
+
"remorse": {
|
147 |
+
'heading': "Reflecting on remorse and learning.",
|
148 |
+
'info': "Reflect and understand with these introspective tunes that delve into remorse.",
|
149 |
+
'category': "reflectiveandunderstand",
|
150 |
+
'class': "emotion-info emotion-heading"
|
151 |
+
},
|
152 |
+
"sadness": {
|
153 |
+
'heading': "Embrace the sadness and find solace.",
|
154 |
+
'info': "Navigate through feelings of sadness with these comforting tracks.",
|
155 |
+
'category': "reflectiveandunderstand",
|
156 |
+
'class': "emotion-info emotion-heading"
|
157 |
+
},
|
158 |
+
"surprise": {
|
159 |
+
'heading': "Expect the unexpected!",
|
160 |
+
'info': "Embrace the element of surprise with these unpredictable tracks.",
|
161 |
+
'category': "engageandexplore",
|
162 |
+
'class': "emotion-info emotion-heading"
|
163 |
+
},
|
164 |
+
"neutral": {
|
165 |
+
'heading': "Find balance and neutrality.",
|
166 |
+
'info': "Stay grounded with these tranquil tracks that embody neutrality.",
|
167 |
+
'category': "soothieanduplift",
|
168 |
+
'class':"emotion-info emotion-heading"
|
169 |
+
}
|
170 |
+
}
|
app/modules/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
app/modules/__init__.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
|
4 |
+
from modules.emotion import Emotion
|
5 |
+
from modules.transcription import Transcription
|
6 |
+
|
7 |
+
transcription_model = "tiny.en"
|
8 |
+
emotion_model = "joeddav/distilbert-base-uncased-go-emotions-student"
|
9 |
+
|
10 |
+
transcription_obj = Transcription(model_name=transcription_model)
|
11 |
+
emotion_obj = Emotion(model_name=emotion_model)
|
12 |
+
|
13 |
+
class Module:
|
14 |
+
|
15 |
+
def predict(self, audio_path: str) -> str:
|
16 |
+
"""Loads audio, gets transcription and detects emotion
|
17 |
+
|
18 |
+
Args:
|
19 |
+
audio_path (str): path to the audio file
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
str: emotion
|
23 |
+
"""
|
24 |
+
print("Getting transcription...")
|
25 |
+
start_time = time.time()
|
26 |
+
if text := transcription_obj.transcribe(audio_path=audio_path):
|
27 |
+
print("Text: ", text, time.time() - start_time)
|
28 |
+
|
29 |
+
start_time = time.time()
|
30 |
+
emotion = emotion_obj.detect_emotion(text=text)
|
31 |
+
print("Emotion: ", emotion, time.time() - start_time)
|
32 |
+
return text, emotion
|
33 |
+
return None
|
34 |
+
|
app/modules/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (1.21 kB). View file
|
|
app/modules/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (1.84 kB). View file
|
|
app/modules/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (1.61 kB). View file
|
|
app/modules/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (1.16 kB). View file
|
|
app/modules/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (1.21 kB). View file
|
|
app/modules/__pycache__/utils.cpython-310(1).pyc
ADDED
Binary file (707 Bytes). View file
|
|
app/modules/__pycache__/utils.cpython-310.pyc
ADDED
Binary file (738 Bytes). View file
|
|
app/modules/__pycache__/utils.cpython-311.pyc
ADDED
Binary file (911 Bytes). View file
|
|
app/modules/__pycache__/utils.cpython-312.pyc
ADDED
Binary file (840 Bytes). View file
|
|
app/modules/__pycache__/utils.cpython-38.pyc
ADDED
Binary file (678 Bytes). View file
|
|
app/modules/__pycache__/utils.cpython-39.pyc
ADDED
Binary file (726 Bytes). View file
|
|
app/modules/audio/__init__.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any
|
2 |
+
|
3 |
+
import whisper
|
4 |
+
|
5 |
+
|
6 |
+
class Audio:
|
7 |
+
@classmethod
|
8 |
+
def load_audio(cls, audio_path: str) -> Any:
|
9 |
+
"""Loads audio file from the disk
|
10 |
+
|
11 |
+
Args:
|
12 |
+
audio_path (str): path of the audio file
|
13 |
+
|
14 |
+
Returns:
|
15 |
+
Any: loaded audio file in numbers
|
16 |
+
"""
|
17 |
+
return whisper.load_audio(audio_path)
|
18 |
+
|
app/modules/audio/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (693 Bytes). View file
|
|
app/modules/emotion/__init__.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Any
|
2 |
+
|
3 |
+
from modules.utils import Pipeline, load_model
|
4 |
+
|
5 |
+
|
6 |
+
class Emotion:
|
7 |
+
task: str = "text-classification"
|
8 |
+
|
9 |
+
def __init__(self, model_name: str) -> None:
|
10 |
+
# model_name: str = "/models/distilbert-base-uncased-go-emotions-student/"
|
11 |
+
print("Loading emotion model...")
|
12 |
+
self.emotion_model: Pipeline = load_model(task=self.task, model=model_name)
|
13 |
+
print("Loaded emotion model")
|
14 |
+
|
15 |
+
def detect_emotion(self, text: str) -> str:
|
16 |
+
"""Detects emotion of the given text
|
17 |
+
|
18 |
+
Args:
|
19 |
+
text (str): text
|
20 |
+
|
21 |
+
Returns:
|
22 |
+
str: emotion
|
23 |
+
"""
|
24 |
+
return self.emotion_model(text)[0]['label']
|
app/modules/emotion/__pycache__/__init__.cpython-310.pyc
ADDED
Binary file (1.09 kB). View file
|
|
app/modules/emotion/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (1.48 kB). View file
|
|
app/modules/emotion/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (1.27 kB). View file
|
|
app/modules/emotion/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (1.04 kB). View file
|
|
app/modules/emotion/__pycache__/__init__.cpython-39.pyc
ADDED
Binary file (1.09 kB). View file
|
|
app/modules/transcription/__init__.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from faster_whisper import WhisperModel
|
3 |
+
|
4 |
+
|
5 |
+
class Transcription:
|
6 |
+
|
7 |
+
def __init__(self, model_name: str) -> None:
|
8 |
+
print("Loading whisper model...")
|
9 |
+
self.whisper_model = self.load_whisper(model_id=model_name)
|
10 |
+
print("Loaded whisper model")
|
11 |
+
|
12 |
+
def load_whisper(self, model_id: str):
|
13 |
+
|
14 |
+
device = "cuda:0" if torch.cuda.is_available() else "cpu"
|
15 |
+
torch_dtype = "float16" if torch.cuda.is_available() else "float32"
|
16 |
+
|
17 |
+
return WhisperModel(model_id, device=device, compute_type=torch_dtype)
|
18 |
+
|
19 |
+
def transcribe(self, audio_path: str) -> str:
|
20 |
+
"""Transcribes the given audio data
|
21 |
+
|
22 |
+
Args:
|
23 |
+
audio_path (str): audio path
|
24 |
+
|
25 |
+
Returns:
|
26 |
+
str: text
|
27 |
+
"""
|
28 |
+
segments, info = self.whisper_model.transcribe(audio_path, language="en")
|
29 |
+
return "".join(segment.text for segment in segments)
|
30 |
+
|
app/modules/transcription/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (2.23 kB). View file
|
|
app/modules/transcription/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (1.99 kB). View file
|
|
app/modules/transcription/__pycache__/__init__.cpython-38.pyc
ADDED
Binary file (1.48 kB). View file
|
|
app/modules/utils.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from transformers import pipeline
|
3 |
+
from transformers.pipelines.base import Pipeline
|
4 |
+
|
5 |
+
|
6 |
+
def load_model(task: str, model: str) -> Pipeline:
|
7 |
+
"""Loads the given transformers model based on the given task
|
8 |
+
|
9 |
+
Args:
|
10 |
+
task (str): NLP task
|
11 |
+
model (str): transformers model
|
12 |
+
|
13 |
+
Returns:
|
14 |
+
Pipeline: transformers pipeline object
|
15 |
+
"""
|
16 |
+
return pipeline(
|
17 |
+
task=task,
|
18 |
+
model=model,
|
19 |
+
device = 0 if torch.cuda.is_available() else -1
|
20 |
+
)
|
app/static/audio_main.js
ADDED
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
let now_playing = document.querySelector(".now-playing");
|
2 |
+
let track_art = document.querySelector(".track-art");
|
3 |
+
let track_name = document.querySelector(".track-name");
|
4 |
+
let track_artist = document.querySelector(".track-artist");
|
5 |
+
|
6 |
+
let playpause_btn = document.querySelector(".playpause-track");
|
7 |
+
let next_btn = document.querySelector(".next-track");
|
8 |
+
let prev_btn = document.querySelector(".prev-track");
|
9 |
+
|
10 |
+
let seek_slider = document.querySelector(".seek_slider");
|
11 |
+
let volume_slider = document.querySelector(".volume_slider");
|
12 |
+
let curr_time = document.querySelector(".current-time");
|
13 |
+
let total_duration = document.querySelector(".total-duration");
|
14 |
+
|
15 |
+
let track_index = 0;
|
16 |
+
let isPlaying = false;
|
17 |
+
let updateTimer;
|
18 |
+
|
19 |
+
// Create new audio element
|
20 |
+
let curr_track = document.createElement('audio');
|
21 |
+
|
22 |
+
// Define the tracks that have to be played
|
23 |
+
let track_list = [
|
24 |
+
{
|
25 |
+
name: "Night Owl",
|
26 |
+
artist: "Broke For Free",
|
27 |
+
image: "https://images.pexels.com/photos/2264753/pexels-photo-2264753.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=250&w=250",
|
28 |
+
path: "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/WFMU/Broke_For_Free/Directionless_EP/Broke_For_Free_-_01_-_Night_Owl.mp3"
|
29 |
+
},
|
30 |
+
{
|
31 |
+
name: "Enthusiast",
|
32 |
+
artist: "Tours",
|
33 |
+
image: "https://images.pexels.com/photos/3100835/pexels-photo-3100835.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=250&w=250",
|
34 |
+
path: "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/no_curator/Tours/Enthusiast/Tours_-_01_-_Enthusiast.mp3"
|
35 |
+
},
|
36 |
+
{
|
37 |
+
name: "Shipping Lanes",
|
38 |
+
artist: "Chad Crouch",
|
39 |
+
image: "https://images.pexels.com/photos/1717969/pexels-photo-1717969.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=250&w=250",
|
40 |
+
path: "https://files.freemusicarchive.org/storage-freemusicarchive-org/music/ccCommunity/Chad_Crouch/Arps/Chad_Crouch_-_Shipping_Lanes.mp3",
|
41 |
+
},
|
42 |
+
{
|
43 |
+
name: "Starboy",
|
44 |
+
artist: "Weeknd",
|
45 |
+
image: "/static/weeknd.jpeg",
|
46 |
+
path: "/static/The Weeknd - Starboy ft.mp3",
|
47 |
+
},
|
48 |
+
|
49 |
+
];
|
50 |
+
|
51 |
+
function random_bg_color() {
|
52 |
+
|
53 |
+
// Get a number between 64 to 256 (for getting lighter colors)
|
54 |
+
let red = Math.floor(Math.random() * 256) + 64;
|
55 |
+
let green = Math.floor(Math.random() * 256) + 64;
|
56 |
+
let blue = Math.floor(Math.random() * 256) + 64;
|
57 |
+
|
58 |
+
// Construct a color withe the given values
|
59 |
+
let bgColor = "rgb(" + red + "," + green + "," + blue + ")";
|
60 |
+
|
61 |
+
// Set the background to that color
|
62 |
+
document.body.style.background = bgColor;
|
63 |
+
}
|
64 |
+
|
65 |
+
function loadTrack(track_index) {
|
66 |
+
clearInterval(updateTimer);
|
67 |
+
resetValues();
|
68 |
+
curr_track.src = track_list[track_index].path;
|
69 |
+
curr_track.load();
|
70 |
+
|
71 |
+
track_art.style.backgroundImage = "url(" + track_list[track_index].image + ")";
|
72 |
+
track_name.textContent = track_list[track_index].name;
|
73 |
+
track_artist.textContent = track_list[track_index].artist;
|
74 |
+
now_playing.textContent = "PLAYING " + (track_index + 1) + " OF " + track_list.length;
|
75 |
+
|
76 |
+
updateTimer = setInterval(seekUpdate, 1000);
|
77 |
+
curr_track.addEventListener("ended", nextTrack);
|
78 |
+
random_bg_color();
|
79 |
+
}
|
80 |
+
function resetValues() {
|
81 |
+
curr_time.textContent = "00:00";
|
82 |
+
total_duration.textContent = "00:00";
|
83 |
+
seek_slider.value = 0;
|
84 |
+
}
|
85 |
+
|
86 |
+
// Load the first track in the tracklist
|
87 |
+
loadTrack(track_index);
|
88 |
+
|
89 |
+
function playpauseTrack() {
|
90 |
+
if (!isPlaying) playTrack();
|
91 |
+
else pauseTrack();
|
92 |
+
}
|
93 |
+
|
94 |
+
function playTrack() {
|
95 |
+
curr_track.play();
|
96 |
+
isPlaying = true;
|
97 |
+
playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
|
98 |
+
}
|
99 |
+
|
100 |
+
function pauseTrack() {
|
101 |
+
curr_track.pause();
|
102 |
+
isPlaying = false;
|
103 |
+
playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';;
|
104 |
+
}
|
105 |
+
|
106 |
+
function nextTrack() {
|
107 |
+
if (track_index < track_list.length - 1) {
|
108 |
+
track_index += 1;
|
109 |
+
} else {
|
110 |
+
track_index = 0;
|
111 |
+
}
|
112 |
+
|
113 |
+
loadTrack(track_index); // Load the new track
|
114 |
+
|
115 |
+
// Once the track is loaded, call playTrack
|
116 |
+
curr_track.addEventListener('loadeddata', playTrack);
|
117 |
+
}
|
118 |
+
|
119 |
+
function prevTrack() {
|
120 |
+
if (track_index > 0)
|
121 |
+
track_index -= 1;
|
122 |
+
else track_index = track_list.length;
|
123 |
+
loadTrack(track_index);
|
124 |
+
playTrack();
|
125 |
+
}
|
126 |
+
|
127 |
+
function seekTo() {
|
128 |
+
let seekto = curr_track.duration * (seek_slider.value / 100);
|
129 |
+
curr_track.currentTime = seekto;
|
130 |
+
}
|
131 |
+
|
132 |
+
function setVolume() {
|
133 |
+
curr_track.volume = volume_slider.value / 100;
|
134 |
+
}
|
135 |
+
|
136 |
+
function seekUpdate() {
|
137 |
+
let seekPosition = 0;
|
138 |
+
|
139 |
+
if (!isNaN(curr_track.duration)) {
|
140 |
+
seekPosition = curr_track.currentTime * (100 / curr_track.duration);
|
141 |
+
|
142 |
+
seek_slider.value = seekPosition;
|
143 |
+
|
144 |
+
let currentMinutes = Math.floor(curr_track.currentTime / 60);
|
145 |
+
let currentSeconds = Math.floor(curr_track.currentTime - currentMinutes * 60);
|
146 |
+
let durationMinutes = Math.floor(curr_track.duration / 60);
|
147 |
+
let durationSeconds = Math.floor(curr_track.duration - durationMinutes * 60);
|
148 |
+
|
149 |
+
if (currentSeconds < 10) { currentSeconds = "0" + currentSeconds; }
|
150 |
+
if (durationSeconds < 10) { durationSeconds = "0" + durationSeconds; }
|
151 |
+
if (currentMinutes < 10) { currentMinutes = "0" + currentMinutes; }
|
152 |
+
if (durationMinutes < 10) { durationMinutes = "0" + durationMinutes; }
|
153 |
+
|
154 |
+
curr_time.textContent = currentMinutes + ":" + currentSeconds;
|
155 |
+
total_duration.textContent = durationMinutes + ":" + durationSeconds;
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
|
app/static/audio_to_text.css
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
background: linear-gradient(to right, #0f4da6, #0f4da6, #1e272e, #1e272e);
|
3 |
+
margin: 0; /* Remove default body margin */
|
4 |
+
padding: 0; /* Remove default body padding */
|
5 |
+
}
|
6 |
+
|
7 |
+
.container {
|
8 |
+
position: relative;
|
9 |
+
}
|
10 |
+
|
11 |
+
.row {
|
12 |
+
background: linear-gradient(to right, #0f4da6, #0f4da6, #1e272e, #1e272e);
|
13 |
+
border-radius: 8px;
|
14 |
+
padding: 20px;
|
15 |
+
margin-bottom: 20px;
|
16 |
+
display: flex; /* Use Flexbox */
|
17 |
+
justify-content: space-around;
|
18 |
+
}
|
19 |
+
|
20 |
+
.column {
|
21 |
+
width: 45%; /* Adjust as needed */
|
22 |
+
padding: 15px;
|
23 |
+
color: #f0f0f5;
|
24 |
+
}
|
25 |
+
|
26 |
+
#recording-instructions {
|
27 |
+
text-align: left;
|
28 |
+
margin-top: 10px;
|
29 |
+
font-style: italic;
|
30 |
+
}
|
31 |
+
|
32 |
+
.row {
|
33 |
+
display: flex;
|
34 |
+
flex-direction: column; /* Stack items vertically */
|
35 |
+
align-items: left;
|
36 |
+
margin-bottom: 3%;
|
37 |
+
background-color: #060073;
|
38 |
+
}
|
39 |
+
|
40 |
+
/* Clear floats after the columns */
|
41 |
+
.row:after {
|
42 |
+
content: "";
|
43 |
+
display: table;
|
44 |
+
clear: both;
|
45 |
+
}
|
46 |
+
|
47 |
+
/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */
|
48 |
+
@media screen and (max-width: 600px) {
|
49 |
+
.column1 {
|
50 |
+
width: 100%;
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
@media screen and (max-width: 600px) {
|
55 |
+
.column2 {
|
56 |
+
width: 100%;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
#imgInp {
|
61 |
+
opacity: 0;
|
62 |
+
position: absolute;
|
63 |
+
z-index: -1;
|
64 |
+
}
|
65 |
+
|
66 |
+
label {
|
67 |
+
cursor: pointer;
|
68 |
+
padding-left: 10%;
|
69 |
+
padding-right: 10%;
|
70 |
+
padding-top: 2%;
|
71 |
+
padding-bottom: 2%;
|
72 |
+
font-size: 100%;
|
73 |
+
color: #000000;
|
74 |
+
border-radius: 25px;
|
75 |
+
background-color: #228B22;
|
76 |
+
}
|
77 |
+
|
78 |
+
#blah {
|
79 |
+
max-width: 60%;
|
80 |
+
max-height: 60%;
|
81 |
+
}
|
82 |
+
|
83 |
+
#image_div1 {
|
84 |
+
max-width: 70%;
|
85 |
+
max-height: 70%;
|
86 |
+
}
|
87 |
+
|
88 |
+
#stop, #start {
|
89 |
+
background-color: black;
|
90 |
+
color: white;
|
91 |
+
padding: 10px 20px;
|
92 |
+
border: none;
|
93 |
+
border-radius: 4px;
|
94 |
+
cursor: pointer;
|
95 |
+
margin: 10px; /* Add margin to create gap */
|
96 |
+
transition: background-color 0.3s ease; /* Add transition for smooth effect */
|
97 |
+
}
|
98 |
+
|
99 |
+
#stop {
|
100 |
+
margin-right: 5px; /* Adjust margin to create gap */
|
101 |
+
}
|
102 |
+
|
103 |
+
#stop:hover, #start:hover {
|
104 |
+
background-color: #333; /* Change background color on hover */
|
105 |
+
}
|
106 |
+
|
107 |
+
.animated-title {
|
108 |
+
font-size: 2.5rem;
|
109 |
+
font-weight: bold;
|
110 |
+
color: white;
|
111 |
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
|
112 |
+
animation: fadeIn 2s forwards;
|
113 |
+
transition: color 0.5s ease-in-out, text-shadow 0.5s ease-in-out;
|
114 |
+
white-space: nowrap;
|
115 |
+
position: absolute;
|
116 |
+
left: 200px; /* Adjust the value as needed */
|
117 |
+
top: 20px;
|
118 |
+
}
|
119 |
+
|
120 |
+
@keyframes fadeIn {
|
121 |
+
0% {
|
122 |
+
opacity: 0;
|
123 |
+
transform: translateY(-20px);
|
124 |
+
}
|
125 |
+
100% {
|
126 |
+
opacity: 1;
|
127 |
+
transform: translateY(0);
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
.animated-title:hover {
|
132 |
+
color: black;
|
133 |
+
text-shadow: 4px 4px 8px rgba(0, 0, 0, 0.8);
|
134 |
+
}
|
135 |
+
|
app/static/audiodisplay.js
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function drawBuffer( width, height, context, data ) {
|
2 |
+
var step = Math.ceil( data.length / width );
|
3 |
+
var amp = height / 2;
|
4 |
+
context.fillStyle = "silver";
|
5 |
+
context.clearRect(0,0,width,height);
|
6 |
+
for(var i=0; i < width; i++){
|
7 |
+
var min = 1.0;
|
8 |
+
var max = -1.0;
|
9 |
+
for (j=0; j<step; j++) {
|
10 |
+
var datum = data[(i*step)+j];
|
11 |
+
if (datum < min)
|
12 |
+
min = datum;
|
13 |
+
if (datum > max)
|
14 |
+
max = datum;
|
15 |
+
}
|
16 |
+
context.fillRect(i,(1+min)*amp,1,Math.max(1,(max-min)*amp));
|
17 |
+
}
|
18 |
+
}
|
19 |
+
|
app/static/dem.css
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*{
|
2 |
+
font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
|
3 |
+
color: #171717;
|
4 |
+
background-color: antiquewhite;
|
5 |
+
}
|
6 |
+
header {
|
7 |
+
text-align: center;
|
8 |
+
|
9 |
+
}
|
10 |
+
.grid-container {
|
11 |
+
display: grid;
|
12 |
+
grid-template-columns: repeat(3, 1fr);
|
13 |
+
gap: 20px;
|
14 |
+
}
|
15 |
+
|
16 |
+
.card {
|
17 |
+
border: 3px solid #f6a503;
|
18 |
+
border-radius: 8px;
|
19 |
+
overflow: hidden;
|
20 |
+
}
|
21 |
+
|
22 |
+
.card img {
|
23 |
+
width: 100%;
|
24 |
+
height: 600px;
|
25 |
+
display: block;
|
26 |
+
}
|
27 |
+
|
28 |
+
.card-content {
|
29 |
+
padding: 20px;
|
30 |
+
}
|
31 |
+
|
32 |
+
.card-content h2 {
|
33 |
+
margin-top: 0;
|
34 |
+
}
|
35 |
+
|
36 |
+
.card-content h4 {
|
37 |
+
margin-bottom: 10px;
|
38 |
+
}
|
39 |
+
|
40 |
+
.card-content button {
|
41 |
+
background-color: #f6a503;
|
42 |
+
color: #000000;
|
43 |
+
border: none;
|
44 |
+
padding: 10px 20px;
|
45 |
+
border-radius: 5px;
|
46 |
+
cursor: pointer;
|
47 |
+
transition: background-color 0.3s ease;
|
48 |
+
}
|
49 |
+
|
50 |
+
.card-content button:hover {
|
51 |
+
background-color: #ffffff;
|
52 |
+
}
|
53 |
+
|
app/static/demo.css
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* style.css */
|
2 |
+
.audio-container {
|
3 |
+
display: flex;
|
4 |
+
flex-wrap: wrap;
|
5 |
+
justify-content: space-around;
|
6 |
+
background-color: #2caaf3
|
7 |
+
}
|
8 |
+
|
9 |
+
.audio-player {
|
10 |
+
width: 300px;
|
11 |
+
margin: 15px;
|
12 |
+
border: 1px solid #ccc;
|
13 |
+
padding: 15px;
|
14 |
+
border-radius: 8px;
|
15 |
+
text-align: center;
|
16 |
+
background-color: #0af32d; /* Light background color */
|
17 |
+
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1); /* Subtle shadow effect */
|
18 |
+
}
|
19 |
+
|
20 |
+
.audio-player:nth-child(odd) {
|
21 |
+
background-color: #c71a82; /* Alternating background */
|
22 |
+
}
|
23 |
+
|
24 |
+
.audio-image {
|
25 |
+
width: 100%;
|
26 |
+
height: 200px;
|
27 |
+
object-fit: cover;
|
28 |
+
border-radius: 8px;
|
29 |
+
}
|
30 |
+
|
31 |
+
.audio-info {
|
32 |
+
margin-top: 10px;
|
33 |
+
}
|
34 |
+
|
35 |
+
/* Hover effect on the audio player */
|
36 |
+
.audio-player:hover {
|
37 |
+
background-color: #fcfbf9;
|
38 |
+
cursor: pointer;
|
39 |
+
}
|
40 |
+
|
app/static/distract.js
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
let now_playing = document.querySelector(".now-playing");
|
2 |
+
let track_art = document.querySelector(".track-art");
|
3 |
+
let track_name = document.querySelector(".track-name");
|
4 |
+
let track_artist = document.querySelector(".track-artist");
|
5 |
+
|
6 |
+
let playpause_btn = document.querySelector(".playpause-track");
|
7 |
+
let next_btn = document.querySelector(".next-track");
|
8 |
+
let prev_btn = document.querySelector(".prev-track");
|
9 |
+
|
10 |
+
let seek_slider = document.querySelector(".seek_slider");
|
11 |
+
let volume_slider = document.querySelector(".volume_slider");
|
12 |
+
let curr_time = document.querySelector(".current-time");
|
13 |
+
let total_duration = document.querySelector(".total-duration");
|
14 |
+
|
15 |
+
let track_index = 0;
|
16 |
+
let isPlaying = false;
|
17 |
+
let updateTimer;
|
18 |
+
|
19 |
+
// Create new audio element
|
20 |
+
let curr_track = document.createElement('audio');
|
21 |
+
|
22 |
+
// Define the tracks that have to be played
|
23 |
+
let track_list = [
|
24 |
+
{
|
25 |
+
name: "Happy",
|
26 |
+
artist: "Pharrell Williams",
|
27 |
+
image: "/static/happy.jpeg",
|
28 |
+
path: "/static/Pharrell Williams - Happy (Video).mp3"
|
29 |
+
},
|
30 |
+
{
|
31 |
+
name: "CAN'T STOP THE FEELING! ",
|
32 |
+
artist: "DreamWorks",
|
33 |
+
image: "/static/couldntstopfeel.jpeg",
|
34 |
+
path: "/static/CAN'T STOP THE FEELING! (from DreamWorks Animation's TROLLS) (Official Video).mp3"
|
35 |
+
},
|
36 |
+
{
|
37 |
+
name: "I'm Still Standing",
|
38 |
+
artist: "Elton John",
|
39 |
+
image: "/static/imstillstanding.jpeg",
|
40 |
+
path: "/static/Elton John - I'm Still Standing.mp3",
|
41 |
+
},
|
42 |
+
{
|
43 |
+
name: "Starboy",
|
44 |
+
artist: "Weeknd",
|
45 |
+
image: "/static/weeknd.png",
|
46 |
+
path: "/static/The Weeknd - Starboy ft.mp3",
|
47 |
+
},
|
48 |
+
{
|
49 |
+
name: "All Star",
|
50 |
+
artist: "Smash Mouth",
|
51 |
+
image: "/static/allstarsmash.jpeg",
|
52 |
+
path: "/static/Smash Mouth - All Star (Official Music Video).mp3",
|
53 |
+
}
|
54 |
+
|
55 |
+
];
|
56 |
+
|
57 |
+
function random_bg_color() {
|
58 |
+
|
59 |
+
// Get a number between 64 to 256 (for getting lighter colors)
|
60 |
+
let red = Math.floor(Math.random() * 256) + 64;
|
61 |
+
let green = Math.floor(Math.random() * 256) + 64;
|
62 |
+
let blue = Math.floor(Math.random() * 256) + 64;
|
63 |
+
|
64 |
+
// Construct a color withe the given values
|
65 |
+
let bgColor = "rgb(" + red + "," + green + "," + blue + ")";
|
66 |
+
|
67 |
+
// Set the background to that color
|
68 |
+
document.body.style.background = bgColor;
|
69 |
+
}
|
70 |
+
|
71 |
+
function loadTrack(track_index) {
|
72 |
+
clearInterval(updateTimer);
|
73 |
+
resetValues();
|
74 |
+
curr_track.src = track_list[track_index].path;
|
75 |
+
curr_track.load();
|
76 |
+
|
77 |
+
track_art.style.backgroundImage = "url(" + track_list[track_index].image + ")";
|
78 |
+
track_name.textContent = track_list[track_index].name;
|
79 |
+
track_artist.textContent = track_list[track_index].artist;
|
80 |
+
now_playing.textContent = "PLAYING " + (track_index + 1) + " OF " + track_list.length;
|
81 |
+
|
82 |
+
updateTimer = setInterval(seekUpdate, 1000);
|
83 |
+
curr_track.addEventListener("ended", nextTrack);
|
84 |
+
random_bg_color();
|
85 |
+
}
|
86 |
+
function resetValues() {
|
87 |
+
curr_time.textContent = "00:00";
|
88 |
+
total_duration.textContent = "00:00";
|
89 |
+
seek_slider.value = 0;
|
90 |
+
}
|
91 |
+
|
92 |
+
// Load the first track in the tracklist
|
93 |
+
loadTrack(track_index);
|
94 |
+
|
95 |
+
function playpauseTrack() {
|
96 |
+
if (!isPlaying) playTrack();
|
97 |
+
else pauseTrack();
|
98 |
+
}
|
99 |
+
|
100 |
+
function playTrack() {
|
101 |
+
curr_track.play();
|
102 |
+
isPlaying = true;
|
103 |
+
playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
|
104 |
+
}
|
105 |
+
|
106 |
+
function pauseTrack() {
|
107 |
+
curr_track.pause();
|
108 |
+
isPlaying = false;
|
109 |
+
playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';;
|
110 |
+
}
|
111 |
+
|
112 |
+
function nextTrack() {
|
113 |
+
if (track_index < track_list.length - 1) {
|
114 |
+
track_index += 1;
|
115 |
+
} else {
|
116 |
+
track_index = 0;
|
117 |
+
}
|
118 |
+
|
119 |
+
loadTrack(track_index); // Load the new track
|
120 |
+
|
121 |
+
// Once the track is loaded, call playTrack
|
122 |
+
curr_track.addEventListener('loadeddata', playTrack);
|
123 |
+
}
|
124 |
+
|
125 |
+
function prevTrack() {
|
126 |
+
if (track_index > 0)
|
127 |
+
track_index -= 1;
|
128 |
+
else track_index = track_list.length;
|
129 |
+
loadTrack(track_index);
|
130 |
+
playTrack();
|
131 |
+
}
|
132 |
+
|
133 |
+
function seekTo() {
|
134 |
+
let seekto = curr_track.duration * (seek_slider.value / 100);
|
135 |
+
curr_track.currentTime = seekto;
|
136 |
+
}
|
137 |
+
|
138 |
+
function setVolume() {
|
139 |
+
curr_track.volume = volume_slider.value / 100;
|
140 |
+
}
|
141 |
+
|
142 |
+
function seekUpdate() {
|
143 |
+
let seekPosition = 0;
|
144 |
+
|
145 |
+
if (!isNaN(curr_track.duration)) {
|
146 |
+
seekPosition = curr_track.currentTime * (100 / curr_track.duration);
|
147 |
+
|
148 |
+
seek_slider.value = seekPosition;
|
149 |
+
|
150 |
+
let currentMinutes = Math.floor(curr_track.currentTime / 60);
|
151 |
+
let currentSeconds = Math.floor(curr_track.currentTime - currentMinutes * 60);
|
152 |
+
let durationMinutes = Math.floor(curr_track.duration / 60);
|
153 |
+
let durationSeconds = Math.floor(curr_track.duration - durationMinutes * 60);
|
154 |
+
|
155 |
+
if (currentSeconds < 10) { currentSeconds = "0" + currentSeconds; }
|
156 |
+
if (durationSeconds < 10) { durationSeconds = "0" + durationSeconds; }
|
157 |
+
if (currentMinutes < 10) { currentMinutes = "0" + currentMinutes; }
|
158 |
+
if (durationMinutes < 10) { durationMinutes = "0" + durationMinutes; }
|
159 |
+
|
160 |
+
curr_time.textContent = currentMinutes + ":" + currentSeconds;
|
161 |
+
total_duration.textContent = durationMinutes + ":" + durationSeconds;
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
|
app/static/distractandchange.css
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* style.css */
|
2 |
+
.audio-player {
|
3 |
+
background-color: var(--secondary-color);
|
4 |
+
background-image: url("path/to/subtle-pattern.png"); /* Optional */
|
5 |
+
border-radius: 15px;
|
6 |
+
padding: 30px;
|
7 |
+
box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
|
8 |
+
}
|
9 |
+
|
10 |
+
.player-controls {
|
11 |
+
display: flex;
|
12 |
+
justify-content: center;
|
13 |
+
width: 100%;
|
14 |
+
margin-bottom: 15px;
|
15 |
+
}
|
16 |
+
|
17 |
+
.player-controls button {
|
18 |
+
/* Style your buttons */
|
19 |
+
}
|
20 |
+
|
21 |
+
.song-info {
|
22 |
+
text-align: center;
|
23 |
+
}
|
24 |
+
|
25 |
+
.album-cover {
|
26 |
+
width: 150px;
|
27 |
+
height: 150px;
|
28 |
+
margin-bottom: 10px;
|
29 |
+
}
|
app/static/energy.js
ADDED
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
let now_playing = document.querySelector(".now-playing");
|
2 |
+
let track_art = document.querySelector(".track-art");
|
3 |
+
let track_name = document.querySelector(".track-name");
|
4 |
+
let track_artist = document.querySelector(".track-artist");
|
5 |
+
|
6 |
+
let playpause_btn = document.querySelector(".playpause-track");
|
7 |
+
let next_btn = document.querySelector(".next-track");
|
8 |
+
let prev_btn = document.querySelector(".prev-track");
|
9 |
+
|
10 |
+
let seek_slider = document.querySelector(".seek_slider");
|
11 |
+
let volume_slider = document.querySelector(".volume_slider");
|
12 |
+
let curr_time = document.querySelector(".current-time");
|
13 |
+
let total_duration = document.querySelector(".total-duration");
|
14 |
+
|
15 |
+
let track_index = 0;
|
16 |
+
let isPlaying = false;
|
17 |
+
let updateTimer;
|
18 |
+
|
19 |
+
// Create new audio element
|
20 |
+
let curr_track = document.createElement('audio');
|
21 |
+
|
22 |
+
// Define the tracks that have to be played
|
23 |
+
let track_list = [
|
24 |
+
{
|
25 |
+
name: "Stronger",
|
26 |
+
artist: "Kanye West",
|
27 |
+
image: "stronger.jpeg",
|
28 |
+
path: "Kanye West - Stronger.mp3"
|
29 |
+
},
|
30 |
+
{
|
31 |
+
name: "Chak De India",
|
32 |
+
artist: "Salim-Sulaiman",
|
33 |
+
image: "chakdeindia.jpeg",
|
34 |
+
path: "Chak De India Song Title Song Shah Rukh Khan Sukhwinder Singh Salim-Sulaiman Jaideep Sahni.mp3 },
|
35 |
+
{
|
36 |
+
name: "Dhaakad",
|
37 |
+
artist: "Pritam",
|
38 |
+
image: "dangal.jpeg",
|
39 |
+
path: "Dhaakad - Full Video Dangal Aamir Khan Pritam Amitabh Bhattacharya Raftaar.mp3 },
|
40 |
+
{
|
41 |
+
name: "Roar",
|
42 |
+
artist: "Katy Perry",
|
43 |
+
image: "/static/roar.jpeg",
|
44 |
+
path: "/static/Katy Perry - Roar.mp3",
|
45 |
+
},
|
46 |
+
|
47 |
+
{
|
48 |
+
name: "Uptown Funk",
|
49 |
+
artist: "Mark Ronson",
|
50 |
+
image: "/static/uptownfunk.jpeg",
|
51 |
+
path: "/static/Mark Ronson - Uptown Funk (Official Video) ft. Bruno Mars.mp3"
|
52 |
+
},
|
53 |
+
];
|
54 |
+
|
55 |
+
function random_bg_color() {
|
56 |
+
|
57 |
+
// Get a number between 64 to 256 (for getting lighter colors)
|
58 |
+
let red = Math.floor(Math.random() * 256) + 64;
|
59 |
+
let green = Math.floor(Math.random() * 256) + 64;
|
60 |
+
let blue = Math.floor(Math.random() * 256) + 64;
|
61 |
+
|
62 |
+
// Construct a color withe the given values
|
63 |
+
let bgColor = "rgb(" + red + "," + green + "," + blue + ")";
|
64 |
+
|
65 |
+
// Set the background to that color
|
66 |
+
document.body.style.background = bgColor;
|
67 |
+
}
|
68 |
+
|
69 |
+
function loadTrack(track_index) {
|
70 |
+
clearInterval(updateTimer);
|
71 |
+
resetValues();
|
72 |
+
curr_track.src = track_list[track_index].path;
|
73 |
+
curr_track.load();
|
74 |
+
|
75 |
+
track_art.style.backgroundImage = "url(" + track_list[track_index].image + ")";
|
76 |
+
track_name.textContent = track_list[track_index].name;
|
77 |
+
track_artist.textContent = track_list[track_index].artist;
|
78 |
+
now_playing.textContent = "PLAYING " + (track_index + 1) + " OF " + track_list.length;
|
79 |
+
|
80 |
+
updateTimer = setInterval(seekUpdate, 1000);
|
81 |
+
curr_track.addEventListener("ended", nextTrack);
|
82 |
+
random_bg_color();
|
83 |
+
}
|
84 |
+
function resetValues() {
|
85 |
+
curr_time.textContent = "00:00";
|
86 |
+
total_duration.textContent = "00:00";
|
87 |
+
seek_slider.value = 0;
|
88 |
+
}
|
89 |
+
|
90 |
+
// Load the first track in the tracklist
|
91 |
+
loadTrack(track_index);
|
92 |
+
|
93 |
+
function playpauseTrack() {
|
94 |
+
if (!isPlaying) playTrack();
|
95 |
+
else pauseTrack();
|
96 |
+
}
|
97 |
+
|
98 |
+
function playTrack() {
|
99 |
+
curr_track.play();
|
100 |
+
isPlaying = true;
|
101 |
+
playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
|
102 |
+
}
|
103 |
+
|
104 |
+
function pauseTrack() {
|
105 |
+
curr_track.pause();
|
106 |
+
isPlaying = false;
|
107 |
+
playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';;
|
108 |
+
}
|
109 |
+
|
110 |
+
function nextTrack() {
|
111 |
+
if (track_index < track_list.length - 1) {
|
112 |
+
track_index += 1;
|
113 |
+
} else {
|
114 |
+
track_index = 0;
|
115 |
+
}
|
116 |
+
|
117 |
+
loadTrack(track_index); // Load the new track
|
118 |
+
|
119 |
+
// Once the track is loaded, call playTrack
|
120 |
+
curr_track.addEventListener('loadeddata', playTrack);
|
121 |
+
}
|
122 |
+
|
123 |
+
function prevTrack() {
|
124 |
+
if (track_index > 0)
|
125 |
+
track_index -= 1;
|
126 |
+
else track_index = track_list.length;
|
127 |
+
loadTrack(track_index);
|
128 |
+
playTrack();
|
129 |
+
}
|
130 |
+
|
131 |
+
function seekTo() {
|
132 |
+
let seekto = curr_track.duration * (seek_slider.value / 100);
|
133 |
+
curr_track.currentTime = seekto;
|
134 |
+
}
|
135 |
+
|
136 |
+
function setVolume() {
|
137 |
+
curr_track.volume = volume_slider.value / 100;
|
138 |
+
}
|
139 |
+
|
140 |
+
function seekUpdate() {
|
141 |
+
let seekPosition = 0;
|
142 |
+
|
143 |
+
if (!isNaN(curr_track.duration)) {
|
144 |
+
seekPosition = curr_track.currentTime * (100 / curr_track.duration);
|
145 |
+
|
146 |
+
seek_slider.value = seekPosition;
|
147 |
+
|
148 |
+
let currentMinutes = Math.floor(curr_track.currentTime / 60);
|
149 |
+
let currentSeconds = Math.floor(curr_track.currentTime - currentMinutes * 60);
|
150 |
+
let durationMinutes = Math.floor(curr_track.duration / 60);
|
151 |
+
let durationSeconds = Math.floor(curr_track.duration - durationMinutes * 60);
|
152 |
+
|
153 |
+
if (currentSeconds < 10) { currentSeconds = "0" + currentSeconds; }
|
154 |
+
if (durationSeconds < 10) { durationSeconds = "0" + durationSeconds; }
|
155 |
+
if (currentMinutes < 10) { currentMinutes = "0" + currentMinutes; }
|
156 |
+
if (durationMinutes < 10) { durationMinutes = "0" + durationMinutes; }
|
157 |
+
|
158 |
+
curr_time.textContent = currentMinutes + ":" + currentSeconds;
|
159 |
+
total_duration.textContent = durationMinutes + ":" + durationSeconds;
|
160 |
+
}
|
161 |
+
}
|
162 |
+
|
163 |
+
|
app/static/engage.js
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
let now_playing = document.querySelector(".now-playing");
|
2 |
+
let track_art = document.querySelector(".track-art");
|
3 |
+
let track_name = document.querySelector(".track-name");
|
4 |
+
let track_artist = document.querySelector(".track-artist");
|
5 |
+
|
6 |
+
let playpause_btn = document.querySelector(".playpause-track");
|
7 |
+
let next_btn = document.querySelector(".next-track");
|
8 |
+
let prev_btn = document.querySelector(".prev-track");
|
9 |
+
|
10 |
+
let seek_slider = document.querySelector(".seek_slider");
|
11 |
+
let volume_slider = document.querySelector(".volume_slider");
|
12 |
+
let curr_time = document.querySelector(".current-time");
|
13 |
+
let total_duration = document.querySelector(".total-duration");
|
14 |
+
|
15 |
+
let track_index = 0;
|
16 |
+
let isPlaying = false;
|
17 |
+
let updateTimer;
|
18 |
+
|
19 |
+
// Create new audio element
|
20 |
+
let curr_track = document.createElement('audio');
|
21 |
+
|
22 |
+
// Define the tracks that have to be played
|
23 |
+
let track_list = [
|
24 |
+
{
|
25 |
+
name: "Smells Like Teen Spirit ",
|
26 |
+
artist: "Nirvana",
|
27 |
+
image: "/static/smellsliketeen.jpeg",
|
28 |
+
path: "/static/Nirvana - Smells Like Teen Spirit (Official Music Video).mp3",
|
29 |
+
},
|
30 |
+
{
|
31 |
+
name: "lifeonmars",
|
32 |
+
artist: "David Bowie",
|
33 |
+
image: "/static/lifeonmars.jpeg",
|
34 |
+
path: "/static/David Bowie Life On Mars_ (Official Video).mp3"
|
35 |
+
},
|
36 |
+
{
|
37 |
+
name: "Queen",
|
38 |
+
artist: "Bohemian Rhapsody",
|
39 |
+
image: "/static/queen.jpeg",
|
40 |
+
path: "/static/Queen Bohemian Rhapsody (Official Video Remastered).mp3"
|
41 |
+
},
|
42 |
+
{
|
43 |
+
name: "Hotel California",
|
44 |
+
artist: "Remaster",
|
45 |
+
image: "/static/hotelcalifornia.jpeg",
|
46 |
+
path: "/static/Hotel California (2013 Remaster).mp3",
|
47 |
+
},
|
48 |
+
{
|
49 |
+
name: "Hallelujah",
|
50 |
+
artist: "Leonard Cohen",
|
51 |
+
image: "/static/hallelujah.jpeg",
|
52 |
+
path: "/static/Leonard Cohen - Hallelujah (Live In London).mp3",
|
53 |
+
}
|
54 |
+
|
55 |
+
];
|
56 |
+
|
57 |
+
function random_bg_color() {
|
58 |
+
|
59 |
+
// Get a number between 64 to 256 (for getting lighter colors)
|
60 |
+
let red = Math.floor(Math.random() * 256) + 64;
|
61 |
+
let green = Math.floor(Math.random() * 256) + 64;
|
62 |
+
let blue = Math.floor(Math.random() * 256) + 64;
|
63 |
+
|
64 |
+
// Construct a color withe the given values
|
65 |
+
let bgColor = "rgb(" + red + "," + green + "," + blue + ")";
|
66 |
+
|
67 |
+
// Set the background to that color
|
68 |
+
document.body.style.background = bgColor;
|
69 |
+
}
|
70 |
+
|
71 |
+
function loadTrack(track_index) {
|
72 |
+
clearInterval(updateTimer);
|
73 |
+
resetValues();
|
74 |
+
curr_track.src = track_list[track_index].path;
|
75 |
+
curr_track.load();
|
76 |
+
|
77 |
+
track_art.style.backgroundImage = "url(" + track_list[track_index].image + ")";
|
78 |
+
track_name.textContent = track_list[track_index].name;
|
79 |
+
track_artist.textContent = track_list[track_index].artist;
|
80 |
+
now_playing.textContent = "PLAYING " + (track_index + 1) + " OF " + track_list.length;
|
81 |
+
|
82 |
+
updateTimer = setInterval(seekUpdate, 1000);
|
83 |
+
curr_track.addEventListener("ended", nextTrack);
|
84 |
+
random_bg_color();
|
85 |
+
}
|
86 |
+
function resetValues() {
|
87 |
+
curr_time.textContent = "00:00";
|
88 |
+
total_duration.textContent = "00:00";
|
89 |
+
seek_slider.value = 0;
|
90 |
+
}
|
91 |
+
|
92 |
+
// Load the first track in the tracklist
|
93 |
+
loadTrack(track_index);
|
94 |
+
|
95 |
+
function playpauseTrack() {
|
96 |
+
if (!isPlaying) playTrack();
|
97 |
+
else pauseTrack();
|
98 |
+
}
|
99 |
+
|
100 |
+
function playTrack() {
|
101 |
+
curr_track.play();
|
102 |
+
isPlaying = true;
|
103 |
+
playpause_btn.innerHTML = '<i class="fa fa-pause-circle fa-5x"></i>';
|
104 |
+
}
|
105 |
+
|
106 |
+
function pauseTrack() {
|
107 |
+
curr_track.pause();
|
108 |
+
isPlaying = false;
|
109 |
+
playpause_btn.innerHTML = '<i class="fa fa-play-circle fa-5x"></i>';;
|
110 |
+
}
|
111 |
+
|
112 |
+
function nextTrack() {
|
113 |
+
if (track_index < track_list.length - 1) {
|
114 |
+
track_index += 1;
|
115 |
+
} else {
|
116 |
+
track_index = 0;
|
117 |
+
}
|
118 |
+
|
119 |
+
loadTrack(track_index); // Load the new track
|
120 |
+
|
121 |
+
// Once the track is loaded, call playTrack
|
122 |
+
curr_track.addEventListener('loadeddata', playTrack);
|
123 |
+
}
|
124 |
+
|
125 |
+
function prevTrack() {
|
126 |
+
if (track_index > 0)
|
127 |
+
track_index -= 1;
|
128 |
+
else track_index = track_list.length;
|
129 |
+
loadTrack(track_index);
|
130 |
+
playTrack();
|
131 |
+
}
|
132 |
+
|
133 |
+
function seekTo() {
|
134 |
+
let seekto = curr_track.duration * (seek_slider.value / 100);
|
135 |
+
curr_track.currentTime = seekto;
|
136 |
+
}
|
137 |
+
|
138 |
+
function setVolume() {
|
139 |
+
curr_track.volume = volume_slider.value / 100;
|
140 |
+
}
|
141 |
+
|
142 |
+
function seekUpdate() {
|
143 |
+
let seekPosition = 0;
|
144 |
+
|
145 |
+
if (!isNaN(curr_track.duration)) {
|
146 |
+
seekPosition = curr_track.currentTime * (100 / curr_track.duration);
|
147 |
+
|
148 |
+
seek_slider.value = seekPosition;
|
149 |
+
|
150 |
+
let currentMinutes = Math.floor(curr_track.currentTime / 60);
|
151 |
+
let currentSeconds = Math.floor(curr_track.currentTime - currentMinutes * 60);
|
152 |
+
let durationMinutes = Math.floor(curr_track.duration / 60);
|
153 |
+
let durationSeconds = Math.floor(curr_track.duration - durationMinutes * 60);
|
154 |
+
|
155 |
+
if (currentSeconds < 10) { currentSeconds = "0" + currentSeconds; }
|
156 |
+
if (durationSeconds < 10) { durationSeconds = "0" + durationSeconds; }
|
157 |
+
if (currentMinutes < 10) { currentMinutes = "0" + currentMinutes; }
|
158 |
+
if (durationMinutes < 10) { durationMinutes = "0" + durationMinutes; }
|
159 |
+
|
160 |
+
curr_time.textContent = currentMinutes + ":" + currentSeconds;
|
161 |
+
total_duration.textContent = durationMinutes + ":" + durationSeconds;
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
|
app/static/footer.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function myFunction() {
|
2 |
+
var x = document.getElementById("myFootnav");
|
3 |
+
if (x.className === "footnov") {
|
4 |
+
x.className += " responsive";
|
5 |
+
} else {
|
6 |
+
x.className = "footnov";
|
7 |
+
}
|
8 |
+
}
|
app/static/footer_file.css
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.footnov {
|
2 |
+
overflow: hidden;
|
3 |
+
background-color: #333; /* Darker gray for better contrast */
|
4 |
+
color: #f2f2f2;
|
5 |
+
padding: 20px 0; /* Added padding for content */
|
6 |
+
}
|
7 |
+
|
8 |
+
.footnov a {
|
9 |
+
float: left;
|
10 |
+
display: block;
|
11 |
+
color: #f2f2f2;
|
12 |
+
text-align: center;
|
13 |
+
padding: 16px 20px;
|
14 |
+
text-decoration: none;
|
15 |
+
font-size: 17px;
|
16 |
+
transition: background-color 0.3s ease; /* Adding transition */
|
17 |
+
}
|
18 |
+
|
19 |
+
.footnov a:hover {
|
20 |
+
background-color: #555; /* Slightly darker hover effect */
|
21 |
+
}
|
22 |
+
|
23 |
+
.footnov a.active {
|
24 |
+
background-color: rgb(80, 61, 226); /* Match header for consistency */
|
25 |
+
color: white;
|
26 |
+
}
|
27 |
+
|
28 |
+
@media screen and (max-width: 600px) {
|
29 |
+
.footnov a:not(:first-child) {display: none;}
|
30 |
+
.footnov a.icon {
|
31 |
+
float: right;
|
32 |
+
display: block;
|
33 |
+
}
|
34 |
+
}
|
35 |
+
|
36 |
+
@media screen and (max-width: 100px) {
|
37 |
+
.footnov.responsive {position: relative;}
|
38 |
+
.footnov.responsive .icon {
|
39 |
+
position: absolute;
|
40 |
+
right: 0;
|
41 |
+
top: 0;
|
42 |
+
}
|
43 |
+
.footnov.responsive a {
|
44 |
+
float: none;
|
45 |
+
display: block;
|
46 |
+
text-align: left;
|
47 |
+
}
|
48 |
+
}
|
app/static/header.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function myFunction() {
|
2 |
+
var x = document.getElementById("mytopnav");
|
3 |
+
if (x.className === "topnav") {
|
4 |
+
x.className += " responsive";
|
5 |
+
} else {
|
6 |
+
x.className = "topnav";
|
7 |
+
}
|
8 |
+
}
|
app/static/header_file.css
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
margin: 0;
|
3 |
+
text-align: left;
|
4 |
+
font-family: 'Roboto', sans-serif; /* More modern font choice */
|
5 |
+
}
|
6 |
+
|
7 |
+
.topnav {
|
8 |
+
overflow: hidden;
|
9 |
+
background-color: #007bff;
|
10 |
+
}
|
11 |
+
|
12 |
+
.topnav a {
|
13 |
+
float: left;
|
14 |
+
display: block;
|
15 |
+
color: white;
|
16 |
+
text-align: center;
|
17 |
+
padding: 16px 20px; /* Increased padding for a more spacious look */
|
18 |
+
text-decoration: none;
|
19 |
+
font-size: 17px;
|
20 |
+
margin-right: 15px;
|
21 |
+
transition: background-color 0.3s ease; /* Adding transition */
|
22 |
+
}
|
23 |
+
|
24 |
+
.topnav a:hover {
|
25 |
+
background-color: black; /* Black with low opacity */
|
26 |
+
color: white; /* Cleaner contrast */
|
27 |
+
}
|
28 |
+
|
29 |
+
.topnav a.active {
|
30 |
+
color: white;
|
31 |
+
}
|
32 |
+
|
33 |
+
/* Responsive Design */
|
34 |
+
@media screen and (max-width: 600px) {
|
35 |
+
.topnav a:not(:first-child) { display: none; }
|
36 |
+
.topnav a.icon {
|
37 |
+
float: right;
|
38 |
+
display: block;
|
39 |
+
font-size: 24px; /* Larger icon for better visibility */
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
@media screen and (max-width: 600px) {
|
44 |
+
.topnav.responsive { position: relative; }
|
45 |
+
.topnav.responsive .icon {
|
46 |
+
position: absolute;
|
47 |
+
right: 0;
|
48 |
+
top: 0;
|
49 |
+
}
|
50 |
+
.topnav.responsive a {
|
51 |
+
float: none;
|
52 |
+
display: block;
|
53 |
+
text-align: left;
|
54 |
+
}
|
55 |
+
}
|
56 |
+
|
57 |
+
|
58 |
+
.alert {
|
59 |
+
padding: 20px;
|
60 |
+
background-color: #f44336;
|
61 |
+
color: black;
|
62 |
+
}
|
63 |
+
|
64 |
+
.closebtn {
|
65 |
+
margin-left: 15px;
|
66 |
+
color: white;
|
67 |
+
font-weight: bold;
|
68 |
+
float: right;
|
69 |
+
font-size: 22px;
|
70 |
+
line-height: 20px;
|
71 |
+
cursor: pointer;
|
72 |
+
transition: 0.3s;
|
73 |
+
}
|
74 |
+
|
75 |
+
.closebtn:hover {
|
76 |
+
color: black;
|
77 |
+
}
|
app/static/login.css
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* login.css and register.css (adjust as needed) */
|
2 |
+
.container {
|
3 |
+
width: 400px;
|
4 |
+
margin: 50px auto;
|
5 |
+
padding: 20px;
|
6 |
+
border: 1px solid #ddd;
|
7 |
+
border-radius: 8px;
|
8 |
+
text-align: center;
|
9 |
+
background-color: #f8f8f8;
|
10 |
+
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
|
11 |
+
}
|
12 |
+
|
13 |
+
h1 {
|
14 |
+
margin-bottom: 20px;
|
15 |
+
color: #333;
|
16 |
+
}
|
17 |
+
|
18 |
+
input[type="text"], input[type="email"], input[type="password"] {
|
19 |
+
width: 100%;
|
20 |
+
padding: 10px;
|
21 |
+
margin-bottom: 15px;
|
22 |
+
border: 1px solid #ccc;
|
23 |
+
border-radius: 4px;
|
24 |
+
}
|
25 |
+
|
26 |
+
.button-primary { /* Reuse from previous example */
|
27 |
+
background-color: #007bff;
|
28 |
+
color: white;
|
29 |
+
border: none;
|
30 |
+
padding: 10px 20px;
|
31 |
+
text-decoration: none;
|
32 |
+
border-radius: 5px;
|
33 |
+
font-size: 1rem;
|
34 |
+
transition: background-color 0.3s ease;
|
35 |
+
}
|
36 |
+
|
37 |
+
.button-primary:hover {
|
38 |
+
background-color: #0056b3;
|
39 |
+
}
|
app/static/main.css
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Add a gradient background color to the body */
|
2 |
+
body {
|
3 |
+
background: linear-gradient(to right, #0f4da6, #0f4da6, #1e272e, #1e272e);
|
4 |
+
}
|
5 |
+
|
6 |
+
/* Center the content */
|
7 |
+
.container {
|
8 |
+
display: flex;
|
9 |
+
align-items: center;
|
10 |
+
justify-content: center;
|
11 |
+
flex-direction: column;
|
12 |
+
min-height: 100vh;
|
13 |
+
}
|
14 |
+
|
15 |
+
/* Style the header */
|
16 |
+
header {
|
17 |
+
background-color: #007bff;
|
18 |
+
color: white;
|
19 |
+
padding: 1rem;
|
20 |
+
position: fixed;
|
21 |
+
top: 0;
|
22 |
+
left: 0;
|
23 |
+
width: 100%;
|
24 |
+
z-index: 100;
|
25 |
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
26 |
+
}
|
27 |
+
|
28 |
+
h1.title-font {
|
29 |
+
font-family: 'Dancing Script', cursive;
|
30 |
+
font-weight: 400;
|
31 |
+
margin-bottom: 0.5rem;
|
32 |
+
color: white; /* Change the color to your desired color */
|
33 |
+
font-size: 2.5rem; /* Increase the font size */
|
34 |
+
animation: fadeIn 2s forwards; /* Apply animation */
|
35 |
+
}
|
36 |
+
|
37 |
+
p {
|
38 |
+
font-family: 'Dancing Script', cursive;
|
39 |
+
font-weight: 400;
|
40 |
+
margin-bottom: 0.5rem;
|
41 |
+
color: black; /* Change the color to your desired color */
|
42 |
+
font-size: 1.5rem; /* Increase the font size */
|
43 |
+
animation: fadeIn 2s forwards; /* Apply animation */
|
44 |
+
transition: color 0.5s ease-in-out; /* Apply transition */
|
45 |
+
|
46 |
+
}
|
47 |
+
|
48 |
+
@keyframes typing {
|
49 |
+
from { width: 0; }
|
50 |
+
to { width: 100%; }
|
51 |
+
}
|
52 |
+
|
53 |
+
@keyframes blink-caret {
|
54 |
+
from, to { border-color: transparent; }
|
55 |
+
50% { border-color: #ff00ff; } /* Change the color to your desired color */
|
56 |
+
}
|
57 |
+
|
58 |
+
|
59 |
+
p.title {
|
60 |
+
font-size: 2.5rem;
|
61 |
+
font-weight: bold;
|
62 |
+
text-transform: uppercase;
|
63 |
+
letter-spacing: 2px;
|
64 |
+
color: white;
|
65 |
+
margin-bottom: 2rem;
|
66 |
+
text-align: center;
|
67 |
+
animation: fadeIn 2s forwards;
|
68 |
+
transition: color 0.5s ease-in-out;
|
69 |
+
}
|
70 |
+
|
71 |
+
/* Animation for fading in */
|
72 |
+
@keyframes fadeIn {
|
73 |
+
0% {
|
74 |
+
opacity: 0;
|
75 |
+
}
|
76 |
+
100% {
|
77 |
+
opacity: 1;
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
/* Style the button */
|
82 |
+
.button-primary {
|
83 |
+
background-color: white;
|
84 |
+
color: black;
|
85 |
+
border: none;
|
86 |
+
padding: 10px 20px;
|
87 |
+
text-decoration: none;
|
88 |
+
border-radius: 5px;
|
89 |
+
font-size: 1rem;
|
90 |
+
transition: background-color 0.3s ease;
|
91 |
+
margin-top: 2rem;
|
92 |
+
animation: pulse 1s ease-in-out infinite;
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
.button-primary:hover {
|
97 |
+
background-color: #f0f0f0;
|
98 |
+
}
|
99 |
+
@keyframes pulse {
|
100 |
+
0% {
|
101 |
+
box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.5);
|
102 |
+
}
|
103 |
+
50% {
|
104 |
+
box-shadow: 0 0 0 10px rgba(0, 0, 0, 0.5);
|
105 |
+
}
|
106 |
+
100% {
|
107 |
+
box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.5);
|
108 |
+
}
|
109 |
+
}
|
app/static/main.js
ADDED
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* Copyright 2013 Chris Wilson
|
2 |
+
|
3 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
you may not use this file except in compliance with the License.
|
5 |
+
You may obtain a copy of the License at
|
6 |
+
|
7 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
|
9 |
+
Unless required by applicable law or agreed to in writing, software
|
10 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
See the License for the specific language governing permissions and
|
13 |
+
limitations under the License.
|
14 |
+
*/
|
15 |
+
|
16 |
+
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
17 |
+
|
18 |
+
var audioContext = new AudioContext();
|
19 |
+
var audioInput = null,
|
20 |
+
realAudioInput = null,
|
21 |
+
inputPoint = null,
|
22 |
+
audioRecorder = null;
|
23 |
+
var rafID = null;
|
24 |
+
var analyserContext = null;
|
25 |
+
var canvasWidth, canvasHeight;
|
26 |
+
var recIndex = 0;
|
27 |
+
|
28 |
+
|
29 |
+
function gotBuffers(buffers) {
|
30 |
+
audioRecorder.exportMonoWAV(doneEncoding);
|
31 |
+
}
|
32 |
+
|
33 |
+
function doneEncoding(soundBlob) {
|
34 |
+
fetch('/audio', {
|
35 |
+
method: "POST", // Specify POST method
|
36 |
+
body: soundBlob
|
37 |
+
})
|
38 |
+
.then(response => {
|
39 |
+
if (response.ok) {
|
40 |
+
return response.json(); // Parse JSON response
|
41 |
+
} else {
|
42 |
+
throw new Error("Error in Flask /audio route: " + response.status);
|
43 |
+
}
|
44 |
+
})
|
45 |
+
.then(data => {
|
46 |
+
window.location.href = data.url; // Redirect using URL from the response
|
47 |
+
})
|
48 |
+
.catch(error => {
|
49 |
+
console.error(error);
|
50 |
+
});
|
51 |
+
}
|
52 |
+
|
53 |
+
|
54 |
+
function stopRecording() {
|
55 |
+
// stop recording
|
56 |
+
audioRecorder.stop();
|
57 |
+
document.getElementById('stop').disabled = true;
|
58 |
+
document.getElementById('start').removeAttribute('disabled');
|
59 |
+
audioRecorder.getBuffers(gotBuffers);
|
60 |
+
}
|
61 |
+
|
62 |
+
function startRecording() {
|
63 |
+
|
64 |
+
// start recording
|
65 |
+
if (!audioRecorder)
|
66 |
+
return;
|
67 |
+
document.getElementById('start').disabled = true;
|
68 |
+
document.getElementById('stop').removeAttribute('disabled');
|
69 |
+
audioRecorder.clear();
|
70 |
+
audioRecorder.record();
|
71 |
+
}
|
72 |
+
|
73 |
+
function convertToMono(input) {
|
74 |
+
var splitter = audioContext.createChannelSplitter(2);
|
75 |
+
var merger = audioContext.createChannelMerger(2);
|
76 |
+
|
77 |
+
input.connect(splitter);
|
78 |
+
splitter.connect(merger, 0, 0);
|
79 |
+
splitter.connect(merger, 0, 1);
|
80 |
+
return merger;
|
81 |
+
}
|
82 |
+
|
83 |
+
function cancelAnalyserUpdates() {
|
84 |
+
window.cancelAnimationFrame(rafID);
|
85 |
+
rafID = null;
|
86 |
+
}
|
87 |
+
|
88 |
+
function updateAnalysers(time) {
|
89 |
+
if (!analyserContext) {
|
90 |
+
var canvas = document.getElementById("analyser");
|
91 |
+
console.log("Canvas:", canvas); // Log 1
|
92 |
+
if (canvas) { // Check canvas exists
|
93 |
+
canvasWidth = canvas.width;
|
94 |
+
canvasHeight = canvas.height;
|
95 |
+
analyserContext = canvas.getContext('2d');
|
96 |
+
} else {
|
97 |
+
console.error("Canvas with ID 'analyser' not found!");
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
// analyzer draw code here
|
102 |
+
{
|
103 |
+
var SPACING = 3;
|
104 |
+
var BAR_WIDTH = 1;
|
105 |
+
var numBars = Math.round(canvasWidth / SPACING);
|
106 |
+
var freqByteData = new Uint8Array(analyserNode.frequencyBinCount);
|
107 |
+
|
108 |
+
analyserNode.getByteFrequencyData(freqByteData);
|
109 |
+
|
110 |
+
analyserContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
111 |
+
analyserContext.fillStyle = '#F6D565';
|
112 |
+
analyserContext.lineCap = 'round';
|
113 |
+
var multiplier = analyserNode.frequencyBinCount / numBars;
|
114 |
+
|
115 |
+
// Draw rectangle for each frequency bin.
|
116 |
+
for (var i = 0; i < numBars; ++i) {
|
117 |
+
var magnitude = 0;
|
118 |
+
var offset = Math.floor(i * multiplier);
|
119 |
+
// gotta sum/average the block, or we miss narrow-bandwidth spikes
|
120 |
+
for (var j = 0; j < multiplier; j++)
|
121 |
+
magnitude += freqByteData[offset + j];
|
122 |
+
magnitude = magnitude / multiplier;
|
123 |
+
var magnitude2 = freqByteData[i * multiplier];
|
124 |
+
analyserContext.fillStyle = "hsl( " + Math.round((i * 360) / numBars) + ", 100%, 50%)";
|
125 |
+
analyserContext.fillRect(i * SPACING, canvasHeight, BAR_WIDTH, -magnitude);
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
rafID = window.requestAnimationFrame(updateAnalysers);
|
130 |
+
}
|
131 |
+
|
132 |
+
function toggleMono() {
|
133 |
+
if (audioInput != realAudioInput) {
|
134 |
+
audioInput.disconnect();
|
135 |
+
realAudioInput.disconnect();
|
136 |
+
audioInput = realAudioInput;
|
137 |
+
} else {
|
138 |
+
realAudioInput.disconnect();
|
139 |
+
audioInput = convertToMono(realAudioInput);
|
140 |
+
}
|
141 |
+
|
142 |
+
audioInput.connect(inputPoint);
|
143 |
+
}
|
144 |
+
|
145 |
+
function gotStream(stream) {
|
146 |
+
document.getElementById('start').removeAttribute('disabled');
|
147 |
+
|
148 |
+
inputPoint = audioContext.createGain();
|
149 |
+
|
150 |
+
// Create an AudioNode from the stream.
|
151 |
+
realAudioInput = audioContext.createMediaStreamSource(stream);
|
152 |
+
audioInput = realAudioInput;
|
153 |
+
audioInput.connect(inputPoint);
|
154 |
+
|
155 |
+
// audioInput = convertToMono( input );
|
156 |
+
|
157 |
+
analyserNode = audioContext.createAnalyser();
|
158 |
+
analyserNode.fftSize = 2048;
|
159 |
+
inputPoint.connect(analyserNode);
|
160 |
+
|
161 |
+
audioRecorder = new Recorder(inputPoint);
|
162 |
+
|
163 |
+
zeroGain = audioContext.createGain();
|
164 |
+
zeroGain.gain.value = 0.0;
|
165 |
+
inputPoint.connect(zeroGain);
|
166 |
+
zeroGain.connect(audioContext.destination);
|
167 |
+
updateAnalysers();
|
168 |
+
}
|
169 |
+
|
170 |
+
function initAudio() {
|
171 |
+
if (!navigator.getUserMedia)
|
172 |
+
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
|
173 |
+
if (!navigator.cancelAnimationFrame)
|
174 |
+
navigator.cancelAnimationFrame = navigator.webkitCancelAnimationFrame || navigator.mozCancelAnimationFrame;
|
175 |
+
if (!navigator.requestAnimationFrame)
|
176 |
+
navigator.requestAnimationFrame = navigator.webkitRequestAnimationFrame || navigator.mozRequestAnimationFrame;
|
177 |
+
|
178 |
+
navigator.getUserMedia(
|
179 |
+
{
|
180 |
+
"audio": {
|
181 |
+
"mandatory": {
|
182 |
+
"googEchoCancellation": "false",
|
183 |
+
"googAutoGainControl": "false",
|
184 |
+
"googNoiseSuppression": "false",
|
185 |
+
"googHighpassFilter": "false"
|
186 |
+
},
|
187 |
+
"optional": []
|
188 |
+
},
|
189 |
+
}, gotStream, function (e) {
|
190 |
+
alert('Error getting audio');
|
191 |
+
console.log(e);
|
192 |
+
});
|
193 |
+
}
|
194 |
+
|
195 |
+
window.addEventListener('load', initAudio);
|
196 |
+
|
197 |
+
function unpause() {
|
198 |
+
document.getElementById('init').style.display = 'none';
|
199 |
+
audioContext.resume().then(() => {
|
200 |
+
console.log('Playback resumed successfully');
|
201 |
+
});
|
202 |
+
}
|
app/static/recorder.js
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function(window){
|
2 |
+
|
3 |
+
var WORKER_PATH = '/static/recorderWorker.js';
|
4 |
+
|
5 |
+
var Recorder = function(source, cfg){
|
6 |
+
var config = cfg || {};
|
7 |
+
var bufferLen = config.bufferLen || 4096;
|
8 |
+
this.context = source.context;
|
9 |
+
if(!this.context.createScriptProcessor){
|
10 |
+
this.node = this.context.createJavaScriptNode(bufferLen, 2, 2);
|
11 |
+
} else {
|
12 |
+
this.node = this.context.createScriptProcessor(bufferLen, 2, 2);
|
13 |
+
}
|
14 |
+
|
15 |
+
var worker = new Worker(config.workerPath || WORKER_PATH);
|
16 |
+
worker.postMessage({
|
17 |
+
command: 'init',
|
18 |
+
config: {
|
19 |
+
sampleRate: this.context.sampleRate
|
20 |
+
}
|
21 |
+
});
|
22 |
+
var recording = false,
|
23 |
+
currCallback;
|
24 |
+
|
25 |
+
this.node.onaudioprocess = function(e){
|
26 |
+
if (!recording) return;
|
27 |
+
worker.postMessage({
|
28 |
+
command: 'record',
|
29 |
+
buffer: [
|
30 |
+
e.inputBuffer.getChannelData(0),
|
31 |
+
e.inputBuffer.getChannelData(1)
|
32 |
+
]
|
33 |
+
});
|
34 |
+
}
|
35 |
+
|
36 |
+
this.configure = function(cfg){
|
37 |
+
for (var prop in cfg){
|
38 |
+
if (cfg.hasOwnProperty(prop)){
|
39 |
+
config[prop] = cfg[prop];
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
this.record = function(){
|
45 |
+
recording = true;
|
46 |
+
}
|
47 |
+
|
48 |
+
this.stop = function(){
|
49 |
+
recording = false;
|
50 |
+
}
|
51 |
+
|
52 |
+
this.clear = function(){
|
53 |
+
worker.postMessage({ command: 'clear' });
|
54 |
+
}
|
55 |
+
|
56 |
+
this.getBuffers = function(cb) {
|
57 |
+
currCallback = cb || config.callback;
|
58 |
+
worker.postMessage({ command: 'getBuffers' })
|
59 |
+
}
|
60 |
+
|
61 |
+
this.exportWAV = function(cb, type){
|
62 |
+
currCallback = cb || config.callback;
|
63 |
+
type = type || config.type || 'audio/wav';
|
64 |
+
if (!currCallback) throw new Error('Callback not set');
|
65 |
+
worker.postMessage({
|
66 |
+
command: 'exportWAV',
|
67 |
+
type: type
|
68 |
+
});
|
69 |
+
}
|
70 |
+
|
71 |
+
this.exportMonoWAV = function(cb, type){
|
72 |
+
currCallback = cb || config.callback;
|
73 |
+
type = type || config.type || 'audio/wav';
|
74 |
+
if (!currCallback) throw new Error('Callback not set');
|
75 |
+
worker.postMessage({
|
76 |
+
command: 'exportMonoWAV',
|
77 |
+
type: type
|
78 |
+
});
|
79 |
+
}
|
80 |
+
|
81 |
+
worker.onmessage = function(e){
|
82 |
+
var blob = e.data;
|
83 |
+
currCallback(blob);
|
84 |
+
}
|
85 |
+
|
86 |
+
source.connect(this.node);
|
87 |
+
this.node.connect(this.context.destination); // if the script node is not connected to an output the "onaudioprocess" event is not triggered in chrome.
|
88 |
+
};
|
89 |
+
|
90 |
+
Recorder.setupDownload = function(blob, filename){
|
91 |
+
var url = (window.URL || window.webkitURL).createObjectURL(blob);
|
92 |
+
var link = document.getElementById("save");
|
93 |
+
link.href = url;
|
94 |
+
link.download = filename || 'output.wav';
|
95 |
+
}
|
96 |
+
|
97 |
+
window.Recorder = Recorder;
|
98 |
+
|
99 |
+
})(window);
|