diff --git a/.gitignore b/.gitignore
index 38d4e915..93a7262a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ server/.env
server/Accounts/
server/package-lock.json
server/q_api/notebooks/.ipynb_checkpoints
+server/manual_save
.env
interface/.env
server/toia-dm/.env
diff --git a/README.md b/README.md
index fa906e4c..660b3018 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,11 @@
# TOIA-2.0
-This is a repository for the TOIA 2.0 System.
+This is a repository for TOIA 2.0 System with Soojin's Capstone Project "Elephant in the Room". You can watch a short demo
+[here](https://www.youtube.com/watch?v=4EK19DnM4_c), and read the full documentation [here](https://meadow-oboe-807.notion.site/Elephant-in-the-Room-060a99def2bb4b8192e351aac2db52f1).
+# Project Specific Setup
+
+All the code that is written for the project is under the file named shhh... including ShhhPage.js ShhhPlayer.js, shhhsuggestivesearch.js and ShhhPage.css.
# Developer Setup
@@ -13,24 +17,24 @@ There are three `.env` files. One in the root directory, one in the `/interface`
EXPRESS_PORT=3001
DM_PORT=5001
-
+
ENVIRONMENT=development
-
+
EXPRESS_HOST=http://localhost
DM_ROUTE=http://toia-dm:5001/dialogue_manager
Q_API_ROUTE=http://q_api:5000/generateNextQ
-
+
DB_CONNECTION=mysql
DB_DATABASE=toia
-
+
DB_HOST=mysql
DB_USERNAME=root
DB_PASSWORD=
-
+
GC_BUCKET=
GOOGLE_SPEECH_API_CREDENTIALS_FILE=/speech_to_text/toia-capstone-2021-b944d1cc65aa.json
GOOGLE_CLOUD_STORE_CREDENTIALS_FILE=/toia-capstone-2021-a17d9d7dd482.json
-
+
OPENAI_API_KEY=
1. Set the `DB_PASSWORD`
@@ -55,11 +59,11 @@ Note: It's probably a good idea to place Google cloud related environment variab
## Database Migration
-1. Create a folder called `Accounts` in the server folder, if it does not exist.
+1. Create a folder called `Accounts` in the server folder, if it does not exist.
2. Copy the video folders to the `Accounts` folder provided by admin.
3. Navigate to [localhost:8080](localhost:8080) with the username and password provided in `.env` in the root folder.
4. Drop all the tables in toia (if needed backup the current toia db using export).
-5. Import the database sql file into the toia table.
+5. Import the database sql file into the toia table.
## Running the app
@@ -72,10 +76,10 @@ Make sure you have installed docker and the docker daemon is running.
Making Changes Under Development Mode
- The docker-compose file is setup such that react and nodejs changes are reflected as soon as you change the files in `/interface` or `/server`
-- If you change anything inside `/server/q_api` or `/server/toia-dm`, you have to restart that particular container.
+- If you change anything inside `/server/q_api` or `/server/toia-dm`, you have to restart that particular container.
- By default, the files and database are persistent under development mode (Check volume mounts in `docker-compose-dev.yml`). If you wish to start a fresh environment, run `docker-compose down -v` to make sure all the volumes are purged when shutting down the containers. Then start the containers using the command above.
-- If the dialogue manager (toia-dm) shuts down when running in docker, change docker settings to allow more RAM (check [this](https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container)).
+- If the dialogue manager (toia-dm) shuts down when running in docker, change docker settings to allow more RAM (check [this](https://stackoverflow.com/questions/44533319/how-to-assign-more-memory-to-docker-container)).
#### Production mode
-- Change the `ENVIRONMENT` variable in .env file to production and run `docker-compose up`
\ No newline at end of file
+- Change the `ENVIRONMENT` variable in .env file to production and run `docker-compose up`
diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml
index bb3a186f..b89af7a4 100644
--- a/docker-compose-dev.yml
+++ b/docker-compose-dev.yml
@@ -46,6 +46,7 @@ services:
- ${DM_PORT}:${DM_PORT}
volumes:
- ./server/toia-dm:/app
+ tty: true
depends_on:
mysql:
condition: service_healthy
@@ -86,7 +87,8 @@ services:
- /app/node_modules
env_file:
- ./.env
- - ./interface/.env
+ environment:
+ - CHOKIDAR_USEPOLLING=true
metabase-sql-wrapper:
build:
diff --git a/interface/package.json b/interface/package.json
index 85adeb19..08e18076 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -22,6 +22,7 @@
"firebase": "^8.6.8",
"fuse.js": "^6.4.6",
"get-blob-duration": "^1.2.0",
+ "i18next-browser-languagedetector": "^7.0.1",
"id3js": "^2.1.1",
"install": "^0.13.0",
"mp3": "^0.1.0",
@@ -32,6 +33,7 @@
"react-bottom-scroll-listener": "^5.0.0",
"react-dom": "^17.0.1",
"react-elastic-carousel": "^0.11.5",
+ "react-flag-icon-css": "^1.0.25",
"react-notifications": "^1.7.3",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
@@ -39,7 +41,7 @@
"react-speech-recognition": "^3.8.2",
"react-switch": "^6.0.0",
"react-webcam": "^5.2.4",
- "sass": "^1.49.9",
+ "sass": "1.39.0",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^2.0.1",
"socket.io": "^4.3.2",
diff --git a/interface/src/App.css b/interface/src/App.css
index 7f4f8a66..97cb118e 100644
--- a/interface/src/App.css
+++ b/interface/src/App.css
@@ -116,6 +116,30 @@
color: white;
opacity: 0.8;
}
+
+
+.nav-shhh_icon {
+ top: 0%;
+ left: 50%;
+ position: absolute;
+ font-weight: 800;
+ font-size: 20px;
+ line-height: 22px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ letter-spacing: -0.015em;
+ height: 40px;
+ width: 145px;
+ border-radius: 3px;
+ cursor: pointer;
+ color: white;
+ opacity: 0.8;
+}
+.elephant-icon{
+ width: 30px;
+}
+
.nav-login_icon {
top: 0%;
left: 90%;
@@ -141,7 +165,11 @@
opacity: 0.8;
}
-.nav-about_icon:hover {
+.nav-shhh_icon:hover{
+ opacity: 1;
+}
+
+.nav-about_icon:hover{
opacity: 1;
}
.nav-talk_icon:hover {
@@ -154,6 +182,55 @@
opacity: 1;
}
+/* Dropdown Button */
+.nav-dropbtn {
+ background-color: transparent;
+ color: white;
+ width: 30px;
+ text-align: center;
+ font-size: 16px;
+ border: none;
+}
+
+/* The container
- needed to position the dropdown content */
+.nav-dropdown {
+ top: 0%;
+ left: 0%;
+ position: relative;
+ display: inline-block;
+}
+
+/* Dropdown Content (Hidden by Default) */
+.nav-dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #f1f1f1;
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+}
+
+/* Links inside the dropdown */
+.nav-dropdown-content a {
+ color: black;
+ width: 30px;
+ height: 20px;
+ text-align: center;
+ text-decoration: none;
+ display: block;
+}
+
+.nav-dropdown-content div.header:hover::after {
+ background-color: transparent;
+}
+/* Change color of dropdown links on hover */
+.nav-dropdown-content option:hover {background-color: #ddd;}
+
+/* Show the dropdown menu on hover */
+.nav-dropdown:hover .nav-dropdown-content {display: block;}
+
+/* Change the background color of the dropdown button when the dropdown content is shown */
+/* .nav-dropdown:hover .nav-dropbtn {background-color: #3e8e41;} */
+
/*login popup*/
.login_popup {
height: 40vh;
@@ -273,3 +350,7 @@
.fade-exit-done {
opacity: 0;
}
+
+
+
+
diff --git a/interface/src/images/birth/alison.png b/interface/src/images/birth/alison.png
new file mode 100644
index 00000000..8737dbaa
Binary files /dev/null and b/interface/src/images/birth/alison.png differ
diff --git a/interface/src/images/birth/ashley.png b/interface/src/images/birth/ashley.png
new file mode 100644
index 00000000..a354cf25
Binary files /dev/null and b/interface/src/images/birth/ashley.png differ
diff --git a/interface/src/images/birth/christian.png b/interface/src/images/birth/christian.png
new file mode 100644
index 00000000..e04ff101
Binary files /dev/null and b/interface/src/images/birth/christian.png differ
diff --git a/interface/src/images/birth/kaylee.png b/interface/src/images/birth/kaylee.png
new file mode 100644
index 00000000..5f12061d
Binary files /dev/null and b/interface/src/images/birth/kaylee.png differ
diff --git a/interface/src/images/birth/kieona.png b/interface/src/images/birth/kieona.png
new file mode 100644
index 00000000..d5fcbce8
Binary files /dev/null and b/interface/src/images/birth/kieona.png differ
diff --git a/interface/src/images/birth/krista.png b/interface/src/images/birth/krista.png
new file mode 100644
index 00000000..fd79483a
Binary files /dev/null and b/interface/src/images/birth/krista.png differ
diff --git a/interface/src/images/birth/stephanie.png b/interface/src/images/birth/stephanie.png
new file mode 100644
index 00000000..d2f1432f
Binary files /dev/null and b/interface/src/images/birth/stephanie.png differ
diff --git a/interface/src/images/bishnu.jpg b/interface/src/images/bishnu.jpg
new file mode 100644
index 00000000..9ef585d1
Binary files /dev/null and b/interface/src/images/bishnu.jpg differ
diff --git a/interface/src/images/child_birth.png b/interface/src/images/child_birth.png
new file mode 100644
index 00000000..0fbab979
Binary files /dev/null and b/interface/src/images/child_birth.png differ
diff --git a/interface/src/images/death.png b/interface/src/images/death.png
new file mode 100644
index 00000000..49475320
Binary files /dev/null and b/interface/src/images/death.png differ
diff --git a/interface/src/images/death/brian.png b/interface/src/images/death/brian.png
new file mode 100644
index 00000000..af530536
Binary files /dev/null and b/interface/src/images/death/brian.png differ
diff --git a/interface/src/images/death/ian.png b/interface/src/images/death/ian.png
new file mode 100644
index 00000000..15a08c6d
Binary files /dev/null and b/interface/src/images/death/ian.png differ
diff --git a/interface/src/images/death/james.png b/interface/src/images/death/james.png
new file mode 100644
index 00000000..cd76529d
Binary files /dev/null and b/interface/src/images/death/james.png differ
diff --git a/interface/src/images/death/jj.png b/interface/src/images/death/jj.png
new file mode 100644
index 00000000..f28eb030
Binary files /dev/null and b/interface/src/images/death/jj.png differ
diff --git a/interface/src/images/death/kekyong.png b/interface/src/images/death/kekyong.png
new file mode 100644
index 00000000..12ab5a13
Binary files /dev/null and b/interface/src/images/death/kekyong.png differ
diff --git a/interface/src/images/death/leila.png b/interface/src/images/death/leila.png
new file mode 100644
index 00000000..6e494376
Binary files /dev/null and b/interface/src/images/death/leila.png differ
diff --git a/interface/src/images/death/norman.png b/interface/src/images/death/norman.png
new file mode 100644
index 00000000..90c96ac8
Binary files /dev/null and b/interface/src/images/death/norman.png differ
diff --git a/interface/src/images/death/rahma.png b/interface/src/images/death/rahma.png
new file mode 100644
index 00000000..2584791e
Binary files /dev/null and b/interface/src/images/death/rahma.png differ
diff --git a/interface/src/images/death/rina.png b/interface/src/images/death/rina.png
new file mode 100644
index 00000000..dcae48a1
Binary files /dev/null and b/interface/src/images/death/rina.png differ
diff --git a/interface/src/images/death/sally.png b/interface/src/images/death/sally.png
new file mode 100644
index 00000000..48a264d6
Binary files /dev/null and b/interface/src/images/death/sally.png differ
diff --git a/interface/src/images/death/serene.png b/interface/src/images/death/serene.png
new file mode 100644
index 00000000..e25fe9a0
Binary files /dev/null and b/interface/src/images/death/serene.png differ
diff --git a/interface/src/images/elephant-icon.png b/interface/src/images/elephant-icon.png
new file mode 100644
index 00000000..4e493d41
Binary files /dev/null and b/interface/src/images/elephant-icon.png differ
diff --git a/interface/src/images/elephant.png b/interface/src/images/elephant.png
new file mode 100644
index 00000000..f8342550
Binary files /dev/null and b/interface/src/images/elephant.png differ
diff --git a/interface/src/images/gautam.jpeg b/interface/src/images/gautam.jpeg
new file mode 100644
index 00000000..435c06e3
Binary files /dev/null and b/interface/src/images/gautam.jpeg differ
diff --git a/interface/src/images/muhammad.jpeg b/interface/src/images/muhammad.jpeg
new file mode 100644
index 00000000..778fda5f
Binary files /dev/null and b/interface/src/images/muhammad.jpeg differ
diff --git a/interface/src/images/sex.png b/interface/src/images/sex.png
new file mode 100644
index 00000000..00a57c24
Binary files /dev/null and b/interface/src/images/sex.png differ
diff --git a/interface/src/images/sex/chris.png b/interface/src/images/sex/chris.png
new file mode 100644
index 00000000..8a4d0793
Binary files /dev/null and b/interface/src/images/sex/chris.png differ
diff --git a/interface/src/images/sex/ellis.png b/interface/src/images/sex/ellis.png
new file mode 100644
index 00000000..013d5ce1
Binary files /dev/null and b/interface/src/images/sex/ellis.png differ
diff --git a/interface/src/images/sex/kendel.png b/interface/src/images/sex/kendel.png
new file mode 100644
index 00000000..f24c7ecb
Binary files /dev/null and b/interface/src/images/sex/kendel.png differ
diff --git a/interface/src/images/sex/kenny.png b/interface/src/images/sex/kenny.png
new file mode 100644
index 00000000..3d26f454
Binary files /dev/null and b/interface/src/images/sex/kenny.png differ
diff --git a/interface/src/images/sex/klarissa.png b/interface/src/images/sex/klarissa.png
new file mode 100644
index 00000000..15383a19
Binary files /dev/null and b/interface/src/images/sex/klarissa.png differ
diff --git a/interface/src/images/sex/lauren.png b/interface/src/images/sex/lauren.png
new file mode 100644
index 00000000..2f337920
Binary files /dev/null and b/interface/src/images/sex/lauren.png differ
diff --git a/interface/src/images/sex/lucy.png b/interface/src/images/sex/lucy.png
new file mode 100644
index 00000000..4b9fbe4c
Binary files /dev/null and b/interface/src/images/sex/lucy.png differ
diff --git a/interface/src/images/sex/zaldy.png b/interface/src/images/sex/zaldy.png
new file mode 100644
index 00000000..8a4ced36
Binary files /dev/null and b/interface/src/images/sex/zaldy.png differ
diff --git a/interface/src/images/soojin.jpeg b/interface/src/images/soojin.jpeg
new file mode 100644
index 00000000..75e4995d
Binary files /dev/null and b/interface/src/images/soojin.jpeg differ
diff --git a/interface/src/main.scss b/interface/src/main.scss
index 43382f74..f5e8b03a 100644
--- a/interface/src/main.scss
+++ b/interface/src/main.scss
@@ -11,3 +11,4 @@
@import "pages/Player.css";
@import "pages/SignUpPage.css";
@import "semantic-ui-css/semantic.css";
+
diff --git a/interface/src/pages/AboutUsPage.css b/interface/src/pages/AboutUsPage.css
index 1aa6c4df..edae150e 100644
--- a/interface/src/pages/AboutUsPage.css
+++ b/interface/src/pages/AboutUsPage.css
@@ -117,7 +117,7 @@
font-size: 3rem;
text-align: left;
letter-spacing: -0.015em;
- position: absolute;
+ /* position: absolute; */
/* left: 50%; */
top: 80px;
color: black;
@@ -129,15 +129,15 @@
}
.about-grid {
padding: 5px;
- overflow-y: auto;
+ /* overflow-y: auto; */
height: 70%;
/* width: 84vw; */
- width: 113.5%;
+ /* width: 113.5%; */
/* left: 8%;
top: 25%; */
left: -6.5%;
top: 175px;
- position: absolute;
+ /* position: absolute; */
display: flex;
flex-wrap: wrap;
flex-direction: row;
@@ -153,7 +153,7 @@
font-size: 20px;
font-weight: 500;
text-align: center;
- margin-bottom: 0px;
+ margin-bottom: 30px !important;
}
.image-sizing {
diff --git a/interface/src/pages/AboutUsPage.js b/interface/src/pages/AboutUsPage.js
index ed222a37..a2aa1892 100644
--- a/interface/src/pages/AboutUsPage.js
+++ b/interface/src/pages/AboutUsPage.js
@@ -1,25 +1,28 @@
-import React, { useState, useEffect } from "react";
+import axios from "axios";
+import React, { useEffect, useState } from "react";
+import {
+ NotificationContainer,
+ NotificationManager
+} from "react-notifications";
+import { Modal } from "semantic-ui-react";
import submitButton from "../icons/submit-button.svg";
-import sampleVideo from "../icons/sample-video.svg";
import alberto from "../images/alberto.jpeg";
-import wahib from "../images/wahib.jpg";
-import kertu from "../images/kertu.jpg";
+import armaan from "../images/armaan.jpg";
+import bishnu from "../images/bishnu.jpg";
+import camel from "../images/camel.png";
import erin from "../images/erin.jpeg";
-import nizar from "../images/nizar.jpg";
+import gautam from "../images/gautam.jpeg";
import goffredo from "../images/goffredo.jpeg";
-import tyeece from "../images/Tyeece.jpg";
-import armaan from "../images/armaan.jpg";
+import kertu from "../images/kertu.jpg";
+import muhammad from "../images/muhammad.jpeg";
+import nizar from "../images/nizar.jpg";
import nyuad from "../images/nyuad-rb.png";
-import camel from "../images/camel.png";
-import history from "../services/history";
-import { Modal } from "semantic-ui-react";
-import sigDail from "../pdf/SIGDIAL_2021_TOIA_camera_ready_.pdf";
-import axios from "axios";
-import {
- NotificationContainer,
- NotificationManager,
-} from "react-notifications";
+import soojin from "../images/soojin.jpeg";
import toia_logo from "../images/TOIA_Logo.png";
+import tyeece from "../images/Tyeece.jpg";
+import wahib from "../images/wahib.jpg";
+import sigDail from "../pdf/SIGDIAL_2021_TOIA_camera_ready_.pdf";
+import history from "../services/history";
import Tracker from "../utils/tracker";
function AvatarViewPage() {
@@ -61,6 +64,10 @@ function AvatarViewPage() {
{ still: erin, member: "Erin Collins" },
{ still: goffredo, member: "Goffredo Puccetti" },
{ still: nizar, member: "Nizar Habash" },
+ { still: soojin, member: "Soojin Lee" },
+ { still: muhammad, member: "Muhammad Ali" },
+ { still: gautam, member: "Gautam Dinesh" },
+ { still: bishnu, member: "Bishnu Dev" },
];
const renderTeam = (card, index) => {
@@ -205,8 +212,7 @@ function AvatarViewPage() {
size="large"
style={inlineStyle.modal}
open={open}
- onClose={() => dispatch(false)}
- >
+ onClose={() => dispatch(false)}>
Welcome Back
@@ -243,8 +249,7 @@ function AvatarViewPage() {
/>
+ onClick={signup}>
Don't have an Account? Sign Up
@@ -253,32 +258,27 @@ function AvatarViewPage() {
+ className="nav-toia_icon app-opensans-normal">
TOIA
+ className="nav-about_icon app-monsterrat-black nav-selected">
About Us
+ className="nav-talk_icon app-monsterrat-black ">
Talk To TOIA
+ className="nav-my_icon app-monsterrat-black ">
My TOIA
+ className="nav-login_icon app-monsterrat-black">
{isLoggedIn ? "Logout" : "Login"}
@@ -320,8 +320,7 @@ function AvatarViewPage() {
+ className="reference-item">
Github Repo
diff --git a/interface/src/pages/AvatarGardenPage.js b/interface/src/pages/AvatarGardenPage.js
index 3a548158..33451fc4 100644
--- a/interface/src/pages/AvatarGardenPage.js
+++ b/interface/src/pages/AvatarGardenPage.js
@@ -821,7 +821,7 @@ function AvatarGardenPage() {
/>
{streamSetting}
-
+
@@ -935,17 +935,6 @@ function AvatarGardenPage() {
});
}
- function album_page() {
- history.push({
- pathname: "/stream",
- state: {
- toiaName,
- toiaLanguage,
- toiaID,
- },
- });
- }
-
function groupSelect() {
//function called when the multiple videos are selected
if (selectedIndex == null) {
@@ -1401,7 +1390,7 @@ function AvatarGardenPage() {
className="modal-ans font-class-1"
value={playbackVideoAnswer}
type={"text"}
- onChange={() => {}}
+ onChange={() => { }}
/>
diff --git a/interface/src/pages/AvatarLibraryPage.css b/interface/src/pages/AvatarLibraryPage.css
index 8276d5b0..58e4dd9c 100644
--- a/interface/src/pages/AvatarLibraryPage.css
+++ b/interface/src/pages/AvatarLibraryPage.css
@@ -8,6 +8,16 @@
width: 100%;
}
+.shhh-page {
+ background-color:#302D2D;
+ height: 100vh;
+ margin: 0px;
+ min-height: 700px;
+ min-width: 1440px;
+ position: relative;
+ width: 100%;
+}
+
.library-page-setup {
position: absolute;
top: 80px;
diff --git a/interface/src/pages/AvatarLibraryPage.js b/interface/src/pages/AvatarLibraryPage.js
index 1dd29b68..78261b34 100644
--- a/interface/src/pages/AvatarLibraryPage.js
+++ b/interface/src/pages/AvatarLibraryPage.js
@@ -120,7 +120,7 @@ function AvatarLibraryPage() {
const renderStream = (card, index) => {
//cards for streams
-
+ console.log(card)
return (
TOIA
+
+
+
+
{
+ if (res.data == -1) {
+ //alert('Email not found');
+ NotificationManager.error("Incorrect e-mail address.");
+ } else if (res.data == -2) {
+ NotificationManager.error("Incorrect password.");
+ } else {
+ console.log(res.data);
+ history.push({
+ pathname: 'mytoia',
+ state: {
+ toiaName: res.data.firstName,
+ toiaLanguage: res.data.language,
+ toiaID: res.data.toia_id
+ }
+ });
+ }
+ });
+ }
+
+ const inlineStyle = {
+ modal: {
+ height: '560px',
+ width: '600px',
+ }
+ };
+
+ function login_modal() {
+ return (
+
dispatch({ type: 'close' })}
+ >
+
+ {t("nav_welcome_back")}
+ {t("nav_login_request")}
+
+
+
+
+
+
+ );
+ }
+ // style = {{direction: i18n.dir(i18n.language)}} style = {{"unicode-bidi": "plaintext"}}
+ return (
+
+
+ {props.showLoginModal ? login_modal() : ''}
+
+
+
+
+
+
+ {t("nav_toia")}
+
+
+ {t("shhh")}
+
+
+ {t("nav_about_us")}
+
+
+ {t("nav_talk_to_toia")}
+
+
+ {t("nav_my_toia")}
+
+
+ {props.isLoggedIn ? t("nav_logout") : t("nav_login")}
+
+
+
+ );
+
+}
+
+
+
+export default NavBar;
\ No newline at end of file
diff --git a/interface/src/pages/Player.css b/interface/src/pages/Player.css
index 80ed5167..97503c6b 100644
--- a/interface/src/pages/Player.css
+++ b/interface/src/pages/Player.css
@@ -138,12 +138,25 @@
color: #49769c;
}
-.cards-suggestion-header {
+.player-cards-wrapper {
+ display: flex;
+ flex-direction: column;
position: absolute;
left: 75.5%;
+ top: 3%;
+}
+
+.player-cards-wrapper > div {
+ margin-bottom: 1rem;
+
}
-.card-1 {
+/* .cards-suggestion-header {
+ position: absolute;
+ left: 75.5%;
+} */
+
+/* .card-1 {
position: absolute;
left: 75.5%;
top: 3%;
@@ -171,8 +184,95 @@
position: absolute;
left: 75.5%;
top: 86%;
+} */
+
+.card-overview {
+ transition: background 1s !important;
+}
+
+.card-waiting-true {
+ background: #d7f5ff !important;
+ box-shadow: 0px 4px 4px rgba(46, 122, 210, 0.25) !important;
+ border-radius: 5px !important;
+}
+
+.card-width-control {
+ max-height: 30%;
+ min-height: 24%;
+}
+.cursor-disabled {
+ cursor: not-allowed !important;
+}
+
+.redo-icon {
+ color: #006a94;
+}
+
+.transcript {
+ background-color: rgba(126, 124, 124, 0.1);
+ border: 0;
+ border-radius: 3px;
+ height: 41px;
+ /* left: 39%; */
+ left: 1%;
+ padding: 5px;
+ position: absolute;
+ resize: none;
+ text-align: left;
+ /* top: 75%; */
+ top: 89.75%;
+ width: 70%;
+ color: #707070;
+ font-size: 1.5rem;
+ padding-top: 25px;
+ padding-bottom: 25px;
+}
+
+.submit-button {
+ position: absolute;
+ top: 93.7%;
+ left: 57.5%;
+ width: 13.5%;
+ height: 7.5%;
+ font-size: 1.5rem;
+ color: #49769c;
+}
+
+/* .cards-suggestion-header {
+ position: absolute;
+ left: 75.5%;
+} */
+
+/* .card-1 {
+ position: absolute;
+ left: 75.5%;
+ top: 3%;
+}
+
+.card-2 {
+ position: absolute;
+ left: 75.5%;
+ top: 20%;
+}
+
+.card-3 {
+ position: absolute;
+ left: 75.5%;
+ top: 42%;
}
+.card-4 {
+ position: absolute;
+ left: 75.5%;
+ top: 64%;
+}
+
+.card-5 {
+ position: absolute;
+ left: 75.5%;
+ top: 86%;
+} */
+
.card-overview {
transition: background 1s !important;
}
@@ -214,3 +314,59 @@
padding-top: 25px;
padding-bottom: 25px;
}
+
+/* Selecting Language for Player */
+
+/* Dropdown Button */
+.lang-dropbtn {
+ background-color: transparent;
+ color: white;
+ width: 30px;
+ text-align: center;
+ font-size: 16px;
+ border: none;
+ }
+
+ /* The container
- needed to position the dropdown content */
+ .lang-container {
+ position: absolute;
+ top: 75.4%;
+ left: 65%;
+ height: 7%;
+ font-size: 1.5rem;
+ }
+ .lang-dropdown {
+ position: relative;
+ display: inline-block;
+ z-index: 10;
+ }
+
+ /* Dropdown Content (Hidden by Default) */
+ .lang-dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #dad3d3;
+ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+ }
+
+ /* Links inside the dropdown */
+ .lang-dropdown-content a {
+ color: black;
+ width: 30px;
+ height: 20px;
+ font-size:15px;
+ text-align: center;
+ text-decoration: none;
+ display: block;
+ }
+
+ .lang-dropdown-content div.header:hover::after {
+ background-color: transparent;
+ }
+ /* Change color of dropdown links on hover */
+ .lang-dropdown-content option:hover {background-color: #ddd;}
+
+ /* Show the dropdown menu on hover */
+ .lang-dropdown:hover .lang-dropdown-content {display: block;}
+
\ No newline at end of file
diff --git a/interface/src/pages/Player.js b/interface/src/pages/Player.js
index fa9ed1b5..7d24639c 100644
--- a/interface/src/pages/Player.js
+++ b/interface/src/pages/Player.js
@@ -11,7 +11,6 @@ import history from "../services/history";
import SuggestionCard from "../suggestiveSearch/suggestionCards";
import SuggestiveSearch from "../suggestiveSearch/suggestiveSearch";
import speechToTextUtils from "../transcription_utils";
-import PopModal from "../userRating/popModal";
import Tracker from "../utils/tracker";
import VideoPlaybackPlayer from "./sub-components/Videoplayback.Player";
@@ -39,11 +38,7 @@ function Player() {
let allSuggestedQuestions = [];
const [videoProperties, setVideoProperties] = useState(null);
- const [hasRated, setHasRated] = useState(true); // controll the rating field
const [transcribedAudio, setTranscribedAudio] = useState("");
- const [ratingParams, setRatingParams] = useState({
- active: false,
- });
// suggested questions for cards
@@ -147,7 +142,7 @@ function Player() {
axios
.request(options)
- .then(function (response) {})
+ .then(function (response) { })
.catch(function (error) {
alert("You do not have permission to access this page");
library();
@@ -155,11 +150,6 @@ function Player() {
}
// if user asks one of the suggested questions
function askQuestionFromCard(question) {
- if (!hasRated) {
- NotificationManager.warning("Please provide a rating", "", 3000);
- return;
- }
-
const mode = "CARD";
const oldQuestion = question;
@@ -192,11 +182,6 @@ function Player() {
setVideoProperties({
key: res.data.url + new Date(), // add timestamp to force video transition animation when the key hasn't changed
onEnded: () => {
- setRatingParams({
- video_id: res.data.video_id,
- question: oldQuestion.question,
- });
- setHasRated(false);
fetchFiller();
},
source: res.data.url,
@@ -226,7 +211,7 @@ function Player() {
if (data.isFinal) {
question.current = data.alternatives[0].transcript;
- speechToTextUtils.stopRecording();
+ // speechToTextUtils.stopRecording();
fetchData("VOICE");
}
} else {
@@ -293,51 +278,7 @@ function Player() {
}
}
- useEffect(() => {
- if (hasRated) {
- if (interacting.current == "true") {
- speechToTextUtils.initRecording(handleDataReceived, error => {
- console.error("Error when transcribing", error);
- });
- }
- }
- }, [hasRated]);
-
- const recordUserRating = function (ratingValue) {
- const options = {
- method: "POST",
- url: "/api/save_player_feedback",
- headers: { "Content-Type": "application/json" },
- data: {
- ...(history.location.state.toiaID && {
- user_id: history.location.state.toiaID,
- }),
- video_id: ratingParams.video_id,
-
- question: ratingParams.question,
- rating: ratingValue,
- },
- };
-
- axios
- .request(options)
- .then(function (response) {
- console.log(response.data);
- })
- .catch(function (error) {
- console.error(error);
- })
- .finally(() => {
- setHasRated(true);
- });
- };
-
function fetchData(mode = "UNKNOWN") {
- if (!hasRated) {
- NotificationManager.warning("Please provide a rating", "", 3000);
- return;
- }
-
const oldQuestion = question.current;
if (question.current == null || question.current == "") {
setFillerPlaying(true);
@@ -370,11 +311,6 @@ function Player() {
setVideoProperties({
key: res.data.url + new Date(), // add timestamp to force video transition animation when the key hasn't changed
onEnded: () => {
- setRatingParams({
- video_id: res.data.video_id,
- question: oldQuestion,
- });
- setHasRated(false);
fetchFiller();
},
source: res.data.url,
@@ -406,18 +342,10 @@ function Player() {
setMicString("STOP ASK BY VOICE");
interacting.current = "true";
- if (hasRated) {
- speechToTextUtils.initRecording(handleDataReceived, error => {
- console.error("Error when transcribing", error);
- // No further action needed, as stream already closes itself on error
- });
- } else {
- NotificationManager.warning(
- "Please provide a rating",
- "",
- 3000,
- );
- }
+ speechToTextUtils.initRecording(handleDataReceived, error => {
+ console.error("Error when transcribing", error);
+ // No further action needed, as stream already closes itself on error
+ });
} else {
speechToTextUtils.stopRecording();
setMicStatus(true);
@@ -484,10 +412,6 @@ function Player() {
}
function submitResponse(e, mode = "UNKNOWN") {
- if (!hasRated) {
- NotificationManager.warning("Please provide a rating", "", 3000);
- return;
- }
question.current = textInput.current
? textInput.current
@@ -518,11 +442,6 @@ function Player() {
setVideoProperties({
key: res.data.url + new Date(), // add timestamp to force video transition animation when the key hasn't changed
onEnded: () => {
- setRatingParams({
- video_id: res.data.video_id,
- question: oldQuestion,
- });
- setHasRated(false);
fetchFiller();
},
source: res.data.url,
@@ -669,8 +588,7 @@ function Player() {
size="large"
style={inlineStyle.modal}
open={open}
- onClose={() => dispatch({ type: "close" })}
- >
+ onClose={() => dispatch({ type: "close" })}>
Welcome Back
@@ -707,44 +625,37 @@ function Player() {
/>
+ onClick={signup}>
Don't have an Account? Sign Up
- {!hasRated &&
}
+ className="nav-toia_icon app-opensans-normal">
TOIA
+ className="nav-about_icon app-monsterrat-black ">
About Us
+ className="nav-talk_icon app-monsterrat-black ">
Talk To TOIA
+ className="nav-my_icon app-monsterrat-black ">
My TOIA
+ className="nav-login_icon app-monsterrat-black">
{isLoggedIn ? "Logout" : "Login"}
@@ -760,8 +671,7 @@ function Player() {
+ classNames="fade">
+ onClick={micStatusChange}>
+ onClick={micStatusChange}>
@@ -811,14 +719,12 @@ function Player() {
{isFillerPlaying.current == "false" ? (
+ onClick={fetchFiller}>
{" "}
Skip to End{" "}
+ class="angle double right icon">
) : null}
@@ -841,7 +747,6 @@ function Player() {
setRefreshQuestionsFalse={
setRefreshQuestionsFalse
}
- hasRated={hasRated}
notificationManager={NotificationManager}
/>
@@ -850,8 +755,7 @@ function Player() {
className="ui linkedin button submit-button"
onClick={e => {
submitResponse(e, "SEARCH");
- }}
- >
+ }}>
ASK
diff --git a/interface/src/pages/Recorder.css b/interface/src/pages/Recorder.css
index 3478c22f..9749456c 100644
--- a/interface/src/pages/Recorder.css
+++ b/interface/src/pages/Recorder.css
@@ -649,3 +649,7 @@ video {
margin-top: 8px;
border-radius: 5px;
}
+
+.cursor-pointer {
+ cursor: pointer;
+}
diff --git a/interface/src/pages/Recorder.js b/interface/src/pages/Recorder.js
index ecf35510..19e49c01 100644
--- a/interface/src/pages/Recorder.js
+++ b/interface/src/pages/Recorder.js
@@ -1,30 +1,26 @@
-import React, { useState, useEffect, useRef } from "react";
-import Webcam from "react-webcam";
import axios from "axios";
-import SpeechRecognition, {
- useSpeechRecognition,
-} from "react-speech-recognition";
-import history from "../services/history";
-import { Button, Image, Modal, Popup, TextArea, Icon } from "semantic-ui-react";
-import { Multiselect } from "multiselect-react-dropdown";
import { default as EditCreateMultiSelect } from "editable-creatable-multiselect";
+import getBlobDuration from "get-blob-duration";
+import { Multiselect } from "multiselect-react-dropdown";
+import React, { useEffect, useRef, useState } from "react";
+import { NotificationManager } from "react-notifications";
+import NotificationContainer from "react-notifications/lib/NotificationContainer";
+import { useSpeechRecognition } from "react-speech-recognition";
import Switch from "react-switch";
-import {
- RecordAVideoCard,
- OnBoardingQCard,
- SuggestedQCard,
- SuggestedQCardNoAction,
-} from "./AvatarGardenPage";
+import Webcam from "react-webcam";
+import { Button, Icon, Image, Modal, Popup, TextArea } from "semantic-ui-react";
+import videoTypesJSON from "../configs/VideoTypes.json";
import CheckMarkIcon from "../icons/check-mark-success1.webp";
import RecordButton from "../icons/record1.png";
import RecordingGif from "../icons/recording51.gif";
-import videoTypesJSON from "../configs/VideoTypes.json";
-import io from "socket.io-client";
+import history from "../services/history";
import speechToTextUtils from "../transcription_utils";
import Tracker from "../utils/tracker";
-import NotificationContainer from "react-notifications/lib/NotificationContainer";
-import { NotificationManager } from "react-notifications";
-import getBlobDuration from "get-blob-duration";
+import {
+ OnBoardingQCard,
+ RecordAVideoCard,
+ SuggestedQCardNoAction,
+} from "./AvatarGardenPage";
const videoConstraints = {
width: 720,
@@ -57,8 +53,7 @@ function ModalQSuggestion(props) {
open={props.active}
onClose={ModalOnClose}
onOpen={ModalOnOpen}
- trigger={Question Suggestion Modal }
- >
+ trigger={Question Suggestion Modal }>
Successful! Your TOIA has been saved.
@@ -123,6 +118,7 @@ function Recorder() {
command: "*",
});
+ const uploadElementRef = useRef(null);
const webcamRef = useRef(null);
const mediaRecorderRef = useRef(null);
const [capturing, setCapturing] = useState(false);
@@ -630,6 +626,7 @@ function Recorder() {
save_as_new = false,
old_video_id = "",
old_video_type = "",
+ from_upload = false,
) => {
return new Promise((resolve, reject) => {
let endTimestamp = +new Date();
@@ -647,9 +644,11 @@ function Recorder() {
form.append("streams", JSON.stringify(listStreams));
form.append("video_duration", videoDuration.toString());
- form.append("start_time", recordStartTimestamp);
- form.append("end_time", endTimestamp);
- setRecordEndTimestamp(endTimestamp);
+ if (!from_upload){
+ form.append("start_time", recordStartTimestamp);
+ form.append("end_time", endTimestamp);
+ setRecordEndTimestamp(endTimestamp);
+ }
if (is_editing) {
form.append("is_editing", true);
@@ -947,8 +946,7 @@ function Recorder() {
: backgroundDefaultColor,
}}
onClick={onClickHandler}
- video-type={props.type}
- >
+ video-type={props.type}>
{props.buttonText}
}
@@ -979,6 +977,20 @@ function Recorder() {
return jsx;
};
+ const handleVideoUpload = e => {
+ const file = e.target.files[0];
+ if (file) {
+ setRecordedVideo(file);
+ setAnswerProvided("");
+ setViewingRecordedVideo(true);
+ }
+ };
+
+ const onUploadClick = () => {
+ // simulate click on hidden file input element
+ uploadElementRef.current.click();
+ };
+
return (
+ className="nav-toia_icon app-opensans-normal">
TOIA
+ className="nav-about_icon app-monsterrat-black">
About Us
+ className="nav-talk_icon app-monsterrat-black ">
Talk To TOIA
+ className="nav-my_icon app-monsterrat-black ">
My TOIA
+ className="nav-login_icon app-monsterrat-black ">
Logout
@@ -1043,8 +1050,7 @@ function Recorder() {
backgroundColor: isPrivate
? backgroundDefaultColor
: backgroundActiveColor,
- }}
- >
+ }}>
Public
0 &&
!isRecording
}
- content={"Record a video to proceed"}
+ content={"Record/Upload a video to proceed"}
trigger={
+ className="right floated recorder-next-btn-wrapper">
0
) || isRecording
- }
- >
+ }>
Next
@@ -1156,12 +1160,27 @@ function Recorder() {
icon
labelPosition="left"
className="right floated"
- onClick={handleStartCaptureClick}
- >
+ onClick={handleStartCaptureClick}>
Record Again
)}
+
+
+
+
+ Upload
+
+ data-tooltip="Stop Recording">
{/* */}
{/* */}
{/* */}
@@ -1207,8 +1225,7 @@ function Recorder() {
+ data-tooltip="Start Recording">
{/* */}
{
togglePreviewBox();
}}
- data-tooltip="Save Video"
- >
+ data-tooltip="Save Video">
)}
@@ -1254,8 +1270,7 @@ function Recorder() {
disabled={
waitingServerResponse ||
!videoDuration
- }
- >
+ }>
Save As New
}
@@ -1268,8 +1283,7 @@ function Recorder() {
waitingServerResponse ||
!videoDuration
}
- positive
- >
+ positive>
Update
@@ -1282,8 +1296,7 @@ function Recorder() {
waitingServerResponse ||
!videoDuration
}
- onClick={handleDownload}
- >
+ onClick={handleDownload}>
Save Video
)}
@@ -1295,8 +1308,7 @@ function Recorder() {
onClick={() =>
setViewingRecordedVideo(false)
}
- disabled={waitingServerResponse}
- >
+ disabled={waitingServerResponse}>
Record Again
@@ -1323,8 +1335,7 @@ function Recorder() {
videoPlaybackRef.current.currentTime = 0;
}
}}
- ref={videoPlaybackRef}
- >
+ ref={videoPlaybackRef}>
div {
+ padding: 10.2px;
+ flex: 1;
+}
+
+/* creating card for shhh */
+
+
+.shhh-page-setup {
+ position: relative;
+ width: 80vw;
+ height: 80vh;
+}
+
+.shhh-carousel-card::-webkit-scrollbar {
+ display: none;
+ width: 0;
+ }
+
+.shhh-carousel-card {
+ display: flex;
+ height:100%;
+ overflow-x: scroll;
+}
+
+.shhh-carousel-card > div {
+ margin:20px;
+}
+
+.Birth, .Sex, .Death{
+ background-color: rgba(255, 255, 255, 0.298);
+ border-radius: 20px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ transition: all 0.2s ease;
+ width: 100%;
+}
+
+
+.Birth-img, .Sex-img, .Death-img {
+ height: 65%;
+}
+
+ .Sex-img{
+ width: 75%;
+}
+
+.Birth-img {
+ width: 75%;
+ margin-left: auto;
+}
+
+
+.valign-text-middle {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.subhead {
+ align-items: flex-start;
+ align-self: stretch;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ height: 55px;
+}
+
+.Birth:hover, .Sex:hover, .Death:hover {
+ transform: scale(1.1);
+}
+
+
+.headline-subhead {
+ align-items: flex-start;
+ display: flex;
+ flex-direction: column;
+ padding: 1.5vw;
+ position: relative;
+ width: 100%;
+}
+
+.headline {
+ align-items: flex-start;
+ align-self: stretch;
+ display: flex;
+ width: 100%;
+}
+
+.heading {
+ flex: 1;
+ font-size: 1.5vw;
+ font-weight: 600;
+ padding: 0, 1vw;
+ white-space: nowrap;
+ }
+
+.Birth-title {
+ color: #de8163;
+}
+
+.Sex-title {
+ color: #9489dd;
+ }
+
+.Death-title {
+ color: #ccc47c;
+ }
+
+.description{
+ letter-spacing: 0;
+ line-height:1.3;
+ margin-top: 1vw;
+ width: 100%;
+ color: white;
+ font-size: 1vw;
+ font-weight: 400;
+}
+
+.elephant {
+ position: absolute;
+ opacity:0.2;
+ width: 50vw;
+ top: 50%;
+ left: 50vw;
+ transform: translate(-50%, -50%);
+ }
+
+/* ShhhPlayer*/
+.shhh-player {
+ padding: 0 5vw;
+ background-color: #302D2D;
+ height: 100%;
+ margin: 0px;
+ display: flex;
+ align-items: center;
+ position: relative;
+ width: 100vw;
+}
+
+
+.shhh-player-cards-wrapper {
+ flex: 1 1 auto;
+ display: flex;
+ flex-wrap: wrap;
+ position: absolute;
+ right: 0%;
+ padding: 0.1vw;
+ width: 25%;
+ max-height: 70%;
+ overflow-y: scroll;
+ }
+
+.shhh-player-cards-wrapper::-webkit-scrollbar {
+display: none;
+}
+
+
+.shhh-player-cards-wrapper > div {
+ margin-bottom: 9%;
+
+}
+
+.ask_box .ui.cards {
+ margin: 0;
+}
+
+.shhh-player-cards-wrapper .ui.card {
+ flex-direction: row !important;
+ width: 22vw;
+}
+
+.shhh-player-cards-wrapper .ui.buttons{
+ flex-direction: column !important;
+}
+.shhh-player-cards-wrapper .button {
+ width: 100% !important;
+}
+.ask_box .ui.buttons .button:first-child {
+ border-radius: 0.28571429rem;
+ margin-bottom: 0.5vw;
+}
+
+.ask_box .ui.buttons .button:last-child {
+ border-radius: 0.28571429rem;
+
+}
+
+.shhh-player-cards-wrapper .ui.card > .content > .description {
+
+ color: #b9d2e9 !important;
+}
+
+.shhh-player-group{
+ position: relative;
+ width:100vw;
+ height:100vh;
+}
+.ask_box{
+ position: absolute;
+ display: flex; /* set the container to use flexbox */
+ flex-direction: column;
+ top:20%;
+ height: 80%;
+ width: 90vw;
+ right:0%;
+}
+
+.shhh-submit-button {
+ position:absolute;
+ top: 36.5vw;
+ right:0%;
+ width: 4vw;
+ height: 4vw;
+ font-size: 1.5rem;
+}
+
+.shhh-player-vid {
+ background-color: transparent;
+ top: 20%;
+ left: 0%;
+ position: absolute;
+ width: 70%;
+ border-radius: 5px;
+}
+
+.shhh-mute-button {
+ position: fixed;
+ margin: 0 !important;
+ top: 49vw;
+ width: 10%;
+ height: 4vw;
+ font-size: 1vw;
+ background-color: #614CB8 !important;
+ z-index: 999999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ }
+
+ .shhh-mute-button i {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ }
+
+ .shhh-transcript {
+ background-color: transparent;
+ border: 0;
+ border-bottom: 1px solid #707070;
+ border-radius: 0;
+ height: 4vw;
+ padding: 5px;
+ padding-left: 15px;
+ position: fixed;
+ resize: none;
+ text-align: left;
+ top: 49vw;
+ margin-left: 12%;
+ width: 51%;
+ color: #707070;
+ font-size: 1.5rem;
+ }
+
+.ask_box .css-1qqsdnr-MuiAutocomplete-root .MuiOutlinedInput-root {
+ height: 4vw !important;
+}
+
+.ask_box .MuiInputBase-input{
+ height:4vw !important;
+ padding:0;
+ padding-left: 1vw;
+}
+
+.MuiInputBase-root.MuiOutlinedInput-root.MuiInputBase-colorPrimary.MuiInputBase-fullWidth.MuiInputBase-formControl.MuiAutocomplete-inputRoot.css-md26zr-MuiInputBase-root-MuiOutlinedInput-root{
+ height: 4vw;
+ border-color: transparent;
+}
+.AskMe {
+ width: 20vw;
+ position: absolute;
+ right:3vw;
+ line-height: 2vw;
+ color: white;
+ font-size: 1vw;
+
+}
+
+.icons {
+ top: 55%;
+ right: 7vw;
+ width: 20vw; /* adjust the width to fit the 3x3 grid */
+ position: absolute;
+ display: grid; /* change display to grid */
+ grid-template-columns: repeat(4, 1fr); /* create three columns with equal width */
+ grid-gap: 2vw; /* add gap between icons */
+ justify-content: center; /* center the icons horizontally */
+ }
+
+ .icons img {
+ border-radius: 10%;
+ height: 100%;
+ width: auto;
+ filter: grayscale(0%);
+ z-index: 7;
+ transition: filter 0.3s ease-in-out;
+ }
+
+
+ .icons img.selected {
+ opacity: 1;
+ }
+
+ .icon-container {
+ position: relative;
+ color: white;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ height: 4vw; /* set a fixed height to match the image */
+ }
+
+.icon-description {
+ position: absolute;
+ bottom: -6vw;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 15vw;
+ background-color: black;
+ color: white;
+ padding: 10px;
+ opacity: 0;
+ transition: opacity 0.3s ease-in-out;
+ z-index: 3; /* Increase the z-index value */
+}
+
+ .icon-container.muted .icon-name {
+ color: #999; /* Change to the desired muted color */
+}
+ .icon-container:hover .icon-description {
+ opacity: 1;
+ width: 15vw;
+ z-index:999999;
+ }
+
+ .icon-container.muted img {
+ /* Apply styling to muted icons */
+ opacity: 0.5;
+ }
+
+ .icons.toggle-on .icon-container:not(.selected) {
+ /* Apply styling to muted icons when toggle is on */
+ opacity: 0.5;
+ }
+
+ .icons.toggle-off .icon-container {
+ /* Apply styling to unmuted icons when toggle is off */
+ opacity: 1;
+ }
+
+ .shhh-skip-end-button {
+ position: absolute;
+ top: 65%;
+ left: 50%;
+ width: 15%;
+ height: 7%;
+ font-size: 1.8rem;
+ z-index: 9;
+}
+
+.back-to-shhh {
+ position: absolute;
+ top: 10%;
+ left: 5%;
+ z-index: 999;
+}
+
+.back-to-shhh i {
+ font-size: 2rem; /* adjust the size as needed */
+ color: white; /* set the color to white */
+ transition: transform 0.3s ease-in-out; /* add transition for hover effect */
+}
+
+.back-to-shhh i:hover {
+ transform: scale(1.2); /* make the icon slightly bigger on hover */
+}
\ No newline at end of file
diff --git a/interface/src/pages/ShhhPage.js b/interface/src/pages/ShhhPage.js
new file mode 100644
index 00000000..7be05467
--- /dev/null
+++ b/interface/src/pages/ShhhPage.js
@@ -0,0 +1,211 @@
+//Landing page for Elephant in the room
+import React, { useState, useEffect } from "react";
+import Fuse from "fuse.js";
+import sampleVideo from "../icons/sample-video.svg";
+import submitButton from "../icons/submit-button.svg";
+import history from "../services/history";
+import { Modal } from "semantic-ui-react";
+import axios from "axios";
+import Tracker from "../utils/tracker";
+import elephant from "../images/elephant.png";
+import './ShhhPage.css';
+
+//Description for each card
+const BirthText = "Ask moms about their childbirth experiences that you're too afraid to ask, from labor horror stories to body transformations.";
+const DeathText = "Join in a heartfelt conversation about death with elderly individuals and people with chronic conditions. Are you scared of death?";
+const SexText = "Don't be shy! Join us to have open, juicy, and playful conversations about sex that you are curious but don't dare to ask in real-life. We welcome your curiosity!";
+
+
+function ShhhPage() {
+
+ const [open2, dispatch2] = useState(false); // this is to open the view pop up
+
+ function openModal2(e) {
+ dispatch2(true);
+ e.preventDefault();
+ }
+
+ const [open3, dispatch3] = useState(false); // this is to open the view pop up
+
+ function openModal3(e) {
+ dispatch3(true);
+ e.preventDefault();
+ }
+
+ const [toiaName, setName] = useState(null);
+ const [toiaLanguage, setLanguage] = useState(null);
+ const [toiaID, setTOIAid] = useState(null);
+ const [isLoggedIn, setLoginState] = useState(false);
+ const [allData, setAllData] = useState([]);
+ const [searchData, setSearchData] = useState([]);
+
+ const [interactionLanguage, setInteractionLanguage] = useState(null);
+
+ useEffect(() => {
+ if (history.location.state != undefined) {
+ setLoginState(true);
+ setName(history.location.state.toiaName);
+ setLanguage(history.location.state.toiaLanguage);
+ setTOIAid(history.location.state.toiaID);
+ }
+
+ console.log("Trying my best here!", history.location.state?.toiaID);
+
+ axios.get(`/api/getAllStreams`).then(res => {
+ let user_id = history.location.state?.toiaID;
+ axios
+ .get(`/api/permission/streams?user_id=${user_id}`)
+ .then(permission_res => {
+ let filtered_streams = res.data.filter(item => {
+ return permission_res.data.includes(item.id_stream);
+ });
+ setAllData(filtered_streams);
+ setSearchData(filtered_streams);
+ });
+ });
+
+ // Track
+ new Tracker().startTracking(history.location.state);
+ }, []);
+
+ function goToPlayer(element) {
+ if (isLoggedIn) {
+ history.push({
+ pathname: "/shhhplayer",
+ state: {
+ toiaName,
+ toiaLanguage,
+ toiaID,
+ toiaToTalk: element.id,
+ toiaFirstNameToTalk: element.first_name,
+ toiaLastNameToTalk: element.last_name,
+ streamToTalk: element.id_stream,
+ streamNameToTalk: element.name + " stream",
+ },
+ });
+ } else {
+ history.push({
+ pathname: "/shhhplayer",
+ state: {
+ toiaToTalk: element.id,
+ toiaFirstNameToTalk: element.first_name,
+ toiaLastNameToTalk: element.last_name,
+ streamToTalk: element.id_stream,
+ streamNameToTalk: element.name + " stream",
+ },
+ });
+ }
+ }
+ //Display stream cards under the name of "Birth, Sex and Death"
+ const renderStream = (card, index) => {
+ console.log(card);
+ console.log('cardname' + card.name);
+ const orderedCards = ["Birth", "Sex", "Death"];
+ if (orderedCards.includes(card.name)) {
+ //cards for streams
+ return (
+
+
{
+ goToPlayer(card);
+ }}>
+
+
+
+
+ {(() => {
+ switch (card.name) {
+ case "Birth":
+ return BirthText;
+ case "Death":
+ return DeathText;
+ case "Sex":
+ return SexText;
+ default:
+ return "";
+ }
+ })()}
+
+
+
+
+ );
+ }
+ };
+
+ const inlineStyle = {
+ modal: {
+ height: '560px',
+ width: '600px',
+ }
+ };
+
+ const inlineStyleSetting = {
+ modal: {
+ height: '70vh',
+ width: '50vw',
+ }
+ };
+
+ return (
+
+
+
Elephant In the Room
+
dispatch3({ type: "close" })}
+ >
+
+
+ All Stream{" "}
+
+
+ Here is the following information about your stream
+
+
+
+
+ Name:{" "}
+
+
+ Stream Name{" "}
+
+
+
+ Language:{" "}
+
+
+ Stream Language{" "}
+
+
+
+ Bio:{" "}
+
+
+
+ {" "}
+ Stream Bio
+
+
+
+
+
+ {searchData.map(renderStream)}
+
+
+
+ );
+}
+
+export default ShhhPage;
diff --git a/interface/src/pages/ShhhPlayer.js b/interface/src/pages/ShhhPlayer.js
new file mode 100644
index 00000000..07392600
--- /dev/null
+++ b/interface/src/pages/ShhhPlayer.js
@@ -0,0 +1,901 @@
+//Elephant in the Room Interaction Page
+import RecordVoiceOverRoundedIcon from "@mui/icons-material/RecordVoiceOverRounded";
+import VoiceOverOffRoundedIcon from "@mui/icons-material/VoiceOverOffRounded";
+import axios from "axios";
+import React, { useEffect, useState } from "react";
+import { NotificationManager } from "react-notifications";
+import NotificationContainer from "react-notifications/lib/NotificationContainer";
+import { CSSTransition, TransitionGroup } from "react-transition-group";
+import { Modal } from "semantic-ui-react";
+import submitButton from "../icons/submit-button.svg";
+import history from "../services/history";
+import SuggestiveSearch from "../suggestiveSearch/shhhsuggestiveSearch.js";
+import speechToTextUtils from "../transcription_utils";
+import Tracker from "../utils/tracker";
+import ShhhVideoPlaybackPlayer from "./sub-components/shhh-Videoplayback.Player";
+import './ShhhPage.css';
+//Characters in each stream
+//Death
+import james from "../images/death/james.png";
+import rina from "../images/death/rina.png";
+import sally from "../images/death/sally.png";
+import brian from "../images/death/brian.png";
+import jj from "../images/death/jj.png";
+import ian from "../images/death/ian.png";
+import layla from "../images/death/leila.png";
+import norman from "../images/death/norman.png";
+//Sex
+import lucy from "../images/sex/lucy.png";
+import lauren from "../images/sex/lauren.png";
+import klarissa from "../images/sex/klarissa.png";
+import ellis from "../images/sex/ellis.png";
+import kenny from "../images/sex/kenny.png";
+import kendel from "../images/sex/kendel.png";
+import chris from "../images/sex/chris.png";
+import zaldy from "../images/sex/zaldy.png";
+//Birth
+import krista from "../images/birth/krista.png";
+import ashley from "../images/birth/ashley.png";
+import alison from "../images/birth/alison.png";
+import kieona from "../images/birth/kieona.png";
+import kaylee from "../images/birth/kaylee.png";
+import christian from "../images/birth/christian.png";
+import stephanie from "../images/birth/stephanie.png";
+
+const death_icons = [brian, jj, layla, james, rina, sally, ian, norman];
+const sex_icons = [lucy, lauren, klarissa, ellis, kenny, kendel, chris, zaldy];
+const birth_icons = [krista, ashley, alison, kieona, kaylee, christian, stephanie];
+const death_names = ['Brian', 'JJ', 'Layla', 'James', 'Rina', 'Sally', 'Ian', 'Norman'];
+const sex_names = ['Lucy', 'Lauren', 'Klarissa', 'Ellis', 'Kenny', 'Kendel', 'Chris', 'Zaldy'];
+const birth_names = ['Krista', 'Ashley', 'Alison', 'Kieona', 'Kaylee', 'Christian', 'Stephanie'];
+const death_descriptions = ['[Brian] A man with Parkinsons and its symptoms that can lead to earlier death', '[JJ] A 34-year-old man has been diagnosed with incurable colon cancer', '[Layla] A woman with end-stage renal disease', '[James] A Singaporean Man talks about life and superstition', '[Rina] A humorous Singaporean woman who has no regrets in life', '[Sally] A Singaporean woman who speaks about death in Mandarin', '[Ian] Singaporean Man', '[Norman] A Singaporean man who learned how to accept death'];
+const sex_descriptions = ['[Lucy] A young woman who grew up in a culture of taboo around sex', '[Lauren] A sexual confidence coach who encourages open and non-judgmental conversations about sex', '[Klarissa] A bubbly young woman who talks about her first sexual experience and the things she wished she knew beforehand', '[Ellis] A gay man discusses his frustration with categorizing people and setting expectations in sexual encounters', '[Kenny] A gay man shares his insights on gay pornography and the importance of setting boundaries', '[Kendel] A gay man who gives a candid advice for first-time sex', '[Chris] A straight man who shares his past sexual insecurities and anxieties', '[Zaldy] A straight man who shares his definition of consent and shares his sexual insecurities, pressures, and more'];
+const birth_descriptions = ['[Krista] A mother with one child delivered vaginally in a hospital setting and had an epidural.', '[Ashley]A mother of two children, both born vaginally.',
+ '[Alison] A mother of two daughters delivered via two scheduled c-sections', '[Kieona] A mother of one daughter had a regular vaginal birth.', '[Kaylee] A mother who shares her candid pregnancy experiences', '[Christian] A mother who gave a birth through c-section and shares her high-blood pressure issues during pregnancy', '[Stephanie] A mother who underwent an emergency C-section and shares her body-transformation stories during pregnancy.'];
+//Questions listed to help users ideate type of questions they can ask
+const death_questions = [
+ "Are you afraid of death?",
+ "Who is not invited to your funeral?",
+ "How does dying feel like?",
+ "Who would be happy that you are gone?",
+ "What would you miss the most?",
+ "Have you tried giving up?"
+];
+const sex_questions = [
+ "What does penetration feel like?",
+ "Do you get emotionally attached?",
+ "Top or bottom?",
+ "What should I know about gay sex?",
+ "Any advice for someone's first time?",
+ "How often do you think about sex?",
+ "Is period sex okay?"
+];
+
+const birth_questions = [
+ "What was labor like?",
+ "Did you use epidural (spinal anesthesia)?",
+ "Did you see your baby come out?",
+ "How painful was labor?",
+ "What's your most embarrassing story?",
+ "Does your body change after giving birth?",
+ "What’s the hardest part of pregnancy?",
+ "Did you plan pregnancy?"
+];
+
+function ShhhPlayer() {
+ function exampleReducer(state, action) {
+ switch (action.type) {
+ case "close":
+ return { open: false };
+ case "open":
+ return { open: true };
+ }
+ }
+ const [toiaName, setName] = React.useState(null);
+ const [toiaLanguage, setLanguage] = React.useState(null);
+ const [toiaID, setTOIAid] = React.useState(null);
+ const [isLoggedIn, setLoginState] = useState(false);
+
+ const [toiaFirstNameToTalk, setTOIAFirstNameToTalk] = useState(null);
+ const [toiaLastNameToTalk, setTOIALastNameToTalk] = useState(null);
+ const [streamNameToTalk, setStreamNameToTalk] = useState(null);
+ const [fillerPlaying, setFillerPlaying] = useState(true);
+
+ const [answeredQuestions, setAnsweredQuestions] = useState([]);
+ let allSuggestedQuestions = [];
+
+ const [videoProperties, setVideoProperties] = useState(null);
+ const [transcribedAudio, setTranscribedAudio] = useState("");
+
+
+ const [icons, setIcons] = useState([]);
+ const [iconNames, setIconNames] = useState([]);
+ const [iconDescriptions, setIconDescriptions] = useState([]);
+
+ const textInput = React.useRef("");
+ const question = React.useRef("");
+ const isFillerPlaying = React.useRef("true");
+ const allQuestions = React.useRef([]);
+ const shouldRefreshQuestions = React.useRef(false); // flag to indicate that the SuggestionCard module needs to refresh questions
+
+ const interimTextInput = React.useRef("");
+
+ var input1, input2;
+ const [micMute, setMicMute] = useState(true);
+ const [micString, setMicString] = useState("ASK BY VOICE");
+ const interacting = React.useRef(false); // Ref for indicating whether the user is currently interacting or not
+ const [textInputValue, setTextInputValue] = React.useState(""); // Stores the value of the text input
+ const [dataIsFinal, setDataIsFinal] = React.useState(null) // Differentiates space key up with and without data
+
+ useEffect(() => {
+ // Login check. Note: This is very insecure and naive approach. Replace once a proper authentication system has been adopted.
+ if (
+ history.location.state === undefined ||
+ history.location.state.toiaName === undefined ||
+ history.location.state.toiaLanguage === undefined ||
+ history.location.state.toiaID === undefined
+ ) {
+ alert("You must be logged in to access this page");
+ history.push({
+ pathname: "/",
+ });
+ }
+ setName(history.location.state.toiaName);
+ setLanguage(history.location.state.toiaLanguage);
+ setTOIAid(history.location.state.toiaID);
+
+ if (history.location.state.toiaID != undefined) {
+ setLoginState(true);
+ setTOIAid(history.location.state.toiaID);
+ setName(history.location.state.toiaName);
+ setLanguage(history.location.state.toiaLanguage);
+ }
+
+ setTOIAFirstNameToTalk(history.location.state.toiaFirstNameToTalk);
+ setTOIALastNameToTalk(history.location.state.toiaLastNameToTalk);
+ setStreamNameToTalk(history.location.state.streamNameToTalk);
+ canAccessStream();
+
+ fetchAnsweredQuestions();
+ fetchAllStreamQuestions();
+
+ fetchFiller();
+ // Tracker
+ new Tracker().startTracking(history.location.state);
+ }, []);
+
+
+ useEffect(() => {
+ // set the icon and icon name arrays based on streamNameToTalk
+ if ({ streamNameToTalk }.streamNameToTalk === "Death stream") {
+ setIcons(death_icons);
+ setIconNames(death_names);
+ setIconDescriptions(death_descriptions);
+ } else if ({ streamNameToTalk }.streamNameToTalk === "Sex stream") {
+ setIcons(sex_icons);
+ setIconNames(sex_names);
+ setIconDescriptions(sex_descriptions);
+ } else if ({ streamNameToTalk }.streamNameToTalk === "Birth stream") {
+ setIcons(birth_icons);
+ setIconNames(birth_names)
+ setIconDescriptions(birth_descriptions);
+ }
+ }, [streamNameToTalk]);
+
+ //ask question on enter
+ useEffect(() => {
+ const listener = event => {
+ if (event.code === "Enter" || event.code === "NumpadEnter") {
+ event.preventDefault();
+
+ submitResponse(event, "SEARCH");
+ }
+ };
+ document.addEventListener("keydown", listener);
+ return () => {
+ document.removeEventListener("keydown", listener);
+ };
+ }, []);
+
+ //press space bar to unmute
+ const [isSpaceKeyPressed, setIsSpaceKeyPressed] = React.useState(false);
+ const isSpaceKey = React.useRef("false")
+ const firstRender = React.useRef(false)
+
+ //identify whether the spacebar is up or down (recording or not)
+ useEffect(() => {
+ // listener for spacebar down (not for while typing)
+ const listenDown = event => {
+ if (textInput.current == "" && event.code === "Space" && isSpaceKey.current === "false") {
+ setIsSpaceKeyPressed(true)
+ isSpaceKey.current = "true"
+ setMicMute(false)
+ console.log("key down");
+ }
+ };
+ // listener for spacebar up
+ const listenUp = event => {
+ if (textInput.current == "" && event.code === "Space" && isSpaceKey.current === "true") {
+ setIsSpaceKeyPressed(false)
+ isSpaceKey.current = "false"
+ setMicMute(true)
+ console.log("key up");
+ }
+ };
+ document.addEventListener("keydown", listenDown);
+ document.addEventListener("keyup", listenUp);
+ return () => {
+ document.removeEventListener("keydown", listenDown);
+ document.removeEventListener("keyup", listenUp);
+ };
+ }, []);
+
+ //identify whether it is now being recorded, or not
+ useEffect((e) => {
+
+ if (firstRender.current) {
+ if (!micMute) {
+ speechToTextUtils.stopRecording();
+ if (dataIsFinal === false) {
+ textInput.current = transcribedAudio
+ submitResponse(e, "SEARCH")
+ }
+
+ } else {
+ interacting.current = true;
+ speechToTextUtils.initRecording(handleDataReceived, (error) => {
+ console.error("Error when transcribing", error);
+ // No further action needed, as stream already closes itself on error
+ });
+ }
+ } else {
+ firstRender.current = true
+ }
+
+
+ }, [isSpaceKeyPressed])
+
+
+
+ const [state, dispatch] = React.useReducer(exampleReducer, { open: false });
+ const { open } = state;
+
+ function openModal(e) {
+ dispatch({ type: "open" });
+ e.preventDefault();
+ }
+
+ function myChangeHandler(event) {
+ event.preventDefault();
+ var name = event.target.name;
+
+ switch (name) {
+ case "email":
+ input1 = event.target.value;
+ break;
+ case "pass":
+ input2 = event.target.value;
+ break;
+ }
+ }
+
+ function canAccessStream() {
+ let toiaID = history.location.state.toiaID;
+ let streamID = history.location.state.streamToTalk;
+
+ const options = {
+ method: "POST",
+ url: "/api/permission/stream",
+ headers: { "Content-Type": "application/json" },
+ data: { user_id: toiaID, stream_id: streamID },
+ };
+
+ axios
+ .request(options)
+ .then(function (response) { })
+ .catch(function (error) {
+ alert("You do not have permission to access this page");
+ library();
+ });
+ }
+
+ // handling data recieved from server
+ function handleDataReceived(data) {
+ // setting the transcribedAudio
+ if (data) {
+ setTranscribedAudio(data.alternatives[0].transcript);
+ setDataIsFinal(false)
+ if (data.isFinal) {
+ question.current = data.alternatives[0].transcript;
+ setDataIsFinal(true)
+ fetchData("VOICE");
+ }
+ } else {
+ console.log("no data received from server");
+ }
+ }
+
+ // Sets the value of 'allQuestions' array
+ // to be the string list of all questions of the stream
+ function fetchAllStreamQuestions() {
+ axios
+ .get(
+ `/api/questions/answered_filtered/${history.location.state.toiaToTalk}/${history.location.state.streamToTalk}`,
+ )
+ .then(res => {
+ allQuestions.current = res.data || [];
+ });
+ }
+ // function to fetch answered smart questions from the database
+ // question: the last question asked by the user
+ // answer: the answer given by the avatar
+ function fetchAnsweredQuestions(question = "", answer = "") {
+ axios
+ .post("/api/getSmartQuestions", {
+ params: {
+ toiaIDToTalk: history.location.state.toiaToTalk,
+ toiaFirstNameToTalk:
+ history.location.state.toiaFirstNameToTalk,
+ avatar_id: history.location.state.toiaToTalk,
+ stream_id: history.location.state.streamToTalk,
+ latest_question: question,
+ latest_answer: answer,
+ },
+ })
+ .then(res => {
+ // res.data contains the smart questions generated
+ // If res.data is not an array, then there is an error, so stop.
+ if (res.data.constructor !== Array) {
+ return;
+ }
+
+ res.data.forEach(q => {
+ // If the question is not an empty string AND has not been previously asked AND is not in the current list of possible questions
+ // then add it to the list of possible suggestions
+ if (
+ q.question != "" &&
+ !allSuggestedQuestions.includes(q)
+ ) {
+ answeredQuestions.push(q);
+ allSuggestedQuestions.push(q);
+ }
+ });
+
+ shouldRefreshQuestions.current = true;
+ setAnsweredQuestions([...answeredQuestions]);
+ });
+ }
+
+
+ function fetchData(mode = "UNKNOWN") {
+ const oldQuestion = question.current;
+ if (question.current == null || question.current == "") {
+ setFillerPlaying(true);
+ fetchFiller();
+ } else {
+ axios
+ .post(`/api/player`, {
+ params: {
+ toiaIDToTalk: history.location.state.toiaToTalk,
+
+ toiaFirstNameToTalk:
+ history.location.state.toiaFirstNameToTalk,
+ question,
+ streamIdToTalk: history.location.state.streamToTalk,
+ record_log: "true",
+ ...(history.location.state.toiaID && {
+ interactor_id: history.location.state.toiaID,
+ }),
+ mode: mode,
+ },
+ })
+ .then(res => {
+ if (res.data === "error") {
+ setFillerPlaying(true);
+ } else {
+ setFillerPlaying(true);
+
+ isFillerPlaying.current = "false";
+ fetchAnsweredQuestions(oldQuestion, res.data.answer);
+ setVideoProperties({
+ key: res.data.url + new Date(), // add timestamp to force video transition animation when the key hasn't changed
+ onEnded: () => {
+ fetchFiller();
+ },
+ source: res.data.url,
+ fetchFiller: fetchFiller,
+ muted: false,
+ filler: false,
+ duration_seconds: res.data.duration_seconds || null,
+ question: question.current,
+ video_id: res.data.video_id,
+ });
+
+ setTranscribedAudio("");
+ }
+ })
+ .catch(e => {
+ console.error(e);
+ });
+ }
+ }
+
+ function endTranscription() {
+ speechToTextUtils.stopRecording();
+ }
+
+ //changeing the status of the mic button
+ const micStatusChange = (e) => {
+ if (!micMute) {
+ speechToTextUtils.stopRecording();
+ if (dataIsFinal === false) {
+ textInput.current = transcribedAudio
+ submitResponse(e, "SEARCH")
+ }
+
+ } else {
+ interacting.current = true;
+ speechToTextUtils.initRecording(handleDataReceived, (error) => {
+ console.error("Error when transcribing", error);
+ // No further action needed, as stream already closes itself on error
+ });
+ }
+
+ setMicMute(!micMute);
+ setMicString(micMute ? "STOP ASK BY VOICE" : "ASK BY VOICE");
+ interacting.current = micMute ? true : false;
+ };
+
+ function fetchFiller() {
+ isFillerPlaying.current = "true";
+ if (fillerPlaying) {
+ axios
+ .post(`/api/fillerVideo`, {
+ params: {
+ toiaIDToTalk: history.location.state.toiaToTalk,
+ streamIdToTalk: history.location.state.streamToTalk,
+ toiaFirstNameToTalk:
+ history.location.state.toiaFirstNameToTalk,
+ record_log: "true",
+ ...(history.location.state.toiaID && {
+ interactor_id: history.location.state.toiaID,
+ }),
+ },
+ })
+ .then(async res => {
+ setVideoProperties({
+ key: res.data + new Date(), // add timestamp to force video transition animation when the key hasn't changed
+ onEnded: fetchFiller,
+ source: res.data,
+ muted: true,
+ filler: true,
+ duration_seconds: null,
+ });
+
+ document.getElementById("vidmain").load();
+ const playPromise = document
+ .getElementById("vidmain")
+ .play();
+ if (playPromise !== undefined) {
+ playPromise
+ .then(_ => {
+ // Automatic playback started!
+ // Show playing UI.
+ })
+ .catch(error => {
+ // Auto-play was prevented
+ // Show paused UI.
+
+ fetchFiller();
+ });
+ }
+ });
+ }
+ }
+
+ function setRefreshQuestionsFalse() {
+ shouldRefreshQuestions.current = false;
+ }
+
+ function textChange(e) {
+ textInput.current = `${textInput.current} ${e.target.value}`;
+ interimTextInput.current = textInput.current;
+ setTextInputValue(e.target.value);
+ }
+
+ function submitResponse(e, mode = "UNKNOWN") {
+ question.current = textInput.current
+ ? textInput.current
+ : interimTextInput.current;
+ if (question.current != "") {
+ const oldQuestion = question.current;
+ axios
+ .post(`/api/player`, {
+ params: {
+ toiaIDToTalk: history.location.state.toiaToTalk,
+ toiaFirstNameToTalk:
+ history.location.state.toiaFirstNameToTalk,
+ question,
+ streamIdToTalk: history.location.state.streamToTalk,
+ record_log: "true",
+ ...(history.location.state.toiaID && {
+ interactor_id: history.location.state.toiaID,
+ }),
+ mode: mode,
+ },
+ })
+ .then(res => {
+ setFillerPlaying(true);
+ if (res.data !== "error") {
+ isFillerPlaying.current = "false";
+
+ setVideoProperties({
+ key: res.data.url + new Date(), // add timestamp to force video transition animation when the key hasn't changed
+ onEnded: () => {
+ fetchFiller();
+ },
+ source: res.data.url,
+ muted: false,
+ filler: false,
+ duration_seconds: res.data.duration_seconds || null,
+ question: question.current,
+ video_id: res.data.video_id,
+ });
+
+ fetchAnsweredQuestions(oldQuestion, res.data.answer);
+ setTranscribedAudio("");
+ question.current = "";
+ }
+ })
+ .catch(e => {
+ console.error(e);
+ });
+ textInput.current = "";
+ interimTextInput.current = "";
+ setTextInputValue("");
+ }
+ }
+
+ function submitHandler(e) {
+ e.preventDefault();
+
+ let params = {
+ email: input1,
+ pwd: input2,
+ };
+
+ axios.post(`/api/login`, params).then(res => {
+ if (res.data == -1) {
+ //alert('Email not found');
+ NotificationManager.error("Incorrect e-mail address.");
+ } else if (res.data == -2) {
+ NotificationManager.error("Incorrect password.");
+ } else {
+ history.push({
+ pathname: "/mytoia",
+ state: {
+ toiaName: res.data.firstName,
+ toiaLanguage: res.data.language,
+ toiaID: res.data.toia_id,
+ },
+ });
+ }
+ });
+ }
+
+ function home() {
+ if (isLoggedIn) {
+ endTranscription();
+ history.push({
+ pathname: "/",
+ state: {
+ toiaName,
+ toiaLanguage,
+ toiaID,
+ },
+ });
+ } else {
+ history.push({
+ pathname: "/",
+ });
+ }
+ }
+
+ function shhh() {
+ if (isLoggedIn) {
+ history.push({
+ pathname: "/shhh",
+ state: {
+ toiaName,
+ toiaLanguage,
+ toiaID,
+ },
+ });
+ } else {
+ history.push({
+ pathname: "/shhh",
+ });
+ }
+ }
+
+ function about() {
+ if (isLoggedIn) {
+ endTranscription();
+ history.push({
+ pathname: "/about",
+ state: {
+ toiaName,
+ toiaLanguage,
+ toiaID,
+ },
+ });
+ } else {
+ history.push({
+ pathname: "/about",
+ });
+ }
+ }
+
+ function library() {
+ if (history.location.state.toiaID != undefined) {
+ endTranscription();
+ history.push({
+ pathname: "/library",
+ state: {
+ toiaName: history.location.state.toiaName,
+ toiaLanguage: history.location.state.toiaLanguage,
+ toiaID: history.location.state.toiaID,
+ },
+ });
+ } else {
+ history.push({
+ pathname: "/library",
+ });
+ }
+ }
+
+ function garden(e) {
+ if (isLoggedIn) {
+ endTranscription();
+ history.push({
+ pathname: "/mytoia",
+ state: {
+ toiaName,
+ toiaLanguage,
+ toiaID,
+ },
+ });
+ } else {
+ openModal(e);
+ }
+ }
+
+ function logout() {
+ //logout function needs to be implemented (wahib)
+ history.push({
+ pathname: "/",
+ });
+ endTranscription();
+ }
+
+ function signup() {
+ history.push({
+ pathname: "/signup",
+ });
+ endTranscription();
+ }
+
+ const inlineStyle = {
+ modal: {
+ height: "560px",
+ width: "600px",
+ },
+ };
+
+ const [selectedIconIndex, setSelectedIconIndex] = useState(null);
+
+
+ const handleIconClick = (index) => {
+ const iconName = iconNames[index];
+ if (index === selectedIconIndex) {
+ setSelectedIconIndex(null);
+ // unmute all icons
+ const iconContainers = document.querySelectorAll('.icon-container');
+ iconContainers.forEach((container) => {
+ container.classList.remove('muted');
+ });
+ textInput.current = ""; // reset to empty string
+ } else {
+ setSelectedIconIndex(index);
+ // mute all icons except selected one
+ const iconContainers = document.querySelectorAll('.icon-container');
+ iconContainers.forEach((container, i) => {
+ if (i === index) {
+ container.classList.remove('muted');
+ } else {
+ container.classList.add('muted');
+ }
+ });
+ textInput.current = iconName;
+ interimTextInput.current = textInput.current;
+ }
+ };
+
+
+ return (
+
+
dispatch({ type: "close" })}>
+
+
+ Welcome Back
+
+
+ Enter the following information to login to your TOIA
+ account
+
+
+
+
+
+
+
+
+
+ {icons.map((icon, index) => (
+
+
handleIconClick(index)}
+ />
+
{iconNames[index]}
+
{iconDescriptions[index]}
+
+ ))}
+
+
+ {videoProperties && (
+
+
+
+
+
+ )}
+ {micMute ? (
+
micStatusChange(e)}>
+
+
+
+
+ ) : (
+
+
+
+
+
+ )
+ }
+
+
+ {isFillerPlaying.current == "false" ? (
+
+ {" "}
+ Skip to End{" "}
+
+
+ ) : null}
+
+
+
+
+
+ {streamNameToTalk && streamNameToTalk.includes(" stream") && (
+
Hey, let's talk about {streamNameToTalk.replace(" stream", "")}
+ )}
+
+ {streamNameToTalk === "Death stream" && death_questions.map((question, index) => (
+ {question}
+ ))}
+ {streamNameToTalk === "Sex stream" && sex_questions.map((question, index) => (
+ {question}
+ ))}
+ {streamNameToTalk === "Birth stream" && birth_questions.map((question, index) => (
+ {question}
+ ))}
+
+
+
+
+
+
+
+
+
+
+ );
+}
+export default ShhhPlayer;
\ No newline at end of file
diff --git a/interface/src/pages/sub-components/shhh-Videoplayback.Player.js b/interface/src/pages/sub-components/shhh-Videoplayback.Player.js
new file mode 100644
index 00000000..57f56eb0
--- /dev/null
+++ b/interface/src/pages/sub-components/shhh-Videoplayback.Player.js
@@ -0,0 +1,43 @@
+import { useRef, useState, useEffect } from "react";
+
+export default function ShhhVideoPlaybackPlayer(props) {
+ const videoRef = useRef(null);
+
+ // let skippedLastSecond = false;
+
+ // useEffect(() => {
+ // skippedLastSecond = false;
+ // }, [props])
+
+ // const onTimeUpdate = () => {
+ // if (!props.filler && props.duration_seconds && props.duration_seconds > 3){
+ // if ((props.duration_seconds - videoRef.current.currentTime) <= 1){
+ // if (!skippedLastSecond){
+ // skippedLastSecond = true;
+ // props.onEnded();
+ // console.log("Ending:", props.duration_seconds)
+ // }
+ // }
+ // }
+ // }
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/interface/src/routes/index.js b/interface/src/routes/index.js
index a4bbd1ba..0323b945 100644
--- a/interface/src/routes/index.js
+++ b/interface/src/routes/index.js
@@ -1,20 +1,22 @@
import React from "react";
import { Route, Switch } from "react-router-dom";
-
import Home from "../pages/HomePage";
import SignUp from "../pages/SignUpPage";
import AvatarGarden from "../pages/AvatarGardenPage";
+import Shhh from "../pages/ShhhPage";
import AvatarLibrary from "../pages/AvatarLibraryPage";
import Settings from "../pages/AvatarStream";
import AboutUs from "../pages/AboutUsPage";
import Recorder from "../pages/Recorder";
import Player from "../pages/Player";
+import shhhPlayer from "../pages/ShhhPlayer";
import EditRecorder from "../pages/EditRecorderPage";
export default function Routes() {
return (
+
@@ -23,6 +25,7 @@ export default function Routes() {
+
{/* redirect user to SignIn page if route does not exist and user is not authenticated */}
diff --git a/interface/src/services/languageHelper.js b/interface/src/services/languageHelper.js
new file mode 100644
index 00000000..b0efd8c1
--- /dev/null
+++ b/interface/src/services/languageHelper.js
@@ -0,0 +1,12 @@
+// pan class="fi fi-us">
+//
+// {/* SP */}
+//
+
+const languageFlagsCSS = {
+ 'en-US' : "fi fi-us",
+ 'ar-AE' : "fi fi-ae",
+ 'fr-FR' : "fi fi-fr",
+};
+
+export default languageFlagsCSS;
\ No newline at end of file
diff --git a/interface/src/suggestiveSearch/shhhsuggesitonCards.js b/interface/src/suggestiveSearch/shhhsuggesitonCards.js
new file mode 100644
index 00000000..5f16d81d
--- /dev/null
+++ b/interface/src/suggestiveSearch/shhhsuggesitonCards.js
@@ -0,0 +1,289 @@
+// import * as React from "react";
+import React, { useEffect, useState } from "react";
+import { Button, Card } from "semantic-ui-react";
+import '../pages/ShhhPage.css';
+
+export default function ShhhSuggestionCards(props) {
+ // keeping track of position of each of the five cards
+ // const firstQuestion = React.useRef(0);
+ const [firstQuestion, setFirstQuestion] = useState({
+ questionData: null,
+ waiting: true,
+ highlighBackground: false,
+ });
+
+ const [secondQuestion, setSecondQuestion] = useState({
+ questionData: null,
+ waiting: true,
+ highlighBackground: false,
+ });
+
+ const [thirdQuestion, setThirdQuestion] = useState({
+ questionData: null,
+ waiting: true,
+ highlighBackground: false,
+ });
+
+ const [fourthQuestion, setFourthQuestion] = useState({
+ questionData: null,
+ waiting: true,
+ highlighBackground: false,
+ });
+
+ const [fifthQuestion, setFifthQuestion] = useState({
+ questionData: null,
+ waiting: true,
+ highlighBackground: false,
+ });
+
+ const cardQuestions = [
+ firstQuestion,
+ secondQuestion,
+ thirdQuestion,
+ fourthQuestion,
+ fifthQuestion,
+ ];
+ // const setQuestion = [setFirstQuestion,setSecondQuestion,setThirdQuestion,setFourthQuestion,setFifthQuestion];
+
+ const getSuggestion = questionCard => {
+ // console.log("getSuggestion:");
+ // console.log(questionCard.questionData && questionCard.questionData.question ? questionCard.questionData.question : "No question loaded!");
+ return questionCard.questionData && questionCard.questionData.question
+ ? questionCard.questionData.question
+ : "Loading ...";
+ };
+
+ const delayedQuestionCardChange = (questionCard, setQuestionCard) => {
+ return () => {
+ questionCard.highlighBackground = false;
+ if (questionCard.waiting) {
+ questionCard.questionData = null;
+ setQuestionCard({ ...questionCard });
+ }
+ };
+ };
+
+ const askQuestion = (questionCard, setQuestionCard) => {
+ // console.log("askQuestion:");
+ props.askQuestion(questionCard.questionData);
+ questionCard.waiting = true;
+ questionCard.highlighBackground = true;
+ setTimeout(
+ delayedQuestionCardChange(questionCard, setQuestionCard),
+ 3000,
+ );
+ setQuestionCard({ ...questionCard });
+ };
+
+ const getNextQuestion = (questionCard, setQuestionCard) => {
+ // console.log("getNextQuestion:");
+ if (props.questions.length > 0) {
+ // console.log("getNextQuestion: got question");
+ questionCard.questionData = props.questions.pop();
+ setQuestionCard({ ...questionCard });
+ }
+ };
+
+ const refreshQuestion = (questionCard, setQuestionCard) => {
+ // console.log("refreshQuestion: refreshing question...");
+ if (
+ props.questions.length > 0 &&
+ questionCard.waiting &&
+ props.shouldRefreshQuestions?.current
+ ) {
+ // console.log("refreshQuestion: refreshed question...");
+ questionCard.waiting = false;
+ questionCard.highlighBackground = false;
+ questionCard.questionData = props.questions.pop();
+ // console.log("refreshQuestion: new question: ", questionCard.questionData.question);
+ setQuestionCard({ ...questionCard });
+ }
+ };
+
+ const shouldStopRefreshing = () => {
+ for (let questionCard in cardQuestions) {
+ // If any card question is still waiting, even after updating the questions
+ // Then we still want to refresh questions where possible
+ if (questionCard.waiting && props.shouldRefreshQuestions?.current) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ useEffect(() => {
+ getNextQuestion(firstQuestion, setFirstQuestion);
+ getNextQuestion(secondQuestion, setSecondQuestion);
+ }, []);
+
+ return props.questions ? (
+
+
+
+
+
+ {refreshQuestion(fourthQuestion, setFourthQuestion)}
+ {getSuggestion(fourthQuestion)}
+
+
+
+
+ {
+ askQuestion(
+ fourthQuestion,
+ setFourthQuestion,
+ );
+ }}
+ />
+ {
+ getNextQuestion(
+ fourthQuestion,
+ setFourthQuestion,
+ );
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ {refreshQuestion(thirdQuestion, setThirdQuestion)}
+ {getSuggestion(thirdQuestion)}
+
+
+
+
+ {
+ askQuestion(
+ thirdQuestion,
+ setThirdQuestion,
+ );
+ }}
+ />
+ {
+ getNextQuestion(
+ thirdQuestion,
+ setThirdQuestion,
+ );
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ {refreshQuestion(secondQuestion, setSecondQuestion)}
+ {getSuggestion(secondQuestion)}
+
+
+
+
+ {
+ askQuestion(
+ secondQuestion,
+ setSecondQuestion,
+ );
+ }}
+ />
+ {
+ getNextQuestion(
+ secondQuestion,
+ setSecondQuestion,
+ );
+ }}
+ />
+
+
+
+
+
+
+
+
+
+ {refreshQuestion(firstQuestion, setFirstQuestion)}
+ {getSuggestion(firstQuestion)}
+
+
+
+
+ {
+ askQuestion(
+ firstQuestion,
+ setFirstQuestion,
+ );
+ }}
+ />
+ {
+ getNextQuestion(
+ firstQuestion,
+ setFirstQuestion,
+ );
+ }}
+ />
+
+
+
+
+
+ {shouldStopRefreshing() ? props.setRefreshQuestionsFalse() : ""}
+
+ ) : null;
+}
+
diff --git a/interface/src/suggestiveSearch/shhhsuggestiveSearch.js b/interface/src/suggestiveSearch/shhhsuggestiveSearch.js
new file mode 100644
index 00000000..45db84b5
--- /dev/null
+++ b/interface/src/suggestiveSearch/shhhsuggestiveSearch.js
@@ -0,0 +1,41 @@
+import React from "react";
+import TextField from "@mui/material/TextField";
+import '../pages/ShhhPage.css';
+
+
+export default function FreeSoloCreateOption(props) {
+ return (
+ {
+ props.handleTextChange(e);
+ }}
+ />
+ );
+}
diff --git a/interface/src/suggestiveSearch/suggestionCards.js b/interface/src/suggestiveSearch/suggestionCards.js
index 14ad6d4d..f5cdf815 100644
--- a/interface/src/suggestiveSearch/suggestionCards.js
+++ b/interface/src/suggestiveSearch/suggestionCards.js
@@ -1,7 +1,7 @@
// import * as React from "react";
import React, { useEffect, useState } from "react";
import { Button, Card } from "semantic-ui-react";
-import "../pages/Player.css";
+// import "../pages/Player.css";
export default function SuggestionCards(props) {
// keeping track of position of each of the five cards
@@ -64,15 +64,6 @@ export default function SuggestionCards(props) {
};
const askQuestion = (questionCard, setQuestionCard) => {
- if (!props.hasRated) {
- props.notificationManager.warning(
- "Please provide a rating",
- "",
- 3000,
- );
- return;
- }
-
// console.log("askQuestion:");
props.askQuestion(questionCard.questionData);
questionCard.waiting = true;
@@ -126,7 +117,7 @@ export default function SuggestionCards(props) {
}, []);
return props.questions ? (
-
+
Some things you can ask me…
@@ -150,6 +141,7 @@ export default function SuggestionCards(props) {
color="linkedin"
icon="send"
labelPosition="left"
+
onClick={() => {
askQuestion(
fifthQuestion,
@@ -356,10 +348,10 @@ export default function SuggestionCards(props) {
}
/**
- *
- *
- *
- *
-
+ *
+ *
+ *
+ *
+
*/
diff --git a/interface/src/suggestiveSearch/suggestiveSearch.js b/interface/src/suggestiveSearch/suggestiveSearch.js
index 7ca5331c..eb3ba612 100644
--- a/interface/src/suggestiveSearch/suggestiveSearch.js
+++ b/interface/src/suggestiveSearch/suggestiveSearch.js
@@ -90,7 +90,7 @@ export default function FreeSoloCreateOption(props) {
top: "90%",
width: "55.25%",
left: "1%",
- height: "7.5%",
+ height: "30.5%",
// height: "80.25%",
color: "#707070",
fontSize: "1.5rem",
diff --git a/server/.gitignore b/server/.gitignore
index ac57606e..2d4977f3 100644
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -7,4 +7,7 @@ package-lock.json
/.idea
/Accounts
/speech_to_text/toia-capstone-2021-b944d1cc65aa.json
-/interface/build
\ No newline at end of file
+/interface/build
+manual_save/
+/manual_save
+manual_save
diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev
index c63e86d5..07b5a4e9 100644
--- a/server/Dockerfile.dev
+++ b/server/Dockerfile.dev
@@ -21,4 +21,4 @@ RUN npm install
COPY server/ .
-ENTRYPOINT ["nodemon", "app.js"]
\ No newline at end of file
+ENTRYPOINT ["nodemon", "-L", "app.js"]
\ No newline at end of file
diff --git a/server/helper/user_mgmt.js b/server/helper/user_mgmt.js
index 2ca082aa..f68e71ec 100644
--- a/server/helper/user_mgmt.js
+++ b/server/helper/user_mgmt.js
@@ -179,7 +179,7 @@ const linkStreamVideoQuestion = (streamID, videoID, quesID, type, ada_search=nul
let linkQuesQuery = `INSERT INTO videos_questions_streams(id_video, id_question, id_stream, type, ada_search) VALUES(?, ?, ?, ?, ?);`;
connection.query(
linkQuesQuery,
- [videoID, quesID, streamID, type, ada_search],
+ [videoID, quesID, streamID, type, JSON.stringify(ada_search)],
err => {
if (err) throw err;
console.log(
@@ -513,6 +513,7 @@ const canAccessStream = (user_id, stream_id) => {
const getAccessibleStreams = user_id => {
return new Promise(resolve => {
let query = `(SELECT id_stream FROM stream where toia_id = ?) UNION (SELECT stream_id FROM stream_view_permission WHERE toia_id = ?);`;
+ // let query = `SELECT id_stream FROM stream`;
connection.query(query, [user_id, user_id], (err, entries) => {
if (err) throw err;
let stream_ids = entries.map(item => {
@@ -590,7 +591,7 @@ const getExactMatchVideo = (stream_id, question) => {
const getEmbeddings = async (question, answer) => {
try {
const embeddings = await openai.createEmbedding({
- model: "text-search-ada-doc-001",
+ model: "text-embedding-ada-002", //
input: "Question: " + question + "; Answer: " + answer,
});
diff --git a/server/mysql/toia_db.sql b/server/mysql/toia_db.sql
index 12457e29..a286844b 100644
--- a/server/mysql/toia_db.sql
+++ b/server/mysql/toia_db.sql
@@ -1,11 +1,11 @@
-- phpMyAdmin SQL Dump
--- version 5.1.1
+-- version 5.1.3
-- https://www.phpmyadmin.net/
--
-- Host: mysql
--- Generation Time: Jun 23, 2022 at 06:58 PM
+-- Generation Time: Nov 27, 2022 at 06:49 AM
-- Server version: 8.0.27
--- PHP Version: 7.4.27
+-- PHP Version: 8.0.16
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
@@ -35,7 +35,9 @@ CREATE TABLE `conversations_log` (
`timestamp` bigint NOT NULL,
`filler` tinyint(1) NOT NULL,
`question_asked` text,
- `video_played` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
+ `video_played` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+ `ada_similarity_score` float DEFAULT NULL,
+ `mode` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- --------------------------------------------------------
@@ -164,7 +166,7 @@ CREATE TABLE `videos_questions_streams` (
`id_question` int NOT NULL,
`id_stream` int NOT NULL,
`type` enum('filler','greeting','answer','exit','no-answer','y/n-answer') NOT NULL,
- `ada_search` text NOT NULL
+ `ada_search` text CHARACTER SET utf8 COLLATE utf8_general_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
--
diff --git a/server/package.json b/server/package.json
index a137475b..00179131 100644
--- a/server/package.json
+++ b/server/package.json
@@ -45,4 +45,4 @@
"prettier": "2.7.1",
"supertest": "^6.2.1"
}
-}
+}
\ No newline at end of file
diff --git a/server/q_api/test/test.py b/server/q_api/test/test.py
index 389d9bc2..a8a14a76 100644
--- a/server/q_api/test/test.py
+++ b/server/q_api/test/test.py
@@ -6,7 +6,7 @@
openai.api_key = "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"
def printEmbedding(query):
- embedding = get_embedding(query, engine='text-search-ada-query-001')
+ embedding = get_embedding(query, engine='text-embedding-ada-002')
print("====================\nQuery:", query, "\n Embedding:",embedding ,"\n====================")
print("Starting test...", flush=True)
diff --git a/server/q_api/utils.py b/server/q_api/utils.py
index 638d1b28..05535ee0 100644
--- a/server/q_api/utils.py
+++ b/server/q_api/utils.py
@@ -43,7 +43,7 @@ def getFirstNSimilar(df_avatar, query, NUM_SHORTLIST):
def getFreqByCosineSimilarity(query, data):
# Creating embedding for query
- embedding = get_embedding(query, engine='text-search-ada-query-001')
+ embedding = get_embedding(query, engine='text-embedding-ada-002')
# Searching query embedding through avatar's questions' embeddings using cosine similarity
data['similarities'] = data.ada_search.apply(lambda x: cosine_similarity(x, embedding))
diff --git a/server/routes/index.js b/server/routes/index.js
index dc6b4dd9..fc31ff4b 100644
--- a/server/routes/index.js
+++ b/server/routes/index.js
@@ -33,6 +33,7 @@ const {
getAccessibleStreams,
getVideoDetails,
getExactMatchVideo,
+ getEmbeddings,
} = require("../helper/user_mgmt");
const bcrypt = require("bcrypt");
const connection = require("../configs/db-connection");
@@ -1043,11 +1044,20 @@ router.post("/recorder", cors(), async (req, res) => {
}
for (const streamToLink of videoStreams) {
+ let embeddings = "";
+ try {
+ console.log("Generating Embeddings: question: ", q.question, " answer: ", answer);
+ embeddings = await getEmbeddings(q.question, answer);
+ } catch (err) {
+ console.log("Failed to generate embeddings");
+ console.log(err);
+ }
await linkStreamVideoQuestion(
streamToLink.id,
videoID,
q_id,
fields.videoType[0],
+ embeddings,
);
}
diff --git a/server/toia-dm/Dockerfile b/server/toia-dm/Dockerfile
index 8d287ec0..5859eede 100644
--- a/server/toia-dm/Dockerfile
+++ b/server/toia-dm/Dockerfile
@@ -9,6 +9,7 @@ COPY requirements.txt /app/
WORKDIR /app
+RUN apt-get install libmysqlclient-dev -y
RUN pip3 install -r requirements.txt
# RUN python3 -m spacy download en_core_web_lg
RUN apt-get install python3-mysqldb -y
diff --git a/server/toia-dm/PATCH.py b/server/toia-dm/PATCH.py
index 68ccaf11..b7c81bf1 100644
--- a/server/toia-dm/PATCH.py
+++ b/server/toia-dm/PATCH.py
@@ -1,16 +1,8 @@
-import argparse
-from ast import Num
-import os
-import time
-from tokenize import Number
-
import numpy as np
-import openai
import pandas as pd
import sqlalchemy as db
from sqlalchemy import Table
from dotenv import dotenv_values
-from openai.embeddings_utils import get_embedding
from sqlalchemy.sql import text
import friendlywords as fw
import json
@@ -160,5 +152,5 @@ def createUserVariant(user_id):
with open('result.json', 'w') as fp:
json.dump(info, fp)
-# populateAllAdaSearch()
-createVariants()
+populateAllAdaSearch()
+# createVariants()
diff --git a/server/toia-dm/create_embeddings.py b/server/toia-dm/create_embeddings.py
index 33ad9416..37bcf003 100644
--- a/server/toia-dm/create_embeddings.py
+++ b/server/toia-dm/create_embeddings.py
@@ -1,47 +1,33 @@
-import os
from dotenv import dotenv_values
-import openai
-from openai.embeddings_utils import get_embedding
+from openai import OpenAI
import pandas as pd
-import numpy as np
import sqlalchemy as db
from sqlalchemy.sql import text
import argparse
-import time
-
-parser = argparse.ArgumentParser(description='Pass toia_id to insert embeddings into the db.')
-parser.add_argument('-t', type=int, nargs='+',
- help='toia_ids for creating embeddings and insert them into the db')
-args = parser.parse_args()
+# Load environment variables
config = dotenv_values()
-# openai.organization = config['YOUR_ORG_ID']
-openai.api_key = config['OPENAI_API_KEY']
+# Set OpenAI API key
+openaiClient = OpenAI(api_key=config["OPENAI_API_KEY"])
+
+# Database connection URL
SQL_URL = "{dbconnection}://{dbusername}:{dbpassword}@{dbhost}/{dbname}".format(
dbconnection=config["DB_CONNECTION"],
dbusername=config["DB_USERNAME"],
dbpassword=config["DB_PASSWORD"],
dbhost=config["DB_HOST"],
dbname=config["DB_DATABASE"])
-# SQL_URL = "{dbconnection}://{dbusername}:{dbpassword}@{dbhost}/{dbname}".format(dbconnection=config["DB_CONNECTION"],dbusername=config["DB_USERNAME"],dbpassword=config["DB_PASSWORD"],dbhost=config["DB_HOST"],dbname=config["DB_DATABASE"])
print(SQL_URL)
-print("Connecting...")
-
+# Create database engine
ENGINE = db.create_engine(SQL_URL)
METADATA = db.MetaData()
VIDEOS = db.Table('video', METADATA, autoload=True, autoload_with=ENGINE)
-print("Connected successfully!")
-
-def adaSimilarity(x):
- time.sleep(1)
- return get_embedding(x, engine='text-similarity-ada-001')
-
-def adaSearch(x):
- time.sleep(1)
- return get_embedding(x, engine='text-search-ada-doc-001')
+def get_embedding_new(text, model="text-embedding-ada-002"):
+ text = text.replace("\n", " ")
+ return openaiClient.embeddings.create(input=text, model=model).data[0].embedding
def addAdaSearch(toiaID):
retrieve_statement = text("""
@@ -49,9 +35,10 @@ def addAdaSearch(toiaID):
INNER JOIN videos_questions_streams vqs ON vqs.id_video = v.id_video
INNER JOIN questions q ON q.id = vqs.id_question
WHERE v.toia_id = :toiaID AND v.private = 0 AND vqs.type NOT IN ('filler', 'exit');""")
- CONNECTION = ENGINE.connect()
- result_proxy = CONNECTION.execute(retrieve_statement, toiaID=toiaID)
- result_set = result_proxy.fetchall()
+ with ENGINE.connect() as CONNECTION:
+ result_proxy = CONNECTION.execute(retrieve_statement, toiaID=toiaID)
+ result_set = result_proxy.fetchall()
+
df_avatar = pd.DataFrame(result_set,
columns=[
'toia_id',
@@ -61,19 +48,23 @@ def addAdaSearch(toiaID):
'question_id'
])
df_avatar['combined'] = "Question: " + df_avatar.question.str.strip() + "; Answer: " + df_avatar.answer.str.strip()
- # This will take just under 2 minutes
- df_avatar['ada_similarity'] = df_avatar.combined.apply(lambda x: adaSimilarity(x))
- df_avatar['ada_search'] = df_avatar.combined.apply(lambda x: adaSearch(x))
+ df_avatar['ada_search'] = df_avatar.combined.apply(lambda x: get_embedding_new(x))
for videoID in df_avatar.id_video:
- adaSearchVar = str(df_avatar[df_avatar['id_video']==videoID].ada_search.values[0])
+ adaSearchVar = str(df_avatar[df_avatar['id_video'] == videoID].ada_search.values[0])
update_statement = text("""
UPDATE videos_questions_streams vqs SET ada_search = :adaSearchVal
WHERE vqs.id_video = :videoID;
""")
- CONNECTION = ENGINE.connect()
- CONNECTION.execute(update_statement, adaSearchVal=adaSearchVar, videoID=videoID, toiaID=toiaID)
+ with ENGINE.connect() as CONNECTION:
+ CONNECTION.execute(update_statement, adaSearchVal=adaSearchVar, videoID=videoID, toiaID=toiaID)
if __name__ == "__main__":
+ # Parse command line arguments
+ parser = argparse.ArgumentParser(description='Pass toia_id to insert embeddings into the db.')
+ parser.add_argument('-t', type=int, nargs='+',
+ help='toia_ids for creating embeddings and insert them into the db')
+ args = parser.parse_args()
+
for toiaID in args.t:
- addAdaSearch(toiaID)
\ No newline at end of file
+ addAdaSearch(toiaID)
diff --git a/server/toia-dm/main.py b/server/toia-dm/main.py
index c458f8f5..06a2387b 100644
--- a/server/toia-dm/main.py
+++ b/server/toia-dm/main.py
@@ -15,7 +15,8 @@
from pydantic import BaseModel
load_dotenv()
-SQL_URL = "{dbconnection}://{dbusername}:{dbpassword}@{dbhost}/{dbname}".format(dbconnection=os.environ.get("DB_CONNECTION"),dbusername=os.environ.get("DB_USERNAME"),dbpassword=os.environ.get("DB_PASSWORD"),dbhost=os.environ.get("DB_HOST"),dbname=os.environ.get("DB_DATABASE"))
+SQL_URL = "{dbconnection}://{dbusername}:{dbpassword}@{dbhost}/{dbname}".format(dbconnection=os.environ.get("DB_CONNECTION"), dbusername=os.environ.get(
+ "DB_USERNAME"), dbpassword=os.environ.get("DB_PASSWORD"), dbhost=os.environ.get("DB_HOST"), dbname=os.environ.get("DB_DATABASE"))
ENGINE = db.create_engine(SQL_URL)
@@ -33,53 +34,56 @@ class QuestionInput(BaseModel):
avatar_id: str
stream_id: str
-class DMpayload(BaseModel): #I know this nesting is stupid --- correct this later in the nodejs backend when defining the payload there
+
+class DMpayload(BaseModel): # I know this nesting is stupid --- correct this later in the nodejs backend when defining the payload there
params: QuestionInput
+
@app.post("/dialogue_manager")
def dialogue_manager(payload: DMpayload):
raw_payload = payload.params
-
+
query = raw_payload.query
avatar_id = raw_payload.avatar_id
stream_id = raw_payload.stream_id
- print(query)
- print(avatar_id)
- print(stream_id)
-
statement = text("""SELECT videos_questions_streams.id_stream as stream_id_stream, videos_questions_streams.type, videos_questions_streams.ada_search, questions.question, video.id_video, video.toia_id, video.idx, video.private, video.answer, video.likes, video.views FROM video
INNER JOIN videos_questions_streams ON videos_questions_streams.id_video = video.id_video
INNER JOIN questions ON questions.id = videos_questions_streams.id_question
WHERE videos_questions_streams.id_stream = :streamID AND video.private = 0 AND videos_questions_streams.type NOT IN ('filler', 'exit');""")
CONNECTION = ENGINE.connect()
- result_proxy = CONNECTION.execute(statement,streamID=stream_id)
+ result_proxy = CONNECTION.execute(statement, streamID=stream_id)
result_set = result_proxy.fetchall()
df_avatar = pd.DataFrame(result_set,
- columns=[
- 'stream_id_stream',
- 'type',
- 'ada_search',
- 'question',
- 'id_video',
- 'toia_id',
- 'idx',
- 'private',
- 'answer',
- 'likes',
- 'views',
- ])
-
- df_avatar['ada_search'] = df_avatar.ada_search.apply(eval).apply(np.array) #needed when np array stored as txt
+ columns=[
+ 'stream_id_stream',
+ 'type',
+ 'ada_search',
+ 'question',
+ 'id_video',
+ 'toia_id',
+ 'idx',
+ 'private',
+ 'answer',
+ 'likes',
+ 'views',
+ ])
+
+ print("ok connected to db")
+ df_avatar['ada_search'] = df_avatar.ada_search.apply(
+ eval).apply(np.array) # needed when np array stored as txt
+ print("ok ada_search")
# df_greetings = df_avatar[df_avatar['type'] == "greeting"]
- if query is None:
- return 'Please enter a query', 400
-
- response = toia_answer(query, df_avatar)
+ # if query is None:
+ # return 'Please enter a query', 400
+ print(query)
+ response = toia_answer(query, df_avatar, ENGINE, interactor_id=avatar_id) # this works only for one toia account interacting with its strams. Need to change to focus only on interactor ID
+ print("does it make response")
+ print(response)
answer = response[0]
id_video = response[1]
@@ -94,5 +98,6 @@ def dialogue_manager(payload: DMpayload):
json.dumps(result)
return result
+
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("DM_PORT")))
diff --git a/server/toia-dm/notebooks/dm-dev.ipynb b/server/toia-dm/notebooks/dm-dev.ipynb
index 857f9d3a..24e9e5ab 100644
--- a/server/toia-dm/notebooks/dm-dev.ipynb
+++ b/server/toia-dm/notebooks/dm-dev.ipynb
@@ -21,7 +21,7 @@
},
{
"cell_type": "code",
- "execution_count": 19,
+ "execution_count": 1,
"id": "e2ffbe54-c168-4e86-be33-d0c646533100",
"metadata": {},
"outputs": [],
@@ -31,13 +31,14 @@
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": 50,
"id": "1353aae9-ff9d-4967-a1f1-7512dd821948",
"metadata": {},
"outputs": [],
"source": [
"import sqlalchemy as db\n",
"from sqlalchemy.sql import text\n",
+ "import mysql.connector\n",
"import pandas as pd\n",
"import numpy as np\n",
"import numpy\n",
@@ -48,8 +49,12 @@
"from sklearn.feature_extraction.text import TfidfTransformer\n",
"from sklearn.metrics.pairwise import cosine_similarity\n",
"from nltk.stem.snowball import SnowballStemmer\n",
- "import spacy\n",
- "import spacy_sentence_bert"
+ "# import spacy\n",
+ "# import spacy_sentence_bert\n",
+ "\n",
+ "from dotenv import dotenv_values\n",
+ "\n",
+ "config = dotenv_values(\".env\")"
]
},
{
@@ -62,76 +67,65 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 51,
"id": "1a13e027-2066-4fc9-be10-47d5a69bd838",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "['sentence_bert']"
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "NLP = spacy.load(\"en_core_web_lg\")\n",
- "# NLP_BERT = spacy.load(\"en_paraphrase_distilroberta_base_v1\")\n",
- "# NLP_BERT = spacy_sentence_bert.load_model('multi-qa-mpnet-base-dot-v1')\n",
- "NLP_BERT = spacy.blank('en')\n",
- "NLP_BERT.add_pipe('sentence_bert', config={'model_name': 'multi-qa-MiniLM-L6-cos-v1'})\n",
- "NLP_BERT.pipe_names"
+ "# NLP = spacy.load(\"en_core_web_lg\")\n",
+ "# # NLP_BERT = spacy.load(\"en_paraphrase_distilroberta_base_v1\")\n",
+ "# # NLP_BERT = spacy_sentence_bert.load_model('multi-qa-mpnet-base-dot-v1')\n",
+ "# NLP_BERT = spacy.blank('en')\n",
+ "# NLP_BERT.add_pipe('sentence_bert', config={'model_name': 'multi-qa-MiniLM-L6-cos-v1'})\n",
+ "# NLP_BERT.pipe_names"
]
},
{
"cell_type": "markdown",
"id": "052e0142-0c2e-4aa4-8d64-b55e32350d7c",
- "metadata": {},
+ "metadata": {
+ "tags": []
+ },
"source": [
"### get data"
]
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 64,
"id": "18ba4c61-c95d-4488-8a07-9aff189551b9",
"metadata": {},
"outputs": [],
"source": [
"# stream_ids = '(5, 7, 8, 9, 12, 17, 18, 19, 20, 21)'\n",
- "stream_id = 1\n",
- "TOIA_ID = 1"
+ "stream_id = 721\n",
+ "# TOIA_ID = 1"
]
},
{
"cell_type": "code",
- "execution_count": 28,
+ "execution_count": 73,
"id": "e12b33cc-d96d-496e-bb70-c04dccfc4149",
"metadata": {},
"outputs": [],
"source": [
- "sql_url = \"mysql+mysqlconnector://root:anypasswords@localhost:3307/toia\"\n",
+ "sql_url = \"{dbconnection}://{dbusername}:{dbpassword}@{dbhost}:{dbport}/{dbname}\".format(\n",
+ " dbconnection=config[\"DB_CONNECTION\"], \n",
+ " dbusername=config[\"DB_USERNAME\"], \n",
+ " dbpassword=config[\"DB_PASSWORD\"], \n",
+ " dbhost=config[\"DB_HOST\"], \n",
+ " dbport=config[\"DB_PORT\"],\n",
+ " dbname=config[\"DB_DATABASE\"]\n",
+ ")\n",
+ "\n",
+ "# sql_url = \"mysql+mysqlconnector://root:root@localhost:3307/toia\"\n",
"\n",
"engine = db.create_engine(sql_url)\n",
"connection = engine.connect()\n",
- "metadata = db.MetaData()\n",
- "\n",
- "# statement = text(f\"\"\"\n",
- "# SELECT vqs.id_stream as stream_id_stream, \n",
- "# vqs.type, q.question, v.answer, v.id_video, q.id\n",
- "# FROM video v\n",
- "# JOIN videos_questions_streams vqs ON vqs.id_video = v.id_video\n",
- "# JOIN questions q ON q.id = vqs.id_question\n",
- "# WHERE vqs.id_stream in {stream_ids}\n",
- "# AND v.private = 0 \n",
- "# AND vqs.type NOT IN ('filler');\"\"\")\n",
"\n",
"statement = text(f\"\"\"\n",
" SELECT vqs.id_stream as stream_id_stream, \n",
- " vqs.type, q.question, v.answer, v.id_video\n",
+ " vqs.type, vqs.ada_search, q.question, v.answer, v.id_video\n",
" FROM video v\n",
" JOIN videos_questions_streams vqs ON vqs.id_video = v.id_video\n",
" JOIN questions q ON q.id = vqs.id_question\n",
@@ -139,33 +133,24 @@
" AND v.private = 0 \n",
" AND vqs.type NOT IN ('filler');\"\"\")\n",
"\n",
- "# ResultProxy = connection.execute(avatar_kb)\n",
- "ResultProxy = connection.execute(statement)\n",
- "ResultSet = ResultProxy.fetchall()\n",
- "\n",
- "# df_avatar = pd.DataFrame(ResultSet, \n",
- "# columns=[\n",
- "# 'stream_id_stream',\n",
- "# 'type',\n",
- "# 'question',\n",
- "# 'answer',\n",
- "# 'id_video',\n",
- "# 'id_question',\n",
- "# ])\n",
+ "result_proxy = connection.execute(statement)\n",
+ "result_set = result_proxy.fetchall()\n",
"\n",
- "df_avatar = pd.DataFrame(ResultSet, \n",
- " columns=[\n",
- " 'stream_id_stream',\n",
- " 'type',\n",
- " 'question',\n",
- " 'answer',\n",
- " 'id_video',\n",
- " ])"
+ "df_avatar = pd.DataFrame(\n",
+ " result_set,\n",
+ " columns=[\n",
+ " 'stream_id_stream',\n",
+ " 'type',\n",
+ " 'ada_search',\n",
+ " 'question',\n",
+ " 'answer',\n",
+ " 'id_video'\n",
+ " ])"
]
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 74,
"id": "4f9f0827-9536-4eed-b240-2c4461566bf7",
"metadata": {},
"outputs": [
@@ -192,6 +177,7 @@
" \n",
" stream_id_stream \n",
" type \n",
+ " ada_search \n",
" question \n",
" answer \n",
" id_video \n",
@@ -200,198 +186,99 @@
" \n",
" \n",
" 0 \n",
- " 1 \n",
- " no-answer \n",
- " Say: I don't have an answer to that right now. \n",
- " I don't. \n",
- " Alberto_1_11_6cfcb663.mp4 \n",
+ " 721 \n",
+ " y/n-answer \n",
+ " [0.0020983361,0.030330962,0.0019777715,0.05068... \n",
+ " Record yourself saying No. You can add questio... \n",
+ " . \n",
+ " Soojin _41_3867_38623030.mp4 \n",
" \n",
" \n",
" 1 \n",
- " 1 \n",
+ " 721 \n",
" no-answer \n",
- " Say: Sorry, I didn't record answers to that qu... \n",
- " Sorry,. \n",
- " Alberto_1_12_56020feb.mp4 \n",
+ " [-0.0008500544,0.00853398,0.029238785,0.043580... \n",
+ " Say: I don't have an answer to that right now. \n",
+ " . \n",
+ " Soojin _41_3869_517398f6.mp4 \n",
" \n",
" \n",
" 2 \n",
- " 1 \n",
+ " 721 \n",
" no-answer \n",
- " Say: Can you try rephrasing the question? \n",
- " Didn't get it,. \n",
- " Alberto_1_13_fecb8829.mp4 \n",
+ " [-0.00058192614,0.016313002,0.0016513861,0.041... \n",
+ " Say: Sorry, I didn't record answers to that qu... \n",
+ " . \n",
+ " Soojin _41_3870_77c1cb8e.mp4 \n",
" \n",
" \n",
" 3 \n",
- " 1 \n",
+ " 721 \n",
" greeting \n",
+ " [-0.0010867842,0.027357157,0.010503011,0.04084... \n",
" Record a greeting (e.g., hello, hi) \n",
- " Hi. \n",
- " Alberto_1_14_44a17e28.mp4 \n",
+ " . \n",
+ " Soojin _41_3872_45bdf208.mp4 \n",
" \n",
" \n",
" 4 \n",
- " 1 \n",
+ " 721 \n",
" exit \n",
+ " [0.013473576,0.023772048,0.0075254096,0.042554... \n",
" Record a goodbye (or end of conversation sente... \n",
- " Go away. \n",
- " Alberto_1_15_b37dded9.mp4 \n",
- " \n",
- " \n",
- " 5 \n",
- " 1 \n",
- " answer \n",
- " What is your name? \n",
- " My name is Alberto. \n",
- " Alberto_1_16_9c461b90.mp4 \n",
- " \n",
- " \n",
- " 6 \n",
- " 1 \n",
- " answer \n",
- " Where and when were you born? \n",
- " Milan. Italy, 1985. \n",
- " Alberto_1_17_e0d7e418.mp4 \n",
- " \n",
- " \n",
- " 7 \n",
- " 1 \n",
- " answer \n",
- " What do you do for a living? \n",
- " I do what they do. \n",
- " Alberto_1_18_85b921a9.mp4 \n",
- " \n",
- " \n",
- " 8 \n",
- " 1 \n",
- " y/n-answer \n",
- " Record yourself saying Yes. You cann add quest... \n",
- " haha. \n",
- " Alberto_1_19_f63f6b5c.mp4 \n",
- " \n",
- " \n",
- " 9 \n",
- " 1 \n",
- " y/n-answer \n",
- " Record yourself saying No. You can add questio... \n",
- " nana. \n",
- " Alberto_1_20_113d66fc.mp4 \n",
- " \n",
- " \n",
- " 10 \n",
- " 1 \n",
- " answer \n",
- " What is your job? \n",
- " and a CFO and the analytics ahead of a seed st... \n",
- " Alberto_1_21_0813c283.mp4 \n",
- " \n",
- " \n",
- " 11 \n",
- " 1 \n",
- " answer \n",
- " Whici startup? \n",
- " It is called Around. It is a sort of Airbnb fo... \n",
- " Alberto_1_22_7c4398b9.mp4 \n",
- " \n",
- " \n",
- " 12 \n",
- " 1 \n",
- " no-answer \n",
- " Cannot Answer \n",
- " Either, I didn't get you a question or I do no... \n",
- " Alberto_1_23_8edf7438.mp4 \n",
+ " . \n",
+ " Soojin _41_3873_0382a76b.mp4 \n",
" \n",
" \n",
"\n",
" "
],
"text/plain": [
- " stream_id_stream type \\\n",
- "0 1 no-answer \n",
- "1 1 no-answer \n",
- "2 1 no-answer \n",
- "3 1 greeting \n",
- "4 1 exit \n",
- "5 1 answer \n",
- "6 1 answer \n",
- "7 1 answer \n",
- "8 1 y/n-answer \n",
- "9 1 y/n-answer \n",
- "10 1 answer \n",
- "11 1 answer \n",
- "12 1 no-answer \n",
+ " stream_id_stream type \\\n",
+ "0 721 y/n-answer \n",
+ "1 721 no-answer \n",
+ "2 721 no-answer \n",
+ "3 721 greeting \n",
+ "4 721 exit \n",
"\n",
- " question \\\n",
- "0 Say: I don't have an answer to that right now. \n",
- "1 Say: Sorry, I didn't record answers to that qu... \n",
- "2 Say: Can you try rephrasing the question? \n",
- "3 Record a greeting (e.g., hello, hi) \n",
- "4 Record a goodbye (or end of conversation sente... \n",
- "5 What is your name? \n",
- "6 Where and when were you born? \n",
- "7 What do you do for a living? \n",
- "8 Record yourself saying Yes. You cann add quest... \n",
- "9 Record yourself saying No. You can add questio... \n",
- "10 What is your job? \n",
- "11 Whici startup? \n",
- "12 Cannot Answer \n",
+ " ada_search \\\n",
+ "0 [0.0020983361,0.030330962,0.0019777715,0.05068... \n",
+ "1 [-0.0008500544,0.00853398,0.029238785,0.043580... \n",
+ "2 [-0.00058192614,0.016313002,0.0016513861,0.041... \n",
+ "3 [-0.0010867842,0.027357157,0.010503011,0.04084... \n",
+ "4 [0.013473576,0.023772048,0.0075254096,0.042554... \n",
"\n",
- " answer \\\n",
- "0 I don't. \n",
- "1 Sorry,. \n",
- "2 Didn't get it,. \n",
- "3 Hi. \n",
- "4 Go away. \n",
- "5 My name is Alberto. \n",
- "6 Milan. Italy, 1985. \n",
- "7 I do what they do. \n",
- "8 haha. \n",
- "9 nana. \n",
- "10 and a CFO and the analytics ahead of a seed st... \n",
- "11 It is called Around. It is a sort of Airbnb fo... \n",
- "12 Either, I didn't get you a question or I do no... \n",
+ " question answer \\\n",
+ "0 Record yourself saying No. You can add questio... . \n",
+ "1 Say: I don't have an answer to that right now. . \n",
+ "2 Say: Sorry, I didn't record answers to that qu... . \n",
+ "3 Record a greeting (e.g., hello, hi) . \n",
+ "4 Record a goodbye (or end of conversation sente... . \n",
"\n",
- " id_video \n",
- "0 Alberto_1_11_6cfcb663.mp4 \n",
- "1 Alberto_1_12_56020feb.mp4 \n",
- "2 Alberto_1_13_fecb8829.mp4 \n",
- "3 Alberto_1_14_44a17e28.mp4 \n",
- "4 Alberto_1_15_b37dded9.mp4 \n",
- "5 Alberto_1_16_9c461b90.mp4 \n",
- "6 Alberto_1_17_e0d7e418.mp4 \n",
- "7 Alberto_1_18_85b921a9.mp4 \n",
- "8 Alberto_1_19_f63f6b5c.mp4 \n",
- "9 Alberto_1_20_113d66fc.mp4 \n",
- "10 Alberto_1_21_0813c283.mp4 \n",
- "11 Alberto_1_22_7c4398b9.mp4 \n",
- "12 Alberto_1_23_8edf7438.mp4 "
+ " id_video \n",
+ "0 Soojin _41_3867_38623030.mp4 \n",
+ "1 Soojin _41_3869_517398f6.mp4 \n",
+ "2 Soojin _41_3870_77c1cb8e.mp4 \n",
+ "3 Soojin _41_3872_45bdf208.mp4 \n",
+ "4 Soojin _41_3873_0382a76b.mp4 "
]
},
- "execution_count": 29,
+ "execution_count": 74,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "df_avatar"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 541,
- "id": "9047b1ea-dd28-4c33-9d4a-e70f306a7274",
- "metadata": {},
- "outputs": [],
- "source": [
- "df_first_10 = df_avatar.sort_values(by=['stream_id_stream', 'id_question']).groupby('stream_id_stream').nth(range(10, 20))\n",
- "df_avatar = df_first_10.reset_index().copy()"
+ "df_avatar.head()"
]
},
{
"cell_type": "markdown",
"id": "29fcfdba-16a1-4f17-a317-33f0d8d102c4",
- "metadata": {},
+ "metadata": {
+ "jp-MarkdownHeadingCollapsed": true,
+ "tags": []
+ },
"source": [
"## NLP analysis with spaCy"
]
@@ -483,14 +370,16 @@
{
"cell_type": "markdown",
"id": "65ca9fce-b406-4fad-a898-bd30768941dd",
- "metadata": {},
+ "metadata": {
+ "jp-MarkdownHeadingCollapsed": true
+ },
"source": [
"## helper functions"
]
},
{
"cell_type": "code",
- "execution_count": 371,
+ "execution_count": 7,
"id": "d4b14530-483d-4437-a5ad-36ec9df0fd3c",
"metadata": {},
"outputs": [],
@@ -511,7 +400,7 @@
},
{
"cell_type": "code",
- "execution_count": 372,
+ "execution_count": 8,
"id": "bebbb785-0e26-4938-a4e6-5bbe15691122",
"metadata": {},
"outputs": [],
@@ -528,7 +417,7 @@
},
{
"cell_type": "code",
- "execution_count": 373,
+ "execution_count": null,
"id": "0bb204c7-cd82-4bc9-bec4-d0e3d87f0cf6",
"metadata": {},
"outputs": [],
@@ -641,7 +530,9 @@
{
"cell_type": "markdown",
"id": "485590a0-eeff-4fd8-a502-8c73f5ebd3a2",
- "metadata": {},
+ "metadata": {
+ "jp-MarkdownHeadingCollapsed": true
+ },
"source": [
"### testing update helper functions"
]
@@ -1041,7 +932,7 @@
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 76,
"id": "85c5cd4b-6918-4d87-93fa-e9063a78b59d",
"metadata": {},
"outputs": [],
@@ -1052,8 +943,8 @@
"import pandas as pd\n",
"import numpy as np\n",
"\n",
- "config = dotenv_values()\n",
- "openai.organization = config['YOUR_ORG_ID']\n",
+ "config = dotenv_values(\".env\")\n",
+ "# openai.organization = config['YOUR_ORG_ID']\n",
"openai.api_key = config['OPENAI_API_KEY']\n",
"# openai.Model.list()"
]
@@ -1066,6 +957,16 @@
"### embed"
]
},
+ {
+ "cell_type": "markdown",
+ "id": "d061e8c2-23f3-4c1f-8a77-1ac89d53666e",
+ "metadata": {},
+ "source": [
+ "**Run the below only the first time**\n",
+ "\n",
+ "Uncomment if needed."
+ ]
+ },
{
"cell_type": "code",
"execution_count": 31,
@@ -1148,18 +1049,8 @@
}
],
"source": [
- "df_avatar['combined'] = \"Question: \" + df_avatar.question.str.strip() + \"; Answer: \" + df_avatar.answer.str.strip()\n",
- "df_avatar.head(2)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d061e8c2-23f3-4c1f-8a77-1ac89d53666e",
- "metadata": {},
- "source": [
- "**Run the below only the first time**\n",
- "\n",
- "Uncomment if needed."
+ "# df_avatar['combined'] = \"Question: \" + df_avatar.question.str.strip() + \"; Answer: \" + df_avatar.answer.str.strip()\n",
+ "# df_avatar.head(2)"
]
},
{
@@ -1184,6 +1075,16 @@
"# df_avatar.to_csv(f\"\"\"output/embedded_1k_toia_id_{TOIA_ID}.csv\"\"\")"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "577da783-527b-4efa-bdbe-0b9731307307",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# df = pd.read_csv(f\"\"\"output/embedded_1k_toia_id_{TOIA_ID}.csv\"\"\")"
+ ]
+ },
{
"cell_type": "markdown",
"id": "af706d5e-b93c-4251-b447-57f4e35d439c",
@@ -1194,18 +1095,19 @@
},
{
"cell_type": "code",
- "execution_count": 56,
+ "execution_count": 77,
"id": "cc4e6bc6-62ad-4abf-b131-6e026a7b2993",
"metadata": {},
"outputs": [],
"source": [
- "df = pd.read_csv(f\"\"\"output/embedded_1k_toia_id_{TOIA_ID}.csv\"\"\")\n",
+ "df = df_avatar.copy()\n",
+ "\n",
"df['ada_search'] = df.ada_search.apply(eval).apply(np.array) #needed if np array stored as txt"
]
},
{
"cell_type": "code",
- "execution_count": 35,
+ "execution_count": 78,
"id": "ee70cadc-41f6-4c48-ba4d-d720ef3eba4d",
"metadata": {},
"outputs": [],
@@ -1224,7 +1126,78 @@
},
{
"cell_type": "code",
- "execution_count": 36,
+ "execution_count": 228,
+ "id": "c03988e0-895b-434a-bf94-d34039793de7",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "def toia_answer(query, data, engine, interactor_id=41, memory=10, minutes=15):\n",
+ " print(\"toia_answer\")\n",
+ " print(query)\n",
+ " embedding = get_embedding(query, engine='text-search-ada-query-001')\n",
+ " print(\"API worked\")\n",
+ " data['similarities'] = data.ada_search.apply(\n",
+ " lambda x: cosine_similarity(x, embedding))\n",
+ " res = data.sort_values('similarities', ascending=False)\n",
+ "\n",
+ " ada_similarity_scores = res.similarities.values\n",
+ " \n",
+ " # (removed thresholding. Keep every answer)\n",
+ " if ada_similarity_scores[0] > 0: \n",
+ " # take first 10 answers from the chatlog\"\n",
+ " # connect to the db\n",
+ " engine = db.create_engine(sql_url)\n",
+ " connection = engine.connect()\n",
+ " # retrieve the video IDs already played. The logic here is \n",
+ " # to retrieve the top {memory} last logs from the db and take the ones\n",
+ " # that aren't older than {minutes}\n",
+ " statement = text(f\"\"\"\n",
+ " SELECT cl.video_played,\n",
+ " (cl.timestamp - LAG(cl.timestamp, 1) OVER (ORDER BY cl.timestamp)) / 60000 AS time_diff_min\n",
+ " FROM (SELECT * FROM conversations_log WHERE question_asked != \"None\") cl\n",
+ " WHERE cl.interactor_id = {interactor_id}\n",
+ " ORDER BY cl.timestamp DESC\n",
+ " LIMIT {memory}\n",
+ " ;\"\"\")\n",
+ " result_proxy = connection.execute(statement)\n",
+ " result_set = result_proxy.fetchall()\n",
+ " # put them in a df\n",
+ " chatlog = pd.DataFrame(result_set)\n",
+ " # take cumsum of top minute differences -- only problem to highlith here:\n",
+ " # WE DON'T HAVE A NOTION OF WHAT TIME IS NOW\n",
+ " chatlog['cum_time_diff_min'] = chatlog['time_diff_min'].cumsum()\n",
+ " \n",
+ " # define the temp cache of played video IDs -- adding here the notion of NOW: first question of new\n",
+ " # session is going to be put in the cache regardless. Then if time lag is too long from first and last,\n",
+ " # the cache is just that. Then it starts populating.\n",
+ " if chatlog['cum_time_diff_min'][0] >= minutes:\n",
+ " video_cache = chatlog['video_played'].values[0]\n",
+ " else: \n",
+ " video_cache = chatlog[chatlog['cum_time_diff_min'] < minutes]['video_played'].values\n",
+ " \n",
+ " # store outputs (already sorted by decreasing order of retrieval)\n",
+ " answers = res['answer'].values\n",
+ " videos = res['id_video'].values\n",
+ " scores = ada_similarity_scores\n",
+ " if len(set(video_cache).intersection(set(videos))) > 0:\n",
+ " next_best_idx = next(x for x, vid in enumerate(videos) if vid not in video_cache)\n",
+ " return answers[next_best_idx], videos[next_best_idx], scores[next_best_idx]\n",
+ " else:\n",
+ " return answers[0], videos[0], scores[0]\n",
+ " else:\n",
+ " df_noanswers = data[data['type'] == \"no-answer\"]\n",
+ " if df_noanswers.shape[0] > 0:\n",
+ " answers = df_noanswers.sample(n=1)\n",
+ " return answers['answer'].values[0], answers['id_video'].values[0], ada_similarity_score\n",
+ " else:\n",
+ " return \"You haven't recorded no-answers\", \"204\", \"No Content\"\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 247,
"id": "fbd9d141-882b-47a0-bd59-af91ccfcc3a9",
"metadata": {},
"outputs": [
@@ -1232,24 +1205,94 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Record a greeting (e.g., hello, hi): Hi.\n",
- "\n",
- "Whici startup?: It is called Around. It is a sort of Airbnb for Office Space.\n",
- "\n",
- "Record yourself saying Yes. You cann add questions for this answer later.: haha.\n",
- "\n"
+ "toia_answer\n",
+ "Are you afraid of death?\n",
+ "API worked\n"
]
}
],
"source": [
- "res = answer_retrieval(df, \"Hi!\", n=3)"
+ "res = toia_answer(\"Are you afraid of death?\", df)"
]
},
{
"cell_type": "code",
- "execution_count": 37,
+ "execution_count": 248,
"id": "e54ef8fe-9f94-4ec7-ba2b-163e6f1cc333",
"metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(\"[Brian] I'm not dying, I'm just losing my ability to live.\\r\\nYeah, take advantage of it.\\r\\nLife isn't guaranteed to any of us.\",\n",
+ " 'Soojin _41_3892_c12c6f9f.mp4',\n",
+ " 0.3665458862681638)"
+ ]
+ },
+ "execution_count": 248,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c1bb2971-b288-4044-9c93-92e05e331f15",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cc8b89af-eaf1-4845-9fa5-1e6188d22e2e",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 249,
+ "id": "8b3c2672-603e-4af0-9280-274ef8b32da2",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [],
+ "source": [
+ "# We need to know the interactor_id\n",
+ "interactor_id = 41\n",
+ "memory = 10\n",
+ "minutes = 15\n",
+ "# engine = db.create_engine(sql_url)\n",
+ "connection = engine.connect()\n",
+ "\n",
+ "statement = text(f\"\"\"\n",
+ " SELECT *, cl.video_played,\n",
+ " (cl.timestamp - LAG(cl.timestamp, 1) OVER (ORDER BY cl.timestamp)) / 60000 AS time_diff_min\n",
+ " FROM (SELECT * FROM conversations_log WHERE question_asked != \"None\") cl\n",
+ " WHERE cl.interactor_id = {interactor_id}\n",
+ " ORDER BY cl.timestamp DESC\n",
+ " LIMIT {memory}\n",
+ " ;\"\"\")\n",
+ "\n",
+ "result_proxy = connection.execute(statement)\n",
+ "result_set = result_proxy.fetchall()\n",
+ "\n",
+ "chatlog = pd.DataFrame(result_set)\n",
+ "chatlog['cum_time_diff_min'] = chatlog['time_diff_min'].cumsum()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 250,
+ "id": "39608674-6003-4a39-9849-9d299bcb1ff6",
+ "metadata": {
+ "tags": []
+ },
"outputs": [
{
"data": {
@@ -1272,108 +1315,105 @@
" \n",
" \n",
" \n",
- " Unnamed: 0 \n",
- " stream_id_stream \n",
- " type \n",
- " question \n",
- " answer \n",
- " id_video \n",
- " combined \n",
- " ada_similarity \n",
- " ada_search \n",
- " similarities \n",
+ " interactor_id \n",
+ " toia_id \n",
+ " timestamp \n",
+ " filler \n",
+ " question_asked \n",
+ " video_played \n",
+ " ada_similarity_score \n",
+ " mode \n",
+ " video_played \n",
+ " time_diff_min \n",
+ " cum_time_diff_min \n",
" \n",
" \n",
" \n",
" \n",
- " 3 \n",
- " 3 \n",
- " 1 \n",
- " greeting \n",
- " Record a greeting (e.g., hello, hi) \n",
- " Hi. \n",
- " Alberto_1_14_44a17e28.mp4 \n",
- " Question: Record a greeting (e.g., hello, hi);... \n",
- " [0.0024500133004039526, 0.014042790979146957, ... \n",
- " [-0.0015507441712543368, 0.03209500387310982, ... \n",
- " 0.339486 \n",
+ " 0 \n",
+ " 41 \n",
+ " 41 \n",
+ " 1678882528525 \n",
+ " 0 \n",
+ " JJ, are you afraid of death \n",
+ " Soojin _41_3900_503a1862.mp4 \n",
+ " 0.431172 \n",
+ " SEARCH \n",
+ " Soojin _41_3900_503a1862.mp4 \n",
+ " 0.4515 \n",
+ " 0.4515 \n",
" \n",
" \n",
- " 11 \n",
- " 11 \n",
- " 1 \n",
- " answer \n",
- " Whici startup? \n",
- " It is called Around. It is a sort of Airbnb fo... \n",
- " Alberto_1_22_7c4398b9.mp4 \n",
- " Question: Whici startup?; Answer: It is called... \n",
- " [0.005293071269989014, 0.021358370780944824, -... \n",
- " [0.0287274569272995, 0.046579521149396896, 0.0... \n",
- " 0.286512 \n",
+ " 1 \n",
+ " 41 \n",
+ " 41 \n",
+ " 1678882501438 \n",
+ " 0 \n",
+ " Brian, are you afraid of death? \n",
+ " Soojin _41_3881_760068fc.mp4 \n",
+ " 0.430592 \n",
+ " SEARCH \n",
+ " Soojin _41_3881_760068fc.mp4 \n",
+ " 0.8085 \n",
+ " 1.2600 \n",
" \n",
" \n",
- " 8 \n",
- " 8 \n",
- " 1 \n",
- " y/n-answer \n",
- " Record yourself saying Yes. You cann add quest... \n",
- " haha. \n",
- " Alberto_1_19_f63f6b5c.mp4 \n",
- " Question: Record yourself saying Yes. You cann... \n",
- " [0.0019218891393393278, 0.013361705467104912, ... \n",
- " [-0.0023853471502661705, 0.041393689811229706,... \n",
- " 0.253179 \n",
+ " 2 \n",
+ " 41 \n",
+ " 41 \n",
+ " 1678882452926 \n",
+ " 0 \n",
+ " are you afraid of death \n",
+ " Soojin _41_3918_5f56b7e3.mp4 \n",
+ " 0.422513 \n",
+ " SEARCH \n",
+ " Soojin _41_3918_5f56b7e3.mp4 \n",
+ " 0.6283 \n",
+ " 1.8883 \n",
" \n",
" \n",
"\n",
" "
],
"text/plain": [
- " Unnamed: 0 stream_id_stream type \\\n",
- "3 3 1 greeting \n",
- "11 11 1 answer \n",
- "8 8 1 y/n-answer \n",
- "\n",
- " question \\\n",
- "3 Record a greeting (e.g., hello, hi) \n",
- "11 Whici startup? \n",
- "8 Record yourself saying Yes. You cann add quest... \n",
- "\n",
- " answer \\\n",
- "3 Hi. \n",
- "11 It is called Around. It is a sort of Airbnb fo... \n",
- "8 haha. \n",
- "\n",
- " id_video \\\n",
- "3 Alberto_1_14_44a17e28.mp4 \n",
- "11 Alberto_1_22_7c4398b9.mp4 \n",
- "8 Alberto_1_19_f63f6b5c.mp4 \n",
+ " interactor_id toia_id timestamp filler \\\n",
+ "0 41 41 1678882528525 0 \n",
+ "1 41 41 1678882501438 0 \n",
+ "2 41 41 1678882452926 0 \n",
"\n",
- " combined \\\n",
- "3 Question: Record a greeting (e.g., hello, hi);... \n",
- "11 Question: Whici startup?; Answer: It is called... \n",
- "8 Question: Record yourself saying Yes. You cann... \n",
+ " question_asked video_played \\\n",
+ "0 JJ, are you afraid of death Soojin _41_3900_503a1862.mp4 \n",
+ "1 Brian, are you afraid of death? Soojin _41_3881_760068fc.mp4 \n",
+ "2 are you afraid of death Soojin _41_3918_5f56b7e3.mp4 \n",
"\n",
- " ada_similarity \\\n",
- "3 [0.0024500133004039526, 0.014042790979146957, ... \n",
- "11 [0.005293071269989014, 0.021358370780944824, -... \n",
- "8 [0.0019218891393393278, 0.013361705467104912, ... \n",
+ " ada_similarity_score mode video_played time_diff_min \\\n",
+ "0 0.431172 SEARCH Soojin _41_3900_503a1862.mp4 0.4515 \n",
+ "1 0.430592 SEARCH Soojin _41_3881_760068fc.mp4 0.8085 \n",
+ "2 0.422513 SEARCH Soojin _41_3918_5f56b7e3.mp4 0.6283 \n",
"\n",
- " ada_search similarities \n",
- "3 [-0.0015507441712543368, 0.03209500387310982, ... 0.339486 \n",
- "11 [0.0287274569272995, 0.046579521149396896, 0.0... 0.286512 \n",
- "8 [-0.0023853471502661705, 0.041393689811229706,... 0.253179 "
+ " cum_time_diff_min \n",
+ "0 0.4515 \n",
+ "1 1.2600 \n",
+ "2 1.8883 "
]
},
- "execution_count": 37,
+ "execution_count": 250,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "res"
+ "chatlog[chatlog['cum_time_diff_min'] < minutes]"
]
},
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d230fd73-d450-4789-99bc-8e1cdf5d2a00",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
{
"cell_type": "markdown",
"id": "95b386e7-e73a-43b4-b668-434707333263",
@@ -2276,7 +2316,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.9"
+ "version": "3.9.16"
}
},
"nbformat": 4,
diff --git a/server/toia-dm/old_toia-dm_files/toia-capstone-2021-1b8f8a91c797.json b/server/toia-dm/old_toia-dm_files/toia-capstone-2021-1b8f8a91c797.json
new file mode 100644
index 00000000..1bd29cf0
--- /dev/null
+++ b/server/toia-dm/old_toia-dm_files/toia-capstone-2021-1b8f8a91c797.json
@@ -0,0 +1,12 @@
+{
+ "type": "service_account",
+ "project_id": "toia-capstone-2021",
+ "private_key_id": "1b8f8a91c797ef805e147f681408f40f3862846f",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDESOBk7yeufif\nWIPM3W5k2Ut44iO2+5siSX9X9MZlIVjLhYRZuq4mrDGRGE5HhlNbyQtCStkHK6Pa\nJwP5isMuou3Ol87INM1dEPYjim7JFBqVD8olNjNHojNVmg8Xc5AdSY26uicQv/ji\nqnwpu68w1bIEDKaz6djigoeS3wi9BBvrqKdLBvsKN1Fq6pUb0utFyGyREZpGF9QO\nPeW9eLyrLdRxU4k74hyquN17olhfA3K8X+SxyHca+UEjHmAhDcnn59TMcbUdKom4\niKCWcCj/licvoYBj/HA9rAo7L09obNWv9Bov6uhvqD51uB4W421Ro6EcgJ1vqb1r\nJHT6KFjjAgMBAAECggEAAgW9UwZcky3cPF4g/1Cc+usrWZPtf+oH/qFwWfAaLGIm\n1xmJtct/Q5eqrsAw22NdeQc9TDct+DC6o6Tn0NW1zWQHJq8kJjlt7GjCj/igjYPp\nmzazUHQesNgnVehkkUhL37BWQHX6rHhnKIXjT/OlfIk55KUj+zo2WwP9oIQmy5DH\nTzg76xus3JdIiEZa65hAHB53r/16PBz4Yos2rwhM74DpSfzW/oShylJPe1vxz6uJ\nQHGl1G2EKc5BtT+1n/Yp1lfrzk7ip8uGYiM1os1wTJfDd+9pBXCh7bNd4O3nrRen\nzoJjEGIgxreOkAmuhTSUnFPsfVI+n/yKiS2CxvTmCQKBgQDzLOj/TFutgG6DLdmN\nANW033lLCWfjfOxFaHpy/X3PpbZf68v8hpgBtJqX+/inylNzu4GKigYOYTMABcod\nOWcjuXbbgmSIOw0HjdU09PcORotlriu8Ku8Qel05Pwu7f/VEE8g2JxzBOeUuHYX2\n+o0gWnjBzCwr42hOF15EWZvKHQKBgQDNWrhfvjwUgtu9oVPJ0LPx9Yeg2J9QLI7H\n1EGc/3qyGu2MlSlP/JD7S40YZNeExUQzQUvwtKCVOT+X1Iv2PcsuV4uhtGV6Bjv6\nEWn3NQcNE2ez91L+zYTP27jTouRuO6RjNNSEdacW3s1UEB/k00wW+s40QwKZXI9I\nCOOKWnM+/wKBgDQP5mZaI7qWp5JgK5Z7mkVaHu7IubxDj5Ygky6xRNFDCjOpGQgc\njMi4sOxfHtJVh95cQ5S0ji1f8/pKQwZUttc4KtE+LmXYNqbqX74xv/8HbWq8ilKD\n4qDlgbXy4IEpGQqVLaUiZI6d5Yok+fxxketeU0IygzZ2PmuRpzX89VSlAoGAfRUo\nPvFSCTBYBp6wuboNEXF75oZsK9qoMaHhQW8AXmI2la35lwYBjX/MdrJd8Dp0O0An\nsHtlYN+ZE7NceWXUT+r1W07VjMklWUGoKPK808MhJKaegCPRJQbyAr8yos5jaCYy\n2GgNmcmmifC0bJ4jt8+XMJAskhumDruTVZ+YmSMCgYAOQX/NYldkZuHXZGu3XZ0Y\nIjMuM//gTlGgKsbkSA61Tjv9CNyKSps99R8VRvTiBpa3QXGVvTvp2ffXsvn41way\nci/LzVkKYBqtS0Anu2EoNy7EbzrtcCOivzZ0vAOFuengD6CkHKeFC7/JCOggLugS\nX/3BJ6UHVn6VtE7xAkTioA==\n-----END PRIVATE KEY-----\n",
+ "client_email": "toia-cloudconnect@toia-capstone-2021.iam.gserviceaccount.com",
+ "client_id": "102222036243607638338",
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://oauth2.googleapis.com/token",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/toia-cloudconnect%40toia-capstone-2021.iam.gserviceaccount.com"
+}
diff --git a/server/toia-dm/requirements.txt b/server/toia-dm/requirements.txt
index 01c682eb..766517b1 100644
--- a/server/toia-dm/requirements.txt
+++ b/server/toia-dm/requirements.txt
@@ -1,77 +1,94 @@
-aiohttp==3.8.1
-aiosignal==1.2.0
-anyio==3.5.0
-asgiref==3.5.0
-async-timeout==4.0.2
-attrs==21.4.0
-blis==0.7.5
-cachetools==5.0.0
-catalogue==2.0.6
-certifi==2021.10.8
-cffi==1.15.0
-charset-normalizer==2.0.12
-click==8.0.4
+aiohttp==3.8.6
+aiosignal==1.3.1
+anyio==3.7.1
+async-timeout==4.0.3
+attrs==23.1.0
+blinker==1.7.0
+blis==0.7.11
+cachetools==5.3.2
+catalogue==2.0.10
+certifi==2023.7.22
+cffi==1.16.0
+charset-normalizer==3.3.2
+click==8.1.7
cloud-sql-python-connector==0.5.1
-cryptography==36.0.1
-cymem==2.0.6
-fastapi==0.74.0
-frozenlist==1.3.0
+confection==0.1.3
+contourpy==1.1.1
+cryptography==41.0.5
+cycler==0.12.1
+cymem==2.0.8
+exceptiongroup==1.1.3
+fastapi==0.104.1
+flask==3.0.0
+fonttools==4.44.3
+friendlywords==1.1.2
+frozenlist==1.4.0
google-api-core==2.5.0
google-api-python-client==2.37.0
google-auth==2.6.0
google-auth-httplib2==0.1.0
googleapis-common-protos==1.54.0
-greenlet==1.1.2
-h11==0.13.0
-httplib2==0.20.4
-idna==3.3
-Jinja2==3.0.3
-joblib==1.1.0
+greenlet==3.0.1
+h11==0.14.0
+httplib2==0.22.0
+idna==3.4
+importlib-metadata==6.8.0
+importlib-resources==6.1.1
+itsdangerous==2.1.2
+Jinja2==3.1.2
+joblib==1.3.2
+kiwisolver==1.4.5
langcodes==3.3.0
-MarkupSafe==2.1.0
-matplotlib
-multidict==6.0.2
-murmurhash==1.0.6
-nltk==3.7
-numpy==1.22.2
-openai
-packaging==21.3
-pandas==1.4.1
-pathy==0.6.1
-plotly
-preshed==3.0.6
-protobuf==3.19.4
-pyasn1==0.4.8
-pyasn1-modules==0.2.8
+MarkupSafe==2.1.3
+matplotlib==3.7.3
+multidict==6.0.4
+murmurhash==1.0.10
+mysqlclient==1.4.4
+nltk==3.8.1
+numpy==1.24.4
+openai==0.27.8
+packaging==23.2
+pandas==2.0.3
+pathy==0.10.3
+Pillow==10.1.0
+plotly==5.18.0
+preshed==3.0.9
+protobuf==4.21.12
+pyasn1==0.5.0
+pyasn1-modules==0.3.0
pycparser==2.21
-pydantic==1.8.2
-pyOpenSSL==22.0.0
-pyparsing==3.0.7
+pydantic==1.10.6
+PyMySQL==1.1.0
+pyOpenSSL==23.3.0
+pyparsing==3.1.1
python-dateutil==2.8.2
-python-dotenv==0.19.2
-pytz==2021.3
-regex==2022.1.18
-requests==2.27.1
-rsa==4.8
-scikit-learn==1.0.2
-scipy==1.8.0
+python-dotenv==1.0.0
+pytz==2023.3.post1
+regex==2023.10.3
+requests==2.31.0
+rsa==4.9
+scikit-learn==1.2.1
+scipy==1.10.1
six==1.16.0
-sklearn==0.0
-smart-open==5.2.1
-sniffio==1.2.0
-spacy==3.2.2
-spacy-legacy==3.0.8
-spacy-loggers==1.0.1
+smart-open==6.4.0
+sniffio==1.3.0
+spacy==3.5.1
+spacy-legacy==3.0.12
+spacy-loggers==1.0.5
SQLAlchemy==1.4.31
-srsly==2.4.2
-starlette==0.17.1
-thinc==8.0.13
-threadpoolctl==3.1.0
-tqdm==4.62.3
-typer==0.4.0
-typing-extensions==4.1.1
+srsly==2.4.8
+starlette==0.27.0
+tenacity==8.2.3
+thinc==8.1.12
+threadpoolctl==3.2.0
+tqdm==4.66.1
+typer==0.7.0
+typing-extensions==4.8.0
+tzdata==2023.3
uritemplate==4.1.1
-urllib3==1.26.8
-uvicorn==0.17.5
-wasabi==0.9.0
-yarl==1.7.2
\ No newline at end of file
+urllib3==2.1.0
+uvicorn==0.24.0.post1
+wasabi==1.1.2
+werkzeug==3.0.1
+yarl==1.9.2
+zipp==3.17.0
diff --git a/server/toia-dm/requirements_old.txt b/server/toia-dm/requirements_old.txt
new file mode 100644
index 00000000..581414c1
--- /dev/null
+++ b/server/toia-dm/requirements_old.txt
@@ -0,0 +1,76 @@
+aiohttp==3.8.1
+aiosignal==1.2.0
+anyio==3.5.0
+asgiref==3.5.0
+async-timeout==4.0.2
+attrs==21.4.0
+blis==0.7.5
+cachetools==5.0.0
+catalogue==2.0.6
+certifi==2021.10.8
+cffi==1.15.0
+charset-normalizer==2.0.12
+click==8.0.4
+cloud-sql-python-connector==0.5.1
+cryptography==36.0.1
+cymem==2.0.6
+fastapi==0.74.0
+frozenlist==1.3.0
+google-api-core==2.5.0
+google-api-python-client==2.37.0
+google-auth==2.6.0
+google-auth-httplib2==0.1.0
+googleapis-common-protos==1.54.0
+greenlet==1.1.2
+h11==0.13.0
+httplib2==0.20.4
+idna==3.3
+Jinja2==3.0.3
+joblib==1.1.0
+langcodes==3.3.0
+MarkupSafe==2.1.0
+matplotlib
+multidict==6.0.2
+murmurhash==1.0.6
+nltk==3.7
+numpy==1.22.2
+openai
+packaging==21.3
+pandas==1.4.1
+pathy==0.6.1
+plotly
+preshed==3.0.6
+protobuf==3.19.4
+pyasn1==0.4.8
+pyasn1-modules==0.2.8
+pycparser==2.21
+pydantic==1.8.2
+pyOpenSSL==22.0.0
+pyparsing==3.0.7
+python-dateutil==2.8.2
+python-dotenv==0.19.2
+pytz==2021.3
+regex==2022.1.18
+requests==2.27.1
+rsa==4.8
+scikit-learn==1.0.2
+scipy==1.8.0
+six==1.16.0
+sklearn==0.0
+smart-open==5.2.1
+sniffio==1.2.0
+spacy==3.2.2
+spacy-legacy==3.0.8
+spacy-loggers==1.0.1
+SQLAlchemy==1.4.31
+srsly==2.4.2
+starlette==0.17.1
+thinc==8.0.13
+threadpoolctl==3.1.0
+tqdm==4.62.3
+typer==0.4.0
+uritemplate==4.1.1
+urllib3==1.26.8
+uvicorn==0.17.5
+wasabi==0.9.0
+yarl==1.7.2
\ No newline at end of file
diff --git a/server/toia-dm/utils_gpt3.py b/server/toia-dm/utils_gpt3.py
index a701ae52..766f6236 100644
--- a/server/toia-dm/utils_gpt3.py
+++ b/server/toia-dm/utils_gpt3.py
@@ -4,6 +4,8 @@
import pandas as pd
import numpy as np
import os
+from sqlalchemy.sql import text
+
config = dotenv_values()
# openai.organization = config['YOUR_ORG_ID']
@@ -13,19 +15,69 @@
openai.api_key = os.environ.get("OPENAI_API_KEY")
# openai.Model.list()
+print("toia_answer")
+
+# remember to change the interactor_id
+
+
+def toia_answer(query, data, engine, interactor_id=41, memory=10, minutes=15):
+ print("toia_answer")
+ print(query)
+ embedding = get_embedding(query, engine='text-embedding-ada-002')
+ print("API worked")
+ data['similarities'] = data.ada_search.apply(
+ lambda x: cosine_similarity(x, embedding))
+ res = data.sort_values('similarities', ascending=False)
-def toia_answer(query, data, k=1):
- embedding = get_embedding(query, engine='text-search-ada-query-001')
- data['similarities'] = data.ada_search.apply(lambda x: cosine_similarity(x, embedding))
- res = data.sort_values('similarities', ascending=False).head(k)
+ ada_similarity_scores = res.similarities.values
- ada_similarity_score = res.similarities.values[0]
- if ada_similarity_score > 0.29:
- return res['answer'].values[0], res['id_video'].values[0], ada_similarity_score
+ # (removed thresholding. Keep every answer)
+ if ada_similarity_scores[0] > 0.79:
+ # take first 10 answers from the chatlog"
+ # connect to the db
+ connection = engine.connect()
+ # retrieve the video IDs already played. The logic here is
+ # to retrieve the top {memory} last logs from the db and take the ones
+ # that aren't older than {minutes}
+ statement = text(f"""
+ SELECT cl.video_played,
+ (cl.timestamp - LAG(cl.timestamp, 1) OVER (ORDER BY cl.timestamp)) / 60000 AS time_diff_min
+ FROM (SELECT * FROM conversations_log WHERE question_asked != "None") cl
+ WHERE cl.interactor_id = {interactor_id}
+ ORDER BY cl.timestamp DESC
+ LIMIT {memory}
+ ;""")
+ result_proxy = connection.execute(statement)
+ result_set = result_proxy.fetchall()
+ # put them in a df
+ chatlog = pd.DataFrame(result_set)
+ # take cumsum of top minute differences -- only problem to highlith here:
+ # WE DON'T HAVE A NOTION OF WHAT TIME IS NOW
+ chatlog['cum_time_diff_min'] = chatlog['time_diff_min'].cumsum()
+
+ # define the temp cache of played video IDs -- adding here the notion of NOW: first question of new
+ # session is going to be put in the cache regardless. Then if time lag is too long from first and last,
+ # the cache is just that. Then it starts populating.
+ if chatlog['cum_time_diff_min'][0] >= minutes:
+ video_cache = chatlog['video_played'].values[0]
+ else:
+ video_cache = chatlog[chatlog['cum_time_diff_min']
+ < minutes]['video_played'].values
+
+ # store outputs (already sorted by decreasing order of retrieval)
+ answers = res['answer'].values
+ videos = res['id_video'].values
+ scores = ada_similarity_scores
+ if len(set(video_cache).intersection(set(videos))) > 0:
+ next_best_idx = next(x for x, vid in enumerate(
+ videos) if vid not in video_cache)
+ return answers[next_best_idx], videos[next_best_idx], scores[next_best_idx]
+ else:
+ return answers[0], videos[0], scores[0]
else:
df_noanswers = data[data['type'] == "no-answer"]
if df_noanswers.shape[0] > 0:
answers = df_noanswers.sample(n=1)
- return answers['answer'].values[0], answers['id_video'].values[0], ada_similarity_score
+ return answers['answer'].values[0], answers['id_video'].values[0], ada_similarity_scores[0]
else:
- return "You haven't recorded no-answers", "204", "No Content"
\ No newline at end of file
+ return "You haven't recorded no-answers", "204", "No Content"
diff --git a/server/translation/toia-translation.json b/server/translation/toia-translation.json
new file mode 100644
index 00000000..e8ef3a8d
--- /dev/null
+++ b/server/translation/toia-translation.json
@@ -0,0 +1,12 @@
+{
+ "type": "service_account",
+ "project_id": "toia-capstone-2021",
+ "private_key_id": "c161f9c66a0183737ce5e2ab5f6b59b7df2d33df",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDV8NLTHJLigoKp\nHWWtEVJsP9vAdDwlPQzovF6/W8TKUe9FTNF8XPg48q7vyLpQLb/G3YNbLpH1jjOE\nEKSl+hdUJqG+uUGUv13e5oPsREBMD9FfJ849Bphc5vz4xWj9J7K2G05C0kp2MmtN\n0gNnTJBRjEk2vQwYfuYQWE5ccPbtT4Ga4n0xKzVPR8kId6HSccy9u1eouUOs3oe2\nOUTAvxJxZ721vT6YG3AZfQa6VcPgZGHPIXyKlFU7vlBrHKG+XQi9qi7xLxki+Ae2\nLTdHEwzEphaiqOOEZS9fOj0uzgEpdmDrhM5tbjwkLugCALNbAOYp5vlLB3j38g5P\nobS4rSt3AgMBAAECggEAApMceAKJUmUffTlUcdHaPy5BKHhECKJK9C2sKdTI/sxT\nB+9fbmxqALlyJhv+ATZqIlKkU/Kw0/0xnOtcWxj+5eB1itrAF/7gYNNyW/0+rthz\n4xeS1+r35qPrAHPTvYdlE0orb3EIPCyDXEZ+Pv4aluvZLhz2HWdaWnEA0TdhnJDj\nDATnJZRBSfDxvR3HA3eFQslVcwgTgfXz3PGR8JJ4V9sZMY0rrGpCjRXQf31Hp2LR\nSQ+Gn/AX56fsQ2yf9TdlBDsq9Oj+456amuVNZIP/hvUux4tab0sJqvg/4rBtPJ7x\nC9j3b+le1plBVEq0KHSq/HphIJ394DH1V9vFN48DBQKBgQDwITYrBPdzw5BM5rGF\nsvX1NO273ehNxgt7t9KOrluamTOBFXrnq1vomTFZr9lInbQVwDpM/dvEKhsKPbXn\niAw5tNZD4ARvBr2J9rKVaIxhALohcRvm9UVITEEeP9q9soWTy72BULoOvnh7YYgf\n1ojirBw8I7hj+G3rkF0pZ2GKzQKBgQDkFIQuT9dK0FsMtvrxS779UFO/cWKGKucZ\nNKDqJ2sflN8lqWRAJMK4oO10VbMgpcLfZPJjfrm4pvhfvULVh2FBJm9dpxNLbIhy\nz0BfhK8ZrxzUAx/eMgKa9ODjjeU7qL0rpZF1I/jX4RbhwRTAEEqfgR0mMLc2C4wT\nWznwMGfXUwKBgQCtffFbB42ZcDQzu4GLLY+TCBizYVLTzkDBtEBGoibA/es+Wjyg\nYShYV0ZWnDyKwJY6GNaGhetgQWOj9I4WqC7dCpC8HYBWjzImGb1RQWYbN6FDRCt6\npL7Xy3BI4K2z3OWxsMRMR/0FZgw6aG8nQaNI0jzcHpq8b+NLDNSic3UACQKBgCWY\nqC1GJfQEIm4XH4h09vekrRlqpFX/bna+MSRH+SWMkbgQkyDrrllm1Z2Onudry5Kt\nfjMeaZjhlSGa/hBar5JgtozWhJyzOE7MkQztvztZnUPpe/BRiBJo+UUpV7cc2on+\nUdrgYh2b0fzGqhf614Ixc0+fSiQThTSPnh5UrFlXAoGBALn0FnW6tnTvQOqdUPaL\n9VOD4y0uRD+WL2gqy3czQU/NOzmp7nTrHtVCLrrNZBE3rLhPiAhTgwJMhE3RsahZ\nepUm/QGoRPMNt7yF5/B34+4Jr+4ptK30rJq1qTpcCoUS9DinnF0zvFc5JNRULXIj\nenXtPra/AfhRtPBzeLjQzm0S\n-----END PRIVATE KEY-----\n",
+ "client_email": "toia-translation@toia-capstone-2021.iam.gserviceaccount.com",
+ "client_id": "112776380172360861687",
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://oauth2.googleapis.com/token",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/toia-translation%40toia-capstone-2021.iam.gserviceaccount.com"
+}