Fix (#1297)
* update yarn * fix dep * upgrade deps * fix document config save * fix #1293 * support long recording assessment * fix bugsnag * fix style * fix #1288 * fix bugsnag config
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -4,4 +4,4 @@ nmHoistingLimits: workspaces
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.5.3.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.6.0.cjs
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"markdown-it-sub": "^2.0.0",
|
||||
"markdown-it-sup": "^2.0.0",
|
||||
"mermaid": "^11.4.1",
|
||||
"sass": "^1.83.4",
|
||||
"vitepress": "^1.5.0",
|
||||
"sass": "^1.85.0",
|
||||
"vitepress": "^1.6.3",
|
||||
"vitepress-plugin-mermaid": "^2.0.17",
|
||||
"vue": "^3.5.13"
|
||||
},
|
||||
@@ -21,6 +21,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0",
|
||||
"swiper": "^11.2.1"
|
||||
"swiper": "^11.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/seo": "^2.0.3",
|
||||
"nuxt": "^3.15.1",
|
||||
"nuxt-og-image": "^4.0.3",
|
||||
"@nuxtjs/seo": "^2.2.0",
|
||||
"nuxt": "^3.15.4",
|
||||
"nuxt-og-image": "^4.1.4",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.5.1",
|
||||
"sass": "^1.83.4",
|
||||
"postcss": "^8.5.3",
|
||||
"sass": "^1.85.0",
|
||||
"tailwindcss": "^3.4.17"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { VitePlugin } from "@electron-forge/plugin-vite";
|
||||
import os from "os";
|
||||
import { FusesPlugin } from "@electron-forge/plugin-fuses";
|
||||
import { FuseV1Options, FuseVersion } from "@electron/fuses";
|
||||
import { DependenciesPlugin } from "electron-forge-plugin-dependencies";
|
||||
import pkg from "./package.json" assert { type: "json" };
|
||||
import pkg from "./package.json" with { type: "json" };
|
||||
|
||||
const config = {
|
||||
packagerConfig: {
|
||||
|
||||
@@ -32,62 +32,63 @@
|
||||
"devDependencies": {
|
||||
"@bugsnag/source-maps": "^2.3.3",
|
||||
"@divisey/js-mdict": "^5.0.0",
|
||||
"@electron-forge/cli": "^7.6.0",
|
||||
"@electron-forge/maker-deb": "^7.6.0",
|
||||
"@electron-forge/maker-dmg": "^7.6.0",
|
||||
"@electron-forge/maker-rpm": "^7.6.0",
|
||||
"@electron-forge/maker-squirrel": "^7.6.0",
|
||||
"@electron-forge/maker-zip": "^7.6.0",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "^7.6.0",
|
||||
"@electron-forge/plugin-fuses": "^7.6.0",
|
||||
"@electron-forge/plugin-vite": "7.6.0",
|
||||
"@electron-forge/publisher-github": "^7.6.0",
|
||||
"@electron-forge/publisher-s3": "^7.6.0",
|
||||
"@electron-forge/cli": "^7.7.0",
|
||||
"@electron-forge/maker-deb": "^7.7.0",
|
||||
"@electron-forge/maker-dmg": "^7.7.0",
|
||||
"@electron-forge/maker-rpm": "^7.7.0",
|
||||
"@electron-forge/maker-squirrel": "^7.7.0",
|
||||
"@electron-forge/maker-zip": "^7.7.0",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "^7.7.0",
|
||||
"@electron-forge/plugin-fuses": "^7.7.0",
|
||||
"@electron-forge/plugin-vite": "7.7.0",
|
||||
"@electron-forge/publisher-github": "^7.7.0",
|
||||
"@electron-forge/publisher-s3": "^7.7.0",
|
||||
"@electron/fuses": "^1.8.0",
|
||||
"@hookform/resolvers": "^3.10.0",
|
||||
"@langchain/community": "^0.3.24",
|
||||
"@langchain/core": "^0.3.30",
|
||||
"@langchain/ollama": "^0.1.4",
|
||||
"@langchain/community": "^0.3.32",
|
||||
"@langchain/core": "^0.3.40",
|
||||
"@langchain/ollama": "^0.2.0",
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@radix-ui/react-accordion": "^1.2.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.4",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.1",
|
||||
"@radix-ui/react-avatar": "^1.1.2",
|
||||
"@radix-ui/react-checkbox": "^1.1.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.2",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
||||
"@radix-ui/react-hover-card": "^1.1.4",
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
||||
"@radix-ui/react-avatar": "^1.1.3",
|
||||
"@radix-ui/react-checkbox": "^1.1.4",
|
||||
"@radix-ui/react-collapsible": "^1.1.3",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-hover-card": "^1.1.6",
|
||||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-label": "^2.1.1",
|
||||
"@radix-ui/react-menubar": "^1.1.4",
|
||||
"@radix-ui/react-popover": "^1.1.4",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
"@radix-ui/react-radio-group": "^1.2.2",
|
||||
"@radix-ui/react-scroll-area": "^1.2.2",
|
||||
"@radix-ui/react-select": "^2.1.4",
|
||||
"@radix-ui/react-separator": "^1.1.1",
|
||||
"@radix-ui/react-slider": "^1.2.2",
|
||||
"@radix-ui/react-slot": "^1.1.1",
|
||||
"@radix-ui/react-switch": "^1.1.2",
|
||||
"@radix-ui/react-tabs": "^1.1.2",
|
||||
"@radix-ui/react-toast": "^1.2.4",
|
||||
"@radix-ui/react-toggle": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-menubar": "^1.1.6",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slider": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-toast": "^1.2.6",
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@rails/actioncable": "8.0.100",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/ahoy.js": "^0.4.2",
|
||||
"@types/autosize": "^4.0.3",
|
||||
"@types/command-exists": "^1.2.3",
|
||||
"@types/diff": "^7",
|
||||
"@types/electron-squirrel-startup": "^1.0.2",
|
||||
"@types/fluent-ffmpeg": "^2.1.27",
|
||||
"@types/html-to-text": "^9.0.4",
|
||||
"@types/intl-tel-input": "^18.1.4",
|
||||
"@types/lodash": "^4.17.14",
|
||||
"@types/lodash": "^4.17.15",
|
||||
"@types/mark.js": "^8.11.12",
|
||||
"@types/mime-types": "^2.1.4",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": "^22.10.6",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/prop-types": "^15.7.14",
|
||||
"@types/rails__actioncable": "^6.1.11",
|
||||
"@types/react": "^18.3.18",
|
||||
@@ -97,8 +98,8 @@
|
||||
"@types/unzipper": "^0.10.10",
|
||||
"@types/validator": "^13.12.2",
|
||||
"@types/wavesurfer.js": "^6.0.12",
|
||||
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
||||
"@typescript-eslint/parser": "^8.20.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.24.1",
|
||||
"@typescript-eslint/parser": "^8.24.1",
|
||||
"@uidotdev/usehooks": "^2.4.1",
|
||||
"@vidstack/react": "^1.12.12",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
@@ -108,72 +109,73 @@
|
||||
"axios": "^1.7.9",
|
||||
"camelcase": "^8.0.0",
|
||||
"camelcase-keys": "^9.1.3",
|
||||
"chart.js": "^4.4.7",
|
||||
"chart.js": "^4.4.8",
|
||||
"cheerio": "^1.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.4",
|
||||
"command-exists": "^1.2.9",
|
||||
"compromise": "^14.14.3",
|
||||
"compromise": "^14.14.4",
|
||||
"compromise-paragraphs": "^0.1.0",
|
||||
"compromise-stats": "^0.1.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"decamelize": "^6.0.0",
|
||||
"decamelize-keys": "^2.0.1",
|
||||
"dependencies-tree": "^2.0.0",
|
||||
"electron": "^34.0.0",
|
||||
"electron-context-menu": "^4.0.4",
|
||||
"diff": "^7.0.0",
|
||||
"electron": "^34.2.0",
|
||||
"electron-context-menu": "^4.0.5",
|
||||
"electron-devtools-installer": "^4.0.0",
|
||||
"electron-forge-plugin-dependencies": "^1.0.0",
|
||||
"electron-log": "^5.2.4",
|
||||
"electron-log": "^5.3.0",
|
||||
"electron-playwright-helpers": "^1.7.1",
|
||||
"electron-squirrel-startup": "^1.0.1",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-import-resolver-typescript": "^3.7.0",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-import-resolver-typescript": "^3.8.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"flora-colossus": "^2.0.0",
|
||||
"foliate-js": "https://github.com/johnfactotum/foliate-js.git#commit=b5ae4c22c197ef70e12ead88277dde2856447634",
|
||||
"foliate-js": "https://github.com/johnfactotum/foliate-js.git",
|
||||
"html-to-text": "^9.0.5",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"i18next": "^24.2.1",
|
||||
"i18next": "^24.2.2",
|
||||
"input-otp": "^1.4.2",
|
||||
"intl-tel-input": "^25.2.1",
|
||||
"intl-tel-input": "^25.3.0",
|
||||
"js-md5": "^0.8.3",
|
||||
"langchain": "^0.3.11",
|
||||
"langchain": "^0.3.19",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-cache": "^11.0.2",
|
||||
"lucide-react": "^0.471.1",
|
||||
"lucide-react": "^0.475.0",
|
||||
"mark.js": "^8.11.1",
|
||||
"media-captions": "^0.0.18",
|
||||
"microsoft-cognitiveservices-speech-sdk": "^1.42.0",
|
||||
"mime-types": "^2.1.35",
|
||||
"mustache": "^4.2.0",
|
||||
"next-themes": "^0.4.4",
|
||||
"octokit": "^4.1.0",
|
||||
"openai": "^4.78.1",
|
||||
"octokit": "^4.1.2",
|
||||
"openai": "^4.85.4",
|
||||
"pitchfinder": "^2.3.2",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss": "^8.5.3",
|
||||
"progress": "^2.0.3",
|
||||
"prop-types": "^15.8.1",
|
||||
"proxy-agent": "^6.5.0",
|
||||
"react": "^18.3.1",
|
||||
"react-activity-calendar": "^2.7.7",
|
||||
"react-activity-calendar": "^2.7.8",
|
||||
"react-audio-visualize": "^1.2.0",
|
||||
"react-audio-voice-recorder": "^2.2.0",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-frame-component": "^5.2.7",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-hotkeys-hook": "^4.6.1",
|
||||
"react-i18next": "^15.4.0",
|
||||
"react-markdown": "^9.0.3",
|
||||
"react-i18next": "^15.4.1",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-router-dom": "^7.2.0",
|
||||
"react-shadow-root": "^6.2.0",
|
||||
"react-tooltip": "^5.28.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-gfm": "^4.0.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"semver": "^7.6.3",
|
||||
"sonner": "^1.7.1",
|
||||
"semver": "^7.7.1",
|
||||
"sonner": "^1.7.4",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwind-scrollbar-hide": "^2.0.0",
|
||||
@@ -183,23 +185,23 @@
|
||||
"tslib": "^2.8.1",
|
||||
"turndown": "^7.2.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.0.7",
|
||||
"vite": "^6.1.1",
|
||||
"vite-plugin-static-copy": "^2.2.0",
|
||||
"wavesurfer.js": "^7.8.16",
|
||||
"zod": "^3.24.1",
|
||||
"zod-to-json-schema": "^3.24.1",
|
||||
"zx": "^8.3.0"
|
||||
"wavesurfer.js": "^7.9.1",
|
||||
"zod": "^3.24.2",
|
||||
"zod-to-json-schema": "^3.24.3",
|
||||
"zx": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@andrkrn/ffprobe-static": "^5.2.0",
|
||||
"@bugsnag/electron": "^8.1.2",
|
||||
"@bugsnag/plugin-react": "^8.1.1",
|
||||
"@bugsnag/electron": "^8.2.0",
|
||||
"@bugsnag/plugin-react": "^8.2.0",
|
||||
"echogarden": "^1.8.7",
|
||||
"electron-settings": "^4.0.4",
|
||||
"ffmpeg-static": "^5.2.0",
|
||||
"file-type": "^19.6.0",
|
||||
"fluent-ffmpeg": "^2.1.3",
|
||||
"fs-extra": "^11.2.0",
|
||||
"fs-extra": "^11.3.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sequelize": "^6.37.5",
|
||||
"sequelize-typescript": "^2.1.6",
|
||||
|
||||
@@ -119,8 +119,6 @@ export const AGENT_FIXTURE_ANDREW = {
|
||||
},
|
||||
};
|
||||
|
||||
export const BUGSNAG_API_KEY = "828ee1de10c079a250be7fd05177662f";
|
||||
|
||||
export const MIME_TYPES: Record<string, string> = {
|
||||
".mp3": "audio/mpeg",
|
||||
".wav": "audio/wav",
|
||||
|
||||
@@ -940,5 +940,6 @@
|
||||
"copyFullText": "Copy full text",
|
||||
"checkingForUpdate": "Checking for update",
|
||||
"updateAvailable": "Update available",
|
||||
"quitAndInstall": "Quit and install"
|
||||
"quitAndInstall": "Quit and install",
|
||||
"pleaseSelect": "Please select"
|
||||
}
|
||||
|
||||
@@ -940,5 +940,6 @@
|
||||
"copyFullText": "复制全文",
|
||||
"checkingForUpdate": "正在检查更新",
|
||||
"updateAvailable": "有新版本",
|
||||
"quitAndInstall": "退出并安装新版本"
|
||||
"quitAndInstall": "退出并安装新版本",
|
||||
"pleaseSelect": "请选择"
|
||||
}
|
||||
|
||||
@@ -8,19 +8,35 @@ import ElectronSquirrelStartup from "electron-squirrel-startup";
|
||||
import contextMenu from "electron-context-menu";
|
||||
import Bugsnag from "@bugsnag/electron";
|
||||
import { t } from "i18next";
|
||||
import { BUGSNAG_API_KEY } from "./constants";
|
||||
import { Client } from "./api";
|
||||
|
||||
const logger = log.scope("main");
|
||||
|
||||
const initBugsnag = async () => {
|
||||
if (!app.isPackaged) return;
|
||||
const webApi = new Client({
|
||||
baseUrl: settings.apiUrl(),
|
||||
logger,
|
||||
});
|
||||
try {
|
||||
const apiKey = await webApi.config("bugsnag_api_key");
|
||||
if (!apiKey) return;
|
||||
|
||||
Bugsnag.start({ apiKey: apiKey.bugsnagApiKey });
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
app.commandLine.appendSwitch("enable-features", "SharedArrayBuffer");
|
||||
|
||||
if (app.isPackaged) {
|
||||
Bugsnag.start({ apiKey: BUGSNAG_API_KEY });
|
||||
} else {
|
||||
if (!app.isPackaged) {
|
||||
app.disableHardwareAcceleration();
|
||||
app.commandLine.appendSwitch("disable-software-rasterizer");
|
||||
}
|
||||
|
||||
initBugsnag();
|
||||
|
||||
// Add context menu
|
||||
contextMenu({
|
||||
showSearchWithGoogle: false,
|
||||
|
||||
@@ -21,12 +21,7 @@ import {
|
||||
UserSetting,
|
||||
} from "@main/db/models";
|
||||
import settings from "@main/settings";
|
||||
import {
|
||||
AudioFormats,
|
||||
MIME_TYPES,
|
||||
VideoFormats,
|
||||
WEB_API_URL,
|
||||
} from "@/constants";
|
||||
import { AudioFormats, MIME_TYPES, VideoFormats } from "@/constants";
|
||||
import { hashFile } from "@main/utils";
|
||||
import path from "path";
|
||||
import fs from "fs-extra";
|
||||
|
||||
@@ -28,7 +28,7 @@ import decompresser from "./decompresser";
|
||||
import { UserSetting } from "@main/db/models";
|
||||
import { t } from "i18next";
|
||||
import { format } from "util";
|
||||
import pkg from "../../package.json" assert { type: "json" };
|
||||
import pkg from "../../package.json" with { type: "json" };
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
|
||||
|
||||
@@ -14,18 +14,27 @@ import { Tooltip } from "react-tooltip";
|
||||
import { LookupWidget, TranslateWidget } from "./components";
|
||||
import Bugsnag from "@bugsnag/electron";
|
||||
import BugsnagPluginReact from "@bugsnag/plugin-react";
|
||||
import { BUGSNAG_API_KEY } from "@/constants";
|
||||
import { Client } from "@/api";
|
||||
import { WEB_API_URL } from "@/constants";
|
||||
|
||||
function App() {
|
||||
window.__ENJOY_APP__.app.isPackaged().then((isPackaged) => {
|
||||
if (isPackaged) {
|
||||
window.__ENJOY_APP__.app.isPackaged().then(async (isPackaged) => {
|
||||
if (!isPackaged) return;
|
||||
const client = new Client({
|
||||
baseUrl: WEB_API_URL,
|
||||
});
|
||||
try {
|
||||
const config = await client.config("bugsnag_api_key");
|
||||
if (!config?.bugsnagApiKey) return;
|
||||
|
||||
Bugsnag.start({
|
||||
apiKey: BUGSNAG_API_KEY,
|
||||
apiKey: config.bugsnagApiKey,
|
||||
plugins: [new BugsnagPluginReact()],
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
window.__ENJOY_APP__.onNotification((_event, notification) => {
|
||||
switch (notification.type) {
|
||||
case "success":
|
||||
|
||||
@@ -107,7 +107,7 @@ export const AudibleBooksSegment = () => {
|
||||
</div>
|
||||
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{books.map((book) => {
|
||||
return (
|
||||
<AudioBookCard
|
||||
|
||||
@@ -65,8 +65,8 @@ export const AudiosSegment = (props: { limit?: number }) => {
|
||||
<MediaAddButton type="Audio" />
|
||||
</div>
|
||||
) : (
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<ScrollArea className="w-full">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{audios.map((audio) => {
|
||||
return (
|
||||
<AudioCard className="w-36" key={audio.id} audio={audio} />
|
||||
|
||||
@@ -43,7 +43,7 @@ export const EnrollmentSegment = () => {
|
||||
</div>
|
||||
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{enrollments.map((enrollment) => {
|
||||
return (
|
||||
<CourseCard
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Readability } from "@mozilla/readability";
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
export const DocumentAddButton = () => {
|
||||
const { EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
const { EnjoyApp, learningLanguage } = useContext(AppSettingsProviderContext);
|
||||
const navigate = useNavigate();
|
||||
const [uri, setUri] = useState("");
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -52,9 +52,11 @@ export const DocumentAddButton = () => {
|
||||
config: {
|
||||
autoTranslate: false,
|
||||
autoNextSpeech: true,
|
||||
layout: "horizontal",
|
||||
tts: {
|
||||
engine: "enjoyai",
|
||||
model: "openai/tts-1",
|
||||
language: learningLanguage,
|
||||
voice: "alloy",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -39,6 +39,12 @@ export const DocumentConfigForm = (props: {
|
||||
onSubmit: (data: z.infer<typeof documentConfigSchema>) => Promise<void>;
|
||||
}) => {
|
||||
const { config, onSubmit } = props;
|
||||
if (!config?.layout) {
|
||||
config.layout = "horizontal";
|
||||
}
|
||||
if (config?.tts && !config?.tts?.language) {
|
||||
config.tts.language = "en-US";
|
||||
}
|
||||
const [submitting, setSubmitting] = useState<boolean>(false);
|
||||
const { ttsConfig } = useContext(AISettingsProviderContext);
|
||||
|
||||
@@ -106,7 +112,7 @@ export const DocumentConfigForm = (props: {
|
||||
<FormLabel>{t("layout")}</FormLabel>
|
||||
<Select value={field.value} onValueChange={field.onChange}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={t("horizontal")} />
|
||||
<SelectValue placeholder={t("pleaseSelect")} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="horizontal">
|
||||
|
||||
@@ -39,7 +39,7 @@ export const DocumentsSegment = () => {
|
||||
</div>
|
||||
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{documents.map((document) => (
|
||||
<DocumentCard
|
||||
key={document.id}
|
||||
|
||||
@@ -66,7 +66,7 @@ export const VideosSegment = (props: { limit?: number }) => {
|
||||
</div>
|
||||
) : (
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{videos.map((video) => {
|
||||
return (
|
||||
<VideoCard className="w-56" key={video.id} video={video} />
|
||||
|
||||
@@ -99,7 +99,7 @@ export const YoutubeVideosSegment = (props: { channel: string }) => {
|
||||
<div className="ml-auto mr-4"></div>
|
||||
</div>
|
||||
<ScrollArea>
|
||||
<div className="flex items-center space-x-4 pb-4">
|
||||
<div className="flex w-max items-center space-x-4 pb-4">
|
||||
{videos.map((video) => {
|
||||
return (
|
||||
<YoutubeVideoCard
|
||||
|
||||
@@ -27,6 +27,8 @@ import {
|
||||
import { t } from "i18next";
|
||||
import { redirect } from "react-router-dom";
|
||||
import { Deposit } from "@renderer/components";
|
||||
import Bugsnag from "@bugsnag/electron";
|
||||
import BugsnagPluginReact from "@bugsnag/plugin-react";
|
||||
|
||||
type AppSettingsProviderState = {
|
||||
webApi: Client;
|
||||
|
||||
@@ -2,7 +2,10 @@ import * as sdk from "microsoft-cognitiveservices-speech-sdk";
|
||||
import { useContext } from "react";
|
||||
import { AppSettingsProviderContext } from "@renderer/context";
|
||||
import camelcaseKeys from "camelcase-keys";
|
||||
import { map, forEach, sum, filter, cloneDeep } from "lodash";
|
||||
import * as Diff from "diff";
|
||||
|
||||
const THIRTY_SECONDS = 30 * 1000;
|
||||
export const usePronunciationAssessments = () => {
|
||||
const { webApi, EnjoyApp } = useContext(AppSettingsProviderContext);
|
||||
|
||||
@@ -36,15 +39,29 @@ export const usePronunciationAssessments = () => {
|
||||
targetType,
|
||||
});
|
||||
|
||||
const result = await assess(
|
||||
{
|
||||
blob,
|
||||
language,
|
||||
reference,
|
||||
},
|
||||
{ token, region }
|
||||
);
|
||||
let result = null;
|
||||
|
||||
if (recording.duration < THIRTY_SECONDS) {
|
||||
result = await assess(
|
||||
{
|
||||
blob,
|
||||
language,
|
||||
reference,
|
||||
},
|
||||
{ token, region }
|
||||
);
|
||||
} else {
|
||||
result = await continousAssess(
|
||||
{
|
||||
blob,
|
||||
language,
|
||||
reference,
|
||||
},
|
||||
{ token, region }
|
||||
);
|
||||
}
|
||||
|
||||
console.log("assess result: ", result);
|
||||
const resultJson = camelcaseKeys(
|
||||
JSON.parse(JSON.stringify(result.detailResult)),
|
||||
{
|
||||
@@ -138,8 +155,211 @@ export const usePronunciationAssessments = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const continousAssess = async (
|
||||
params: {
|
||||
blob: Blob;
|
||||
language: string;
|
||||
reference?: string;
|
||||
},
|
||||
options: {
|
||||
token: string;
|
||||
region: string;
|
||||
}
|
||||
): Promise<sdk.PronunciationAssessmentResult> => {
|
||||
const { blob, language, reference } = params;
|
||||
const { token, region } = options;
|
||||
const config = sdk.SpeechConfig.fromAuthorizationToken(token, region);
|
||||
const audioConfig = sdk.AudioConfig.fromWavFileInput(
|
||||
new File([blob], "audio.wav")
|
||||
);
|
||||
|
||||
const pronunciationAssessmentConfig = new sdk.PronunciationAssessmentConfig(
|
||||
reference,
|
||||
sdk.PronunciationAssessmentGradingSystem.HundredMark,
|
||||
sdk.PronunciationAssessmentGranularity.Phoneme,
|
||||
true
|
||||
);
|
||||
pronunciationAssessmentConfig.phonemeAlphabet = "IPA";
|
||||
|
||||
// setting the recognition language
|
||||
config.speechRecognitionLanguage = language;
|
||||
|
||||
// create the speech recognizer.
|
||||
const reco = new sdk.SpeechRecognizer(config, audioConfig);
|
||||
pronunciationAssessmentConfig.applyTo(reco);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const pronunciationResults: sdk.PronunciationAssessmentResult[] = [];
|
||||
|
||||
// The event recognizing signals that an intermediate recognition result is received.
|
||||
// You will receive one or more recognizing events as a speech phrase is recognized, with each containing
|
||||
// more recognized speech. The event will contain the text for the recognition since the last phrase was recognized.
|
||||
reco.recognizing = function (s, e) {
|
||||
const str =
|
||||
"(recognizing) Reason: " +
|
||||
sdk.ResultReason[e.result.reason] +
|
||||
" Text: " +
|
||||
e.result.text;
|
||||
console.log(str);
|
||||
};
|
||||
|
||||
// The event recognized signals that a final recognition result is received.
|
||||
// This is the final event that a phrase has been recognized.
|
||||
// For continuous recognition, you will get one recognized event for each phrase recognized.
|
||||
reco.recognized = function (s, e) {
|
||||
console.log("pronunciation assessment for: ", e.result.text);
|
||||
const pronunciation_result =
|
||||
sdk.PronunciationAssessmentResult.fromResult(e.result);
|
||||
pronunciationResults.push(pronunciation_result);
|
||||
console.log("pronunciation result: ", pronunciation_result);
|
||||
};
|
||||
|
||||
// The event signals that the service has stopped processing speech.
|
||||
// https://docs.microsoft.com/javascript/api/microsoft-cognitiveservices-speech-sdk/speechrecognitioncanceledeventargs?view=azure-node-latest
|
||||
// This can happen for two broad classes of reasons.
|
||||
// 1. An error is encountered.
|
||||
// In this case the .errorDetails property will contain a textual representation of the error.
|
||||
// 2. Speech was detected to have ended.
|
||||
// This can be caused by the end of the specified file being reached, or ~20 seconds of silence from a microphone input.
|
||||
reco.canceled = function (s, e) {
|
||||
if (e.reason === sdk.CancellationReason.Error) {
|
||||
const str =
|
||||
"(cancel) Reason: " +
|
||||
sdk.CancellationReason[e.reason] +
|
||||
": " +
|
||||
e.errorDetails;
|
||||
console.error(str);
|
||||
reject(new Error(e.errorDetails));
|
||||
}
|
||||
reco.stopContinuousRecognitionAsync();
|
||||
};
|
||||
|
||||
// Signals that a new session has started with the speech service
|
||||
reco.sessionStarted = function (s, e) {};
|
||||
|
||||
// Signals the end of a session with the speech service.
|
||||
reco.sessionStopped = function (s, e) {
|
||||
reco.stopContinuousRecognitionAsync();
|
||||
reco.close();
|
||||
const mergedDetailResult = mergePronunciationResults();
|
||||
console.log("Merged detail result:", mergedDetailResult);
|
||||
const result = {
|
||||
pronunciationScore:
|
||||
mergedDetailResult.PronunciationAssessment.PronScore,
|
||||
accuracyScore:
|
||||
mergedDetailResult.PronunciationAssessment.AccuracyScore,
|
||||
completenessScore:
|
||||
mergedDetailResult.PronunciationAssessment.CompletenessScore,
|
||||
fluencyScore: mergedDetailResult.PronunciationAssessment.FluencyScore,
|
||||
prosodyScore: mergedDetailResult.PronunciationAssessment.ProsodyScore,
|
||||
detailResult: mergedDetailResult,
|
||||
contentAssessmentResult: mergedDetailResult.ContentAssessmentResult,
|
||||
};
|
||||
resolve(result as sdk.PronunciationAssessmentResult);
|
||||
};
|
||||
|
||||
const mergePronunciationResults = () => {
|
||||
const detailResults = pronunciationResults.map((result) =>
|
||||
JSON.parse(JSON.stringify(result.detailResult))
|
||||
);
|
||||
|
||||
const mergedDetailResult = detailResults.reduce(
|
||||
(acc, curr) => {
|
||||
acc.Confidence += curr.Confidence;
|
||||
acc.Display += " " + curr.Display;
|
||||
acc.ITN += " " + curr.ITN;
|
||||
acc.Lexical += " " + curr.Lexical;
|
||||
acc.MaskedITN += " " + curr.MaskedITN;
|
||||
acc.Words.push(...curr.Words);
|
||||
acc.PronunciationAssessment.AccuracyScore +=
|
||||
curr.PronunciationAssessment.AccuracyScore;
|
||||
acc.PronunciationAssessment.CompletenessScore +=
|
||||
curr.PronunciationAssessment.CompletenessScore;
|
||||
acc.PronunciationAssessment.FluencyScore +=
|
||||
curr.PronunciationAssessment.FluencyScore;
|
||||
acc.PronunciationAssessment.ProsodyScore +=
|
||||
curr.PronunciationAssessment?.ProsodyScore ?? 0;
|
||||
acc.PronunciationAssessment.PronScore +=
|
||||
curr.PronunciationAssessment?.PronScore ?? 0;
|
||||
|
||||
acc.ContentAssessmentResult.GrammarScore +=
|
||||
curr.ContentAssessmentResult?.GrammarScore ?? 0;
|
||||
acc.ContentAssessmentResult.VocabularyScore +=
|
||||
curr.ContentAssessmentResult?.VocabularyScore ?? 0;
|
||||
acc.ContentAssessmentResult.TopicScore +=
|
||||
curr.ContentAssessmentResult?.TopicScore ?? 0;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{
|
||||
Confidence: 0,
|
||||
Display: "",
|
||||
ITN: "",
|
||||
Lexical: "",
|
||||
MaskedITN: "",
|
||||
Words: [],
|
||||
PronunciationAssessment: {
|
||||
AccuracyScore: 0,
|
||||
CompletenessScore: 0,
|
||||
FluencyScore: 0,
|
||||
ProsodyScore: 0,
|
||||
PronScore: 0,
|
||||
},
|
||||
ContentAssessmentResult: {
|
||||
GrammarScore: 0,
|
||||
VocabularyScore: 0,
|
||||
TopicScore: 0,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
mergedDetailResult.PronunciationAssessment.AccuracyScore = (
|
||||
mergedDetailResult.PronunciationAssessment.AccuracyScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.PronunciationAssessment.CompletenessScore = (
|
||||
mergedDetailResult.PronunciationAssessment.CompletenessScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.PronunciationAssessment.FluencyScore = (
|
||||
mergedDetailResult.PronunciationAssessment.FluencyScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.PronunciationAssessment.ProsodyScore = (
|
||||
mergedDetailResult.PronunciationAssessment.ProsodyScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.PronunciationAssessment.PronScore = (
|
||||
mergedDetailResult.PronunciationAssessment.PronScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
|
||||
mergedDetailResult.Confidence =
|
||||
mergedDetailResult.Confidence / pronunciationResults.length;
|
||||
|
||||
mergedDetailResult.ContentAssessmentResult.GrammarScore = (
|
||||
mergedDetailResult.ContentAssessmentResult.GrammarScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.ContentAssessmentResult.VocabularyScore = (
|
||||
mergedDetailResult.ContentAssessmentResult.VocabularyScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
mergedDetailResult.ContentAssessmentResult.TopicScore = (
|
||||
mergedDetailResult.ContentAssessmentResult.TopicScore /
|
||||
pronunciationResults.length
|
||||
).toFixed(2);
|
||||
|
||||
return mergedDetailResult;
|
||||
};
|
||||
|
||||
reco.startContinuousRecognitionAsync();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
createAssessment,
|
||||
assess,
|
||||
continousAssess,
|
||||
};
|
||||
};
|
||||
|
||||
2
enjoy/src/types/enjoy-app.d.ts
vendored
2
enjoy/src/types/enjoy-app.d.ts
vendored
@@ -357,7 +357,7 @@ type EnjoyAppType = {
|
||||
set: (key: string, value: any, ttl?: number) => Promise<void>;
|
||||
delete: (key: string) => Promise<void>;
|
||||
clear: () => Promise<void>;
|
||||
writeFile: (filename: string, data: ArrayBuffer) => Promise<string>;
|
||||
writeFile: (filename: string, data: Buffer<ArrayBuffer>) => Promise<string>;
|
||||
};
|
||||
transcriptions: {
|
||||
findOrCreate: (params: any) => Promise<TranscriptionType>;
|
||||
|
||||
12
enjoy/src/types/index.d.ts
vendored
12
enjoy/src/types/index.d.ts
vendored
@@ -7,6 +7,18 @@ declare module "foliate-js/view.js";
|
||||
declare module "foliate-js/epub.js";
|
||||
declare module "compromise-paragraphs";
|
||||
|
||||
declare module "segment" {
|
||||
class Segment {
|
||||
useDefault(): void;
|
||||
loadDict(path: string): void;
|
||||
doSegment(
|
||||
text: string,
|
||||
options: { stripPunctuation: boolean }
|
||||
): Array<{ w: string }>;
|
||||
}
|
||||
export = Segment;
|
||||
}
|
||||
|
||||
type SupportedLlmProviderType = "enjoyai" | "openai";
|
||||
|
||||
type LlmProviderType = {
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
"docs:preview": "yarn workspace 1000-hours preview",
|
||||
"portal:generate": "yarn workspace 1000h-portal generate"
|
||||
},
|
||||
"packageManager": "yarn@4.5.3",
|
||||
"packageManager": "yarn@4.6.0",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user