更新依赖,增强ASR功能,优化代理路由处理,添加登录页面渲染
This commit is contained in:
@@ -47,7 +47,7 @@
|
|||||||
"@kevisual/logger": "^0.0.4",
|
"@kevisual/logger": "^0.0.4",
|
||||||
"@kevisual/query": "0.0.33",
|
"@kevisual/query": "0.0.33",
|
||||||
"@kevisual/query-login": "0.0.7",
|
"@kevisual/query-login": "0.0.7",
|
||||||
"@kevisual/router": "^0.0.51",
|
"@kevisual/router": "^0.0.52",
|
||||||
"@kevisual/types": "^0.0.10",
|
"@kevisual/types": "^0.0.10",
|
||||||
"@kevisual/use-config": "^1.0.21",
|
"@kevisual/use-config": "^1.0.21",
|
||||||
"@types/bun": "^1.3.5",
|
"@types/bun": "^1.3.5",
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kevisual/ha-api": "^0.0.5",
|
"@kevisual/ha-api": "^0.0.6",
|
||||||
"@kevisual/video-tools": "^0.0.13",
|
"@kevisual/video-tools": "^0.0.13",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
"lowdb": "^7.0.1",
|
"lowdb": "^7.0.1",
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ app.route({
|
|||||||
key: 'list',
|
key: 'list',
|
||||||
description: '获取路由列表',
|
description: '获取路由列表',
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const list = ctx.app.getList()
|
const list = ctx.app.getList((item) => {
|
||||||
|
if (item.id === 'auth') return false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
ctx.body = { list }
|
ctx.body = { list }
|
||||||
}).addTo(app);
|
}).addTo(app);
|
||||||
52
assistant/src/module/assistant/html/login.ts
Normal file
52
assistant/src/module/assistant/html/login.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
export const renderNoAuthAndLogin = (text: string) => {
|
||||||
|
return `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Login Required</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: #007BFF;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<p>${text}</p>
|
||||||
|
<a href="/root/home">转到首页</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
}
|
||||||
@@ -453,7 +453,6 @@ export const LoadApp = async (app: AppInfo, opts?: { mainApp?: any, pm2Connect?:
|
|||||||
console.log('gateway app not support');
|
console.log('gateway app not support');
|
||||||
} else if (app.type === AppType.Pm2SystemApp) {
|
} else if (app.type === AppType.Pm2SystemApp) {
|
||||||
const pathEntry = path.join(app.path, app.entry);
|
const pathEntry = path.join(app.path, app.entry);
|
||||||
console.log('pm2 system app start', pathEntry);
|
|
||||||
const pm2Manager = new Pm2Manager({
|
const pm2Manager = new Pm2Manager({
|
||||||
appName: app.key,
|
appName: app.key,
|
||||||
script: pathEntry,
|
script: pathEntry,
|
||||||
@@ -473,7 +472,6 @@ export const LoadApp = async (app: AppInfo, opts?: { mainApp?: any, pm2Connect?:
|
|||||||
if (!pm2Options.cwd) {
|
if (!pm2Options.cwd) {
|
||||||
pm2Options.cwd = path.join(app.path, '../..');
|
pm2Options.cwd = path.join(app.path, '../..');
|
||||||
}
|
}
|
||||||
console.log('pm2 start options', pm2Options);
|
|
||||||
await pm2Manager.start(pm2Options);
|
await pm2Manager.start(pm2Options);
|
||||||
} else if (app.type === AppType.ScriptApp) {
|
} else if (app.type === AppType.ScriptApp) {
|
||||||
// console.log('script app 直接运行,不需要启动');
|
// console.log('script app 直接运行,不需要启动');
|
||||||
|
|||||||
25
assistant/src/services/asr/asr-manager.ts
Normal file
25
assistant/src/services/asr/asr-manager.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
import { QwenAsrRelatime } from "@kevisual/video-tools/src/asr/index.ts";
|
||||||
|
|
||||||
|
export class AsrManger {
|
||||||
|
map: Map<string, QwenAsrRelatime>;
|
||||||
|
constructor() {
|
||||||
|
this.map = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAsr(id: string) {
|
||||||
|
const asr = this.map.get(id);
|
||||||
|
return asr;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAsr(id: string, asr: QwenAsrRelatime) {
|
||||||
|
this.map.set(id, asr);
|
||||||
|
return asr;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteAsr(id: string) {
|
||||||
|
this.map.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const arrManager = new AsrManger();
|
||||||
@@ -4,7 +4,7 @@ import { Listener, WebSocketListenerFun, WebSocketReq } from "@kevisual/router";
|
|||||||
import { lightHA } from "@/routes/ha-api/ha.ts";
|
import { lightHA } from "@/routes/ha-api/ha.ts";
|
||||||
import { assistantConfig } from "@/app.ts";
|
import { assistantConfig } from "@/app.ts";
|
||||||
|
|
||||||
const func: WebSocketListenerFun = async (req: WebSocketReq<{ asr: QwenAsrRelatime, msgId: string, startTime?: number }>, res) => {
|
const func: WebSocketListenerFun = async (req: WebSocketReq<{ asr: QwenAsrRelatime, msgId: string, startTime?: number, loading?: boolean }>, res) => {
|
||||||
const { ws, emitter, id, data } = req;
|
const { ws, emitter, id, data } = req;
|
||||||
let asr = ws.data.asr;
|
let asr = ws.data.asr;
|
||||||
|
|
||||||
@@ -14,6 +14,9 @@ const func: WebSocketListenerFun = async (req: WebSocketReq<{ asr: QwenAsrRelati
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!asr) {
|
if (!asr) {
|
||||||
|
if (ws.data.loading) return;
|
||||||
|
ws.data.loading = true;
|
||||||
|
|
||||||
const confg = assistantConfig.getConfig();
|
const confg = assistantConfig.getConfig();
|
||||||
const asrConfig = confg?.asr;
|
const asrConfig = confg?.asr;
|
||||||
if (!asrConfig?.enabled) {
|
if (!asrConfig?.enabled) {
|
||||||
@@ -27,10 +30,7 @@ const func: WebSocketListenerFun = async (req: WebSocketReq<{ asr: QwenAsrRelati
|
|||||||
ws.close();
|
ws.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 第一次请求
|
const onConnect = () => {
|
||||||
asr = new QwenAsrRelatime({
|
|
||||||
token,
|
|
||||||
onConnect: () => {
|
|
||||||
const asr = ws.data.asr as QwenAsrRelatime;
|
const asr = ws.data.asr as QwenAsrRelatime;
|
||||||
ws.send(JSON.stringify({ type: 'asr', code: 200, message: 'asr服务已连接', time: Date.now() }));
|
ws.send(JSON.stringify({ type: 'asr', code: 200, message: 'asr服务已连接', time: Date.now() }));
|
||||||
if (!asr) return;
|
if (!asr) return;
|
||||||
@@ -96,8 +96,18 @@ const func: WebSocketListenerFun = async (req: WebSocketReq<{ asr: QwenAsrRelati
|
|||||||
});
|
});
|
||||||
asr.start();
|
asr.start();
|
||||||
}
|
}
|
||||||
|
// 第一次请求
|
||||||
|
asr = new QwenAsrRelatime({
|
||||||
|
token,
|
||||||
|
emitter,
|
||||||
|
onConnect,
|
||||||
})
|
})
|
||||||
ws.data.asr = asr;
|
ws.data.asr = asr;
|
||||||
|
ws.data.loading = false;
|
||||||
|
emitter.on('close--' + id, () => {
|
||||||
|
console.log('ASR websocket 关闭, 释放资源');
|
||||||
|
asr?.close?.();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
const isConnected = await asr.checkConnected();
|
const isConnected = await asr.checkConnected();
|
||||||
if (!isConnected) return;
|
if (!isConnected) return;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { getToken } from '@/module/http-token.ts';
|
|||||||
import { getTokenUserCache } from '@/routes/index.ts';
|
import { getTokenUserCache } from '@/routes/index.ts';
|
||||||
import type { WebSocketListenerFun } from "@kevisual/router";
|
import type { WebSocketListenerFun } from "@kevisual/router";
|
||||||
import WebSocket from 'ws';
|
import WebSocket from 'ws';
|
||||||
|
import { renderNoAuthAndLogin } from '@/module/assistant/html/login.ts';
|
||||||
const localProxy = new LocalProxy({});
|
const localProxy = new LocalProxy({});
|
||||||
localProxy.initFromAssistantConfig(assistantConfig);
|
localProxy.initFromAssistantConfig(assistantConfig);
|
||||||
|
|
||||||
@@ -161,7 +162,8 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp
|
|||||||
}
|
}
|
||||||
const filter = await authFilter(req, res);
|
const filter = await authFilter(req, res);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
return res.end('Not Authorized Proxy');
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
||||||
|
return res.end(renderNoAuthAndLogin('Not Authorized Proxy'));
|
||||||
}
|
}
|
||||||
const localProxyProxyList = localProxy.getLocalProxyList();
|
const localProxyProxyList = localProxy.getLocalProxyList();
|
||||||
const localProxyProxy = localProxyProxyList.find((item) => pathname.startsWith(item.path));
|
const localProxyProxy = localProxyProxyList.find((item) => pathname.startsWith(item.path));
|
||||||
|
|||||||
26
pnpm-lock.yaml
generated
26
pnpm-lock.yaml
generated
@@ -115,8 +115,8 @@ importers:
|
|||||||
assistant:
|
assistant:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/ha-api':
|
'@kevisual/ha-api':
|
||||||
specifier: ^0.0.5
|
specifier: ^0.0.6
|
||||||
version: 0.0.5
|
version: 0.0.6
|
||||||
'@kevisual/video-tools':
|
'@kevisual/video-tools':
|
||||||
specifier: ^0.0.13
|
specifier: ^0.0.13
|
||||||
version: 0.0.13(dotenv@17.2.3)(supports-color@10.2.2)
|
version: 0.0.13(dotenv@17.2.3)(supports-color@10.2.2)
|
||||||
@@ -155,8 +155,8 @@ importers:
|
|||||||
specifier: 0.0.7
|
specifier: 0.0.7
|
||||||
version: 0.0.7(@kevisual/query@0.0.33)
|
version: 0.0.7(@kevisual/query@0.0.33)
|
||||||
'@kevisual/router':
|
'@kevisual/router':
|
||||||
specifier: ^0.0.51
|
specifier: ^0.0.52
|
||||||
version: 0.0.51(supports-color@10.2.2)
|
version: 0.0.52(supports-color@10.2.2)
|
||||||
'@kevisual/types':
|
'@kevisual/types':
|
||||||
specifier: ^0.0.10
|
specifier: ^0.0.10
|
||||||
version: 0.0.10
|
version: 0.0.10
|
||||||
@@ -1308,8 +1308,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-4T/m2LqhtwWEW+lWmg7jLxKFW7VtIAftsWFDDZvh10bZunqFf8iXxChHcVSQWikghJb4cq1IkWzPkvc2l+Asdw==}
|
resolution: {integrity: sha512-4T/m2LqhtwWEW+lWmg7jLxKFW7VtIAftsWFDDZvh10bZunqFf8iXxChHcVSQWikghJb4cq1IkWzPkvc2l+Asdw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@kevisual/ha-api@0.0.5':
|
'@kevisual/ha-api@0.0.6':
|
||||||
resolution: {integrity: sha512-0A4Hmw797yqB9B92G2vPIn4sxIoNYWBm8D3+yWkUkH+XjEBOE65ScK2j4aJVBfwBNd470QqGlK4DcZ5NmQT5iw==}
|
resolution: {integrity: sha512-pZwcE4XYCDItTpMhIP0dIuo2+C07YmhWukVMgTvUuUQBgNo4KJmpItYjeGIvBGsvEM4AjsDGV1mCjTOB1zLu3Q==}
|
||||||
|
|
||||||
'@kevisual/hot-api@0.0.3':
|
'@kevisual/hot-api@0.0.3':
|
||||||
resolution: {integrity: sha512-qZ4CNK08StZP4+DR1vWwJhKVDoSXXC+PBFG4ZxtkXF5vO2rybE055zp1n3dg5jo8GwW5wxpqMIG3KBp3pYSTkg==}
|
resolution: {integrity: sha512-qZ4CNK08StZP4+DR1vWwJhKVDoSXXC+PBFG4ZxtkXF5vO2rybE055zp1n3dg5jo8GwW5wxpqMIG3KBp3pYSTkg==}
|
||||||
@@ -1364,6 +1364,9 @@ packages:
|
|||||||
'@kevisual/router@0.0.51':
|
'@kevisual/router@0.0.51':
|
||||||
resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==}
|
resolution: {integrity: sha512-i9qYBeS/um78oC912oWJD3iElB+5NTKyTrz1Hzf4DckiUFnjLL81UPwjIh5I2l9+ul0IZ/Pxx+sFSF99fJkzKg==}
|
||||||
|
|
||||||
|
'@kevisual/router@0.0.52':
|
||||||
|
resolution: {integrity: sha512-Qiv3P1XjzD813Tm79S+atrDb2eickGCI9tuy/aCu512LcoYYJqZhwwkeT4ES0DinnA13Ckqd43QWBR6UmuYkHQ==}
|
||||||
|
|
||||||
'@kevisual/types@0.0.10':
|
'@kevisual/types@0.0.10':
|
||||||
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
|
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
|
||||||
|
|
||||||
@@ -6615,7 +6618,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
'@kevisual/ha-api@0.0.5':
|
'@kevisual/ha-api@0.0.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@kevisual/cache': 0.0.4
|
'@kevisual/cache': 0.0.4
|
||||||
fuse.js: 7.1.0
|
fuse.js: 7.1.0
|
||||||
@@ -6759,6 +6762,15 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@kevisual/router@0.0.52(supports-color@10.2.2)':
|
||||||
|
dependencies:
|
||||||
|
eventemitter3: 5.0.1
|
||||||
|
path-to-regexp: 8.3.0
|
||||||
|
selfsigned: 5.4.0
|
||||||
|
send: 1.2.1(supports-color@10.2.2)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@kevisual/types@0.0.10': {}
|
'@kevisual/types@0.0.10': {}
|
||||||
|
|
||||||
'@kevisual/use-config@1.0.21(dotenv@17.2.3)':
|
'@kevisual/use-config@1.0.21(dotenv@17.2.3)':
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
packages:
|
packages:
|
||||||
- 'assistant'
|
- assistant
|
||||||
- 'cli-center'
|
- cli-center
|
||||||
|
|
||||||
|
onlyBuiltDependencies:
|
||||||
|
- esbuild
|
||||||
|
- sharp
|
||||||
|
|||||||
Reference in New Issue
Block a user