@nualang/nualang-ui-components 0.1.1207 → 0.1.1209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Cards/SubscriptionPlan/SubscriptionPlan.js +6 -5
- package/dist/Containers/App/App.js +22 -18
- package/dist/Dialogs/CreatePhrase/CreatePhrase.js +6 -2
- package/dist/Dialogs/GenerateBot/GenerateBot.js +13 -8
- package/dist/Dialogs/GeneratePhrases/GeneratePhrases.js +13 -4
- package/dist/Dialogs/GenerateQuestion/GenerateQuestion.js +10 -2
- package/dist/Dialogs/GenerateRoleplay/GenerateRoleplay.js +17 -8
- package/dist/Misc/LanguageSelector/LanguageSelector.js +4 -1
- package/dist/hooks/useRecognition.js +11 -2
- package/dist/utils/index.js +8 -2
- package/package.json +1 -1
|
@@ -86,7 +86,7 @@ const PlanFeaturesListItem = (0, _system.styled)("li")(({
|
|
|
86
86
|
theme
|
|
87
87
|
}) => ({
|
|
88
88
|
display: "flex",
|
|
89
|
-
marginTop: theme.spacing(
|
|
89
|
+
marginTop: theme.spacing(2)
|
|
90
90
|
}));
|
|
91
91
|
const PlanFeaturesListItemLabel = (0, _system.styled)(_material.Typography)(() => ({
|
|
92
92
|
display: "flex",
|
|
@@ -116,7 +116,7 @@ const Badge = (0, _system.styled)(_material.Typography)(({
|
|
|
116
116
|
color: theme.palette.common.black,
|
|
117
117
|
fontSize: theme.typography.pxToRem(10),
|
|
118
118
|
borderRadius: "9px",
|
|
119
|
-
padding:
|
|
119
|
+
padding: theme.spacing(0.25, 1),
|
|
120
120
|
display: "flex",
|
|
121
121
|
alignItems: "center",
|
|
122
122
|
marginBottom: "2px"
|
|
@@ -188,7 +188,7 @@ function SubscriptionPlan({
|
|
|
188
188
|
currency
|
|
189
189
|
}) {
|
|
190
190
|
const [displayPlan, setDisplayPlan] = (0, _react.useState)(plan);
|
|
191
|
-
const [buyNowDisabled, setBuyNowDisabled] = (0, _react.useState)(true);
|
|
191
|
+
const [buyNowDisabled, setBuyNowDisabled] = (0, _react.useState)(plan?.planVersions?.length > 0 ? true : false);
|
|
192
192
|
const [anchorEl, setAnchorEl] = (0, _react.useState)(null);
|
|
193
193
|
const open = Boolean(anchorEl);
|
|
194
194
|
const [disableRippleEff, setDisableRippleEff] = (0, _react.useState)(false);
|
|
@@ -307,8 +307,9 @@ function SubscriptionPlan({
|
|
|
307
307
|
onClick: () => plan.button.onClick(),
|
|
308
308
|
bgPrimary: plan.bgPrimary,
|
|
309
309
|
children: plan.button.buttonText
|
|
310
|
-
}),
|
|
311
|
-
|
|
310
|
+
}), displayPlan && billingPeriod && currency && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Box, {
|
|
311
|
+
mt: 2,
|
|
312
|
+
children: [plan.planVersions && displayPlan.subButton && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
312
313
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(PlanButton, {
|
|
313
314
|
id: "plan-button",
|
|
314
315
|
fullWidth: true,
|
|
@@ -10,7 +10,6 @@ var _DefaultColourButton = _interopRequireDefault(require("../../Misc/DefaultCol
|
|
|
10
10
|
var _styles = require("@mui/material/styles");
|
|
11
11
|
var _mui = require("tss-react/mui");
|
|
12
12
|
var _useMediaQuery = _interopRequireDefault(require("@mui/material/useMediaQuery"));
|
|
13
|
-
var _Star = _interopRequireDefault(require("@mui/icons-material/Star"));
|
|
14
13
|
var _Search = _interopRequireDefault(require("@mui/icons-material/Search"));
|
|
15
14
|
var _InputBase = _interopRequireDefault(require("@mui/material/InputBase"));
|
|
16
15
|
var _InputAdornment = _interopRequireDefault(require("@mui/material/InputAdornment"));
|
|
@@ -91,7 +90,8 @@ const SearchIconWrapper = (0, _styles.styled)("div")(({
|
|
|
91
90
|
justifyContent: "center"
|
|
92
91
|
}));
|
|
93
92
|
const StyledInputBase = (0, _styles.styled)(_InputBase.default)(({
|
|
94
|
-
theme
|
|
93
|
+
theme,
|
|
94
|
+
isUpgradePossible
|
|
95
95
|
}) => ({
|
|
96
96
|
color: "inherit",
|
|
97
97
|
width: "100%",
|
|
@@ -100,9 +100,9 @@ const StyledInputBase = (0, _styles.styled)(_InputBase.default)(({
|
|
|
100
100
|
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
|
|
101
101
|
transition: theme.transitions.create("width"),
|
|
102
102
|
[theme.breakpoints.up("lg")]: {
|
|
103
|
-
width: "30ch",
|
|
103
|
+
width: isUpgradePossible ? "20ch" : "30ch",
|
|
104
104
|
"&:focus": {
|
|
105
|
-
width: "35ch"
|
|
105
|
+
width: isUpgradePossible ? "25ch" : "35ch"
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -111,7 +111,8 @@ function AppSearch({
|
|
|
111
111
|
t,
|
|
112
112
|
navigate,
|
|
113
113
|
searchText,
|
|
114
|
-
setSearchText
|
|
114
|
+
setSearchText,
|
|
115
|
+
isUpgradePossible
|
|
115
116
|
}) {
|
|
116
117
|
const [debouncedSearchText, setDebouncedSearchText] = (0, _react.useState)("");
|
|
117
118
|
const [prevDebouncedSearchText, setPrevDebouncedSearchText] = (0, _react.useState)("");
|
|
@@ -146,6 +147,7 @@ function AppSearch({
|
|
|
146
147
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Search.default, {})
|
|
147
148
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledInputBase, {
|
|
148
149
|
autoFocus: true,
|
|
150
|
+
isUpgradePossible: isUpgradePossible,
|
|
149
151
|
placeholder: t("app_search_placeholder"),
|
|
150
152
|
value: searchText,
|
|
151
153
|
onChange: ev => {
|
|
@@ -283,6 +285,7 @@ function App({
|
|
|
283
285
|
};
|
|
284
286
|
const isSearchActive = searchText || isMobileSearchExpanded;
|
|
285
287
|
const isTeacher = user && user["custom:role"] === "teach";
|
|
288
|
+
const isUpgradePossible = subscription && !subscription.isPaidUser && subscription.isUpgradePossible;
|
|
286
289
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
287
290
|
className: classes.root,
|
|
288
291
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Header.default, {
|
|
@@ -307,7 +310,8 @@ function App({
|
|
|
307
310
|
t: t,
|
|
308
311
|
navigate: navigate,
|
|
309
312
|
searchText: searchText,
|
|
310
|
-
setSearchText: setSearchText
|
|
313
|
+
setSearchText: setSearchText,
|
|
314
|
+
isUpgradePossible: isUpgradePossible
|
|
311
315
|
})]
|
|
312
316
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
313
317
|
children: [isLgScreen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
@@ -316,7 +320,8 @@ function App({
|
|
|
316
320
|
t: t,
|
|
317
321
|
navigate: navigate,
|
|
318
322
|
searchText: searchText,
|
|
319
|
-
setSearchText: setSearchText
|
|
323
|
+
setSearchText: setSearchText,
|
|
324
|
+
isUpgradePossible: isUpgradePossible
|
|
320
325
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Box, {
|
|
321
326
|
flexGrow: 1
|
|
322
327
|
})]
|
|
@@ -353,16 +358,6 @@ function App({
|
|
|
353
358
|
}),
|
|
354
359
|
size: isLgScreen ? "medium" : "small",
|
|
355
360
|
children: t("skip_navigation")
|
|
356
|
-
}), subscription && !subscription.isPaidUser && subscription.isUpgradePossible && authenticated && /*#__PURE__*/(0, _jsxRuntime.jsx)(_DefaultColourButton.default, {
|
|
357
|
-
variant: "contained",
|
|
358
|
-
startIcon: isLgScreen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Star.default, {}) : null,
|
|
359
|
-
href: upgradePlanURL,
|
|
360
|
-
size: isLgScreen ? "medium" : "small",
|
|
361
|
-
sx: {
|
|
362
|
-
fontSize: isLgScreen ? null : 12,
|
|
363
|
-
mr: 1
|
|
364
|
-
},
|
|
365
|
-
children: t("upgrade_plan")
|
|
366
361
|
}), isTeacher && (isLgScreen ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Button, {
|
|
367
362
|
variant: "contained",
|
|
368
363
|
onClick: handleClickCreate,
|
|
@@ -381,7 +376,16 @@ function App({
|
|
|
381
376
|
onClick: handleClickCreate,
|
|
382
377
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Add.default, {})
|
|
383
378
|
})
|
|
384
|
-
})),
|
|
379
|
+
})), isUpgradePossible && authenticated && /*#__PURE__*/(0, _jsxRuntime.jsx)(_DefaultColourButton.default, {
|
|
380
|
+
variant: "contained",
|
|
381
|
+
href: upgradePlanURL,
|
|
382
|
+
size: isLgScreen ? "medium" : "small",
|
|
383
|
+
sx: {
|
|
384
|
+
fontSize: isLgScreen ? null : 12,
|
|
385
|
+
ml: 1
|
|
386
|
+
},
|
|
387
|
+
children: t("upgrade_plan")
|
|
388
|
+
}), isLgScreen && /*#__PURE__*/(0, _jsxRuntime.jsx)(_WhatsNew.default, {
|
|
385
389
|
t: t,
|
|
386
390
|
whatsNewMarkdown: whatsNewMarkdown,
|
|
387
391
|
whatsNewDate: whatsNewDate
|
|
@@ -223,10 +223,14 @@ function CreatePhrase({
|
|
|
223
223
|
|
|
224
224
|
const autoFillTranslation = async () => {
|
|
225
225
|
try {
|
|
226
|
-
const activePrompt = `Translate the following phrase "${phrase}" from ${learnLang} to ${forLang}. Provide all the acceptable translations if the phrase has multiple interpretations. Format the response as a valid JSON array with each translation as a string inside the array.`;
|
|
227
226
|
let chatGptResponse = await makeChatGptApiRequest({
|
|
228
227
|
model: "gpt-3.5-turbo",
|
|
229
|
-
|
|
228
|
+
promptKey: "autoFillTranslation",
|
|
229
|
+
promptVariables: {
|
|
230
|
+
learnLang,
|
|
231
|
+
forLang,
|
|
232
|
+
phrase
|
|
233
|
+
}
|
|
230
234
|
});
|
|
231
235
|
chatGptResponse = chatGptResponse.replaceAll("```", '').replaceAll("json", '');
|
|
232
236
|
const translations = JSON.parse(chatGptResponse);
|
|
@@ -138,16 +138,21 @@ function GenerateBotDialog({
|
|
|
138
138
|
setIsBotGenerating(true);
|
|
139
139
|
setErrorMessage("");
|
|
140
140
|
let response;
|
|
141
|
-
let promptWithTopic;
|
|
142
|
-
let promptWithTopicPhrases;
|
|
143
|
-
const topicPrompt = `The questions should be about the topic: '${values.botTopic}'. Focus primarily on the topic to ensure the questions are aligned with it. If there is no relevance or similarity between the topic and the provided phrases, only use the topic for generating questions.`;
|
|
144
|
-
const topicGoalPrompt = `These questions must specifically target the goal: '${topicGoal}’. The questions should only focus on the goal '${topicGoal}’. Avoid generating questions that ask about unrelated details.`;
|
|
145
|
-
bot.selectedTemplate === "nualang.quiz.0.0.1" ? promptWithTopic = `Create ${values.botLengthNumber} questions in ${learnLang} about the topic ${values.botTopic}. Have atleast one correct answer for each question. The questions should be appropriate for ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${bot & bot.difficulty} level learners. Questions and answers must be unique from one another. Return an array with ${values.botLengthNumber} objects inside it. Each object should have the keys questions and answer. The key question should equal to the question that is generated about the topic. The key answer should equal to the corresponding answer to the question, make sure that the answer text is inside brackets like this answer: "(questionAnswer)" if there is more than one correct answer the value of the answer key should be formatted like this answer: "(answer1|answer2)". Use this array as template: ${sampleQuestionArray} Your response should be in JSON.` : promptWithTopic = `Create ${values.botLengthNumber} open ended questions in ${learnLang} about the topic ${values.botTopic}. The questions should be appropriate for ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${bot & bot.difficulty} level learners. Each question must be unique. Return an array with ${values.botLengthNumber} objects inside it. Each object should have the key text. The key text should equal to the question that is generated about the topic. Your response should be in JSON.`;
|
|
146
|
-
bot.selectedTemplate === "nualang.quiz.0.0.1" ? promptWithTopicPhrases = `Create ${values.botLengthNumber} questions in ${learnLang}${values.botTopic.trim() === "" ? " using the following phrases as context to assist in the generations of questions." : "."} ${topicGoal.trim() !== "" ? topicGoalPrompt : ""} ${values.botTopic.trim() !== "" ? topicPrompt : ""} The questions should be appropriate for ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${bot & bot.difficulty} level learners. Include at least one correct answer for each question. Phrases for context: ${phrases}. Questions must be unique from one another. Return an array with ${values.botLengthNumber} objects inside it. Each object should have the keys questions and answer. The key question should equal to the question that is generated about the topic. The key answer should equal to the corresponding answer to the question, make sure that the answer text is inside brackets like this answer: "(questionAnswer)" if there is more than one correct answer the value of the answer key should be formatted like this answer: "(answer1|answer2)". Use this array as template: ${sampleQuestionArray} Your response should be in JSON.` : promptWithTopicPhrases = `Create ${values.botLengthNumber} questions in ${learnLang}${values.botTopic.trim() === "" ? " using the following phrases as context to assist in the generations of questions." : "."} ${topicGoal.trim() !== "" ? topicGoalPrompt : ""} ${values.botTopic.trim() !== "" ? topicPrompt : ""} The questions should be appropriate for ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${bot & bot.difficulty} level learners. Phrases for context: ${phrases}. Questions must be unique from one another. Return an array with ${values.botLengthNumber} objects inside it. Each object should have the key text. The key text should equal to the question that is generated about the topic. Your response should be in JSON.`;
|
|
147
|
-
const activePrompt = usePhrasesContext && phrases.length > 0 ? promptWithTopicPhrases : promptWithTopic;
|
|
148
141
|
let chatGptResponse = await makeChatGptApiRequest({
|
|
149
142
|
model: "gpt-3.5-turbo",
|
|
150
|
-
|
|
143
|
+
promptKey: "generateBot",
|
|
144
|
+
promptVariables: {
|
|
145
|
+
botTopic: values.botTopic,
|
|
146
|
+
topicGoal: topicGoal,
|
|
147
|
+
selectedTemplate: bot.selectedTemplate,
|
|
148
|
+
botLengthNumber: values.botLengthNumber,
|
|
149
|
+
learnLang: learnLang,
|
|
150
|
+
siteLanguage: siteLanguage,
|
|
151
|
+
difficulty: bot.difficulty,
|
|
152
|
+
sampleQuestionArray: sampleQuestionArray,
|
|
153
|
+
phrases: phrases,
|
|
154
|
+
usePhrasesContext: usePhrasesContext
|
|
155
|
+
}
|
|
151
156
|
});
|
|
152
157
|
response = chatGptResponse;
|
|
153
158
|
const jsonResponse = removeExtraTextFromChatGptResponse(response);
|
|
@@ -111,12 +111,21 @@ function GeneratePhrases({
|
|
|
111
111
|
try {
|
|
112
112
|
setIsGenerating(true);
|
|
113
113
|
setErrorMessage(null);
|
|
114
|
-
const goalPrompt = `The generated phrases must specifically target the following linguistic goal: '${values.topicGoal}'. Avoid generating phrases that do not align with this goal. `;
|
|
115
|
-
const prompt = phraseType === "sentences" ? isPhrases ? `The context is a language learning application. Here is a list of phrases or sentences in ${learnLang} and their translations in ${forLang}:\n\n${JSON.stringify(phrases)}\n\nNow, generate ${values.phraseAmount} more unique sentences in ${learnLang} and their translations in ${forLang} on the topic of '${values.phrasesTopic}' in the same JSON format as the ones that I have passed to you. The 'idx' field should contain an index integer which follows on incrementally from the existing phrases. The 'image' field should contain an empty string. Do not include a 'voices' field. ${values.topicGoal.trim() ? goalPrompt : ""}The sentences should be unique and not already in the list. The sentences should be appropriate for ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${difficulty} level. Ensure the formatting of the JSON response is correct and follows this structure.` : `The context is a language learning application. Generate ${values.phraseAmount} unique phrases or sentences in ${learnLang} and their translations in ${forLang} on the topic of '${values.phrasesTopic}'. Return the sentences inside a JSON array of ${values.phraseAmount} objects, each with the following fields: 'phrase', 'translations', 'idx', and 'image'. Each field is required and cannot be omitted. The 'idx' field represents the index of the phrases, starting from 0 and going up by 1 up until the last phrase. The 'image' field should contain an empty string. The 'translations' field should be an array of at least one translation of the sentence in ${forLang}, but it can contain more translations as long as they are grammatically correct. ${values.topicGoal.trim() ? goalPrompt : ""}The sentences should be appropriate for the ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${difficulty} level. The sentences should be unique. Ensure the formatting of the JSON response is correct and follows this structure.` : isPhrases ? `The context is a language learning application. Here is a list of words or very short lexical phrases in ${learnLang} and their translations in ${forLang}:\n\n${JSON.stringify(phrases)}\n\nNow, generate ${values.phraseAmount} more unique words or very short lexical phrases and their translations in ${learnLang} on the topic of '${values.phrasesTopic}'. The input may resemble a script or contain dialogue, but do not generate words or very short lexical phrases formatted as scripts or sentences. Focus only on single words or very short lexical phrases. The 'idx' field should contain an index integer which follows on incrementally from the existing phrases. The 'image' field should contain an empty string. Do not include a 'voices' field. ${values.topicGoal.trim() ? goalPrompt : ""}The words or lexical phrases should be unique and not already in the list. The words or lexical phrases should be ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${difficulty} level. Ensure the formatting of the JSON response is correct and follows this structure.` : `The context is a language learning application. Generate ${values.phraseAmount} unique words or very short lexical phrases in ${learnLang} and their translations in ${forLang} on the topic of '${values.phrasesTopic}'. Return the unique words or very short lexical phrases inside a JSON array of ${values.phraseAmount} objects, each with the following fields: 'phrase', 'translations', 'idx', and 'image'. Each field is required and cannot be omitted. The 'idx' field represents the index of the phrases, starting from 0 and going up by 1 up until the last phrase. The 'image' field should contain an empty string. The 'translations' field should be an array of at least one translation of the phrase in ${forLang}, but it can contain more translations as long as they are grammatically correct. ${values.topicGoal.trim() ? goalPrompt : ""}The input may resemble a script or contain dialogue, but do not interpret or format the input as a script or sentences. Focus only on generating single words or very short lexical phrases. The words or very short lexical phrases should be appropriate for the ${["en-US"].includes(siteLanguage) ? "ACTFL" : "CEFR"} ${difficulty} level. The words or very short lexical phrases should be unique. Ensure the formatting of the JSON response is correct and follows this structure.`;
|
|
116
|
-
// console.log("prompt: ", prompt);
|
|
117
114
|
const chatGptResponse = await makeChatGptApiRequest({
|
|
118
115
|
model: "gpt-3.5-turbo",
|
|
119
|
-
|
|
116
|
+
promptKey: "generatePhrases",
|
|
117
|
+
promptVariables: {
|
|
118
|
+
topicGoal: values.topicGoal,
|
|
119
|
+
learnLang,
|
|
120
|
+
forLang,
|
|
121
|
+
phraseAmount: values.phraseAmount,
|
|
122
|
+
phrasesTopic: values.phrasesTopic,
|
|
123
|
+
siteLanguage,
|
|
124
|
+
difficulty,
|
|
125
|
+
phraseType,
|
|
126
|
+
isPhrases,
|
|
127
|
+
phrases
|
|
128
|
+
}
|
|
120
129
|
});
|
|
121
130
|
const phrasesArray = extractPhrasesArray(chatGptResponse);
|
|
122
131
|
const parsedPhrases = JSON.parse(phrasesArray);
|
|
@@ -87,10 +87,18 @@ function GenerateQuestion({
|
|
|
87
87
|
try {
|
|
88
88
|
setIsMessageGenerating(true);
|
|
89
89
|
setErrorMessage(null);
|
|
90
|
-
const prompt = `Here is a script: ${JSON.stringify(script)}. Refer to Actor 1 as ${values.actor1.name} and Actor 2 as ${values.actor2.name} in the question and the answers. The purpose of this script is to test the reader's ability to read in ${finalLearnLang}. The reader's native language is ${finalForLang}. Please generate a new comprehension question based on the script that is completely unique to any existing questions, preferably referring to a unique part of the script if possible, and provide it in JSON format with the keys 'question' and 'answers'. The 'question' key has the value of the string contraining the question text. The 'answers' key is an array of objects, where each answer object contains 'text', 'correct', and 'type' keys. The type should always be 'multichoice'. There are four possible question types, 'factual', 'inference', 'truefalse' and 'vocabulary'. For factual questions, ensure the new question is explicitly answered by the script, to test the reader's understanding of the script. For inference questions, ensure the new question requires the reader to make an assumption based on the script. For true/false questions, ensure the new question can be answered with a true or false response. For vocabulary questions, ensure the new question tests the reader's understanding of a specific ${finalLearnLang} word or phrase used in the script, to test whether the reader can understand it. Vocabulary questions do not necessarily have to take the context of the conversation into account, they are merely to test the reader's ${finalLearnLang} vocabulary. The question type for this particular question to generate is ${questionType}. The question and answers should be generated in ${questionLanguage}.`;
|
|
91
90
|
const chatGptResponse = await makeChatGptApiRequest({
|
|
92
91
|
model: "gpt-3.5-turbo",
|
|
93
|
-
|
|
92
|
+
promptKey: "generateAnswer",
|
|
93
|
+
promptVariables: {
|
|
94
|
+
script,
|
|
95
|
+
actor1: values.actor1,
|
|
96
|
+
actor2: values.actor2,
|
|
97
|
+
finalLearnLang: finalLearnLang,
|
|
98
|
+
finalForLang: finalForLang,
|
|
99
|
+
questionType,
|
|
100
|
+
questionLanguage
|
|
101
|
+
}
|
|
94
102
|
});
|
|
95
103
|
const jsonResponse = extractJsonObject(chatGptResponse);
|
|
96
104
|
const newQuestion = JSON.parse(jsonResponse);
|
|
@@ -181,8 +181,6 @@ function GenerateRoleplayDialog({
|
|
|
181
181
|
setErrorMessage("");
|
|
182
182
|
let response;
|
|
183
183
|
const roleplayDifficulty = values.roleplayDifficulty;
|
|
184
|
-
// console.log("Roleplay Difficulty:", roleplayDifficulty);
|
|
185
|
-
|
|
186
184
|
const basePrompt = usePdfContext ? `Create an informative conversation between 2 people ${values?.actor1?.name && values?.actor2?.name ? `'${values.actor1.name}' and '${values.actor2.name}' ` : ""} about the topic '${values.roleplayTopic}' in the language ${learnLang}. The conversation should be ${i18nLanguage === "en-US" ? "ACTFL" : "CEFR"} level '${t(roleplayDifficulty)}.'` : `Create a conversation between 2 people ${values?.actor1?.name && values?.actor2?.name ? `'${values.actor1.name}' and '${values.actor2?.name}' ` : ""} about the topic '${values.roleplayTopic}' in the language ${learnLang}. The conversation should be ${i18nLanguage === "en-US" ? "ACTFL" : "CEFR"} level '${t(roleplayDifficulty)}.'`;
|
|
187
185
|
const topicGoalPrompt = topicGoal ? ` The conversation should be guided by the following goal: '${topicGoal}'.` : "";
|
|
188
186
|
const promptWithPhrases = usePhrasesContext ? ` Additionally, use the following phrases as part of the conversation, where appropriate to the topic '${values.roleplayTopic}': ${phrases.map(phrase => phrase.phrase).join(", ")}. Only use these phrases if they fit naturally into the conversation.` : "";
|
|
@@ -192,10 +190,6 @@ function GenerateRoleplayDialog({
|
|
|
192
190
|
const promptWithoutQuestions = usePdfContext ? `${finalPrompt} The conversation should be returned as a single JSON array. The array must contain exactly ${values.roleplayLengthNumber} exchanges (lines). Each piece of dialogue should be represented as an object with the keys 'actor' and 'text'. The 'actor' key should be set to 1 if the dialogue is spoken by the first actor, and 2 if it is spoken by the second actor. The 'text' key should be set to the dialogue text spoken by that actor. Please ensure the entire output is formatted as a single, well-formed JSON array.` : `${finalPrompt} The conversation should be returned as a single JSON array. The array must contain exactly ${values.roleplayLengthNumber} exchanges (lines). Each piece of dialogue should be represented as an object with the keys 'actor' and 'text'. The 'actor' key should be set to 1 if the dialogue is spoken by the first actor, and 2 if it is spoken by the second actor. The 'text' key should be set to the dialogue text spoken by that actor. Please ensure the entire output is formatted as a single, well-formed JSON array.`;
|
|
193
191
|
const promptWithQuestions = usePdfContext ? `${finalPrompt} The conversation should be returned as a single JSON array. The array must contain exactly ${values.roleplayLengthNumber} exchanges (lines), followed by ${values?.questionsAmount} comprehension questions related to the conversation, the question should be generated in ${questionLang}. Each piece of dialogue should be represented as an object with the keys 'actor' and 'text'. The 'actor' key should be set to 1 if the dialogue is spoken by the first actor, and 2 if it is spoken by the second actor. The 'text' key should be set to the dialogue text spoken by that actor. Each comprehension question should also be represented as an object within the same array, with the keys 'question' and 'answers'. The 'answers' key should be an array of 3 objects, each containing 'text', 'correct' (true or false), and 'type' ('correct' or 'incorrect'), the answers should be generated in ${questionLang}. Please ensure the entire output is formatted as a single, well-formed JSON array.` : `${finalPrompt} The conversation should be returned as a single JSON array. The array must contain exactly ${values.roleplayLengthNumber} exchanges (lines), followed by ${values?.questionsAmount} comprehension questions related to the conversation, the question should be generated in ${questionLang}. Each piece of dialogue should be represented as an object with the keys 'actor' and 'text'. The 'actor' key should be set to 1 if the dialogue is spoken by the first actor, and 2 if it is spoken by the second actor. The 'text' key should be set to the dialogue text spoken by that actor. Each comprehension question should also be represented as an object within the same array, with the keys 'question' and 'answers'. The 'answers' key should be an array of 3 objects, each containing 'text', 'correct' (true or false), and 'type' ('correct' or 'incorrect'), the answers should be generated in ${questionLang}. Please ensure the entire output is formatted as a single, well-formed JSON array.`;
|
|
194
192
|
const activePrompt = generateQuestions ? promptWithQuestions : promptWithoutQuestions;
|
|
195
|
-
|
|
196
|
-
// console.log("Final Prompt Sent to API:", activePrompt);
|
|
197
|
-
|
|
198
|
-
// Call the API and handle the response as before
|
|
199
193
|
if (usePdfContext) {
|
|
200
194
|
const getAiQueryResponse = await makeCandooAIQuery({
|
|
201
195
|
modelName: "gpt-4",
|
|
@@ -218,7 +212,23 @@ function GenerateRoleplayDialog({
|
|
|
218
212
|
} else {
|
|
219
213
|
let chatGptResponse = await makeChatGptApiRequest({
|
|
220
214
|
model: "gpt-3.5-turbo",
|
|
221
|
-
|
|
215
|
+
promptKey: "generateRoleplay",
|
|
216
|
+
promptVariables: {
|
|
217
|
+
learnLang: learnLang,
|
|
218
|
+
i18nLanguage: i18nLanguage,
|
|
219
|
+
roleplayDifficulty: t(values.roleplayDifficulty),
|
|
220
|
+
usePdfContext: usePdfContext,
|
|
221
|
+
topicGoal: topicGoal,
|
|
222
|
+
usePhrasesContext: usePhrasesContext,
|
|
223
|
+
phrases: phrases,
|
|
224
|
+
questionLang: questionLang,
|
|
225
|
+
generateQuestions: generateQuestions,
|
|
226
|
+
actor1: values.actor1,
|
|
227
|
+
actor2: values.actor2,
|
|
228
|
+
roleplayTopic: values.roleplayTopic,
|
|
229
|
+
roleplayLengthNumber: values.roleplayLengthNumber,
|
|
230
|
+
questionsAmount: values.questionsAmount
|
|
231
|
+
}
|
|
222
232
|
});
|
|
223
233
|
let isComplete = false;
|
|
224
234
|
while (!isComplete) {
|
|
@@ -236,7 +246,6 @@ function GenerateRoleplayDialog({
|
|
|
236
246
|
}
|
|
237
247
|
|
|
238
248
|
// Log the full response for debugging
|
|
239
|
-
// console.log("Full API Response:", response);
|
|
240
249
|
|
|
241
250
|
const jsonResponse = removeExtraTextFromChatGptResponse(response);
|
|
242
251
|
const roleplayScript = fixMissingComma(jsonResponse);
|
|
@@ -21,6 +21,9 @@ const useStyles = (0, _mui.makeStyles)()(theme => ({
|
|
|
21
21
|
margin: theme.spacing(1)
|
|
22
22
|
},
|
|
23
23
|
language: {
|
|
24
|
+
[theme.breakpoints.down("lg")]: {
|
|
25
|
+
display: "none"
|
|
26
|
+
},
|
|
24
27
|
marginTop: "auto",
|
|
25
28
|
marginBottom: "auto",
|
|
26
29
|
marginLeft: theme.spacing(1),
|
|
@@ -114,7 +117,7 @@ function LanguageSelector({
|
|
|
114
117
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Translate.default, {})
|
|
115
118
|
})
|
|
116
119
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Hidden, {
|
|
117
|
-
|
|
120
|
+
mdDown: true,
|
|
118
121
|
implementation: "js",
|
|
119
122
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
120
123
|
className: classes.language,
|
|
@@ -155,11 +155,21 @@ function useRecognition(props = {}) {
|
|
|
155
155
|
const initRecording = async (gcloudParams, onData, onError) => {
|
|
156
156
|
try {
|
|
157
157
|
await setupAudioContext();
|
|
158
|
+
const {
|
|
159
|
+
mediaDevices
|
|
160
|
+
} = navigator;
|
|
161
|
+
const [availableMicrophones, activeMicrophone, sampleRate] = await (0, _index.getMicrophoneInfo)(mediaDevices);
|
|
162
|
+
let sampleRateToUse = sampleRate;
|
|
163
|
+
if (sampleRate && sampleRate < 8000) {
|
|
164
|
+
sampleRateToUse = 8000;
|
|
165
|
+
} else if (sampleRate && sampleRate > 48000) {
|
|
166
|
+
sampleRateToUse = 48000;
|
|
167
|
+
}
|
|
158
168
|
const handleSuccess = function (stream) {
|
|
159
169
|
const gcloudConfig = {
|
|
160
170
|
config: {
|
|
161
171
|
encoding: "LINEAR16",
|
|
162
|
-
sampleRateHertz: 16000,
|
|
172
|
+
sampleRateHertz: sampleRateToUse || 16000,
|
|
163
173
|
languageCode: gcloudParams.languageCode || "en-US",
|
|
164
174
|
profanityFilter: true,
|
|
165
175
|
enableWordTimeOffsets: false,
|
|
@@ -172,7 +182,6 @@ function useRecognition(props = {}) {
|
|
|
172
182
|
interimResults: gcloudParams.interimResults // If you want interim results, set this to true
|
|
173
183
|
};
|
|
174
184
|
socket.emit("startGoogleCloudStream", gcloudConfig, version); // init socket Google Speech Connection
|
|
175
|
-
|
|
176
185
|
streamRef.current = stream;
|
|
177
186
|
audioInputRef.current = audioContextRef.current.createMediaStreamSource(stream);
|
|
178
187
|
serverErrorRef.current = null;
|
package/dist/utils/index.js
CHANGED
|
@@ -446,7 +446,7 @@ const getMachineInfo = userAgent => {
|
|
|
446
446
|
exports.getMachineInfo = getMachineInfo;
|
|
447
447
|
const getMicrophoneInfo = async mediaDevices => {
|
|
448
448
|
try {
|
|
449
|
-
await mediaDevices.getUserMedia({
|
|
449
|
+
const stream = await mediaDevices.getUserMedia({
|
|
450
450
|
audio: true
|
|
451
451
|
});
|
|
452
452
|
const devices = await mediaDevices.enumerateDevices();
|
|
@@ -454,7 +454,13 @@ const getMicrophoneInfo = async mediaDevices => {
|
|
|
454
454
|
const availableMicrophoneNames = microphones?.filter(device => device.deviceId !== "default").map(device => device.label).join(", ") || "No available microphones detected";
|
|
455
455
|
const activeMicrophone = microphones?.length > 0 ? microphones.find(mic => mic.deviceId === "default") || microphones[0] : null;
|
|
456
456
|
const activeMicrophoneName = activeMicrophone?.label.split("Default - ").pop() || "No active microphone detected";
|
|
457
|
-
|
|
457
|
+
|
|
458
|
+
// Create an AudioContext with the stream from the active microphone
|
|
459
|
+
const sampleRate = stream.getAudioTracks()[0].getSettings().sampleRate;
|
|
460
|
+
|
|
461
|
+
// Stop the audio stream to release the microphone
|
|
462
|
+
stream.getTracks().forEach(track => track.stop());
|
|
463
|
+
return [availableMicrophoneNames, activeMicrophoneName, sampleRate];
|
|
458
464
|
} catch (error) {
|
|
459
465
|
console.error("Error accessing the microphone:", error);
|
|
460
466
|
}
|