diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index c7702faf..645ef600 100755
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,12 +1,12 @@
import React from "react";
-import Page from "../components/utility/Page";
+import Page from "../components/global/utility/Page";
import Hero from "../components/home/Hero";
export default function index() {
return (
diff --git a/src/pages/playground.tsx b/src/pages/playground.tsx
deleted file mode 100644
index e3bb0de8..00000000
--- a/src/pages/playground.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from "react";
-import Playground from "../components/playground/Playground";
-import Page from "../components/utility/Page";
-
-export default function playground() {
- return (
-
-
-
- );
-}
diff --git a/src/pages/rate-limiting-test.tsx b/src/pages/rate-limiting-test.tsx
deleted file mode 100644
index 1c893547..00000000
--- a/src/pages/rate-limiting-test.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from "react";
-import RateLimitingTest from "../components/global/utility/RateLimitingTest";
-
-export default function ratelimitingtest() {
- return
;
-}
diff --git a/src/scripts/generate-evaluation-prompt_v6.ts b/src/scripts/generate-evaluation-prompt_v6.ts
deleted file mode 100644
index 25e859d5..00000000
--- a/src/scripts/generate-evaluation-prompt_v6.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import { selectAttitudes, getFewShotExamples } from "./v6_utils";
-
-export default function formPrompt(
- statement: string,
- category: string,
- reply: string
-) {
- const attitudes = selectAttitudes();
-
- // console.log(attitudes);
-
- const fewShotExamples = getFewShotExamples(category.split("/")[1], attitudes);
- // console.log(fewShotExamples);
-
- const prompt = formEvalPrompt(statement, reply, fewShotExamples);
-
- return prompt;
-}
-
-function formEvalPrompt(
- statement: string,
- reply: string,
- fewShotExamples: any[]
-) {
- let prompt = "";
-
- fewShotExamples.forEach((ex) => {
- console.log(ex);
- prompt += `You said, "${ex["statement"]}"\n`;
- console.log("attitudes:", Object.keys(ex["replies"]));
- Object.values(ex["replies"]).forEach((reply: any, idx: number) => {
- prompt += `(${idx + 1}) I replied, "${reply["reply"]}"\n`;
- prompt += `Feedback: ${capFirst(reply["rating"].trim())} reply. ${
- reply["explanation"]
- }\n`;
- });
- prompt += "\n";
- });
-
- // unseen statement
- prompt += `You said, "${statement}"\n(1) ${reply}\nFeedback:`;
- return prompt;
-}
-
-function capFirst(str: string) {
- return str.charAt(0).toUpperCase() + str.slice(1);
-}
diff --git a/src/scripts/get-reply.ts b/src/scripts/get-reply.ts
index 474a42e3..40cdaa29 100644
--- a/src/scripts/get-reply.ts
+++ b/src/scripts/get-reply.ts
@@ -1,259 +1,20 @@
-import general_statements from "../data/module_statements/general";
-import work_statements from "../data/module_statements/work";
-import Completion from "./Completion";
-import formPrompt from "./generate-evaluation-prompt";
-import { v4 as uuidv4 } from "uuid";
-
-const module_statements = {
- general: general_statements,
- work: work_statements,
-};
-
export default async function getReply(
message: string,
+ id: string,
convoState: any,
- command: string
-) {
- // response loading
- convoState.setValue((cs: any) => ({ ...cs, turn: command }));
-
- let replies = [
- {
- id: uuidv4(),
- fromNoora: true,
- text: "Oops! Something went wrong.",
- sentiment: "neutral",
- statement: false,
- },
- ];
-
- if (command == "get-statement") {
- const statement = await getStatement(convoState)
- replies = [
- {
- id: uuidv4(),
- fromNoora: true,
- text: statement.text,
- sentiment: statement.sentiment,
- statement: true,
- },
- ];
- } else if (command == "rate-reply") {
- convoState.setValue((cs: any) => ({
- ...cs,
- statement: null,
- }));
- let answers = await getRating(
- message,
- convoState.value.statement.statementIdx,
- [...convoState.value.statement.statementObj],
- convoState
- );
-
- replies = answers.map((a: any) => ({
- id: uuidv4(),
- fromNoora: true,
- text: a.text,
- suggestion: a.suggestion,
- sentiment: a.sentiment ? a.sentiment : "neutral",
- statement: false,
- }));
- }
-
- convoState.setValue((cs: any) => ({
- ...cs,
- turn: command == "get-statement" ? "user-select" : "user-answer",
- }));
-
- return replies;
-}
-
-async function getRating(
- message: string,
- statementIdx: number,
- statementObj: any,
- convoState: any
+ setConvoState: any
) {
- const prompt = formPrompt(statementObj[1], statementObj[0], message);
- let target = statementObj[2];
-
- let classification = "";
- let explanation = "";
- let goodAnswer = false;
- let answers = [];
- let goodReplyConfidence = -1;
-
- try {
- // first get good/bad answer
- let output = await fetch("/api/openai", {
- method: "POST",
- body: JSON.stringify({
- model: convoState.value.model.name,
- prompt: prompt,
- temperature: 0,
- max_tokens: 1,
- frequency_penalty: 0,
- presence_penalty: 0,
- logprobs: 5,
- }),
- }).then((res) => res.json());
-
- let probsObj = output["logprobs"]["top_logprobs"][0];
-
- let probs = softmax(Object.values(probsObj));
- let topTokens = Object.keys(probsObj);
- let goodProb = 0.000001;
- if (topTokens.indexOf(" Good") != -1)
- goodProb = probs[topTokens.indexOf(" Good")];
- let badProb = 0.000001;
- if (topTokens.indexOf(" Bad") != -1)
- badProb = probs[topTokens.indexOf(" Bad")];
- goodReplyConfidence = goodProb / (goodProb + badProb);
-
- let threshold =
- message.length < 3 ? 0.9 : convoState.value.model.goodReplyThreshold; // length filtering
- console.log(
- `"good" token probability: ${goodProb}. "bad token probability: ${badProb}. threshold: ${threshold}`
- );
- if (goodReplyConfidence > threshold) {
- classification = "Good reply.";
- goodAnswer = true;
- } else {
- classification = "Bad reply.";
- goodAnswer = false;
- }
-
- console.log("Classification: " + classification);
-
- // console.log(prompt + " " + classification);
-
- output = await Completion({
- model: convoState.value.model.name,
- prompt: prompt + " " + classification,
- temperature: convoState.value.model.temperature,
- max_tokens: 40,
- frequency_penalty: convoState.value.frequencyPenalty,
- presence_penalty: convoState.value.model.presencePenalty,
- stop: "\n",
- });
-
- explanation = output.trim();
- console.log("Explanation: " + explanation);
-
- if (goodAnswer) {
- answers.push({ text: "Good reply!", sentiment: "positive" });
- answers.push({ text: explanation, sentiment: "positive" });
- } else {
- answers.push({ text: "Not quite!" });
- answers.push({ text: explanation });
- answers.push({ text: target.trim(), suggestion: true });
- }
- } catch (error) {
- console.error(error);
- explanation = "Please enter a proper reply.";
- answers = [explanation];
- }
-
- // SET PROGRESS
- convoState.setValue((cs: any) => ({
- ...cs,
- progress: [
- ...cs.progress,
- {
- idx: statementIdx,
- statement: statementObj[1],
- statementCategory: statementObj[0],
- reply: message,
- explanation: explanation,
- replyCategory: null,
- goodAnswer: goodAnswer,
- goodReplyConfidence: goodReplyConfidence,
- goodReplyThreshold: convoState.value.model.goodReplyThreshold,
- },
- ],
- }));
-
- return answers;
-}
-
-export async function getStatement(convoState: any) {
- // choose module
- const modules = convoState.value.modules.filter((m: any) => m.active);
- const sentiments = convoState.value.sentiments.filter((s: any) => s.active);
- const category = getRandomItem(modules)
- .title as keyof typeof module_statements;
- const sentiment = getRandomItem(sentiments)
- .title as keyof typeof module_statements[typeof category];
-
- // await timeout(700);
- // choose statement
- const statementIdx = getStatementIdx(
- category + "/" + sentiment,
- module_statements[category][sentiment],
- convoState
- );
- const statement = module_statements[category][sentiment][statementIdx];
- convoState.setValue((cs: any) => ({
- ...cs,
- statement: { statementIdx: statementIdx, statementObj: statement },
- }));
- // console.log("Selected statement: ");
- // console.log(statement);
-
- return { sentiment: statement[0].split("/")[1], text: statement[1] };
-}
-
-function getStatementIdx(
- category: string,
- statementsList: any[],
- convoState: any
-) {
- let seenIdxs = convoState.value.progress
- .map((p: any) => {
- if (p.statementCategory == category && p.goodAnswer)
- return p.idx; // same category seen, but can repeat ones where user got it wrong
- else {
- return -1;
- }
- })
- .filter((i: number) => i >= 0);
- if (convoState.value.statement)
- seenIdxs.push(convoState.value.statement.statementIdx);
- // console.log("Seen statement indexes:", seenIdxs);
-
- if (seenIdxs.length >= statementsList.length) {
- console.log("Exhausted all statements. Resetting.");
- seenIdxs = seenIdxs.slice(
- statementsList.length *
- Math.floor(seenIdxs.length / statementsList.length),
- seenIdxs.length
- );
- }
-
- let newRandomIdx = 0;
- while (true) {
- newRandomIdx = Math.floor(Math.random() * statementsList.length);
- if (seenIdxs.indexOf(newRandomIdx) == -1) break;
- }
-
- return newRandomIdx;
-}
-
-function getRandomItem(items: any) {
- return items[Math.floor(Math.random() * items.length)];
+ setConvoState({ turn: "noora-reply" });
+ let reply = message;
+ await timeout(5000);
+ return {
+ id: id,
+ fromNoora: true,
+ text: "I currently only echo you. Here was your message: " + reply,
+ };
}
-function softmax(arr: any[]) {
- return arr.map(function (value: any, index: any) {
- return (
- Math.exp(value) /
- arr
- .map(function (y /*value*/) {
- return Math.exp(y);
- })
- .reduce(function (a, b) {
- return a + b;
- })
- );
- });
+function timeout(ms: number) {
+ // for testing purposes
+ return new Promise((resolve) => setTimeout(resolve, ms));
}
diff --git a/src/scripts/Completion.tsx b/src/scripts/gpt-3/Completion.tsx
similarity index 100%
rename from src/scripts/Completion.tsx
rename to src/scripts/gpt-3/Completion.tsx
diff --git a/src/scripts/generate-advice.ts b/src/scripts/gpt-3/generate-advice.ts
similarity index 94%
rename from src/scripts/generate-advice.ts
rename to src/scripts/gpt-3/generate-advice.ts
index 5793b1ec..50c04c97 100644
--- a/src/scripts/generate-advice.ts
+++ b/src/scripts/gpt-3/generate-advice.ts
@@ -1,5 +1,5 @@
import Completion from "./Completion";
-import askNooraPrompt from "../data/prompts/ask-noora-prompt";
+import askNooraPrompt from "../../data/prompts/ask-noora";
const temp = 0.9;
const freqPenalty = 0.6;
diff --git a/src/scripts/generate-evaluation-prompt.ts b/src/scripts/gpt-3/generate-evaluation-prompt.ts
similarity index 81%
rename from src/scripts/generate-evaluation-prompt.ts
rename to src/scripts/gpt-3/generate-evaluation-prompt.ts
index ac5b8f21..9f3273a9 100644
--- a/src/scripts/generate-evaluation-prompt.ts
+++ b/src/scripts/gpt-3/generate-evaluation-prompt.ts
@@ -1,4 +1,4 @@
-import evalPrompts from "../data/prompts/noora-eval-prompt";
+import evalPrompts from "../../data/prompts/noora-eval";
export default function formPrompt(
statement: string,
diff --git a/src/scripts/util.ts b/src/scripts/noora-chat/audio_utils.ts
similarity index 79%
rename from src/scripts/util.ts
rename to src/scripts/noora-chat/audio_utils.ts
index 2b1793f1..c2c067cc 100644
--- a/src/scripts/util.ts
+++ b/src/scripts/noora-chat/audio_utils.ts
@@ -1,7 +1,7 @@
-export function messageToSpeechParams(convoState: any, message: any, currentAudioRef: any, history: any, hidden: any) {
+export function messageToSpeechParams(convoState: any, message: any, audioRef: any, history: any, hidden: any) {
const preText = message.suggestion ? "A better reply might've been: " : ""
const text = message.read ? message.read : message.text
- const postText = message.statement ? " Is this a positive, neutral, or negative statement?" : ""
+ const postText = message.statement ? " When I say this, do I sound positive, neutral, or negative?" : ""
let style = "neutral"
if (message.style)
style = message.style
@@ -19,11 +19,11 @@ export function messageToSpeechParams(convoState: any, message: any, currentAudi
styleDegree: style == "cheerful" ? 1.1 : 1.3,
convoState: convoState,
history: history,
- currentAudioRef: currentAudioRef,
+ audioRef: audioRef,
hidden: hidden,
}
}
export function timeout(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
-}
+}
\ No newline at end of file
diff --git a/src/scripts/noora-chat/get-reply.ts b/src/scripts/noora-chat/get-reply.ts
new file mode 100644
index 00000000..b2ac1fb6
--- /dev/null
+++ b/src/scripts/noora-chat/get-reply.ts
@@ -0,0 +1,261 @@
+import general_statements from "../../data/statement_bank/general";
+import work_statements from "../../data/statement_bank/work";
+import empathy_statements from "../../data/statement_bank/empathy"
+import Completion from "../gpt-3/Completion";
+import { v4 as uuidv4 } from "uuid";
+import formPrompt from "../gpt-3/generate-evaluation-prompt";
+
+const module_statements = {
+ general: general_statements,
+ work: work_statements,
+ empathy: empathy_statements,
+};
+
+export default async function getReply(
+ message: string,
+ convoState: any,
+ command: string
+) {
+ // response loading
+ convoState.setValue((cs: any) => ({ ...cs, turn: command }));
+
+ let replies = [
+ {
+ id: uuidv4(),
+ fromNoora: true,
+ text: "Oops! Something went wrong.",
+ sentiment: "neutral",
+ statement: false,
+ },
+ ];
+
+ if (command == "get-statement") {
+ const statement = await getStatement(convoState)
+ replies = [
+ {
+ id: uuidv4(),
+ fromNoora: true,
+ text: statement.text,
+ sentiment: statement.sentiment,
+ statement: true,
+ },
+ ];
+ } else if (command == "rate-reply") {
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ statement: null,
+ }));
+ let answers = await getRating(
+ message,
+ convoState.value.statement.statementIdx,
+ [...convoState.value.statement.statementObj],
+ convoState
+ );
+
+ replies = answers.map((a: any) => ({
+ id: uuidv4(),
+ fromNoora: true,
+ text: a.text,
+ suggestion: a.suggestion,
+ sentiment: a.sentiment ? a.sentiment : "neutral",
+ statement: false,
+ }));
+ }
+
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ turn: command == "get-statement" ? "user-select" : "user-answer",
+ }));
+
+ return replies;
+}
+
+async function getRating(
+ message: string,
+ statementIdx: number,
+ statementObj: any,
+ convoState: any
+) {
+ const prompt = formPrompt(statementObj[1], statementObj[0], message);
+ let target = statementObj[2];
+
+ let classification = "";
+ let explanation = "";
+ let goodAnswer = false;
+ let answers = [];
+ let goodReplyConfidence = -1;
+
+ try {
+ // first get good/bad answer
+ let output = await fetch("/api/openai", {
+ method: "POST",
+ body: JSON.stringify({
+ model: convoState.value.model.name,
+ prompt: prompt,
+ temperature: 0,
+ max_tokens: 1,
+ frequency_penalty: 0,
+ presence_penalty: 0,
+ logprobs: 5,
+ }),
+ }).then((res) => res.json());
+
+ let probsObj = output["logprobs"]["top_logprobs"][0];
+
+ let probs = softmax(Object.values(probsObj));
+ let topTokens = Object.keys(probsObj);
+ let goodProb = 0.000001;
+ if (topTokens.indexOf(" Good") != -1)
+ goodProb = probs[topTokens.indexOf(" Good")];
+ let badProb = 0.000001;
+ if (topTokens.indexOf(" Bad") != -1)
+ badProb = probs[topTokens.indexOf(" Bad")];
+ goodReplyConfidence = goodProb / (goodProb + badProb);
+
+ let threshold =
+ message.length < 3 ? 0.9 : convoState.value.model.goodReplyThreshold; // length filtering
+ console.log(
+ `"good" token probability: ${goodProb}. "bad token probability: ${badProb}. threshold: ${threshold}`
+ );
+ if (goodReplyConfidence > threshold) {
+ classification = "Good reply.";
+ goodAnswer = true;
+ } else {
+ classification = "Bad reply.";
+ goodAnswer = false;
+ }
+
+ console.log("Classification: " + classification);
+
+ // console.log(prompt + " " + classification);
+
+ output = await Completion({
+ model: convoState.value.model.name,
+ prompt: prompt + " " + classification,
+ temperature: convoState.value.model.temperature,
+ max_tokens: 40,
+ frequency_penalty: convoState.value.frequencyPenalty,
+ presence_penalty: convoState.value.model.presencePenalty,
+ stop: "\n",
+ });
+
+ explanation = output.trim();
+ console.log("Explanation: " + explanation);
+
+ if (goodAnswer) {
+ answers.push({ text: "Good reply!", sentiment: "positive" });
+ answers.push({ text: explanation, sentiment: "positive" });
+ } else {
+ answers.push({ text: "Not quite!" });
+ answers.push({ text: explanation });
+ answers.push({ text: target.trim(), suggestion: true });
+ }
+ } catch (error) {
+ console.error(error);
+ explanation = "Please enter a proper reply.";
+ answers = [explanation];
+ }
+
+ // SET PROGRESS
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ progress: [
+ ...cs.progress,
+ {
+ idx: statementIdx,
+ statement: statementObj[1],
+ statementCategory: statementObj[0],
+ reply: message,
+ explanation: explanation,
+ replyCategory: null,
+ goodAnswer: goodAnswer,
+ goodReplyConfidence: goodReplyConfidence,
+ goodReplyThreshold: convoState.value.model.goodReplyThreshold,
+ },
+ ],
+ }));
+
+ return answers;
+}
+
+export async function getStatement(convoState: any) {
+ // choose module
+ const modules = convoState.value.modules.filter((m: any) => m.active);
+ const sentiments = convoState.value.sentiments.filter((s: any) => s.active);
+ const category = getRandomItem(modules)
+ .title as keyof typeof module_statements;
+ const sentiment = getRandomItem(sentiments)
+ .title as keyof typeof module_statements[typeof category];
+
+ // await timeout(700);
+ // choose statement
+ const statementIdx = getStatementIdx(
+ category + "/" + sentiment,
+ module_statements[category][sentiment],
+ convoState
+ );
+ const statement = module_statements[category][sentiment][statementIdx];
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ statement: { statementIdx: statementIdx, statementObj: statement },
+ }));
+ // console.log("Selected statement: ");
+ // console.log(statement);
+
+ return { sentiment: statement[0].split("/")[1], text: statement[1] };
+}
+
+function getStatementIdx(
+ category: string,
+ statementsList: any[],
+ convoState: any
+) {
+ let seenIdxs = convoState.value.progress
+ .map((p: any) => {
+ if (p.statementCategory == category && p.goodAnswer)
+ return p.idx; // same category seen, but can repeat ones where user got it wrong
+ else {
+ return -1;
+ }
+ })
+ .filter((i: number) => i >= 0);
+ if (convoState.value.statement)
+ seenIdxs.push(convoState.value.statement.statementIdx);
+ // console.log("Seen statement indexes:", seenIdxs);
+
+ if (seenIdxs.length >= statementsList.length) {
+ console.log("Exhausted all statements. Resetting.");
+ seenIdxs = seenIdxs.slice(
+ statementsList.length *
+ Math.floor(seenIdxs.length / statementsList.length),
+ seenIdxs.length
+ );
+ }
+
+ let newRandomIdx = 0;
+ while (true) {
+ newRandomIdx = Math.floor(Math.random() * statementsList.length);
+ if (seenIdxs.indexOf(newRandomIdx) == -1) break;
+ }
+
+ return newRandomIdx;
+}
+
+function getRandomItem(items: any) {
+ return items[Math.floor(Math.random() * items.length)];
+}
+
+function softmax(arr: any[]) {
+ return arr.map(function (value: any, index: any) {
+ return (
+ Math.exp(value) /
+ arr
+ .map(function (y /*value*/) {
+ return Math.exp(y);
+ })
+ .reduce(function (a, b) {
+ return a + b;
+ })
+ );
+ });
+}
diff --git a/src/scripts/noora-chat/handle-submit.ts b/src/scripts/noora-chat/handle-submit.ts
new file mode 100644
index 00000000..4d3c9845
--- /dev/null
+++ b/src/scripts/noora-chat/handle-submit.ts
@@ -0,0 +1,59 @@
+import { v4 as uuidv4 } from "uuid";
+import { saveSessionResult } from "../user-info/session-results";
+import noorasTurn from "./nooras-turn";
+
+export default async function handleSubmit(e: any, convoState: any, history: any, message?: string) {
+ e.preventDefault();
+
+ // stop audio
+ if (convoState.value.audio.player) {
+ convoState.value.audio.player.pause()
+ convoState.value.audio.player.close()
+ }
+
+ message = message ? message : convoState.value.draft.slice();
+ if (!message) message = ""
+
+ let userMsgId = uuidv4();
+
+ history.setValue((h: any) => [
+ ...h,
+ { id: userMsgId, fromNoora: false, text: message, show: true },
+ ]);
+ convoState.setValue((cs: any) => ({ ...cs, draft: "" }));
+
+ let m = message.trim().toLowerCase();
+
+ if (convoState.value.turn.includes("start")) {
+ if (m.includes("no") || m.includes("don")) {
+ history.setValue((h: any) => [
+ ...h,
+ { id: uuidv4(), fromNoora: true, text: "Are you ready to begin?" },
+ ]);
+ } else {
+ await noorasTurn(message, convoState, history, true);
+ }
+ } else if (
+ convoState.value.progress.length < convoState.value.numProblems
+ ) {
+ await noorasTurn(message, convoState, history);
+ } else {
+ if (m == "yes") {
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ numProblems: cs.numProblems + 3,
+ }));
+ await noorasTurn(message, convoState, history, true);
+ } else {
+ handleSessionEnd(convoState)
+ }
+ }
+};
+
+
+function handleSessionEnd(convoState: any) {
+ saveSessionResult(convoState.value.progress)
+
+ // show summary
+ convoState.setValue((cs: any) => ({ ...cs, turn: "summary" }));
+}
\ No newline at end of file
diff --git a/src/scripts/noora-chat/nooras-turn.ts b/src/scripts/noora-chat/nooras-turn.ts
new file mode 100644
index 00000000..658edc28
--- /dev/null
+++ b/src/scripts/noora-chat/nooras-turn.ts
@@ -0,0 +1,78 @@
+import { v4 as uuidv4 } from "uuid";
+import getReply from "./get-reply";
+
+export default async function noorasTurn(
+ message: string,
+ convoState: any,
+ history: any,
+ noorasTurn = false
+) {
+ if (convoState.value.statement) {
+ if (convoState.value.turn.includes("select")) {
+ // handle sentiment classification
+ const targetSentiment = convoState.value.statement.statementObj[0].split("/")[1]
+ const m = message.trim().toLowerCase()
+ const correct = m == targetSentiment.trim().toLowerCase()
+
+
+ history.setValue((h: any) => [...h, {
+ id: uuidv4(),
+ fromNoora: true,
+ read: correct ? null : `Actually, this is a ${targetSentiment} statement.`,
+ sentiment: correct ? "positive" : "neutral",
+ text: correct ? "That's right!" : targetSentiment,
+ correction: !correct,
+ },
+ {
+ id: uuidv4(),
+ fromNoora: true,
+ text: "How would you reply to me?",
+ }]
+ );
+
+ convoState.setValue((cs: any) => ({
+ ...cs,
+ turn: "user-answer",
+ }));
+
+ return
+ }
+ else {
+ // rate reply if statement was given
+ const replies = await getReply(message, convoState, "rate-reply");
+ history.setValue((h: any) => [...h, ...replies]);
+ }
+ }
+
+ // get statement if still need to practice
+ // note that progress state has not updated yet, so we use (length + 1)
+ if (
+ convoState.value.progress.length + 1 < convoState.value.numProblems ||
+ noorasTurn
+ ) {
+ const replies = await getReply(message, convoState, "get-statement");
+
+ history.setValue((h: any) => [
+ ...h,
+ {
+ fromNoora: true,
+ id: uuidv4(),
+ text:
+ convoState.value.turn.includes("start")
+ ? "Let's get started."
+ : "Let's try another one.",
+ },
+ ...replies,
+ ]);
+ } else {
+ history.setValue((h: any) => [
+ ...h,
+ {
+ id: uuidv4(),
+ fromNoora: true,
+ text: `Good job! You practiced ${convoState.value.numProblems} scenarios. Do you want to continue practicing?`,
+ },
+ ]);
+ convoState.setValue((cs: any) => ({ ...cs, turn: "user-select-end" }));
+ }
+}
diff --git a/src/scripts/user-info/local-storage-utils.ts b/src/scripts/user-info/local-storage-utils.ts
new file mode 100644
index 00000000..5669e6cf
--- /dev/null
+++ b/src/scripts/user-info/local-storage-utils.ts
@@ -0,0 +1,23 @@
+export function writeResultToLocal(result: any) {
+ let results = getFromLocal("progress")
+
+ console.log("Current results:", results)
+ result = [result]
+ if (results)
+ result.push(...results) // reverse order
+
+ writeToLocal("progress", JSON.stringify(result))
+}
+
+export function writeToLocal(key: string, value: any) {
+ if (typeof window !== "undefined") {
+ localStorage.setItem(key, value)
+ } else {
+ console.log("Could not write to local storage for key: " + key)
+ }
+}
+
+export function getFromLocal(key: string) {
+ if (typeof window !== "undefined")
+ return JSON.parse(localStorage.getItem(key) as string)
+}
diff --git a/src/scripts/user-info/session-results.ts b/src/scripts/user-info/session-results.ts
new file mode 100644
index 00000000..2fe705e8
--- /dev/null
+++ b/src/scripts/user-info/session-results.ts
@@ -0,0 +1,28 @@
+import { writeResultToLocal } from "./local-storage-utils";
+
+export function saveSessionResult(progressObj: any) {
+ let result = {
+ timeCompleted: Date.now(),
+ scores: {
+ // [correct, attempted]
+ // positive, neutral, negative
+ total: [0, 0]
+ }
+ }
+
+ progressObj.forEach((problem: any) => {
+ let sentiment = problem.statementCategory.split("/")[1]
+ let sentimentKey = sentiment as keyof typeof result.scores
+ if (!result.scores[sentimentKey])
+ result.scores[sentimentKey] = [0, 0]
+
+ result.scores[sentimentKey][1]++;
+ result.scores.total[1]++;
+ result.scores[sentimentKey][0] += problem.goodAnswer ? 1 : 0;
+ result.scores.total[0] += problem.goodAnswer ? 1 : 0;
+ })
+
+ console.log("### Saving to progress: ", result)
+ writeResultToLocal(result)
+ console.log("### Done saving to progress")
+}
\ No newline at end of file
diff --git a/src/scripts/rate-limit.ts b/src/scripts/utils/rate-limit.ts
similarity index 100%
rename from src/scripts/rate-limit.ts
rename to src/scripts/utils/rate-limit.ts
diff --git a/src/scripts/token_util.ts b/src/scripts/utils/token_util.ts
similarity index 100%
rename from src/scripts/token_util.ts
rename to src/scripts/utils/token_util.ts
diff --git a/src/scripts/v6_utils.ts b/src/scripts/v6_utils.ts
deleted file mode 100644
index 1eb4e879..00000000
--- a/src/scripts/v6_utils.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import examples, {
- attitudes as all_attitudes,
-} from "../data/few-shot-examples";
-
-export function selectAttitudes() {
- let all_attitudes_copy = all_attitudes.slice();
- let attitudes = [];
-
- while (all_attitudes_copy.length) {
- var randomIndex = Math.floor(Math.random() * all_attitudes_copy.length),
- element = all_attitudes_copy.splice(randomIndex, 1);
-
- attitudes.push(element[0]);
- }
-
- attitudes = attitudes.slice(0, 15);
-
- attitudes[Math.floor(Math.random() * 10)] = "inquiring";
- return attitudes;
-}
-
-export function getFewShotExamples(sentiment: string, attitudes: string[]) {
- // two objects in fewShotExamples: {statement: '', replies: [{attitude: '', reply: '', rating: '', explanation: ''}]}
- let fewShotExamples: any[] = [];
-
- let currExs = examples[sentiment as keyof typeof examples];
- console.log(sentiment + ":", currExs);
-
- [currExs["general"], currExs["work"]].forEach((exs, i) => {
- console.log(i, exs["statement"]);
- let selectedExs = Object.fromEntries(
- Object.entries(exs).filter(
- ([key]) => attitudes.slice(i * 5, 5 * (i + 1)).indexOf(key) != -1
- )
- );
-
- let replies = Object.keys(selectedExs).map((key) => ({
- ...(selectedExs[key] as Object),
- attitude: key,
- }));
-
- fewShotExamples.push({
- statement: exs["statement"],
- replies: replies,
- attitudes: attitudes.slice(i * 5, 5 * (i + 1)),
- });
- });
-
- return fewShotExamples;
-}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 06b986fa..9b7baed6 100755
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -52,8 +52,8 @@
/* PLAYGROUND */
#chat-window {
- height: 55vh;
- max-height: 55vh;
+ height: 56vh;
+ max-height: 56vh;
overflow: auto !important;
}
diff --git a/yarn.lock b/yarn.lock
index 637accfc..5d8df99c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -216,6 +216,11 @@
resolved "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz"
integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==
+"@types/dateformat@^5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@types/dateformat/-/dateformat-5.0.0.tgz#17ce64b0318f3f36d1c830c58a7a915445f1f93d"
+ integrity sha512-SZg4JdHIWHQGEokbYGZSDvo5wA4TLYPXaqhigs/wH+REDOejcJzgH+qyY+HtEUtWOZxEUkbhbdYPqQDiEgrXeA==
+
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
@@ -433,6 +438,11 @@ array.prototype.flatmap@^1.3.0:
es-abstract "^1.19.2"
es-shim-unscopables "^1.0.0"
+asap@~2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
+
asn1.js-rfc2560@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/asn1.js-rfc2560/-/asn1.js-rfc2560-5.0.1.tgz"
@@ -665,6 +675,19 @@ core-js-pure@^3.20.2:
resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.23.4.tgz"
integrity sha512-lizxkcgj3XDmi7TUBFe+bQ1vNpD5E4t76BrBWI3HdUxdw/Mq1VF4CkiHzIKyieECKtcODK2asJttoofEeUKICQ==
+core-js@^1.0.0:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
+ integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==
+
+create-react-class@^15.6.0:
+ version "15.7.0"
+ resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e"
+ integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==
+ dependencies:
+ loose-envify "^1.3.1"
+ object-assign "^4.1.1"
+
cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
@@ -689,6 +712,11 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
+dateformat@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-5.0.3.tgz#fe2223eff3cc70ce716931cb3038b59a9280696e"
+ integrity sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA==
+
debug@4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"
@@ -801,6 +829,13 @@ emoji-regex@^9.2.2:
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+encoding@^0.1.11:
+ version "0.1.13"
+ resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
+ integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
+ dependencies:
+ iconv-lite "^0.6.2"
+
errlop@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz"
@@ -1103,6 +1138,19 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
+fbjs@^0.8.9:
+ version "0.8.18"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a"
+ integrity sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==
+ dependencies:
+ core-js "^1.0.0"
+ isomorphic-fetch "^2.1.1"
+ loose-envify "^1.0.0"
+ object-assign "^4.1.0"
+ promise "^7.1.1"
+ setimmediate "^1.0.5"
+ ua-parser-js "^0.7.30"
+
file-entry-cache@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
@@ -1313,6 +1361,11 @@ heimdalljs@^0.2.3:
dependencies:
rsvp "~3.2.1"
+heroicons@^2.0.10:
+ version "2.0.10"
+ resolved "https://registry.yarnpkg.com/heroicons/-/heroicons-2.0.10.tgz#ab421e0190cfc4fcf642a116b80b9a2ee55f149f"
+ integrity sha512-4f2UYy2cf2oHswZzdH2frENVk89RV/RLoNnDL577ulV1xsdTWBkM39Gzo2e9AXgTWJ3H95ol/Qs9JBSSU+APBg==
+
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz"
@@ -1321,6 +1374,13 @@ https-proxy-agent@^4.0.0:
agent-base "5"
debug "4"
+iconv-lite@^0.6.2:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3.0.0"
+
ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"
@@ -1451,6 +1511,11 @@ is-shared-array-buffer@^1.0.2:
dependencies:
call-bind "^1.0.2"
+is-stream@^1.0.1:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+ integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
+
is-stream@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz"
@@ -1482,6 +1547,14 @@ isexe@^2.0.0:
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isomorphic-fetch@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
+ integrity sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==
+ dependencies:
+ node-fetch "^1.0.1"
+ whatwg-fetch ">=0.10.0"
+
istextorbinary@^2.5.1:
version "2.6.0"
resolved "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz"
@@ -1566,7 +1639,7 @@ lodash.merge@^4.6.2:
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -1705,6 +1778,14 @@ next@12.2.2:
"@next/swc-win32-ia32-msvc" "12.2.2"
"@next/swc-win32-x64-msvc" "12.2.2"
+node-fetch@^1.0.1:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
+ integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
+ dependencies:
+ encoding "^0.1.11"
+ is-stream "^1.0.1"
+
node-releases@^2.0.6:
version "2.0.6"
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz"
@@ -1720,7 +1801,7 @@ normalize-range@^0.1.2:
resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
-object-assign@^4.1.1:
+object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -1958,7 +2039,14 @@ prelude-ls@^1.2.1:
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-prop-types@^15.8.1:
+promise@^7.1.1:
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
+ integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
+ dependencies:
+ asap "~2.0.3"
+
+prop-types@^15.5.10, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -1982,11 +2070,28 @@ quick-lru@^5.1.1:
resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+react-addons-test-utils@^15.3.2:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.6.2.tgz#c12b6efdc2247c10da7b8770d185080a7b047156"
+ integrity sha512-6IUCnLp7jQRBftm2anf8rP8W+8M2PsC7GPyMFe2Wef3Wfml7j2KybVL//Ty7bRDBqLh8AG4m/zNZbFlwulldFw==
+
react-anchor-link-smooth-scroll@^1.0.12:
version "1.0.12"
resolved "https://registry.npmjs.org/react-anchor-link-smooth-scroll/-/react-anchor-link-smooth-scroll-1.0.12.tgz"
integrity sha512-aaY+9X0yh8YnC0jBfoTKpsiCLdO/Y6pCltww+VB+NnTBPDOvnIdnp1AlazajsDitc1j+cVSQ+yNtaVeTIMQbxw==
+react-circular-progressbar@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz#99e5ae499c21de82223b498289e96f66adb8fa3a"
+ integrity sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==
+
+react-device-detect@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.2.tgz#dbabbce798ec359c83f574c3edb24cf1cca641a5"
+ integrity sha512-zSN1gIAztUekp5qUT/ybHwQ9fmOqVT1psxpSlTn1pe0CO+fnJHKRLOWWac5nKxOxvOpD/w84hk1I+EydrJp7SA==
+ dependencies:
+ ua-parser-js "^1.0.2"
+
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
@@ -1995,6 +2100,16 @@ react-dom@18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-dom@^15.3.2:
+ version "15.7.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.7.0.tgz#39106dee996d0742fb0f43d567ef8b8153483ab2"
+ integrity sha512-mpjXqC2t1FuYsILOLCj0kg6pbg460byZkVA/80VtDmKU/pYmoTdHOtaMcTRIDiyXLz4sIur0cQ04nOC6iGndJg==
+ dependencies:
+ fbjs "^0.8.9"
+ loose-envify "^1.1.0"
+ object-assign "^4.1.0"
+ prop-types "^15.5.10"
+
react-floater@^0.7.5:
version "0.7.5"
resolved "https://registry.yarnpkg.com/react-floater/-/react-floater-0.7.5.tgz#23e1d7d0d3be8228239595b6071cd97e2c9d261f"
@@ -2043,6 +2158,26 @@ react@18.2.0:
dependencies:
loose-envify "^1.1.0"
+react@^15.3.2:
+ version "15.7.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-15.7.0.tgz#10308fd42ac6912a250bf00380751abc41ac7106"
+ integrity sha512-5/MMRYmpmM0sMTHGLossnJCrmXQIiJilD6y3YN3TzAwGFj6zdnMtFv6xmi65PHKRV+pehIHpT7oy67Sr6s9AHA==
+ dependencies:
+ create-react-class "^15.6.0"
+ fbjs "^0.8.9"
+ loose-envify "^1.1.0"
+ object-assign "^4.1.0"
+ prop-types "^15.5.10"
+
+reactjs-percentage-circle@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/reactjs-percentage-circle/-/reactjs-percentage-circle-1.0.0.tgz#0d2629f64d89bca76efb3230361e2c93d71835a7"
+ integrity sha512-Q+Km0D/owm72kuBe2K5VjEkbje3npK18ppIzks8Se7HxWKbNKMYNUbfclGuxHsvkxNh273hPOqHqdno1n5TACQ==
+ dependencies:
+ react "^15.3.2"
+ react-addons-test-utils "^15.3.2"
+ react-dom "^15.3.2"
+
read-cache@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz"
@@ -2128,7 +2263,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
-safer-buffer@^2.1.0:
+"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0:
version "2.1.2"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@@ -2162,6 +2297,11 @@ semver@^7.3.7:
dependencies:
lru-cache "^6.0.0"
+setimmediate@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+ integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
@@ -2264,6 +2404,11 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+swr@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8"
+ integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==
+
tailwindcss@^3.1.6:
version "3.1.6"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.6.tgz"
@@ -2361,6 +2506,16 @@ typescript@4.7.4:
resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz"
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
+ua-parser-js@^0.7.30:
+ version "0.7.31"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
+ integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==
+
+ua-parser-js@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.2.tgz#e2976c34dbfb30b15d2c300b2a53eac87c57a775"
+ integrity sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg==
+
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
@@ -2419,6 +2574,11 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
+whatwg-fetch@>=0.10.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c"
+ integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==
+
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"