Skip to content

Commit 437c133

Browse files
authored
Improve: UI & code (#1179)
* use frameless * frame true * fix UI * disable whisper.cpp for darwin * improve page UI * clean code * refactor shadowing cancel * upgrade deps * fix type * update e2e * downgrade echogarden to fix align error * upgrade echogarden * upgrade * fix profile * refactor login form * may scan to login with Mixin * refactor sidebar * update sidebar ui * update * update UI * update
1 parent ab813da commit 437c133

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1069
-750
lines changed

1000-hours/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"markdown-it-sub": "^2.0.0",
99
"markdown-it-sup": "^2.0.0",
1010
"mermaid": "^11.4.0",
11-
"sass": "^1.80.6",
11+
"sass": "^1.80.7",
1212
"vitepress": "^1.5.0",
1313
"vitepress-plugin-mermaid": "^2.0.17",
1414
"vue": "^3.5.12"

1000h-portal/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
},
1919
"devDependencies": {
2020
"autoprefixer": "^10.4.20",
21-
"postcss": "^8.4.48",
22-
"sass": "^1.80.6",
21+
"postcss": "^8.4.49",
22+
"sass": "^1.80.7",
2323
"tailwindcss": "^3.4.14"
2424
}
2525
}

enjoy/e2e/main.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ test.afterAll(async () => {
6060
await electronApp.close();
6161
});
6262

63-
test("validate echogarden command", async () => {
63+
test("validate echogarden recognition", async () => {
6464
const res = await page.evaluate(() => {
6565
return window.__ENJOY_APP__.echogarden.check({
6666
engine: "whisper",

enjoy/package.json

+13-11
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
"@types/unzipper": "^0.10.10",
6363
"@types/validator": "^13.12.2",
6464
"@types/wavesurfer.js": "^6.0.12",
65-
"@typescript-eslint/eslint-plugin": "^8.13.0",
66-
"@typescript-eslint/parser": "^8.13.0",
65+
"@typescript-eslint/eslint-plugin": "^8.14.0",
66+
"@typescript-eslint/parser": "^8.14.0",
6767
"@vitejs/plugin-react": "^4.3.3",
6868
"autoprefixer": "^10.4.20",
6969
"electron": "^33.2.0",
@@ -83,17 +83,17 @@
8383
"ts-node": "^10.9.2",
8484
"tslib": "^2.8.1",
8585
"typescript": "^5.6.3",
86-
"vite": "^5.4.10",
86+
"vite": "^5.4.11",
8787
"vite-plugin-static-copy": "^2.1.0",
88-
"zx": "^8.2.1"
88+
"zx": "^8.2.2"
8989
},
9090
"dependencies": {
9191
"@andrkrn/ffprobe-static": "^5.2.0",
9292
"@divisey/js-mdict": "^5.0.0",
9393
"@electron-forge/publisher-s3": "^7.5.0",
9494
"@hookform/resolvers": "^3.9.1",
95-
"@langchain/community": "^0.3.12",
96-
"@langchain/core": "^0.3.17",
95+
"@langchain/community": "^0.3.14",
96+
"@langchain/core": "^0.3.18",
9797
"@langchain/ollama": "^0.1.2",
9898
"@mozilla/readability": "^0.5.0",
9999
"@radix-ui/react-accordion": "^1.2.1",
@@ -110,7 +110,7 @@
110110
"@radix-ui/react-popover": "^1.1.2",
111111
"@radix-ui/react-progress": "^1.1.0",
112112
"@radix-ui/react-radio-group": "^1.2.1",
113-
"@radix-ui/react-scroll-area": "^1.2.0",
113+
"@radix-ui/react-scroll-area": "^1.2.1",
114114
"@radix-ui/react-select": "^2.1.2",
115115
"@radix-ui/react-separator": "^1.1.0",
116116
"@radix-ui/react-slider": "^1.2.1",
@@ -119,7 +119,7 @@
119119
"@radix-ui/react-tabs": "^1.1.1",
120120
"@radix-ui/react-toast": "^1.2.2",
121121
"@radix-ui/react-toggle": "^1.1.0",
122-
"@radix-ui/react-tooltip": "^1.1.3",
122+
"@radix-ui/react-tooltip": "^1.1.4",
123123
"@rails/actioncable": "8.0.0",
124124
"@types/turndown": "^5.0.5",
125125
"@uidotdev/usehooks": "^2.4.1",
@@ -141,7 +141,7 @@
141141
"dayjs": "^1.11.13",
142142
"decamelize": "^6.0.0",
143143
"decamelize-keys": "^2.0.1",
144-
"echogarden": "^2.0.0",
144+
"echogarden": "2.0.3",
145145
"electron-context-menu": "^4.0.4",
146146
"electron-log": "^5.2.2",
147147
"electron-settings": "^4.0.4",
@@ -154,20 +154,22 @@
154154
"html-to-text": "^9.0.5",
155155
"https-proxy-agent": "^7.0.5",
156156
"i18next": "^23.16.5",
157+
"input-otp": "^1.4.1",
157158
"intl-tel-input": "^24.7.0",
158159
"js-md5": "^0.8.3",
159160
"langchain": "^0.3.5",
160161
"lodash": "^4.17.21",
161162
"lru-cache": "^11.0.2",
162163
"lucide-react": "^0.456.0",
163164
"mark.js": "^8.11.1",
165+
"media-captions": "^0.0.18",
164166
"microsoft-cognitiveservices-speech-sdk": "^1.41.0",
165167
"mime-types": "^2.1.35",
166168
"mustache": "^4.2.0",
167169
"next-themes": "^0.4.3",
168-
"openai": "^4.71.1",
170+
"openai": "^4.72.0",
169171
"pitchfinder": "^2.3.2",
170-
"postcss": "^8.4.48",
172+
"postcss": "^8.4.49",
171173
"proxy-agent": "^6.4.0",
172174
"react": "^18.3.1",
173175
"react-activity-calendar": "^2.7.1",

enjoy/src/api/client.ts

+4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ export class Client {
106106
return this.api.post("/api/sessions", decamelizeKeys(params));
107107
}
108108

109+
oauthState(state: string): Promise<UserType> {
110+
return this.api.post("/api/sessions/oauth_state", { state });
111+
}
112+
109113
config(key: string): Promise<any> {
110114
return this.api.get(`/api/config/${key}`);
111115
}

enjoy/src/i18n/en.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@
275275
"phoneNumber": "Phone number",
276276
"mixinId": "Mixin ID",
277277
"inputMixinId": "Input your Mixin ID",
278-
"dontHaveMixinAccount": "don't have Mixin account?",
278+
"scanMixinQRCodeDescription": "Scan Mixin QR code in the popup window",
279+
"createMixinAccount": "Create Mixin account",
280+
"scanToLogin": "Scan to login",
279281
"youCanAlsoLoginWith": "You can also login with",
280282
"downloadTranscript": "Download transcript",
281283
"downloadTranscriptFromCloud": "Download transcript from cloud",

enjoy/src/i18n/zh-CN.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,9 @@
275275
"phoneNumber": "手机号",
276276
"mixinId": "Mixin 号",
277277
"inputMixinId": "请输入您的 Mixin ID",
278-
"dontHaveMixinAccount": "没有 Mixin 账号?",
278+
"scanMixinQRCodeDescription": "请在弹出窗口中用 Mixin 扫码",
279+
"createMixinAccount": "创建 Mixin 账号",
280+
"scanToLogin": "扫码登录",
279281
"youCanAlsoLoginWith": "您也可以使用以下方式登录",
280282
"downloadTranscript": "下载字幕",
281283
"downloadTranscriptFromCloud": "从云端下载字幕",

enjoy/src/main.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ app.on("ready", async () => {
139139
// for applications and their menu bar to stay active until the user quits
140140
// explicitly with Cmd + Q.
141141
app.on("window-all-closed", () => {
142-
app.quit();
142+
// Respect the OSX convention of having the application in memory even
143+
// after all windows have been closed
144+
if (process.platform !== "darwin") {
145+
app.quit();
146+
}
143147
});
144148

145149
app.on("activate", () => {

enjoy/src/main/echogarden.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ import settings from "@main/settings";
2424
import fs from "fs-extra";
2525
import ffmpegPath from "ffmpeg-static";
2626
import { enjoyUrlToPath, pathToEnjoyUrl } from "./utils";
27-
import { UserSetting } from "./db/models";
28-
import { UserSettingKeyEnum } from "@/types/enums";
29-
import { WHISPER_MODELS } from "@/constants";
3027

3128
Echogarden.setGlobalOption(
3229
"ffmpegPath",
@@ -107,13 +104,18 @@ class EchogardenWrapper {
107104
try {
108105
logger.info("check:", options);
109106
const result = await this.recognize(sampleFile, options);
110-
logger.info(result?.transcript);
107+
logger.info("transcript:", result?.transcript);
111108
fs.writeJsonSync(
112109
path.join(settings.cachePath(), "echogarden-check.json"),
113110
result,
114111
{ spaces: 2 }
115112
);
116113

114+
const timeline = await this.align(sampleFile, result.transcript, {
115+
language: "en",
116+
});
117+
logger.info("timeline:", !!timeline);
118+
117119
return { success: true, log: "" };
118120
} catch (e) {
119121
logger.error(e);

enjoy/src/main/window.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,8 @@ ${log}
509509

510510
// Create the browser window.
511511
const mainWindow = new BrowserWindow({
512-
icon: "./assets/icon.png",
512+
icon:
513+
process.platform === "win32" ? "./assets/icon.ico" : "./assets/icon.png",
513514
width: 1280,
514515
height: 720,
515516
minWidth: 800,

enjoy/src/renderer/components/audios/audio-player.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ export const AudioPlayer = (props: {
77
id?: string;
88
md5?: string;
99
segmentIndex?: number;
10+
onLoad?: (audio: AudioType) => void;
1011
}) => {
11-
const { id, md5, segmentIndex } = props;
12+
const { id, md5, segmentIndex, onLoad } = props;
1213
const { media, setMedia, setCurrentSegmentIndex, getCachedSegmentIndex } =
1314
useContext(MediaShadowProviderContext);
1415

@@ -21,6 +22,7 @@ export const AudioPlayer = (props: {
2122

2223
useEffect(() => {
2324
setMedia(audio);
25+
onLoad?.(audio);
2426
}, [audio]);
2527

2628
useEffect(() => {

enjoy/src/renderer/components/chats/chat-header.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ export const ChatHeader = (props: {
4242
onClick={toggleSidePanel}
4343
>
4444
{sidePanelCollapsed ? (
45-
<ChevronsRightIcon className="w-5 h-5" />
45+
<ChevronsRightIcon className="size-4" />
4646
) : (
47-
<ChevronsLeftIcon className="w-5 h-5" />
47+
<ChevronsLeftIcon className="size-4" />
4848
)}
4949
</Button>
5050
{chat.type === ChatTypeEnum.CONVERSATION && (
@@ -59,7 +59,7 @@ export const ChatHeader = (props: {
5959
<Dialog open={displayChatForm} onOpenChange={setDisplayChatForm}>
6060
<DialogTrigger asChild>
6161
<Button variant="ghost" size="icon" className="absolute right-4">
62-
<SettingsIcon className="w-5 h-5" />
62+
<SettingsIcon className="size-4" />
6363
</Button>
6464
</DialogTrigger>
6565
<DialogContent className="max-w-screen-sm max-h-[70%] overflow-y-auto">

enjoy/src/renderer/components/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ export * from "./transcriptions";
1919
export * from "./users";
2020
export * from "./videos";
2121
export * from "./widgets";
22+
export * from "./login";

enjoy/src/renderer/components/misc/bandu-login-form.tsx renamed to enjoy/src/renderer/components/login/bandu-login-form.tsx

+26-14
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,16 @@ import {
88
SheetContent,
99
SheetHeader,
1010
SheetTitle,
11+
InputOTP,
12+
InputOTPGroup,
13+
InputOTPSlot,
1114
} from "@renderer/components/ui";
1215
import { useContext, useEffect, useRef, useState } from "react";
1316
import { AppSettingsProviderContext } from "@renderer/context";
1417
import { t } from "i18next";
1518
import intlTelInput from "intl-tel-input/intlTelInputWithUtils";
1619
import "intl-tel-input/build/css/intlTelInput.css";
20+
import { REGEXP_ONLY_DIGITS } from "input-otp";
1721

1822
export const BanduLoginButton = () => {
1923
const [open, setOpen] = useState(false);
@@ -117,30 +121,38 @@ export const BanduLoginForm = () => {
117121
value={phoneNumber}
118122
onInput={validatePhone}
119123
onBlur={validatePhone}
124+
disabled={countdown > 0}
120125
className="border text-lg py-2 px-4 rounded w-80 dark:bg-background dark:text-foreground"
121126
ref={ref}
122127
/>
123128
</div>
124-
<div className="grid gap-2">
125-
<Label htmlFor="verrificationCode">{t("verificationCode")}</Label>
126-
<Input
127-
id="verrificationCode"
128-
className="border py-2 h-10 px-4 rounded"
129-
type="text"
130-
minLength={5}
131-
maxLength={5}
132-
placeholder={t("verificationCode")}
133-
value={code}
134-
onChange={(e) => setCode(e.target.value)}
135-
/>
136-
</div>
129+
{codeSent && (
130+
<div className="grid gap-2">
131+
<Label htmlFor="verrificationCode">{t("verificationCode")}</Label>
132+
<InputOTP
133+
id="verrificationCode"
134+
maxLength={5}
135+
value={code}
136+
pattern={REGEXP_ONLY_DIGITS}
137+
onChange={(value) => setCode(value)}
138+
>
139+
<InputOTPGroup>
140+
<InputOTPSlot index={0} />
141+
<InputOTPSlot index={1} />
142+
<InputOTPSlot index={2} />
143+
<InputOTPSlot index={3} />
144+
<InputOTPSlot index={4} />
145+
</InputOTPGroup>
146+
</InputOTP>
147+
</div>
148+
)}
137149
</div>
138150

139151
<div className="grid grid-cols-2 gap-4">
140152
<Button
141153
variant="secondary"
142154
size="lg"
143-
className="w-full"
155+
className="w-full px-2"
144156
disabled={!phoneNumber || countdown > 0}
145157
onClick={() => {
146158
webApi

enjoy/src/renderer/components/misc/email-login-form.tsx renamed to enjoy/src/renderer/components/login/email-login-form.tsx

+32-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
import { Button, toast, Input, Label } from "@renderer/components/ui";
1+
import {
2+
Button,
3+
toast,
4+
Input,
5+
Label,
6+
InputOTP,
7+
InputOTPSlot,
8+
InputOTPGroup,
9+
} from "@renderer/components/ui";
210
import { useContext, useEffect, useState } from "react";
311
import { AppSettingsProviderContext } from "@renderer/context";
412
import { t } from "i18next";
13+
import { REGEXP_ONLY_DIGITS } from "input-otp";
514

615
export const EmailLoginForm = () => {
716
const [email, setEmail] = useState<string>("");
@@ -41,27 +50,33 @@ export const EmailLoginForm = () => {
4150
/>
4251
</div>
4352

44-
<div className="grid gap-2">
45-
<Label htmlFor="code">{t("verificationCode")}</Label>
46-
<Input
47-
id="code"
48-
className="h-10"
49-
type="text"
50-
required
51-
minLength={5}
52-
maxLength={5}
53-
placeholder={t("verificationCode")}
54-
value={code}
55-
onChange={(e) => setCode(e.target.value)}
56-
/>
57-
</div>
53+
{codeSent && (
54+
<div className="grid gap-2">
55+
<Label htmlFor="code">{t("verificationCode")}</Label>
56+
<InputOTP
57+
id="code"
58+
maxLength={5}
59+
value={code}
60+
pattern={REGEXP_ONLY_DIGITS}
61+
onChange={(value) => setCode(value)}
62+
>
63+
<InputOTPGroup>
64+
<InputOTPSlot index={0} />
65+
<InputOTPSlot index={1} />
66+
<InputOTPSlot index={2} />
67+
<InputOTPSlot index={3} />
68+
<InputOTPSlot index={4} />
69+
</InputOTPGroup>
70+
</InputOTP>
71+
</div>
72+
)}
5873
</div>
5974

6075
<div className="grid grid-cols-2 gap-4">
6176
<Button
6277
variant="secondary"
6378
size="lg"
64-
className="w-full"
79+
className="w-full px-2"
6580
disabled={!email || countdown > 0}
6681
onClick={() => {
6782
webApi
@@ -83,7 +98,7 @@ export const EmailLoginForm = () => {
8398
<Button
8499
variant="default"
85100
size="lg"
86-
className="w-full"
101+
className="w-full px-2"
87102
disabled={!code || code.length < 5 || !email}
88103
onClick={() => {
89104
webApi
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export * from "./mixin-login-form";
2+
export * from "./login-form";
3+
export * from "./email-login-form";
4+
export * from "./bandu-login-form";
5+
export * from "./github-login-form";

0 commit comments

Comments
 (0)