Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .idea/.gitignore +8 -0
- .idea/ai-avatar-backend.iml +11 -0
- .idea/inspectionProfiles/Project_Default.xml +78 -0
- .idea/inspectionProfiles/profiles_settings.xml +6 -0
- .idea/misc.xml +4 -0
- .idea/modules.xml +8 -0
- .idea/vcs.xml +6 -0
- .idea/workspace.xml +55 -0
- Dockerfile +19 -0
- README.md +19 -11
- app.js +45 -0
- bin/www +90 -0
- helpers/blendshapeNames.js +55 -0
- helpers/callOpenAI.js +20 -0
- helpers/tts.js +92 -0
- package-lock.json +0 -0
- package.json +23 -0
- public/speech-1rgjg.mp3 +0 -0
- public/speech-41t4z.mp3 +0 -0
- public/speech-72ibm.mp3 +0 -0
- public/speech-8h55r.mp3 +0 -0
- public/speech-93rz1.mp3 +0 -0
- public/speech-aqzjq.mp3 +0 -0
- public/speech-dhexe.mp3 +0 -0
- public/speech-epmmj.mp3 +0 -0
- public/speech-fzuh9.mp3 +0 -0
- public/speech-g241j.mp3 +0 -0
- public/speech-grdkw.mp3 +0 -0
- public/speech-gsce8.mp3 +0 -0
- public/speech-ide8w.mp3 +0 -0
- public/speech-ir0sf.mp3 +0 -0
- public/speech-jrc8j.mp3 +0 -0
- public/speech-k9whu.mp3 +0 -0
- public/speech-n6nec.mp3 +0 -0
- public/speech-pfhzn.mp3 +0 -0
- public/speech-q0zfc.mp3 +0 -0
- public/speech-un80i.mp3 +0 -0
- public/speech-vz8nr.mp3 +0 -0
- public/speech-vzpdi.mp3 +0 -0
- public/speech-wd5uf.mp3 +0 -0
- public/speech-xcd5h.mp3 +0 -0
- public/stylesheets/style.css +8 -0
- routes/index.js +27 -0
- views/error.pug +6 -0
- views/index.pug +5 -0
- views/layout.pug +7 -0
.idea/.gitignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Default ignored files
|
2 |
+
/shelf/
|
3 |
+
/workspace.xml
|
4 |
+
# Datasource local storage ignored files
|
5 |
+
/dataSources/
|
6 |
+
/dataSources.local.xml
|
7 |
+
# Editor-based HTTP Client requests
|
8 |
+
/httpRequests/
|
.idea/ai-avatar-backend.iml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<module type="PYTHON_MODULE" version="4">
|
3 |
+
<component name="NewModuleRootManager">
|
4 |
+
<content url="file://$MODULE_DIR$" />
|
5 |
+
<orderEntry type="jdk" jdkName="Python 3.9 (avatar-ai)" jdkType="Python SDK" />
|
6 |
+
<orderEntry type="sourceFolder" forTests="false" />
|
7 |
+
</component>
|
8 |
+
<component name="TestRunnerService">
|
9 |
+
<option name="PROJECT_TEST_RUNNER" value="pytest" />
|
10 |
+
</component>
|
11 |
+
</module>
|
.idea/inspectionProfiles/Project_Default.xml
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<profile version="1.0">
|
3 |
+
<option name="myName" value="Project Default" />
|
4 |
+
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
5 |
+
<Languages>
|
6 |
+
<language minSize="79" name="Python" />
|
7 |
+
</Languages>
|
8 |
+
</inspection_tool>
|
9 |
+
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
10 |
+
<option name="ignoredPackages">
|
11 |
+
<value>
|
12 |
+
<list size="45">
|
13 |
+
<item index="0" class="java.lang.String" itemvalue="beautifulsoup4" />
|
14 |
+
<item index="1" class="java.lang.String" itemvalue="bs4" />
|
15 |
+
<item index="2" class="java.lang.String" itemvalue="mecab-python3" />
|
16 |
+
<item index="3" class="java.lang.String" itemvalue="pydantic" />
|
17 |
+
<item index="4" class="java.lang.String" itemvalue="joblib" />
|
18 |
+
<item index="5" class="java.lang.String" itemvalue="scikit-learn" />
|
19 |
+
<item index="6" class="java.lang.String" itemvalue="torch" />
|
20 |
+
<item index="7" class="java.lang.String" itemvalue="numpy" />
|
21 |
+
<item index="8" class="java.lang.String" itemvalue="requests" />
|
22 |
+
<item index="9" class="java.lang.String" itemvalue="unidic-lite" />
|
23 |
+
<item index="10" class="java.lang.String" itemvalue="mysql-connector-python" />
|
24 |
+
<item index="11" class="java.lang.String" itemvalue="sqlalchemy" />
|
25 |
+
<item index="12" class="java.lang.String" itemvalue="pycaret" />
|
26 |
+
<item index="13" class="java.lang.String" itemvalue="tensorflow-text" />
|
27 |
+
<item index="14" class="java.lang.String" itemvalue="keybert" />
|
28 |
+
<item index="15" class="java.lang.String" itemvalue="pandas" />
|
29 |
+
<item index="16" class="java.lang.String" itemvalue="tqdm" />
|
30 |
+
<item index="17" class="java.lang.String" itemvalue="fastapi" />
|
31 |
+
<item index="18" class="java.lang.String" itemvalue="spacy" />
|
32 |
+
<item index="19" class="java.lang.String" itemvalue="regex" />
|
33 |
+
<item index="20" class="java.lang.String" itemvalue="tensorflow-hub" />
|
34 |
+
<item index="21" class="java.lang.String" itemvalue="uvicorn" />
|
35 |
+
<item index="22" class="java.lang.String" itemvalue="xgboost" />
|
36 |
+
<item index="23" class="java.lang.String" itemvalue="onnxruntime" />
|
37 |
+
<item index="24" class="java.lang.String" itemvalue="av" />
|
38 |
+
<item index="25" class="java.lang.String" itemvalue="onnx" />
|
39 |
+
<item index="26" class="java.lang.String" itemvalue="opencv-python-headless" />
|
40 |
+
<item index="27" class="java.lang.String" itemvalue="streamlit_webrtc" />
|
41 |
+
<item index="28" class="java.lang.String" itemvalue="torchvision" />
|
42 |
+
<item index="29" class="java.lang.String" itemvalue="cdifflib" />
|
43 |
+
<item index="30" class="java.lang.String" itemvalue="protobuf" />
|
44 |
+
<item index="31" class="java.lang.String" itemvalue="python-stdnum" />
|
45 |
+
<item index="32" class="java.lang.String" itemvalue="transformers" />
|
46 |
+
<item index="33" class="java.lang.String" itemvalue="nltk" />
|
47 |
+
<item index="34" class="java.lang.String" itemvalue="sentence-transformers" />
|
48 |
+
<item index="35" class="java.lang.String" itemvalue="datasets" />
|
49 |
+
<item index="36" class="java.lang.String" itemvalue="fsspec" />
|
50 |
+
<item index="37" class="java.lang.String" itemvalue="neuralcoref" />
|
51 |
+
<item index="38" class="java.lang.String" itemvalue="dateparse" />
|
52 |
+
<item index="39" class="java.lang.String" itemvalue="faker" />
|
53 |
+
<item index="40" class="java.lang.String" itemvalue="sentencepiece" />
|
54 |
+
<item index="41" class="java.lang.String" itemvalue="langid" />
|
55 |
+
<item index="42" class="java.lang.String" itemvalue="boto3" />
|
56 |
+
<item index="43" class="java.lang.String" itemvalue="redis" />
|
57 |
+
<item index="44" class="java.lang.String" itemvalue="celery" />
|
58 |
+
</list>
|
59 |
+
</value>
|
60 |
+
</option>
|
61 |
+
</inspection_tool>
|
62 |
+
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
63 |
+
<option name="ignoredErrors">
|
64 |
+
<list>
|
65 |
+
<option value="N801" />
|
66 |
+
</list>
|
67 |
+
</option>
|
68 |
+
</inspection_tool>
|
69 |
+
<inspection_tool class="PyTypedDictInspection" enabled="false" level="WARNING" enabled_by_default="false" />
|
70 |
+
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
71 |
+
<option name="ignoredIdentifiers">
|
72 |
+
<list>
|
73 |
+
<option value="wbc.assets.templates.template_script.process.pattern_name" />
|
74 |
+
</list>
|
75 |
+
</option>
|
76 |
+
</inspection_tool>
|
77 |
+
</profile>
|
78 |
+
</component>
|
.idea/inspectionProfiles/profiles_settings.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<component name="InspectionProjectProfileManager">
|
2 |
+
<settings>
|
3 |
+
<option name="USE_PROJECT_PROFILE" value="false" />
|
4 |
+
<version value="1.0" />
|
5 |
+
</settings>
|
6 |
+
</component>
|
.idea/misc.xml
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (avatar-ai)" project-jdk-type="Python SDK" />
|
4 |
+
</project>
|
.idea/modules.xml
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="ProjectModuleManager">
|
4 |
+
<modules>
|
5 |
+
<module fileurl="file://$PROJECT_DIR$/.idea/ai-avatar-backend.iml" filepath="$PROJECT_DIR$/.idea/ai-avatar-backend.iml" />
|
6 |
+
</modules>
|
7 |
+
</component>
|
8 |
+
</project>
|
.idea/vcs.xml
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="VcsDirectoryMappings">
|
4 |
+
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
5 |
+
</component>
|
6 |
+
</project>
|
.idea/workspace.xml
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" encoding="UTF-8"?>
|
2 |
+
<project version="4">
|
3 |
+
<component name="ChangeListManager">
|
4 |
+
<list default="true" id="74049918-f54d-42f5-ad7d-c4697cbf6820" name="Default Changelist" comment="">
|
5 |
+
<change afterPath="$PROJECT_DIR$/Dockerfile" afterDir="false" />
|
6 |
+
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
7 |
+
</list>
|
8 |
+
<option name="SHOW_DIALOG" value="false" />
|
9 |
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
10 |
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
11 |
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
12 |
+
</component>
|
13 |
+
<component name="Git.Settings">
|
14 |
+
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
15 |
+
</component>
|
16 |
+
<component name="ProjectId" id="2WCeCg5aWbUXqGVwe1ThKSdE6Li" />
|
17 |
+
<component name="ProjectViewState">
|
18 |
+
<option name="hideEmptyMiddlePackages" value="true" />
|
19 |
+
<option name="showLibraryContents" value="true" />
|
20 |
+
</component>
|
21 |
+
<component name="PropertiesComponent">
|
22 |
+
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
23 |
+
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
|
24 |
+
<property name="WebServerToolWindowFactoryState" value="false" />
|
25 |
+
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
26 |
+
<property name="nodejs_package_manager_path" value="npm" />
|
27 |
+
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
|
28 |
+
</component>
|
29 |
+
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
30 |
+
<component name="TaskManager">
|
31 |
+
<task active="true" id="Default" summary="Default task">
|
32 |
+
<changelist id="74049918-f54d-42f5-ad7d-c4697cbf6820" name="Default Changelist" comment="" />
|
33 |
+
<created>1696240862794</created>
|
34 |
+
<option name="number" value="Default" />
|
35 |
+
<option name="presentableId" value="Default" />
|
36 |
+
<updated>1696240862794</updated>
|
37 |
+
<workItem from="1696240864567" duration="150000" />
|
38 |
+
</task>
|
39 |
+
<servers />
|
40 |
+
</component>
|
41 |
+
<component name="TypeScriptGeneratedFilesManager">
|
42 |
+
<option name="version" value="3" />
|
43 |
+
</component>
|
44 |
+
<component name="Vcs.Log.Tabs.Properties">
|
45 |
+
<option name="TAB_STATES">
|
46 |
+
<map>
|
47 |
+
<entry key="MAIN">
|
48 |
+
<value>
|
49 |
+
<State />
|
50 |
+
</value>
|
51 |
+
</entry>
|
52 |
+
</map>
|
53 |
+
</option>
|
54 |
+
</component>
|
55 |
+
</project>
|
Dockerfile
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM node:16
|
2 |
+
|
3 |
+
# Set the working directory inside the container
|
4 |
+
WORKDIR /usr/src/app
|
5 |
+
|
6 |
+
# Copy package.json and package-lock.json (if available) to the working directory
|
7 |
+
COPY package*.json ./
|
8 |
+
|
9 |
+
# Install application dependencies
|
10 |
+
RUN npm install
|
11 |
+
|
12 |
+
# Copy the rest of the application to the working directory
|
13 |
+
COPY . .
|
14 |
+
|
15 |
+
# Expose the port the app runs on
|
16 |
+
EXPOSE 5000
|
17 |
+
|
18 |
+
# Command to run the application
|
19 |
+
CMD [ "npm", "start" ]
|
README.md
CHANGED
@@ -1,11 +1,19 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Talking Avatar backend
|
2 |
+
The text to speech and blendShapes converter for https://github.com/bornfree/talking_avatar.
|
3 |
+
Uses the [Azure APIs](https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/how-to-speech-synthesis-viseme) to get stuff done.
|
4 |
+
|
5 |
+
This is a simple ExpressJS app.
|
6 |
+
|
7 |
+
### Get keys from Azure and create a `.env` in the root directory with
|
8 |
+
```
|
9 |
+
AZURE_KEY=
|
10 |
+
AZURE_REGION=
|
11 |
+
```
|
12 |
+
|
13 |
+
|
14 |
+
### To run
|
15 |
+
```
|
16 |
+
$ npm install
|
17 |
+
$ npm start
|
18 |
+
```
|
19 |
+
|
app.js
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var createError = require('http-errors');
|
2 |
+
var express = require('express');
|
3 |
+
var path = require('path');
|
4 |
+
var cookieParser = require('cookie-parser');
|
5 |
+
var logger = require('morgan');
|
6 |
+
var cors = require('cors');
|
7 |
+
|
8 |
+
var indexRouter = require('./routes/index');
|
9 |
+
|
10 |
+
var app = express();
|
11 |
+
|
12 |
+
|
13 |
+
// view engine setup
|
14 |
+
app.set('views', path.join(__dirname, 'views'));
|
15 |
+
app.set('view engine', 'pug');
|
16 |
+
|
17 |
+
var corsOptions = {
|
18 |
+
origin: '*'
|
19 |
+
};
|
20 |
+
app.use(cors(corsOptions));
|
21 |
+
app.use(logger('dev'));
|
22 |
+
app.use(express.json());
|
23 |
+
app.use(express.urlencoded({ extended: false }));
|
24 |
+
app.use(cookieParser());
|
25 |
+
app.use(express.static(path.join(__dirname, 'public')));
|
26 |
+
|
27 |
+
app.use('/', indexRouter);
|
28 |
+
|
29 |
+
// catch 404 and forward to error handler
|
30 |
+
app.use(function(req, res, next) {
|
31 |
+
next(createError(404));
|
32 |
+
});
|
33 |
+
|
34 |
+
// error handler
|
35 |
+
app.use(function(err, req, res, next) {
|
36 |
+
// set locals, only providing error in development
|
37 |
+
res.locals.message = err.message;
|
38 |
+
res.locals.error = req.app.get('env') === 'development' ? err : {};
|
39 |
+
|
40 |
+
// render the error page
|
41 |
+
res.status(err.status || 500);
|
42 |
+
res.render('error');
|
43 |
+
});
|
44 |
+
|
45 |
+
module.exports = app;
|
bin/www
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env node
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Module dependencies.
|
5 |
+
*/
|
6 |
+
|
7 |
+
var app = require('../app');
|
8 |
+
var debug = require('debug')('talking-avatar-backend:server');
|
9 |
+
var http = require('http');
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Get port from environment and store in Express.
|
13 |
+
*/
|
14 |
+
|
15 |
+
var port = normalizePort(process.env.PORT || '5000');
|
16 |
+
app.set('port', port);
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Create HTTP server.
|
20 |
+
*/
|
21 |
+
|
22 |
+
var server = http.createServer(app);
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Listen on provided port, on all network interfaces.
|
26 |
+
*/
|
27 |
+
|
28 |
+
server.listen(port);
|
29 |
+
server.on('error', onError);
|
30 |
+
server.on('listening', onListening);
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Normalize a port into a number, string, or false.
|
34 |
+
*/
|
35 |
+
|
36 |
+
function normalizePort(val) {
|
37 |
+
var port = parseInt(val, 10);
|
38 |
+
|
39 |
+
if (isNaN(port)) {
|
40 |
+
// named pipe
|
41 |
+
return val;
|
42 |
+
}
|
43 |
+
|
44 |
+
if (port >= 0) {
|
45 |
+
// port number
|
46 |
+
return port;
|
47 |
+
}
|
48 |
+
|
49 |
+
return false;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Event listener for HTTP server "error" event.
|
54 |
+
*/
|
55 |
+
|
56 |
+
function onError(error) {
|
57 |
+
if (error.syscall !== 'listen') {
|
58 |
+
throw error;
|
59 |
+
}
|
60 |
+
|
61 |
+
var bind = typeof port === 'string'
|
62 |
+
? 'Pipe ' + port
|
63 |
+
: 'Port ' + port;
|
64 |
+
|
65 |
+
// handle specific listen errors with friendly messages
|
66 |
+
switch (error.code) {
|
67 |
+
case 'EACCES':
|
68 |
+
console.error(bind + ' requires elevated privileges');
|
69 |
+
process.exit(1);
|
70 |
+
break;
|
71 |
+
case 'EADDRINUSE':
|
72 |
+
console.error(bind + ' is already in use');
|
73 |
+
process.exit(1);
|
74 |
+
break;
|
75 |
+
default:
|
76 |
+
throw error;
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Event listener for HTTP server "listening" event.
|
82 |
+
*/
|
83 |
+
|
84 |
+
function onListening() {
|
85 |
+
var addr = server.address();
|
86 |
+
var bind = typeof addr === 'string'
|
87 |
+
? 'pipe ' + addr
|
88 |
+
: 'port ' + addr.port;
|
89 |
+
debug('Listening on ' + bind);
|
90 |
+
}
|
helpers/blendshapeNames.js
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = ["eyeBlinkLeft",
|
2 |
+
"eyeLookDownLeft",
|
3 |
+
"eyeLookInLeft",
|
4 |
+
"eyeLookOutLeft",
|
5 |
+
"eyeLookUpLeft",
|
6 |
+
"eyeSquintLeft",
|
7 |
+
"eyeWideLeft",
|
8 |
+
"eyeBlinkRight",
|
9 |
+
"eyeLookDownRight",
|
10 |
+
"eyeLookInRight",
|
11 |
+
"eyeLookOutRight",
|
12 |
+
"eyeLookUpRight",
|
13 |
+
"eyeSquintRight",
|
14 |
+
"eyeWideRight",
|
15 |
+
"jawForward",
|
16 |
+
"jawLeft",
|
17 |
+
"jawRight",
|
18 |
+
"jawOpen",
|
19 |
+
"mouthClose",
|
20 |
+
"mouthFunnel",
|
21 |
+
"mouthPucker",
|
22 |
+
"mouthLeft",
|
23 |
+
"mouthRight",
|
24 |
+
"mouthSmileLeft",
|
25 |
+
"mouthSmileRight",
|
26 |
+
"mouthFrownLeft",
|
27 |
+
"mouthFrownRight",
|
28 |
+
"mouthDimpleLeft",
|
29 |
+
"mouthDimpleRight",
|
30 |
+
"mouthStretchLeft",
|
31 |
+
"mouthStretchRight",
|
32 |
+
"mouthRollLower",
|
33 |
+
"mouthRollUpper",
|
34 |
+
"mouthShrugLower",
|
35 |
+
"mouthShrugUpper",
|
36 |
+
"mouthPressLeft",
|
37 |
+
"mouthPressRight",
|
38 |
+
"mouthLowerDownLeft",
|
39 |
+
"mouthLowerDownRight",
|
40 |
+
"mouthUpperUpLeft",
|
41 |
+
"mouthUpperUpRight",
|
42 |
+
"browDownLeft",
|
43 |
+
"browDownRight",
|
44 |
+
"browInnerUp",
|
45 |
+
"browOuterUpLeft",
|
46 |
+
"browOuterUpRight",
|
47 |
+
"cheekPuff",
|
48 |
+
"cheekSquintLeft",
|
49 |
+
"cheekSquintRight",
|
50 |
+
"noseSneerLeft",
|
51 |
+
"noseSneerRight",
|
52 |
+
"tongueOut",
|
53 |
+
"headRoll",
|
54 |
+
"leftEyeRoll",
|
55 |
+
"rightEyeRoll"]
|
helpers/callOpenAI.js
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const OpenAI = require('openai');
|
2 |
+
|
3 |
+
const openai = new OpenAI({
|
4 |
+
apiKey: process.env.OPENAI_API_KEY, // defaults to process.env["OPENAI_API_KEY"]
|
5 |
+
dangerouslyAllowBrowser: true
|
6 |
+
});
|
7 |
+
|
8 |
+
async function queryOpenAIAndSave(userContent) {
|
9 |
+
const response = await openai.chat.completions.create({
|
10 |
+
model: "gpt-3.5-turbo",
|
11 |
+
messages: [
|
12 |
+
{"role": "system", "content": "You are a helpful assistant made by Detomo company. Please answer the following questions with maximum 2 sentence. Answer by the language of the question."},
|
13 |
+
{"role": "user", "content": userContent},
|
14 |
+
],
|
15 |
+
});
|
16 |
+
|
17 |
+
return response.choices[0].message.content;
|
18 |
+
}
|
19 |
+
|
20 |
+
module.exports = queryOpenAIAndSave;
|
helpers/tts.js
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// azure-cognitiveservices-speech.js
|
2 |
+
require('dotenv').config()
|
3 |
+
const sdk = require('microsoft-cognitiveservices-speech-sdk');
|
4 |
+
const blendShapeNames = require('./blendshapeNames');
|
5 |
+
const _ = require('lodash');
|
6 |
+
const voicesMap = {
|
7 |
+
'en-US': 'en-US-AmberNeural',
|
8 |
+
'ja-JP': 'ja-JP-MayuNeural',
|
9 |
+
'vi-VN': 'vi-VN-NamMinhNeural',
|
10 |
+
};
|
11 |
+
|
12 |
+
let SSML = `<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="en-US">
|
13 |
+
<voice name="en-US-JennyNeural">
|
14 |
+
<mstts:viseme type="FacialExpression"/>
|
15 |
+
__TEXT__
|
16 |
+
</voice>
|
17 |
+
</speak>`;
|
18 |
+
|
19 |
+
const key = process.env.AZURE_KEY;
|
20 |
+
const region = process.env.AZURE_REGION;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Node.js server code to convert text to speech
|
24 |
+
* @returns stream
|
25 |
+
* @param {*} text text to convert to audio/speech
|
26 |
+
* @param language
|
27 |
+
*/
|
28 |
+
const textToSpeech = async (text, language)=> {
|
29 |
+
|
30 |
+
// convert callback function to promise
|
31 |
+
return new Promise((resolve, reject) => {
|
32 |
+
|
33 |
+
const voice = voicesMap[language];
|
34 |
+
let ssml = SSML.replace("__TEXT__", text).replace("<voice name=\"en-US-JennyNeural\">", `<voice name="${voice}">`);
|
35 |
+
|
36 |
+
|
37 |
+
const speechConfig = sdk.SpeechConfig.fromSubscription(key, region);
|
38 |
+
speechConfig.speechSynthesisOutputFormat = 5; // mp3
|
39 |
+
|
40 |
+
let audioConfig = null;
|
41 |
+
|
42 |
+
// if (filename) {
|
43 |
+
let randomString = Math.random().toString(36).slice(2, 7);
|
44 |
+
let filename = `./public/speech-${randomString}.mp3`;
|
45 |
+
audioConfig = sdk.AudioConfig.fromAudioFileOutput(filename);
|
46 |
+
// }
|
47 |
+
|
48 |
+
let blendData = [];
|
49 |
+
let timeStep = 1/60;
|
50 |
+
let timeStamp = 0;
|
51 |
+
|
52 |
+
const synthesizer = new sdk.SpeechSynthesizer(speechConfig, audioConfig);
|
53 |
+
|
54 |
+
// Subscribes to viseme received event
|
55 |
+
synthesizer.visemeReceived = function (s, e) {
|
56 |
+
|
57 |
+
// `Animation` is an xml string for SVG or a json string for blend shapes
|
58 |
+
var animation = JSON.parse(e.animation);
|
59 |
+
|
60 |
+
_.each(animation.BlendShapes, blendArray => {
|
61 |
+
|
62 |
+
let blend = {};
|
63 |
+
_.each(blendShapeNames, (shapeName, i) => {
|
64 |
+
blend[shapeName] = blendArray[i];
|
65 |
+
});
|
66 |
+
|
67 |
+
blendData.push({
|
68 |
+
time: timeStamp,
|
69 |
+
blendshapes: blend
|
70 |
+
});
|
71 |
+
timeStamp += timeStep;
|
72 |
+
});
|
73 |
+
|
74 |
+
}
|
75 |
+
|
76 |
+
|
77 |
+
synthesizer.speakSsmlAsync(
|
78 |
+
ssml,
|
79 |
+
result => {
|
80 |
+
|
81 |
+
synthesizer.close();
|
82 |
+
resolve({blendData, filename: `/speech-${randomString}.mp3`});
|
83 |
+
|
84 |
+
},
|
85 |
+
error => {
|
86 |
+
synthesizer.close();
|
87 |
+
reject(error);
|
88 |
+
});
|
89 |
+
});
|
90 |
+
};
|
91 |
+
|
92 |
+
module.exports = textToSpeech;
|
package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
package.json
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "talking-avatar-backend",
|
3 |
+
"version": "0.0.0",
|
4 |
+
"private": true,
|
5 |
+
"scripts": {
|
6 |
+
"start": "nodemon ./bin/www"
|
7 |
+
},
|
8 |
+
"dependencies": {
|
9 |
+
"axios": "^1.5.1",
|
10 |
+
"cookie-parser": "~1.4.4",
|
11 |
+
"cors": "^2.8.5",
|
12 |
+
"debug": "~2.6.9",
|
13 |
+
"dotenv": "^16.0.3",
|
14 |
+
"express": "^4.18.2",
|
15 |
+
"fs": "^0.0.1-security",
|
16 |
+
"http-errors": "~1.6.3",
|
17 |
+
"lodash": "^4.17.21",
|
18 |
+
"microsoft-cognitiveservices-speech-sdk": "^1.23.0",
|
19 |
+
"morgan": "~1.9.1",
|
20 |
+
"openai": "^4.11.0",
|
21 |
+
"pug": "^3.0.2"
|
22 |
+
}
|
23 |
+
}
|
public/speech-1rgjg.mp3
ADDED
Binary file (62.5 kB). View file
|
|
public/speech-41t4z.mp3
ADDED
Binary file (16.1 kB). View file
|
|
public/speech-72ibm.mp3
ADDED
Binary file (70 kB). View file
|
|
public/speech-8h55r.mp3
ADDED
Binary file (46.9 kB). View file
|
|
public/speech-93rz1.mp3
ADDED
Binary file (159 kB). View file
|
|
public/speech-aqzjq.mp3
ADDED
Binary file (84.4 kB). View file
|
|
public/speech-dhexe.mp3
ADDED
Binary file (173 kB). View file
|
|
public/speech-epmmj.mp3
ADDED
Binary file (158 kB). View file
|
|
public/speech-fzuh9.mp3
ADDED
Binary file (37.4 kB). View file
|
|
public/speech-g241j.mp3
ADDED
Binary file (36.9 kB). View file
|
|
public/speech-grdkw.mp3
ADDED
Binary file (37.4 kB). View file
|
|
public/speech-gsce8.mp3
ADDED
Binary file (62.5 kB). View file
|
|
public/speech-ide8w.mp3
ADDED
Binary file (17.3 kB). View file
|
|
public/speech-ir0sf.mp3
ADDED
Binary file (62.5 kB). View file
|
|
public/speech-jrc8j.mp3
ADDED
Binary file (33.1 kB). View file
|
|
public/speech-k9whu.mp3
ADDED
Binary file (16.1 kB). View file
|
|
public/speech-n6nec.mp3
ADDED
Binary file (87.8 kB). View file
|
|
public/speech-pfhzn.mp3
ADDED
Binary file (16.1 kB). View file
|
|
public/speech-q0zfc.mp3
ADDED
Binary file (173 kB). View file
|
|
public/speech-un80i.mp3
ADDED
Binary file (158 kB). View file
|
|
public/speech-vz8nr.mp3
ADDED
Binary file (173 kB). View file
|
|
public/speech-vzpdi.mp3
ADDED
Binary file (159 kB). View file
|
|
public/speech-wd5uf.mp3
ADDED
Binary file (22.2 kB). View file
|
|
public/speech-xcd5h.mp3
ADDED
Binary file (173 kB). View file
|
|
public/stylesheets/style.css
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
padding: 50px;
|
3 |
+
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
|
4 |
+
}
|
5 |
+
|
6 |
+
a {
|
7 |
+
color: #00B7FF;
|
8 |
+
}
|
routes/index.js
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
var express = require('express');
|
2 |
+
var router = express.Router();
|
3 |
+
var textToSpeech = require('../helpers/tts');
|
4 |
+
var callOpenAI = require('../helpers/callOpenAI'); // Import the helper function
|
5 |
+
|
6 |
+
router.post('/talk', async function(req, res, next) {
|
7 |
+
try {
|
8 |
+
const ttsResult = await textToSpeech(req.body.text, req.body.language);
|
9 |
+
res.json(ttsResult);
|
10 |
+
|
11 |
+
} catch (err) {
|
12 |
+
res.status(500).json({ error: err.message });
|
13 |
+
}
|
14 |
+
});
|
15 |
+
|
16 |
+
router.post('/chat', async function(req, res, next) {
|
17 |
+
try {
|
18 |
+
const userContent = req.body.text;
|
19 |
+
const openAIResponse = await callOpenAI(userContent);
|
20 |
+
|
21 |
+
res.json({ response: openAIResponse });
|
22 |
+
} catch (err) {
|
23 |
+
res.status(500).json({ error: err.message });
|
24 |
+
}
|
25 |
+
});
|
26 |
+
|
27 |
+
module.exports = router;
|
views/error.pug
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
extends layout
|
2 |
+
|
3 |
+
block content
|
4 |
+
h1= message
|
5 |
+
h2= error.status
|
6 |
+
pre #{error.stack}
|
views/index.pug
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
extends layout
|
2 |
+
|
3 |
+
block content
|
4 |
+
h1= title
|
5 |
+
p Welcome to #{title}
|
views/layout.pug
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
doctype html
|
2 |
+
html
|
3 |
+
head
|
4 |
+
title= title
|
5 |
+
link(rel='stylesheet', href='/stylesheets/style.css')
|
6 |
+
body
|
7 |
+
block content
|