Commit 0a19f058 by chenwl

替换界面

parent d817f764
......@@ -4,6 +4,6 @@ root = true
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
end_of_line = CRLF
insert_final_newline = true
trim_trailing_whitespace = true
\ No newline at end of file
......@@ -8,6 +8,7 @@ module.exports = {
RSData: true
},
extends: [
'vue-global-api',
'eslint:recommended',
'plugin:vue/vue3-recommended',
'@electron-toolkit',
......
......@@ -12,13 +12,5 @@
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.device.usb</key>
<true/>
</dict>
</plist>
appId: com.raisound.VMouse
productName: 千寻智能AI助手
productName: 威鼠
directories:
buildResources: build
files:
......@@ -42,7 +42,7 @@ mac:
- NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
- NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
dmg:
artifactName: QxznAI-Hub-${version}.${ext}
artifactName: VMouse-${version}.${ext}
linux:
target:
- AppImage
......
// electron.vite.config.mjs
import { resolve } from "path";
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
import vue from "@vitejs/plugin-vue";
var electron_vite_config_default = defineConfig({
main: {
plugins: [externalizeDepsPlugin({ exclude: ["vue-cli-plugin-electron-builder"] })],
build: {
rollupOptions: {
external: ["electron-screenshots", "electron-edge-js"]
}
},
resolve: {
alias: {
"@main": resolve("src/main"),
"@resources": resolve("resources")
}
}
},
preload: {
plugins: [externalizeDepsPlugin()]
},
renderer: {
resolve: {
alias: {
"@renderer": resolve("src/renderer/src")
}
},
plugins: [vue()]
}
});
export {
electron_vite_config_default as default
};
import { resolve } from 'path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin({ exclude: ['vue-cli-plugin-electron-builder'] })],
......@@ -26,6 +26,11 @@ export default defineConfig({
'@renderer': resolve('src/renderer/src')
}
},
plugins: [vue()]
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router']
})
]
}
})
{
"name": "QxznAI-Hub",
"version": "1.0.0",
"description": "千寻智能AI助手",
"name": "v-mouse",
"version": "1.0.4",
"description": "An AI mouse application",
"main": "./out/main/index.js",
"author": "5ai.qxznOffice.com",
"homepage": "https://qx.5ai.top/",
"author": "raisound.com",
"homepage": "https://vmouse.raisound.com/index",
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
......@@ -25,7 +25,6 @@
"@azure/core-auth": "^1.6.0",
"@electron-toolkit/preload": "^3.0.0",
"@electron-toolkit/utils": "^3.0.0",
"alibabacloud-nls": "^1.0.4",
"auto-launch": "^5.0.6",
"dayjs": "^1.11.10",
"electron-edge-js": "^29.0.2",
......@@ -42,7 +41,6 @@
"node-windows": "^1.0.0-beta.8",
"node-wmi": "^0.0.5",
"pcm-util": "^3.0.0",
"png2icons": "^2.0.1",
"ref-array-napi": "^1.2.2",
"ref-napi": "^3.0.3",
"robotjs": "^0.6.0",
......@@ -67,14 +65,15 @@
"electron-vite": "^2.0.0",
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.19.2",
"js-base64": "^3.7.7",
"less": "^4.2.0",
"pcm-player": "^0.0.17",
"prettier": "^3.1.1",
"recorder-core": "^1.3.23122400",
"sass": "^1.70.0",
"unplugin-auto-import": "^0.17.6",
"vite": "^5.0.11",
"vue": "^3.4.5",
"vue-global-api": "^0.4.1",
"vue-router": "^4.2.5",
"vue3-perfect-scrollbar": "^1.6.1"
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
No preview for this file type

2.54 KB | W: | H:

1.58 KB | W: | H:

resources/tray32x32@2x.png
resources/tray32x32@2x.png
resources/tray32x32@2x.png
resources/tray32x32@2x.png
  • 2-up
  • Swipe
  • Onion skin
import dayjs from "dayjs"
import dayjs from 'dayjs'
const getUID = ()=>{
const getUID = () => {
return dayjs().unix() + Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2)
}
export const useRSData = (conf) => {
......@@ -10,32 +10,32 @@ export const useRSData = (conf) => {
let _cacheMap = new Map()
let _onDataChange = (data) => {
if(_cacheMap.has('')){
if (_cacheMap.has('')) {
const arr = _cacheMap.get('')
for(let i = 0; i < arr.length; i++){
arr[i]();
for (let i = 0; i < arr.length; i++) {
arr[i]()
}
}
const keys = Array.from(_cacheMap.keys())
for(let j = 0; j < keys.length; j++){
if(keys[j] != ''){
if(typeof keys[j] === 'string') {
if(data.key == keys[j]){
// 执行函数
const arr = _cacheMap.get(data.key)
for(let i = 0; i < arr.length; i++){
arr[i]();
}
for (let j = 0; j < keys.length; j++) {
if (keys[j] != '') {
if (typeof keys[j] === 'string') {
if (data.key == keys[j]) {
// 执行函数
const arr = _cacheMap.get(data.key)
for (let i = 0; i < arr.length; i++) {
arr[i]()
}
}
} else {
console.log(keys)
console.log(keys[j])
if(keys[j].includes(data.key)){
const arr = _cacheMap.get(keys[j])
for(let i = 0; i < arr.length; i++){
arr[i]();
if (keys[j].includes(data.key)) {
const arr = _cacheMap.get(keys[j])
for (let i = 0; i < arr.length; i++) {
arr[i]()
}
}
}
......@@ -131,7 +131,7 @@ export const useRSData = (conf) => {
}
_cacheKey = ''
let arr = []
if(_cacheMap.has('')) {
if (_cacheMap.has('')) {
arr = _cacheKey.get('')
}
arr.push(Array.from(arguments)[0])
......@@ -145,7 +145,7 @@ export const useRSData = (conf) => {
// _cacheFn = fn
let arr = []
if(_cacheMap.has(key)) {
if (_cacheMap.has(key)) {
arr = _cacheKey.get(key)
}
arr.push(fn)
......
......@@ -28,6 +28,7 @@ export const AI_OPEN = 'AI:OPEN'
// 选择文件夹
export const DIALOG_OPEN_DIRECTORY = 'DIALOG:OPEN_DIRECTORY'
export const DIALOG_GET_DIRECTORY = 'DIALOG:GET_DIRECTORY'
// 选择文件
export const DIALOG_GET_FILE = 'DIALOG:DIALOG_GET_FILE'
......@@ -84,29 +85,7 @@ export const MOUSE_SET_DPI = 'MOUSE:SET_DPI'
export const ASR_MAIN_TEMP_TEXT = 'ASR_MAIN:TEMP_TEXT'
export const ASR_MAIN_FINAL_TEXT = 'ASR_MAIN:FINAL_TEXT'
export const ASR_MAIN_WIN_HIDE = 'ASR_MAIN:WIN_HIDE'
export const ASR_RELOAD = 'ASR_MAIN:RELOAD'
// Axios请求
export const AXIOS_REQUEST = 'AXIOS_REQUEST'
// LOG 服务
export const LOG_GET_LIST = 'LOG:GET_LIST'
export const LOG_UPLOAD = 'LOG:UPLOAD'
export const LOG_OPEN_FILE = 'LOG:OPEN_FILE'
export const LOG_OPEN_DIR = 'LOG:OPEN_DIR'
// 更新服务
export const UPDATE_CHECK = 'UPDATE:CHECK'
export const UPDATE_DOWNLOAD = 'UPDATE:DOWNLOAD'
export const UPDATE_VERSION = 'UPDATE:VERSION'
// 截图
export const SCREENSHOTS_KEY = 'SCREENSHOTS:KEY'
// 获取mac地址
export const MACADDRESS_GET = 'MACADDRESS:GET'
// 获取鼠标状态
export const MOUSE_STATUS = 'MOUSE:STATUS'
// 鼠标重新连接
export const MOUSE_RECONNECT = 'MOUSE:RECONNECT'
//系统信息
export const SYSTEM_APP_VERSION = 'SYSTEM:APP_VERSION'
export const SYSTEM_LANGUAGE = 'SYSTEM:LANGUAGE'
import { BrowserWindow, globalShortcut, crashReporter } from 'electron/main'
import { BrowserWindow, globalShortcut } from 'electron/main'
import RSApp from './lib/RSApp'
import {
......@@ -11,14 +11,16 @@ import {
RSFFIPlugin,
RSPageEventPlugin,
// RSVoiceInput
RSLogServicePlugin,
RSMouseSetup,
RSASRPlugin,
RSUpdatePlugin
RSASRPlugin
} from './lib/plugin/index'
import Logger from 'electron-log/main'
import router from './router.js'
import { Menu } from 'electron'
// import AutoLaunch from 'auto-launch'
// import RSDialog from './lib/RSDialog.js'
// import loudness from 'loudness'
// import brightness from 'brightness'
// import * as sudo from 'sudo-prompt'
const RSAppInstance = new RSApp({
router,
......@@ -29,20 +31,19 @@ const RSAppInstance = new RSApp({
console.log('启动失败')
RSAppInstance.quit()
},
onBeforeLoad() {
Menu.setApplicationMenu(null)
},
onBeforeLoad() {},
async onLoaded() {
globalShortcut.register('alt+B', () => {
// crashReporter.start({
// uploadToServer: false
// })
globalShortcut.register('Alt+B', () => {
const win = BrowserWindow.getFocusedWindow()
if (win) {
win.webContents.openDevTools({ mode: 'detach' })
}
})
router.open('/')
router.open('/audioWin', false)
},
onError(err) {
// 收集日志
......@@ -58,8 +59,6 @@ RSAppInstance.use(RSCreateDirPlugin, {
RSAppInstance.use(RSFFIPlugin)
RSAppInstance.use(RSEventPlugin)
RSAppInstance.use(RSDataPlugin)
RSAppInstance.use(RSLogServicePlugin)
RSAppInstance.use(RSUpdatePlugin)
RSAppInstance.use(RSTrayPlugin)
RSAppInstance.use(RSASRPlugin)
RSAppInstance.use(RSScreenshotsPlugin)
......
......@@ -2,6 +2,7 @@ import { join } from 'path'
import { app } from 'electron'
import logger from 'electron-log/main'
import { createDir } from '../tools'
import { merge } from 'lodash'
export const setupDB = () => {
const low = require('lowdb')
......@@ -10,115 +11,109 @@ export const setupDB = () => {
logger.info('配置文件缓存地址:', homeDir)
const adapter = new FileSync(join(homeDir, 'dbCache', 'config.json'))
const db = low(adapter)
if (!db.read().get('isNotFirst').value()) {
let docDir = app.getPath('documents')
docDir = createDir(join(docDir, app.getName(), 'subTitle'))
const defaultData = {
isNotFirst: true,
// voiceCloud: {
// // url: 'wss://api-voice-cloud.raisound.com/rta',
// // apikey: '1GJ0RKJRG0401',
// // apisecret: '18E0UD054T1MJZJBBRVSRYYNQ8TBWC'
// url: 'wss://openapi.raisound.com/rta',
// apikey: '1H1F677TC0401',
// apisecret: 'FNQ6PD1MYVST2RS9A0Y1KMH7YZNZU6'
// },
asrConfig: {
projectId: '1a6dafedc9a3415f8a5d5244e6f62c34',
url: 'wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1',
appkey: 'JWFhUzdUmhQBrT1c',
tokenUrl: 'https://tran.5ai.top/asr/get_token/'
},
typing: {
// 打字模式
mode: 'ai',
// 打字语言
lang: 'JWFhUzdUmhQBrT1c',
// 打字实现方式
achieve: '1',
// 短按
click: true,
// // 自动换行
// enter: false,
// // 输入临时结果
tempWrite: false,
// 去除标点符号
punctuation: true,
// // 打字提示框固定右下角
// fixed: false,
// // 窗口风格
winStyle: '1',
// 语音翻译原文
translateFrom: 'zh',
// 语音翻译译文
translateTo: 'en',
// 对话框模式
isDialog: false,
// 输出模式
outputModel: 1,
// 语言选项
langOptions: [
{
label: '普通话(中英)',
value: 'JWFhUzdUmhQBrT1c'
},
{
label: '粤语(简体)',
value: 'o7oUdFZg4nhfPTSs'
}
]
},
search: {
// 默认搜索引擎
defaultEngine: 'https://www.baidu.com/s?wd=',
commandList: []
},
translate: {
from: 'zh',
let docDir = app.getPath('documents')
docDir = createDir(join(docDir, app.getName(), 'subTitle'))
const defaultData = {
isNotFirst: true,
version:"102",
voiceCloud: {
// url: 'wss://api-voice-cloud.raisound.com/rta',
// apikey: '1GJ0RKJRG0401',
// apisecret: '18E0UD054T1MJZJBBRVSRYYNQ8TBWC'
url: 'wss://openapi.raisound.com/rta',
apikey: '1H1F677TC0401',
apisecret: 'FNQ6PD1MYVST2RS9A0Y1KMH7YZNZU6'
},
typing: {
// 打字模式
mode: 'ai',
// 打字语言
lang: 'zh',
// 打字翻译
isOpenTranslate: false,
// 打字翻译原始语言
translateFrom: 'zh-Hans',
// 打字翻译目标语音
translateTo: 'en',
// 打字实现方式
achieve: '1',
// 短按
click: true,
// 自动换行
enter: false,
// 输入临时结果
tempWrite: false,
// 去除标点符号
punctuation: false,
// 打字提示框固定右下角
fixed: false,
// 窗口风格
winStyle: '1'
},
search: {
// 默认搜索引擎
defaultEngine: 'https://www.baidu.com/s?wd=',
commandList: []
},
translate: {
from: 'zh-Hans',
fromText: '中文(简体)',
to: 'en',
toText: '英文',
scribeWords: {
action: false,
isZhToEn: false,
from: 'zh-Hans',
fromText: '中文',
to: 'en',
toText: '英文',
scribeWords: {
action: false,
isZhToEn: false,
from: 'zh',
fromText: '中文',
to: 'en',
toText: '英文'
}
},
translateKey: {
mainKey: 'shift',
supKey: 'B'
},
setting: {
startAdmin: false,
inStart: true,
showTips: false,
checkNet: false,
openScreenshot: false,
proxy: {
// none, http
type: 'none',
addr: '',
port: '',
user: '',
pass: ''
},
cacheDir: docDir
},
msetting: {
type: 2,
url: ''
toText: '英文'
}
},
setting: {
startAdmin: false,
inStart: true,
showTips: false,
checkNet: false,
openScreenshot: false,
proxy: {
// none, http
type: 'none',
addr: '',
port: '',
user: '',
pass: ''
},
cacheDir: docDir,
lang: 'zh-cn'
},
msetting: {
type: 2,
url: ''
}
}
console.log("配置文件",db.read().get('isNotFirst').value())
if (!db.read().get('isNotFirst').value()) {
logger.info('首次进入应用,初始化数据', defaultData)
db.defaults({
...defaultData,
defaultData
}).write()
} else {
logger.info('已存在配置文件,直接使用')
const localData = db.read().toJSON()
delete localData.defaultData
const version = app.getVersion().split('.').join('')
console.log('本地版本', localData.version, version)
if(!localData.version || version > localData.version) {
logger.info('已存在配置文件,版本更新,合并版本配置文件')
// 配置更新
const mergeData = merge(defaultData, localData)
mergeData.version = version
db.read().assign({...mergeData, defaultData:mergeData}).write()
} else {
logger.info('已存在配置文件,已通过版本更新,更新过配置文件')
}
}
return db
......
......@@ -20,21 +20,12 @@ export const setupFFI = () => {
const LibrarySDK = useLibrarySDK()
const MouseSDK = useMouseSDK()
return {
initMouse(type) {
return MouseSDK.initLd2(type)
},
setConnectCallback(func = () => {}) {
MouseSDK.setConnectCallback(func)
initMouse() {
return MouseSDK.initLd2()
},
initBluetoothAuth() {
return MouseSDK.lotBusinessAuth()
},
startAuthentication() {
return MouseSDK.startAuthentication()
},
releaseMouse() {
return MouseSDK.releaseLd2()
},
setDPI(value) {
return MouseSDK.setDPI(value)
},
......@@ -44,9 +35,6 @@ export const setupFFI = () => {
onMousePCMData(func = () => {}) {
MouseSDK.setBleDATACallback(func)
},
onMouseLog(func = () => {}) {
MouseSDK.setLogCallback(func)
},
/**
* 发送文本内容到光标
* @param {*} s
......@@ -85,21 +73,29 @@ export const setupFFI = () => {
},
// 增加音量
async addVolume(step = 10) {
let vol = await LibrarySDK.getVolume()
vol += step
if (vol > 100) {
LibrarySDK.setVolume(100)
if (platform.isMacOS) {
LibrarySDK.addVolume()
} else {
LibrarySDK.setVolume(vol)
let vol = await LibrarySDK.getVolume()
vol += step
if (vol > 100) {
LibrarySDK.setVolume(100)
} else {
LibrarySDK.setVolume(vol)
}
}
},
async reduceVolume(step = 10) {
let vol = await LibrarySDK.getVolume()
vol -= step
if (vol < 0) {
LibrarySDK.setVolume(0)
if (platform.isMacOS) {
LibrarySDK.reduceVolume()
} else {
LibrarySDK.setVolume(vol)
let vol = await LibrarySDK.getVolume()
vol -= step
if (vol < 0) {
LibrarySDK.setVolume(0)
} else {
LibrarySDK.setVolume(vol)
}
}
},
// 关机
......
import { platform } from "@electron-toolkit/utils"
import {useWinSDK} from './useWinSDK'
import { useMacSDK} from './useMacSDK'
import { useLinuxSDK } from "./useLinuxSDK"
export const useLibrarySDK = ()=>{
if(!platform.isWindows && !platform.isMacOS && !platform.isLinux){
throw new Error("暂未适配该平台")
}
import { platform } from '@electron-toolkit/utils'
import { useWinSDK } from './useWinSDK'
import { useMacSDK } from './useMacSDK'
import { useLinuxSDK } from './useLinuxSDK'
export const useLibrarySDK = () => {
if (!platform.isWindows && !platform.isMacOS && !platform.isLinux) {
throw new Error('暂未适配该平台')
}
if(platform.isWindows){
return useWinSDK()
}
if (platform.isWindows) {
return useWinSDK()
}
if(platform.isMacOS){
return useMacSDK()
}
if (platform.isMacOS) {
return useMacSDK()
}
if(platform.isLinux) {
return useLinuxSDK()
}
}
\ No newline at end of file
if (platform.isLinux) {
return useLinuxSDK()
}
}
export const useLinuxSDK = () =>{
return {
sleep() {
},
setScreenbright(value){
},
getScreenbright(){
return 0
},
sendText(s) {
},
shutdown(){
},
showDesktop() {
},
getVolume() {
},
setVolume(val){
},
inputEnter() {
},
inputBackspace(){
}
}
}
\ No newline at end of file
export const useLinuxSDK = () => {
return {
sleep() {},
setScreenbright(value) {},
getScreenbright() {
return 0
},
sendText(s) {},
shutdown() {},
showDesktop() {},
getVolume() {},
setVolume(val) {},
inputEnter() {},
inputBackspace() {}
}
}
import libraryPath_x86 from '../../../../../resources/lib/mac/intel/AIMouseLibrary.node?asset'
import libraryPath from '../../../../../resources/lib/mac/m1/AIMouseLibrary.node?asset'
import libraryPath_x86 from '@resources/lib/mac/intel/AIMouseLibrary.node?asset'
import libraryPath from '@resources/lib/mac/m1/AIMouseLibrary.node?asset'
import { createRequire } from 'module'
const moduleRequire = createRequire(import.meta.url)
import robot from 'robotjs'
import { isX86 } from '@main/tools/util'
import robot from 'robotjs'
import { exec } from 'child_process'
import Logger from 'electron-log/main'
function execFunc(command) {
exec(command, (error, stdout, stderr) => {
if (error) {
Logger.error(`执行出错: ${error}`)
return
}
Logger.log(`stdout: ${stdout}`)
Logger.error(`stderr: ${stderr}`)
})
}
export const useMacSDK = () => {
const native = moduleRequire(isX86() ? libraryPath_x86 : libraryPath)
return {
sleep() {},
sleep() {
execFunc('pmset sleepnow')
},
setScreenbright(value) {},
getScreenbright() {
return 0
},
sendText(s) {
native.begainSelectTextTranslate(s, (data) => {
console.log('输入状态', data)
Logger.log('输入状态', data)
})
},
shutdown() {},
showDesktop() {},
getVolume() {},
setVolume(val) {},
shutdown() {
execFunc('sudo shutdown -h now')
},
showDesktop() {
const appleScript = `
tell application "System Events"
key code 103 using {command down, option down}
end tell
`
exec(`osascript -e '${appleScript}'`, (error, stdout, stderr) => {
if (error) {
console.error(`Error executing AppleScript: ${error}`)
return
}
console.log('Returned to desktop.')
})
// robot.keyTap('d', ['command', 'option'])
},
addVolume() {
robot.keyTap('audio_vol_up')
},
reduceVolume() {
robot.keyTap('audio_vol_down')
},
inputEnter() {
robot.keyTap('enter')
},
......
import AIMOUSELIBPath from '../../../../../resources/lib/win/AIMOUSELIB_X64/AIMOUSE.dll?asset&asarUnpack'
import AIMouseSDKPath from '../../../../../resources/lib/win/AIMouseSDK/AIMOUSE.dll?asset&asarUnpack'
import AIMOUSELIBPath from '@resources/lib/win/AIMOUSELIB_X64/AIMOUSE.dll?asset&asarUnpack'
import AIMouseSDKPath from '@resources/lib/win/AIMouseSDK/AIMOUSE.dll?asset&asarUnpack'
import loudness from 'loudness'
import { exec } from 'child_process'
import nircmd from 'nircmd'
export const useWinSDK = () =>{
const ffi = require('ffi-napi')
const iconv = require('iconv-lite')
const user32 = new ffi.Library('user32.dll', {
LockWorkStation: ['int', []]
})
const AIMOUSELIB = new ffi.Library(AIMOUSELIBPath, {
setScreenbright: ['void', ['int']],
getScreenbright: ['int', []]
})
const AIMouseSDK = new ffi.Library(AIMouseSDKPath, {
send_editinput: ['int', ['string']],
})
export const useWinSDK = () => {
const ffi = require('ffi-napi')
const iconv = require('iconv-lite')
const user32 = new ffi.Library('user32.dll', {
LockWorkStation: ['int', []]
})
return {
sleep() {
user32.LockWorkStation()
},
setScreenbright(value){
AIMOUSELIB.setScreenbright(value)
},
getScreenbright(){
return AIMOUSELIB.getScreenbright()
},
sendText(s) {
AIMouseSDK.send_editinput(iconv.encode(s, 'GBK'))
},
shutdown(){
exec('shutdown -s -t 0')
},
showDesktop() {
nircmd('sendkeypress rwin+D')
},
getVolume() {
return loudness.getVolume()
},
setVolume(val){
loudness.setVolume(val)
},
inputEnter() {
const AIMOUSELIB = new ffi.Library(AIMOUSELIBPath, {
setScreenbright: ['void', ['int']],
getScreenbright: ['int', []]
})
const AIMouseSDK = new ffi.Library(AIMouseSDKPath, {
send_editinput: ['int', ['string']]
})
},
inputBackspace(){
}
}
return {
sleep() {
user32.LockWorkStation()
},
setScreenbright(value) {
AIMOUSELIB.setScreenbright(value)
},
getScreenbright() {
return AIMOUSELIB.getScreenbright()
},
sendText(s) {
AIMouseSDK.send_editinput(iconv.encode(s, 'GBK'))
},
shutdown() {
exec('shutdown -s -t 0')
},
showDesktop() {
nircmd('sendkeypress rwin+D')
},
getVolume() {
return loudness.getVolume()
},
setVolume(val) {
loudness.setVolume(val)
},
inputEnter() {},
inputBackspace() {}
}
}
import bluetoothSdkPath_x86 from '@resources/lib/mac/intel/AIMouseSDK.node?asset'
import bluetoothSdkPath from '@resources/lib/mac/m1/AIMouseSDK.node?asset'
import AIMouseSDK_x86 from '@resources/lib/mac/intel/AIMouseSDK.node?asset'
import AIMouseSDK from '@resources/lib/mac/m1/AIMouseSDK.node?asset'
import { createRequire } from 'module'
import { isX86 } from '@main/tools/util'
const moduleRequire = createRequire(import.meta.url)
export const useMacBluetoothSDK = () => {
const native = moduleRequire(isX86() ? bluetoothSdkPath_x86 : bluetoothSdkPath)
const native = moduleRequire(isX86() ? AIMouseSDK_x86 : AIMouseSDK)
return {
initLd2() {
......@@ -25,27 +25,12 @@ export const useMacBluetoothSDK = () => {
})
})
},
switchConnect() {
native.switchConnect(0)
},
releaseLd2() {
return new Promise((resolve, reject) => {
console.log('开始断开')
native.disconnectBleDevice((str) => {
console.log('断开', str)
if (str === 'success') {
resolve()
} else {
reject()
}
})
})
},
releaseLd2() {},
lotBusinessAuth() {},
getDeviceInfo() {
return new Promise((resolve, reject) => {
native.getDeviceInfo((err, data) => {
if(err){
if (err) {
reject(err)
return
}
......@@ -69,19 +54,6 @@ export const useMacBluetoothSDK = () => {
native.recordingCallBack((data) => {
func(data)
})
},
setLogCallback(func) {
native.log((data) => {
func(data)
})
},
startAuthentication() {
native.startAuthentication()
},
setConnectCallback(func) {
native.checkConnect((res) => {
func(res)
})
}
}
}
import AIMouseCSharpPath from '../../../../../../resources/lib/win/testelec.dll?asset&asarUnpack'
import '../../../../../../resources/lib/win/sbcble.dll?asset&asarUnpack'
import AIMouseCSharpPath from '@resources/lib/win/testelec.dll?asset&asarUnpack'
import '@resources/lib/win/sbcble.dll?asset&asarUnpack'
export const useWinBluetoothSDK = ()=>{
const edge = require('electron-edge-js')
const TYPE_NAME = 'testelec.MouseTest'
const initLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'initLd2'
})
const releaseLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'releaseLd2'
})
const lotBusinessAuth = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'lotBusinessAuth'
})
const getDeviceInfo = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'getDeviceInfo'
})
const setDPI = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setDPI'
})
const setBleCMDCallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setBleCMDCallback'
})
const setBleDATACallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setBleDATACallback'
})
export const useWinBluetoothSDK = () => {
const edge = require('electron-edge-js')
const TYPE_NAME = 'testelec.MouseTest'
const initLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'initLd2'
})
const releaseLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'releaseLd2'
})
const lotBusinessAuth = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'lotBusinessAuth'
})
return {
initLd2() {
return new Promise((resolve, reject) => {
initLd2({
callback(str) {
console.log(str)
if (str === 'init_success') {
resolve('success')
} else {
reject(new Error('fail'))
}
}
})
})
},
releaseLd2() {
return new Promise((resolve, reject) => {
releaseLd2({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error(str))
}
}
})
})
},
lotBusinessAuth() {
return new Promise((resolve, reject) => {
lotBusinessAuth({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error(str))
}
}
})
})
},
getDeviceInfo() {
return new Promise((resolve) => {
let obj = {}
getDeviceInfo({
callback(data) {
console.log('鼠标信息', data)
const tmp = JSON.parse(data)
if (tmp['version']) {
Object.assign(obj, tmp)
resolve(obj)
} else {
Object.assign(obj, tmp)
}
}
})
})
},
setDPI(value) {
return new Promise((resolve) => {
setDPI({
value,
callback() {
resolve()
}
})
})
},
setBleCMDCallback(func) {
setBleCMDCallback({
callback(data) {
// console.log('指令', data.length, data)
func(data)
}
})
},
setBleDATACallback(func) {
setBleDATACallback({
callback(data) {
// console.log('指令', data.length, data)
func(data)
}
})
},
setLogCallback(func) {
},
startAuthentication(){
const getDeviceInfo = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'getDeviceInfo'
})
const setDPI = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setDPI'
})
const setBleCMDCallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setBleCMDCallback'
})
const setBleDATACallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setBleDATACallback'
})
return {
initLd2() {
return new Promise((resolve, reject) => {
initLd2({
callback(str) {
console.log(str)
if (str === 'init_success') {
resolve(str)
} else {
reject(new Error('fail'))
}
}
})
})
},
releaseLd2() {
return new Promise((resolve, reject) => {
releaseLd2({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error('fail'))
}
}
})
})
},
lotBusinessAuth() {
return new Promise((resolve, reject) => {
console.log('lotBusinessAuth')
lotBusinessAuth({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error('fail'))
}
}
})
})
},
getDeviceInfo() {
return new Promise((resolve) => {
let obj = {}
getDeviceInfo({
callback(data) {
console.log('鼠标信息', data)
const tmp = JSON.parse(data)
if (tmp['version']) {
Object.assign(obj, tmp)
resolve(obj)
} else {
Object.assign(obj, tmp)
}
}
})
})
},
setDPI(value) {
return new Promise((resolve) => {
setDPI({
value,
callback() {
resolve()
}
})
})
},
setBleCMDCallback(func) {
setBleCMDCallback({
callback(data) {
// console.log('指令', data.length, data)
func(data)
}
})
},
setBleDATACallback(func) {
setBleDATACallback({
callback(data) {
// console.log('指令', data.length, data)
func(data)
}
})
}
}
\ No newline at end of file
}
}
......@@ -8,6 +8,7 @@ export const AI_KEY = '42'
export const AI_KEY_LONG_DOWN = '25'
// AI键长按弹起
export const AI_KEY_LONG_UP = '26'
// M键值
export const M_KEY = '43'
// M键长按按下
......@@ -30,27 +31,11 @@ export const useMouseSDK = () => {
let mouseSDK = null
let mouseType = ''
const initLd2 = async (type = 'bluetooth') => {
mouseType = type
// if (type === 'bluetooth') {
// try {
// await bluetoothSDK.switchConnect()
// mouseSDK = bluetoothSDK
// } catch (err) {
// Logger.log('bluetoothSDK初始化失败')
// return Promise.reject(err)
// }
// } else if (type === 'usb') {
// try {
// await usbSDK.initLd2()
// mouseSDK = usbSDK
// } catch (err) {
// Logger.log('usbSDK初始化失败')
// return Promise.reject(err)
// }
// }
const initLd2 = async () => {
mouseType = ''
try {
await bluetoothSDK.initLd2()
await bluetoothSDK.lotBusinessAuth()
Logger.log('bluetoothSDK初始化成功')
mouseSDK = bluetoothSDK
mouseType = 'bluetooth'
......@@ -60,10 +45,12 @@ export const useMouseSDK = () => {
try {
await usbSDK.initLd2()
Logger.log('usbSDK初始化成功')
await usbSDK.lotBusinessAuth()
Logger.log('usbSDK鉴权成功')
mouseSDK = usbSDK
mouseType = 'usb'
} catch (err) {
Logger.log('usbSDK初始化失败')
Logger.log('usbSDK初始化失败', err)
return Promise.reject(err)
}
} else {
......@@ -74,13 +61,6 @@ export const useMouseSDK = () => {
// mouseSDK = usbSDK
}
const setLogCallback = (func = () => {}) => {
mouseSDK && mouseSDK.setLogCallback(func)
}
const releaseLd2 = () => {
console.log('释放一', mouseType, mouseSDK && mouseSDK.releaseLd2)
return mouseSDK && mouseSDK.releaseLd2()
}
const setBleCMDCallback = (func = () => {}) => {
mouseSDK && mouseSDK.setBleCMDCallback(func)
}
......@@ -101,14 +81,6 @@ export const useMouseSDK = () => {
return mouseSDK.setDPI(value)
}
const startAuthentication = () => {
mouseSDK && mouseSDK.startAuthentication()
}
const setConnectCallback = (func = () => {}) => {
mouseSDK && mouseSDK.setConnectCallback(func)
}
return {
initLd2,
getType() {
......@@ -117,10 +89,6 @@ export const useMouseSDK = () => {
setBleCMDCallback,
setBleDATACallback,
getDeviceInfo,
setDPI,
setLogCallback,
releaseLd2,
startAuthentication,
setConnectCallback
setDPI
}
}
import { platform } from "@electron-toolkit/utils";
import { platform } from '@electron-toolkit/utils'
import { useMacUSBSDK } from './useMacUSBSDK'
import { useWinUSBSDK } from './useWinUSBSDK'
import { useLinuxUSBSDK } from "./useLinuxUSBSDK";
export const useUSBSDK = ()=>{
if(!platform.isMacOS && !platform.isWindows && !platform.isLinux){
throw new Error("暂未适配该平台")
}
import { useLinuxUSBSDK } from './useLinuxUSBSDK'
export const useUSBSDK = () => {
if (!platform.isMacOS && !platform.isWindows && !platform.isLinux) {
throw new Error('暂未适配该平台')
}
if(platform.isMacOS){
return useMacUSBSDK()
}
if (platform.isMacOS) {
return useMacUSBSDK()
}
if(platform.isWindows){
return useWinUSBSDK()
}
if(platform.isLinux) {
return useLinuxUSBSDK()
}
}
\ No newline at end of file
if (platform.isWindows) {
return useWinUSBSDK()
}
if (platform.isLinux) {
return useLinuxUSBSDK()
}
}
import usbSdkPath_x86 from '@resources/lib/mac/intel/AIMouseSDK.node?asset'
import usbSdkPath from '@resources/lib/mac/m1/AIMouseSDK.node?asset'
import AIMouseSDK_x86 from '@resources/lib/mac/intel/AIMouseSDK.node?asset'
import AIMouseSDK from '@resources/lib/mac/m1/AIMouseSDK.node?asset'
import { createRequire } from 'module'
const moduleRequire = createRequire(import.meta.url)
import { isX86 } from '@main/tools/util'
export const useMacUSBSDK = () => {
const native = moduleRequire(isX86() ? usbSdkPath_x86 : usbSdkPath)
const native = moduleRequire(isX86() ? AIMouseSDK_x86 : AIMouseSDK)
return {
initLd2() {
return new Promise((resolve, reject) => {
......@@ -20,15 +20,12 @@ export const useMacUSBSDK = () => {
})
})
},
switchConnect() {
native.switchConnect(1)
},
releaseLd2() {},
lotBusinessAuth() {},
getDeviceInfo() {
return new Promise((resolve, reject) => {
native.getDeviceInfo((err, data) => {
if(err){
if (err) {
reject(err)
return
}
......@@ -52,13 +49,6 @@ export const useMacUSBSDK = () => {
native.recordingCallBack((data) => {
func(data)
})
},
setLogCallback(func) {},
startAuthentication() {},
setConnectCallback(func) {
native.checkConnect((res) => {
func(res)
})
}
}
}
import AIMouseCSharpPath from '../../../../../../resources/lib/win/elecUSBMouse.dll?asset&asarUnpack'
import '../../../../../../resources/lib/win/CyUSB.dll?asset&asarUnpack'
import '../../../../../../resources/lib/win/NAudio.dll?asset&asarUnpack'
import AIMouseCSharpPath from '@resources/lib/win/elecUSBMouse.dll?asset&asarUnpack'
import '@resources/lib/win/CyUSB.dll?asset&asarUnpack'
import '@resources/lib/win/NAudio.dll?asset&asarUnpack'
import '@resources/lib/win/Newtonsoft.Json.dll?asset&asarUnpack'
import '@resources/lib/win/Newtonsoft.Json.xml?asset&asarUnpack'
export const useWinUSBSDK = () =>{
const edge = require('electron-edge-js')
export const useWinUSBSDK = () => {
const edge = require('electron-edge-js')
const TYPE_NAME = 'elecUSBMouse.MOUSEUSB'
const initLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'initAIUSB'
})
const releaseLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'releaseAIUSB'
})
const lotBusinessAuth = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'lotBusinessAuthUSB'
})
const getDeviceInfo = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'getDeviceInfoUSB'
})
const setDPI = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setDPIUSB'
})
const setBleCMDCallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setUSBCMDCallback'
})
const setBleDATACallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setUSBDATACallback'
})
const TYPE_NAME = 'elecUSBMouse.MOUSEUSB'
const initLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'initAIUSB'
})
return {
initLd2() {
return new Promise((resolve, reject) => {
initLd2('', (err, data) => {
if (data == 'success') {
resolve()
} else {
reject(new Error(data))
}
})
})
},
releaseLd2() {
return new Promise((resolve, reject) => {
releaseLd2({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error(str))
}
}
})
})
},
lotBusinessAuth() {
return new Promise((resolve, reject) => {
lotBusinessAuth({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error(str))
}
}
})
})
},
getDeviceInfo() {
return new Promise((resolve) => {
let obj = {}
getDeviceInfo({
callback(data) {
console.log('鼠标信息', data)
const tmp = JSON.parse(data)
if (tmp['version']) {
Object.assign(obj, tmp)
resolve(obj)
} else {
Object.assign(obj, tmp)
}
}
})
})
},
setDPI(value) {
return new Promise((resolve, reject) => {
try {
setDPI({ value })
resolve()
} catch (error) {
reject(error)
}
})
},
setBleCMDCallback(func) {
setBleCMDCallback({
callback(data) {
func(data)
}
})
},
setBleDATACallback(func) {
setBleDATACallback({
callback(data) {
func(data)
}
})
},
setLogCallback(func) {
},
startAuthentication(){
const releaseLd2 = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'releaseAIUSB'
})
const lotBusinessAuth = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'lotBusinessAuthUSB'
})
const getDeviceInfo = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'getDeviceInfoUSB'
})
const setDPI = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setDPIUSB'
})
const setBleCMDCallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setUSBCMDCallback'
})
const setBleDATACallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setUSBDATACallback'
})
const setUSBCMDTestCallback = edge.func({
assemblyFile: AIMouseCSharpPath,
typeName: TYPE_NAME,
methodName: 'setUSBCMDTestCallback'
})
return {
initLd2() {
return new Promise((resolve, reject) => {
initLd2('', (err, data) => {
console.log('这是初始化回调', err, data)
if (data == 'success') {
resolve()
} else {
reject(new Error(data))
}
})
})
},
releaseLd2() {
return new Promise((resolve, reject) => {
console.log('释放ld2')
releaseLd2({
callback(str) {}
})
console.log('释放ld1')
resolve()
})
},
lotBusinessAuth() {
return new Promise((resolve, reject) => {
console.log('lotBusinessAuth')
lotBusinessAuth({
callback(str) {
if (str === 'success') {
resolve(str)
} else {
reject(new Error(str))
}
}
})
})
},
getDeviceInfo() {
return new Promise((resolve) => {
let obj = {}
getDeviceInfo({
callback(data) {
console.log('鼠标信息', data)
const tmp = JSON.parse(data)
if (tmp['version']) {
Object.assign(obj, tmp)
resolve(obj)
} else {
Object.assign(obj, tmp)
}
}
})
})
},
setDPI(value) {
return new Promise((resolve, reject) => {
try {
setDPI({ value })
resolve()
} catch (error) {
reject(error)
}
})
},
setBleCMDCallback(func) {
setBleCMDCallback({
callback(data) {
func(data)
}
})
},
setUSBCMDTestCallback(func) {
console.log('onAddRemoveUSBCallback')
setUSBCMDTestCallback({
callback(data) {
func(data)
}
})
},
setBleDATACallback(func) {
setBleDATACallback({
callback(data) {
func(data)
}
})
},
setADDREMOVECallback(func) {
console.log('内部执行')
setUSBCMDTestCallback({
callback(data) {
func(data)
}
})
}
}
}
module.exports = useWinUSBSDK
\ No newline at end of file
module.exports = useWinUSBSDK
import Logger from 'electron-log/main'
import Screenshots from 'electron-screenshots'
import { aliTranslateText, translateText } from '../tools/translate'
import { translateText } from '../tools/translate'
import { useOCRBuilder } from '../tools/OCRBuilder.js'
import fs from 'fs'
export const setupScreenshot = (conf) => {
const { RSData } = conf
......@@ -41,63 +40,31 @@ export const setupScreenshot = (conf) => {
// 点击翻译按钮回调事件
screenshots.on('translate', async (e, buffer, bounds) => {
e.preventDefault()
console.log('translate', buffer.buffer, bounds)
// console.log(Buffer.from(buffer.buffer).toString('base64'))
// console.log('translate', buffer.buffer, bounds)
try {
const translateOptions = await RSData.get('translate')
// const res = await ocr.bufferToText(buffer)
// fs.writeFileSync('./test1.txt', `data:image/png;base64,${Buffer.from(buffer).toString('base64')}`)
const res = await ocr.aliImageBase64ToText(`${Buffer.from(buffer).toString('base64')}`)
if (!res.data.error) {
if(!res.data.data){
Logger.info('OCR:', '识别内容为空')
screenshots.sendTranslateText([
{
type: 'origin',
text: '',
lang: translateOptions.from,
langText: translateOptions.fromText
},
{
type: 'translate',
text: '',
lang: translateOptions.to,
langText: translateOptions.toText
}
])
return
}
const originText = res.data.data
// // 识别出内容
// const originText = res.body.readResult.blocks
// .map((v) => v.lines.map((vi) => vi.text).join(' '))
// .join('\n')
const res = await ocr.bufferToText(buffer)
if (res.body.readResult && res.body.readResult.blocks.length > 0) {
// 识别出内容
const originText = res.body.readResult.blocks
.map((v) => v.lines.map((vi) => vi.text).join(' '))
.join('\n')
Logger.info('OCR:', '识别内容', originText)
// let translateOCRText = ''
const result = await aliTranslateText(
let translateOCRText = ''
if (originText != '') {
const translateOCRTextRes = await translateText(
originText,
translateOptions.from,
translateOptions.to
)
// if (originText != '') {
// const translateOCRTextRes = await translateText(
// originText,
// translateOptions.from,
// translateOptions.to
// )
Logger.info('OCR:', '翻译内容', result)
)
Logger.info('OCR:', '翻译内容', translateOCRTextRes)
// if (translateOCRTextRes && translateOCRTextRes.length > 0) {
// translateOCRText = translateOCRTextRes[0][translateOptions.to]
// }
// }
if (translateOCRTextRes && translateOCRTextRes.length > 0) {
translateOCRText = translateOCRTextRes[0][translateOptions.to]
}
}
screenshots.sendTranslateText([
{
......@@ -108,14 +75,13 @@ export const setupScreenshot = (conf) => {
},
{
type: 'translate',
text: result,
text: translateOCRText,
lang: translateOptions.to,
langText: translateOptions.toText
}
])
} else {
Logger.error('OCR:识别失败', res.error)
Logger.info('OCR:', '识别内容为空')
}
} catch (error) {
Logger.error('OCR:识别失败', error)
......
......@@ -20,7 +20,6 @@ const DEFAULT_WIN_OPTIONS = {
show: false,
autoHideMenuBar: true,
frame: false,
// titleBarStyle: 'hidden',
// resizable: false,
...(platform.isWindows ? { icon: winIcon } : { icon: linuxIcon }),
webPreferences: {
......
......@@ -17,37 +17,53 @@ export const useCommand = (conf) => {
win && win.isVisible() && router.close('/audioWin')
}
RSCommandInstance.register('关闭助手', () => {
// 关闭助手
RSCommandInstance.register('closeApp', () => {
createOrHideAudioWin()
})
RSCommandInstance.register('返回桌面', () => {
// 返回桌面
RSCommandInstance.register('backDesktop', () => {
ffi.showDesktop()
})
RSCommandInstance.register('关机', () => {
// 关机
RSCommandInstance.register('shutdown', () => {
ffi.computerClose()
})
RSCommandInstance.register('进入休眠', () => {
// 进入休眠
RSCommandInstance.register('sleep', () => {
ffi.computerSleep()
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text: '电脑已休眠' })
})
RSCommandInstance.register('音量增加', () => {
// 增加音量
RSCommandInstance.register('volumeAdd', () => {
ffi.addVolume()
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text: '音量已增加' })
})
RSCommandInstance.register('音量减少', () => {
// 减小音量
RSCommandInstance.register('volumeReduce', () => {
ffi.reduceVolume()
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text: '音量已减少' })
})
RSCommandInstance.register('亮度减少', () => {
// 减小亮度
RSCommandInstance.register('lightReduce', () => {
ffi.reduceScreenBright()
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text: '亮度已减少' })
})
RSCommandInstance.register('亮度增加', () => {
// 增加亮度
RSCommandInstance.register('lightAdd', () => {
ffi.addScreenBright()
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text: '亮度已增加' })
})
RSCommandInstance.register('播报日期', () => {
// 播报日期
RSCommandInstance.register('broadcastDate', () => {
// 通知渲染进程播报
const win = router.get('/')
const text = `现在是:${dayjs().format('YYYY年 MM月 DD日 HH时 mm分 ss秒')}`
......@@ -56,7 +72,9 @@ export const useCommand = (conf) => {
})
// RSEvent.send(router.get('/answerPanel'), ANSWER_TEXT, { text })
})
RSCommandInstance.register('播报天气', async () => {
// 播报天气
RSCommandInstance.register('broadcastWeather', async () => {
// 通知渲染进程获取天气并播报
const res = await baiduAPI.weather()
if (res.status === 0) {
......@@ -109,6 +127,10 @@ export const useCommand = (conf) => {
}
return false
},
// 完全匹配直接执行命令
runCommand(name) {
RSCommandInstance.run(name)
}
}
}
......@@ -9,6 +9,4 @@ export { default as RSPageEventPlugin } from './rs-page-event-plugin'
export { default as RSVoiceInput } from './rs-vioce-input'
export { default as RSMouseSetup } from './rs-mouse-setup'
export { default as RSASRPlugin } from './rs-asr-plugin'
export { default as RSLogServicePlugin } from './rs-log-service-plugin'
export { default as RSUpdatePlugin } from './rs-update-plugin'
import Logger from 'electron-log/main'
import { ASR } from '../../raisoundRecordSdk/index'
import { useASRBuilder } from '../../tools/ASRBuilder'
import { ASR_RELOAD } from '../../../eventCenter/constant'
export default {
name: 'RSASRPlugin',
async install(app, name) {
const { RSEventPlugin, RSDataPlugin, RSFFIPlugin } = app.$p
// const { RSEventPlugin, RSDataPlugin, RSFFIPlugin } = app.$p
const asrBuilder = await useASRBuilder(app.$p, app.router)
await asrBuilder.initASR()
app.$p[name] = asrBuilder
console.log('asr赋值成功')
RSEventPlugin.on(ASR_RELOAD, async (event, data) => {
Logger.log("切换ASR语言")
asrBuilder.close()
await asrBuilder.initASR()
app.$p[name] = asrBuilder
})
}
}
......@@ -12,6 +12,5 @@ export default {
Logger.initialize()
Logger.info(`[${name}] 日志插件初始化成功`)
}
}
import { useLogsBuilder } from '../../tools/LogsBuilder'
import { LOG_GET_LIST, LOG_OPEN_DIR, LOG_OPEN_FILE, LOG_UPLOAD } from '../../../eventCenter/constant'
export default {
name: 'RSLogServicePlugin',
install(instance, name) {
const { RSEventPlugin } = instance.$p
const logBuilder = useLogsBuilder()
RSEventPlugin.handle(LOG_GET_LIST, ()=>{
return logBuilder.getLogList()
})
RSEventPlugin.handle(LOG_UPLOAD, (e, logPath)=>{
return logBuilder.uploadLog(logPath)
})
RSEventPlugin.on(LOG_OPEN_FILE, (e, logPath)=>{
logBuilder.openLog(logPath)
})
RSEventPlugin.on(LOG_OPEN_DIR, ()=>{
logBuilder.openLogDir()
})
}
}
import { shell } from 'electron'
import Logger from 'electron-log/main'
export default {
name: 'RSMKey',
async install(app, name) {
const { RSEventPlugin, RSDataPlugin } = app.$p
app.$p[name] = {
async isGetAudio(){
const data = await RSDataPlugin.get('msetting')
return data.type == 1 || data.type == 3
},
async isRunCommand() {
const data = await RSDataPlugin.get('msetting')
return [2,4,5,6,8,9,10].includes(data.type)
},
async runCommand(){
const data = await RSDataPlugin.get('msetting')
if(data.type == 6){
shell.openExternal("https://www.baidu.com")
return
}
if(data.type == 10) {
if(/^(http:\/\/|https:\/\/)/){
shell.openExternal(data.url)
}
return
}
}
}
}
}
import { screen } from 'electron'
import {
ASR_MAIN_TEMP_TEXT,
ASR_MAIN_WIN_HIDE,
MOUSE_ASR_FINISH,
MOUSE_AUDIO_DATA,
MOUSE_LONG_PRESS,
MOUSE_LONG_PRESS_DOWN,
MOUSE_RECONNECT,
MOUSE_STATUS
MOUSE_LONG_PRESS_DOWN
} from '../../../eventCenter/constant'
import {
AI_KEY,
......@@ -18,8 +15,12 @@ import {
M_KEY
} from '../../init/setupFFI'
import Logger from 'electron-log/main'
import { AI_KEY_LONG_DOWN, M_KEY_LONG_DOWN, M_KEY_LONG_UP } from '../../init/setupFFI/mouseSDK'
import fs from 'fs'
import path from 'path'
import wavConverter from 'wav-converter'
import { useMKeyBuilder } from '../../tools/MKeyBuilder'
import { AI_KEY_LONG_DOWN, M_KEY_LONG_DOWN, M_KEY_LONG_UP } from '../../init/setupFFI/mouseSDK'
const handleAudioBase64DataToPCMData = (data) => {
const decodedData = atob(data)
......@@ -50,15 +51,8 @@ export default {
name: 'RSMouseSetup',
async install(app, name) {
const { router } = app
const { RSASRPlugin, RSFFIPlugin, RSEventPlugin, RSDataPlugin } = app.$p
let lastKeycode = ''
global.isConnent = false
global.connectType = 'bluetooth'
global.connectRetryCount = 0
RSEventPlugin.handle(MOUSE_STATUS, () => {
return global.isConnent
})
const { RSASRPlugin, RSFFIPlugin, RSScreenshotsPlugin, RSEventPlugin, RSDataPlugin } = app.$p
let M_KEY_TYPE = await RSDataPlugin.get('msetting.type')
......@@ -86,15 +80,19 @@ export default {
}
}
}
const releaseMous = async () => {
return RSFFIPlugin.releaseMouse()
}
const connectMouse = async () => {
// await RSFFIPlugin.releaseMouse()
// console.log("释放成功")
Logger.log('开始连接鼠标')
await RSFFIPlugin.initMouse(global.connectType)
global.isConnent = true
try {
RSEventPlugin.on(MOUSE_ASR_FINISH, () => {
const win = router.get('/audioWin')
win && win.isVisible() && router.close('/audioWin')
})
// Logger.log('SDK初始化', RSFFIPlugin.initMouse())
// Logger.log('蓝牙鉴权', RSFFIPlugin.initBluetoothAuth())
// console.log('ceshi', )
// console.log('ceshi', RSFFIPlugin.initBluetoothAuth())
console.log(RSFFIPlugin)
await RSFFIPlugin.initMouse()
Logger.log('鼠标初始化成功')
// let pcmData = []
RSFFIPlugin.onMouseClick(async (e) => {
......@@ -103,9 +101,8 @@ export default {
let keyCode = e.slice(10, 12)
keyCode = keyCode ? keyCode : e
lastKeycode = keyCode
// 设置
RSASRPlugin.setKeycode(keyCode)
Logger.log('鼠标点击', keyCode)
RSASRPlugin.setKeycode(keyCode)
if (keyCode === AI_KEY) {
const win = router.get('/web')
if (!win) {
......@@ -133,6 +130,7 @@ export default {
(MKey.isRecoder(M_KEY_TYPE) && keyCode == M_KEY_LONG_DOWN)
) {
// 长按,唤起语音界面
// pcmData = []
createOrHideAudioWin('longClick')
RSASRPlugin.setClickType(2)
return
......@@ -144,8 +142,12 @@ export default {
) {
// 长按松开,发送语音数据
RSASRPlugin.setClickType(3)
RSASRPlugin && RSASRPlugin.end()
RSASRPlugin &&
RSASRPlugin.send(
JSON.stringify({
action: 'PausedASR'
})
)
// 兼容PausedASR没有返回最终结果时,发送文本
RSASRPlugin && RSASRPlugin.sendTempTextToInput()
const win = router.get('/audioWin')
......@@ -167,12 +169,14 @@ export default {
}
if (keyCode === AUDIO_SHORT_UP_KEY) {
RSASRPlugin && RSASRPlugin.end()
// RSASRPlugin && RSASRPlugin.end()
const isEnable = await RSDataPlugin.get('typing.click')
const win = router.get('/audioWin')
if (isEnable || win.isVisible()) {
// 短按松开,关闭窗口,结束转写
if (win) {
// RSEventPlugin.send(win, MOUSE_LONG_PRESS)
// createOrHideAudioWin('click')
RSEventPlugin.send(win, ASR_MAIN_WIN_HIDE)
win.hide()
}
......@@ -182,6 +186,8 @@ export default {
})
RSFFIPlugin.onMousePCMData((data) => {
console.log('收到语音')
// pcmData.push(handleAudioBase64DataToPCMData(data))
if (
[AUDIO_LONG_DOWN_KEY, AUDIO_SHORT_DOWN_KEY].includes(lastKeycode) ||
(MKey.isRecoder(M_KEY_TYPE) && [M_KEY_LONG_DOWN].includes(lastKeycode))
......@@ -190,57 +196,21 @@ export default {
if (win) {
RSEventPlugin.send(win, MOUSE_AUDIO_DATA, data)
}
RSASRPlugin && RSASRPlugin.send(Buffer.from(data, 'base64'))
RSASRPlugin &&
RSASRPlugin.send(
JSON.stringify({
action: 'StreamingASR',
audio_data: data
})
)
}
})
RSFFIPlugin.onMouseLog((data) => {})
}
try {
RSEventPlugin.on(MOUSE_ASR_FINISH, () => {
const win = router.get('/audioWin')
win && win.isVisible() && router.close('/audioWin')
})
await connectMouse()
// await RSFFIPlugin.initMouse(global.connectType)
// RSFFIPlugin.setConnectCallback(async (res) => {
// Logger.log(`setConnectCallback ~ res:`, res, global.connectType)
// if (res === 'success') {
// if (!global.isConnent) {
// connectMouse()
// }
// } else {
// global.isConnent = false
// // if (global.connectRetryCount < 20) {
// // global.connectRetryCount++
// // global.connectType = global.connectType === 'bluetooth' ? 'usb' : 'bluetooth'
// // await RSFFIPlugin.initMouse(global.connectType)
// // } else {
// // Logger.log('蓝牙和USB未连接')
// // }
// Logger.log('蓝牙和USB未连接')
// }
// })
} catch (error) {
Logger.log('鼠标初始化失败', typeof error === 'string' ? error : error.message)
}
RSEventPlugin.handle(MOUSE_RECONNECT, async () => {
// await releaseMous();
// console.log("开始连接")
// await connectMouse()
return RSFFIPlugin.startAuthentication()
})
// RSFFIPlugin.onMouseSelectedAreaText((text) => {
// console.log(text)
// })
}
}
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, time)
})
}
import { BrowserWindow, dialog, shell } from 'electron'
import { BrowserWindow, dialog, shell, app } from 'electron'
import {
DIALOG_OPEN_DIRECTORY,
AUDIO_INPUT_DEVICE_OPEN,
......@@ -10,12 +10,10 @@ import {
ASR_WAKE_UP,
MOUSE_GET_DEVICE_INFO,
MOUSE_SET_DPI,
AXIOS_REQUEST,
MACADDRESS_GET
SYSTEM_APP_VERSION,
SYSTEM_LANGUAGE
} from '../../../../eventCenter/constant'
import { useCommand } from '../../middleware/command'
import axios from 'axios'
import { getMacAddress } from '../../../tools'
export const handleIPCEvent = (conf) => {
const { router, RSEvent, ffi, RSData } = conf
......@@ -23,15 +21,10 @@ export const handleIPCEvent = (conf) => {
// 打开窗口
RSEvent.on(WINDOW_OPEN, (e, url) => {
const win = router.get(url)
if (win && win.isDestroyed()) {
router.remove(url)
if (!win) {
router.open(url)
} else {
if (!win) {
router.open(url)
} else {
win.focus()
}
win.focus()
}
})
......@@ -39,19 +32,16 @@ export const handleIPCEvent = (conf) => {
const win = BrowserWindow.fromWebContents(e.sender)
return dialog.showOpenDialogSync(win, { properties: ['openDirectory', 'createDirectory'] })
})
RSEvent.handle(DIALOG_GET_FILE, (e) => {
const win = BrowserWindow.fromWebContents(e.sender)
return dialog.showOpenDialogSync(win, { properties: ['openDirectory', 'openFile'] })
})
RSEvent.handle(AXIOS_REQUEST, async (e, data) => {
const res = await axios.request(data)
return res.data
})
RSEvent.on(DIALOG_OPEN_DIRECTORY, (e, { dirPath }) => {
shell.openPath(dirPath)
})
RSEvent.handle(DIALOG_GET_FILE, (e) => {
const win = BrowserWindow.fromWebContents(e.sender)
return dialog.showOpenDialogSync(win, { properties: ['openDirectory', 'openFile'] })
})
RSEvent.on(AUDIO_INPUT_DEVICE_OPEN, () => {
const win = router.get('/audioCheckAlert')
if (!win) {
......@@ -97,7 +87,11 @@ export const handleIPCEvent = (conf) => {
return ffi.setDPI(data)
})
RSEvent.handle(MACADDRESS_GET, (e, data) => {
return getMacAddress()
RSEvent.handle(SYSTEM_APP_VERSION, () => {
return app.getVersion()
})
RSEvent.handle(SYSTEM_LANGUAGE, () => {
return app.getLocale()
})
}
import { globalShortcut, BrowserWindow } from 'electron'
import { setupScreenshot } from '../../init/setupScreenshot'
import Logger from 'electron-log/main'
import { SCREENSHOTS_KEY } from '../../../eventCenter/constant'
export default {
name: 'RSScreenshotsPlugin',
async install(app, name) {
const { RSDataPlugin, RSEventPlugin } = app.$p
install(app, name) {
const { RSDataPlugin } = app.$p
if (!RSDataPlugin) {
throw new Error(`[${name}]插件依赖[RSDataPlugin]`)
}
const screenshots = setupScreenshot({ RSData: RSDataPlugin })
RSEventPlugin.handle(SCREENSHOTS_KEY, async(e, data)=>{
const newKey = `${data.main}+${data.sup}`
console.log(newKey)
const isFlag = globalShortcut.isRegistered(newKey)
console.log(isFlag)
if(isFlag){
return Promise.reject("注册失败")
}
const res = await RSDataPlugin.get('translateKey')
const oldKey = `${res.mainKey}+${res.supKey}`
if(globalShortcut.isRegistered(oldKey)) {
globalShortcut.unregister(oldKey)
}
globalShortcut.register(newKey, ()=>{
if (screenshots.$win?.isFocused()) {
screenshots.endCapture()
}
screenshots.startCapture()
})
await RSDataPlugin.set('translateKey.mainKey', data.main)
await RSDataPlugin.set('translateKey.supKey', data.sup)
return Promise.resolve()
})
const res = await RSDataPlugin.get('translateKey')
console.log(res)
const key = `${res.mainKey}+${res.supKey}`
Logger.log(key)
globalShortcut.register(key, () => {
globalShortcut.register('ctrl+shift+b', () => {
if (screenshots.$win?.isFocused()) {
screenshots.endCapture()
}
......
import { UPDATE_CHECK, UPDATE_DOWNLOAD, UPDATE_VERSION } from "../../../eventCenter/constant"
import { useUpdateBuilder } from "../../tools/UpdataBuilder"
export default {
name: 'RSUpdatePlugin',
install(instance, name) {
const { RSEventPlugin } = instance.$p
const updateBuilder = useUpdateBuilder()
RSEventPlugin.handle(UPDATE_CHECK, ()=>{
return updateBuilder.checkUpdate()
})
RSEventPlugin.handle(UPDATE_VERSION, ()=>{
return updateBuilder.getLocalVersion()
})
RSEventPlugin.on(UPDATE_DOWNLOAD, (e, url)=>{
updateBuilder.jumpToDownload(url)
})
}
}
import RSPage from '../lib/RSPage'
export default new RSPage({
create() {
return {
width: 700,
height: 600,
resizable: false,
skipTaskbar: true,
frame: true,
// transparent: true,
webPreferences: {
webviewTag: true
}
}
},
async open(RSM, key) {
const op = await Promise.resolve().then(() => this.create())
const id = RSM.create(key, {...op, parent:RSM.get('/')})
const win = RSM.get(id)
this.$RSPage = {
id: win.id,
key,
RSM,
win
}
win.on('ready-to-show', () => {
win.setTitle('应用设置')
win.show()
})
}
// close(RSM, key) {
// if (RSM.get(key)) {
// RSM.get(key).hide()
// }
// }
})
......@@ -42,7 +42,7 @@ export default new RSPage({
if (isShow) {
win.setAlwaysOnTop(true, 'pop-up-menu', 1)
win.showInactive()
win.setAlwaysOnTop(false)
// win.setAlwaysOnTop(false)
}
})
} else {
......@@ -52,7 +52,7 @@ export default new RSPage({
if (win) {
win.setAlwaysOnTop(true, 'pop-up-menu', 1)
win.showInactive()
win.setAlwaysOnTop(false)
// win.setAlwaysOnTop(false)
}
}
},
......
// export { default as TTS } from './libs/TTS/index'
export { default as ASR } from './libs/ASR/index'
export { default as ALiASR } from './libs/ALiASR/index'
// export { default as Record } from './libs/record/index'
// export { default as usePCMPlayer } from './usePCMPlayer'
// export { default as WakeUp } from './libs/Wakeup/index'
import axios from 'axios'
import NLS from 'alibabacloud-nls'
import Logger from 'electron-log/main'
import { triggerEventInstance } from '../../util'
class ALiASR {
constructor(op={}){
if(!op || (op && !op.projectId && !op.url && !op.appkey && !op.tokenUrl)){
throw new Error("初始化参数错误,请检查传入参数")
}
this._op = op
// 事件储存器
this.events = new Map()
this.ws = null
const trigger = triggerEventInstance(this.events)
this._init(trigger)
}
async _init(trigger){
const res = await axios.get(`${this._op.tokenUrl}?ss=${this._op.projectId}`)
if(!(res.status ==200 && res.data && res.data.data) || res.data.error){
Logger.log("获取ASR token 失败", res.data.error)
throw new Error("获取ASR token 失败")
}
const token = res.data.data
const appkey = this._op.appkey
const url = this._op.url
const st = this.ws = new NLS.SpeechTranscription({
url,
appkey,
token
})
await trigger('open', '')
st.on('started',async (e)=>{
console.log('这是开始', e)
await trigger(ALiASR.ASR_INIT, e)
})
st.on("changed",async(e)=>{
console.log('这是中间状态',e)
const data = JSON.parse(e)
await trigger(ALiASR.ASR_RESULT_PROGRESS, {
origin: data,
results:data.payload.result
})
})
st.on("end",async(e)=>{
console.log('这是触发end',e)
const data = JSON.parse(e)
await trigger(ALiASR.ASR_RESULT_FINAL, {
origin: data,
results:data.payload.result
})
})
st.on("completed", async(e)=>{
console.log("这是最终结果2", e)
// await trigger(ALiASR.ASR_RESULT_FINAL, e)
})
st.on("closed",async ()=>{
console.log("这是结束")
if (this.events.get('close')) {
const tmp = this.events.get('close')
for (const [, func] of tmp) {
await func()
}
}
this.events = new Map()
})
st.on('failed',async (e)=>{
console.log("这是失败",e)
if (this.events.get('erroe')) {
const tmp = this.events.get('erroe')
for (const [, func] of tmp) {
await func(e)
}
}
})
await st.start(st.defaultStartParams(), true, 5000)
}
on(name, func) {
if (this.events.has(name)) {
const tmp = this.events.get(name)
tmp.set(`${name}_${tmp.size + 1}`, func)
this.events.set(name, tmp)
} else {
const tmp = new Map()
tmp.set(`${name}_${tmp.size + 1}`, func)
this.events.set(name, tmp)
}
}
off(name) {
this.events.delete(name)
}
send(data) {
console.log('发送数据:',data)
this.ws.sendAudio(data)
}
close() {
this.ws && this.ws.shutdown()
}
end() {
this.ws && this.ws.close()
}
}
// 定义类属性
// 已连接到ASR
ALiASR.ASR_CONNECTED = 'ASR_CONNECTED'
//ASR初始化成功
ALiASR.ASR_INIT = 'ASR_INIT'
// ASR结果
ALiASR.ASR_RESULT = 'ASR_RESULT'
// ASR获取一句话结果完成
ALiASR.ASR_RESULT_FINAL = 'ASR_RESULT_FINAL'
// ASR获取结果结束
ALiASR.ASR_RESULT_END = 'ASR_RESULT_END'
// ASR获取结果中
ALiASR.ASR_RESULT_PROGRESS = 'ASR_RESULT_PROGRESS'
export default ALiASR
\ No newline at end of file
......@@ -6,19 +6,17 @@ import audioWinPage from './page/audioWin'
import commandPanel from './page/commandPanel'
import answerPanel from './page/answerPanel'
import captions from './page/captions'
import NMHome from './page/nmHome'
import appSetting from './page/appSetting'
// import NMHome from './page/nmHome'
const router = new RSRouter()
// router.register('/', homePage)
router.register('/', NMHome)
router.register('/', homePage)
// router.register('/', NMHome)
router.register('/web', aiPage)
router.register('/audioCheckAlert', checkAudioAlertPage)
router.register('/audioWin', audioWinPage)
router.register('/commandPanel', commandPanel)
router.register('/answerPanel', answerPanel)
router.register('/captions', captions)
router.register('/appSetting', appSetting)
export default router
import Logger from 'electron-log/main'
import { shell } from 'electron'
import { ASR, ALiASR } from '../raisoundRecordSdk/index'
import {
ASR_MAIN_FINAL_TEXT,
ASR_MAIN_TEMP_TEXT,
ASR_MAIN_WIN_HIDE
} from '../../eventCenter/constant'
import { ASR } from '../raisoundRecordSdk/index'
import { ASR_MAIN_FINAL_TEXT, ASR_MAIN_TEMP_TEXT } from '../../eventCenter/constant'
import { useCommand } from '../lib/middleware/command'
import { M_KEY_LONG_UP } from '../init/setupFFI/mouseSDK'
import { aliTranslateText } from './translate'
import { translateText } from './translate'
import { AUDIO_LONG_UP_KEY, M_KEY_LONG_UP, AUDIO_SHORT_DOWN_KEY } from '../init/setupFFI/mouseSDK'
export const useQueue = () => {
const queue = []
......@@ -36,27 +32,49 @@ export const useQueue = () => {
}
}
function useVoiceSearch(text, commandList) {
let type,
resText,
isKeywordsCommand = false
text = text.replace(/,|\.|,|。|\?|?|!|!|、|\s/g, '')
const item = commandList.find((el) => el.keywords.toUpperCase() == text.toUpperCase())
if (item?.keywords) {
type = item.type
resText = item.content
isKeywordsCommand = true
} else if (text.startsWith('搜索')) {
type = 'search'
resText = text.replace('搜索', '')
}
return {
type,
resText,
isKeywordsCommand
}
}
// 设置单前按键类型
let keyCode = ''
// 执行队列
const queue = useQueue()
export const useASRBuilder = async (conf, router) => {
const { RSEventPlugin, RSDataPlugin, RSFFIPlugin } = conf
let isClearPunctuation = await RSDataPlugin.get('typing.punctuation')
let isCommandMode = await RSDataPlugin.get('typing.mode')
let mType = await RSDataPlugin.get('msetting.type')
let isOpenTranslate = await RSDataPlugin.get('typing.isOpenTranslate')
let translateFrom = await RSDataPlugin.get('typing.translateFrom')
let translateTo = await RSDataPlugin.get('typing.translateTo')
let mType = await RSDataPlugin.get('msetting.type')
let defaultEngine = await RSDataPlugin.get('search.defaultEngine')
let commandList = await RSDataPlugin.get('search.commandList')
global.asr = null
// 1 短按, 2长按按下-记录文本, 3长按弹起-发送文本
let clickType = ''
let tempText = ''
// ASR转写是否完成
let isFinish = false
// 设置单前按键类型
let keyCode = ''
// 执行队列
const queue = useQueue()
// 指令模块
const CMD = useCommand({ RSEvent: RSEventPlugin, router, ffi: RSFFIPlugin, RSData: RSDataPlugin })
......@@ -64,10 +82,11 @@ export const useASRBuilder = async (conf, router) => {
// 监听数据变化
RSDataPlugin.onDataChange(
[
'typing.translateFrom',
'typing.translateTo',
'typing.punctuation',
'typing.mode',
'typing.isOpenTranslate',
'typing.translateFrom',
'typing.translateTo',
'msetting.type',
'search.defaultEngine',
'search.commandList'
......@@ -75,74 +94,65 @@ export const useASRBuilder = async (conf, router) => {
async () => {
isClearPunctuation = await RSDataPlugin.get('typing.punctuation')
isCommandMode = await RSDataPlugin.get('typing.mode')
mType = await RSDataPlugin.get('msetting.type')
isOpenTranslate = await RSDataPlugin.get('typing.isOpenTranslate')
translateFrom = await RSDataPlugin.get('typing.translateFrom')
translateTo = await RSDataPlugin.get('typing.translateTo')
mType = await RSDataPlugin.get('msetting.type')
defaultEngine = await RSDataPlugin.get('search.defaultEngine')
commandList = await RSDataPlugin.get('search.commandList')
Logger.log('mType', mType)
}
)
function useVoiceSearch(text, commandList) {
let type, resText
text = text.replace(/,|\.|,|。|\?|?|!|!|、/g, '')
const item = commandList.find((el) => el.keywords.toUpperCase() == text.toUpperCase())
if (item?.keywords) {
type = item.type
resText = item.content
} else if (text.startsWith('搜索')) {
type = 'search'
resText = text.replace('搜索', '')
}
return {
type,
resText
}
}
const sendTextToInput = async (text) => {
tempText = ''
// const win = router.get('/audioWin')
// win && RSEventPlugin.send(win, ASR_MAIN_WIN_HIDE)
// let isCommand = false
// if (isCommandMode === 'ai') {
// Logger.log('命中指令模式,执行指令')
// isCommand = await CMD.hitCommandAndRunMethod(text)
// }
const { type, resText, isKeywordsCommand } = await useVoiceSearch(text, commandList)
// if (isCommandMode !== 'ai' || !isCommand) {
Logger.log(keyCode, keyCode == M_KEY_LONG_UP, mType)
if (keyCode == M_KEY_LONG_UP && mType == 3) {
// 翻译打字
// 把文本翻译丢入翻译队列,翻译完成才会向聚焦框输入
queue.push(async () => {
const res = await aliTranslateText(text, translateFrom, translateTo)
RSFFIPlugin.sendEditInput(res)
})
queue.run()
} else if (keyCode == M_KEY_LONG_UP && mType == 7) {
// 语音搜索
// type 'web' | 'exe' | 'dir' | 'search'
const { type, resText } = await useVoiceSearch(text, commandList)
let isCommand = false
if (isCommandMode === 'ai') {
Logger.log('命中指令模式,执行指令')
// isCommand = await CMD.hitCommandAndRunMethod(text)
isCommand = isKeywordsCommand
}
Logger.log('命中指令', keyCode, isCommand, isCommandMode)
if ((keyCode === AUDIO_LONG_UP_KEY || keyCode === AUDIO_SHORT_DOWN_KEY) && isCommand) {
if (type === 'web') {
shell.openExternal(resText)
} else if (['exe', 'dir'].includes(type)) {
shell.openPath(resText)
} else if (type === 'search') {
shell.openExternal(`${defaultEngine}${resText}`)
// shell.openExternal(`${defaultEngine}${resText}`)
} else if (type === 'command') {
CMD.runCommand(resText)
}
} else if (keyCode == M_KEY_LONG_UP && mType == 7) {
text = text.replace(/,|\.|,|。|\?|?|!|!|、|\s/g, '')
shell.openExternal(`${defaultEngine}${text}`)
} else if (
(keyCode == M_KEY_LONG_UP && mType == 3) ||
(keyCode === AUDIO_LONG_UP_KEY && isOpenTranslate) ||
(keyCode == AUDIO_SHORT_DOWN_KEY && isOpenTranslate)
) {
// 翻译打字
queue.push(async () => {
const res = await translateText(text, translateFrom, translateTo)
if (res?.length > 0) {
const resText = res[0][translateTo]
RSFFIPlugin.sendEditInput(resText)
}
})
queue.run()
} else {
// 不是命令,执行其他
// ffi.sendEditInput(text)
Logger.log('?==输入文本', text)
RSFFIPlugin.sendEditInput(text)
Logger.log('?==输入完成')
}
// }
//命令命中
}
......@@ -160,25 +170,26 @@ export const useASRBuilder = async (conf, router) => {
const initASR = async () => {
resetWS()
const res = await RSDataPlugin.get('asrConfig')
Logger.log("ASR配置", res)
global.asr = new ALiASR(res)
console.log(global.asr)
const res = await RSDataPlugin.get('voiceCloud')
global.asr = new ASR(res.url, {
apikey: res.apikey,
apisecret: res.apisecret
})
global.asr.on(ALiASR.ASR_INIT, () => {
global.asr.on(ASR.ASR_INIT, () => {
Logger.log('ASR初始化成功')
})
global.asr.on(ALiASR.ASR_RESULT_PROGRESS, (result) => {
global.asr.on(ASR.ASR_RESULT_PROGRESS, (result) => {
isFinish = false
Logger.log('ASR临时结果', result)
// RSFFIPlugin.sendEditInput(result && result.results)
RSEventPlugin.broadcast(ASR_MAIN_TEMP_TEXT, result.results)
})
global.asr.on(ALiASR.ASR_RESULT_FINAL, (result) => {
global.asr.on(ASR.ASR_RESULT_FINAL, (result) => {
Logger.log('ASR 最终结果', result)
let text = result.results
if (!isClearPunctuation) {
if (isClearPunctuation) {
text = text.replace(/,|\.|,|。|\?|?|!|!|、/g, '')
}
RSEventPlugin.broadcast(ASR_MAIN_FINAL_TEXT, text)
......@@ -202,15 +213,10 @@ export const useASRBuilder = async (conf, router) => {
global.asr.on('close', () => {
if (isAutoClose) {
Logger.log('ASR 自动关闭,等待重连')
if (retryNum == 1) {
setTimeout(() => {
Logger.log(`ASR 5秒后重连(${retryNum++})...`)
initASR()
} else {
setTimeout(() => {
Logger.log(`ASR 5秒后重连(${retryNum++})...`)
initASR()
}, 5000)
}
}, 5000)
// 处理自动关闭的
} else {
Logger.log('ASR手动关闭,不做处理')
......@@ -237,10 +243,6 @@ export const useASRBuilder = async (conf, router) => {
}
}
const end = () => {
global.asr && global.asr.end()
}
const setKeycode = (code) => {
keyCode = code
}
......@@ -248,10 +250,9 @@ export const useASRBuilder = async (conf, router) => {
return {
send,
setClickType,
setKeycode,
initASR,
close,
sendTempTextToInput,
end
setKeycode
}
}
import axios from "axios"
import { app, shell } from "electron"
import fs from 'fs'
import path from "path"
export const useLogsBuilder = ()=>{
const getLogList = () =>{
return new Promise((resolve, reject)=>{
const logDirPath = app.getPath('logs')
fs.readdir(logDirPath, (err, dirs)=>{
if(err){
reject(err)
return
}
const logArr = dirs.map(v=>({
name: v,
path:path.join(logDirPath,`${v}`)
})).sort((a,b)=>-1)
console.log(logArr)
resolve(logArr)
})
})
}
const uploadLog = (logPath) =>{
const fd = new FormData()
fd.append('file', fs.createReadStream(logPath))
return axios.post('https://app.5ai.top/app/log_upload', fd, {
headers:{
'Content-type':"multipart/form-data"
}
})
}
const openLog = (logPath)=>{
shell.openPath(logPath)
}
const openLogDir = () =>{
const logDirPath = app.getPath('logs')
shell.openPath(logDirPath)
}
return {
getLogList,
uploadLog,
openLog,
openLogDir
}
}
\ No newline at end of file
import { shell } from 'electron'
import robot from 'robotjs'
import { platform } from '@electron-toolkit/utils'
import { exec } from 'child_process'
export const useMKeyBuilder = (conf) => {
const { RSScreenshotsPlugin, RSDataPlugin } = conf
......@@ -42,8 +45,12 @@ export const useMKeyBuilder = (conf) => {
}
if (type == 9) {
// tab
robot.keyTap('tab')
// 窗口切换
if (platform.isMacOS) {
robot.keyTap('tab', ['command'])
} else {
robot.keyTap('tab', ['alt'])
}
return
}
......
......@@ -2,7 +2,6 @@
// import createClient from '@azure-rest/ai-vision-image-analysis'
const createClient = require('@azure-rest/ai-vision-image-analysis').default
import { AzureKeyCredential } from '@azure/core-auth'
import axios from 'axios'
export const useOCRBuilder = () => {
const credential = new AzureKeyCredential('948f12bf08fc4c74bb43b1b13d2c1a63')
const client = createClient('https://orcdev.cognitiveservices.azure.com', credential)
......@@ -16,13 +15,6 @@ export const useOCRBuilder = () => {
},
contentType: 'application/octet-stream'
})
},
aliImageBase64ToText(data){
return axios.post("https://poster.maijigc.com/ocr/api/?ss=1a6dafedc9a3415f8a5d5244e6f62c34", {data}, {
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
}
}
import axios from "axios"
import { app, shell } from "electron"
import Logger from "electron-log/main"
export const useUpdateBuilder = ()=>{
const checkUpdate = async() =>{
try {
const localVersion = app.getVersion()
const res = await axios.get('https://app.5ai.top/app/version_mac')
Logger.log("获取版本信息", res.data)
const localVersionCode = Number(localVersion.split('.').join(''))
const removeVersionCode = res.data.version_code
if(localVersionCode < removeVersionCode) {
return res.data.download_url
} else {
return ''
}
} catch (error) {
Logger.log("检查更新失败", error)
return Promise.reject("检查更新失败")
}
}
const jumpToDownload = (url) =>{
Logger.log("跳转下载", url)
shell.openExternal(url)
}
const getLocalVersion = ()=>{
return app.getVersion()
}
return {
checkUpdate,
jumpToDownload,
getLocalVersion
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ import { is } from '@electron-toolkit/utils'
import { join } from 'path'
import { BrowserWindow, screen } from 'electron'
import fs from 'fs'
import { networkInterfaces } from 'os'
// 获取完整的地址
export const getWinURL = (key) => {
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
......@@ -55,25 +55,3 @@ export const getWindowUnderMouse = () => {
scaleFactor
}
}
/**获取mac地址信息 */
export const getMacAddress = function () {
const interfaces = networkInterfaces();
let macAddress = "";
for (const interfaceName of Object.keys(interfaces)) {
const interfaceInfos = interfaces[interfaceName];
if (interfaceInfos) {
for (const interfaceInfo of interfaceInfos) {
if (interfaceInfo.mac && interfaceInfo.mac !== "00:00:00:00:00:00") {
macAddress = interfaceInfo.mac;
break;
}
}
}
if (macAddress.length > 0) break;
}
return macAddress;
};
\ No newline at end of file
import axios from 'axios'
import Logger from 'electron-log/main'
export const translateLang = async () => {
try {
......@@ -48,25 +47,3 @@ export const translateText = async (text, from, to) => {
// return Promise.reject(error)
}
}
export const aliTranslateText = async(text, from, to) =>{
try {
const res = await axios.post("https://tran.5ai.top/translate/api/?ss=1a6dafedc9a3415f8a5d5244e6f62c34", {
from,
to,
text
},
{
headers:{
'Content-Type': 'application/json;charset=UTF-8'
}
}
)
Logger.log(`翻译参数:原文:${text}, from:${from}, to:${to}, 译文:${res.data.data}`)
return res.data.data
} catch (error) {
Logger.log("调用翻译接口失败")
return ''
}
}
\ No newline at end of file
import { contextBridge, net } from 'electron'
import { contextBridge } from 'electron'
import { useRSEvent } from '../eventCenter/RSEvent/renderer'
import { useRSData } from '../dataCenter/RSData/renderer'
import { usePageMethods } from './usePageMethods'
......@@ -16,6 +16,7 @@ const rs = {
...appMethods,
...ffiMethods
}
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('rs', rs)
......
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useLink: typeof import('vue-router')['useLink']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}
<script setup>
import zhCN from 'ant-design-vue/es/locale/zh_CN'
import { setLanguage, antLang } from '@renderer/i18n'
onMounted(() => {
RSData.onDataChange(['setting.lang'], () => {
handleGetValue()
})
handleGetValue()
})
const handleGetValue = async () => {
const lang = await RSData.get('setting.lang')
setLanguage(lang)
}
</script>
<template>
<a-config-provider :locale="zhCN">
<a-config-provider :locale="antLang">
<router-view></router-view>
</a-config-provider>
</template>
......
import { createI18n } from 'vue-i18n'
function loadLanguages() {
const context = import.meta.glob('./languages/*.[t|j]s', { eager: true })
const languages = {}
const langs = Object.keys(context)
for (const key of langs) {
if (key === './index.ts') return
const lang = context[key].lang
const name = key.replace(/(\.\/languages\/|\.[t|j]s)/g, '')
languages[name] = lang
}
return languages
}
export function i18nt(key) {
return i18n.global.d(key)
}
export const i18n = createI18n({
legacy: false,
locale: 'zh-cn',
fallbackLocale: 'zh-cn',
messages: loadLanguages()
})
export function setLanguage(locale) {
i18n.global.locale.value = locale
}
import { computed, ref } from 'vue'
import zhCN from 'ant-design-vue/es/locale/zh_CN'
import zhTW from 'ant-design-vue/es/locale/zh_TW'
import en from 'ant-design-vue/es/locale/en_US'
export const globalLang = ref('zh-cn')
export function loadLanguages() {
const context = import.meta.glob('./languages/*.[t|j]s', { eager: true })
const languages = {}
const langs = Object.keys(context)
for (const key of langs) {
if (key === './index.ts') return
const lang = context[key].lang
const name = key.replace(/(\.\/languages\/|\.[t|j]s)/g, '')
languages[name] = lang
}
return languages
}
const antLangsObj = {
'zh-cn': zhCN,
'zh-tw': zhTW,
en: en
}
export const i18nt = computed(() => {
const lang = loadLanguages()
return lang[globalLang.value]
})
export const antLang = computed(() => {
return antLangsObj[globalLang.value]
})
export function setLanguage(locale) {
globalLang.value = locale
}
export const lang = {
// Left menu
quit: 'Quit Assistant',
menu: {
typing: 'Typing',
translate: 'Translate',
subtitle: 'Subtitles',
aiRui: 'AI Rui',
mouse: 'Mouse',
MKey: 'M Key',
control: 'Control',
settings: 'Settings',
others: 'Others'
},
// First-level menu-Typing
typing: {
modeSetting: {
title: 'Mode Setting',
aiMode: 'AI Mode',
typingMode: 'Typing Mode'
},
typingLanguage: {
title: 'Typing Language',
language: 'Chinese'
},
typingTranslate: {
title: 'Typing Translation',
open: 'Open',
close: 'Close',
fromLabel: 'Recognition Language',
fromValue: 'Chinese',
toLabel: 'Translation Language',
placeholder: 'Select Language'
},
typingMethod: {
title: 'Typing Implementation Method',
method: '1: Dynamic Correction Typing (Default)',
method1_title: 'Long-time Continuous Speech Input (Short press mode)',
method1_subtitle: 'Voice key short press to start, short press again to stop',
method2_title: 'Text Display During Speaking (Dynamic Correction)',
method2_subtitle: 'Support Mandarin, Cantonese',
method3: 'Remove Punctuation',
method4: 'Typing prompt box fixed in the lower right corner'
},
tips: {
title: 'Typing Prompt Box'
}
},
// First-level menu-Translation
translate: {
// Screenshot translation
capture: {
title: 'Screenshot Translation',
subtitle: 'Long press "translate key" for voice translation',
fromLabel: 'Recognition Language',
toLabel: 'Translation Language',
placeholder: 'Select Language'
},
// Word translation
cross: {
title: 'Word Translation',
subtitle: 'Select a piece of text, press "translate key" for word translation',
option1: 'Word translation + AI assistant',
option2: 'Chinese-English translation',
fromLabel: 'Recognition Language',
toLabel: 'Translation Language',
placeholder: 'Select Language'
}
},
// First-level menu-Subtitles
captions: {
voice: {
title: 'Voice Subtitles',
openLabel: 'Open Subtitles'
},
tips: 'Language settings can be set in "Translation Settings"'
},
// First-level menu-Mouse
mouse: {
name: 'Mouse Name',
power: 'Power',
version: 'Firmware Version'
},
// First-level menu-M Key
mSettins: {
title: 'M Key Settings',
tips: 'Set the M key of the mouse to your commonly used functions, press "M key" to enable the function',
openWeb: 'Open the web page with one click (default browser)',
placeholder: 'Enter the URL',
options: {
voiceTyping: 'Voice typing',
captureTranslate: 'Screenshot translation',
translateTyping: 'Translation typing',
enter: 'Enter',
back: 'Back',
openBaidu: 'One-click Baidu',
voiceSearch: 'Voice search',
changeTab: 'Window switch'
},
engineOptions: {
baidu: 'Baidu',
360: '360 Search',
sogou: 'Sogou',
bing: 'Bing',
google: 'Google'
}
},
// First-level menu-Control
controls: {
command: {
title: 'Try these commands',
tips: 'Tip',
addSuccessTips: 'Add successful',
deletSuccessTips: 'Delete successful',
keywords: {
label: 'Command word',
placeholder: 'Please enter the key command word first',
tips: 'Command word cannot be empty',
repeatTips: 'Duplicate command word already exists, please re-enter'
},
type: {
label: 'Command type',
placeholder: 'Please select command type',
options: {
exe: 'Application/File',
dir: 'Folder',
web: 'Website',
command: 'System command'
}
},
content: {
label: 'Command content',
placeholder: 'Next, please select a file or enter a URL',
tips: 'Please enter the URL',
selectTips: 'Please select application/file, folder, system command'
},
table: {
type: 'Type',
keywords: 'Set command words',
content: 'Content',
action: 'Action'
},
btn: {
add: 'Add',
delet: 'Delete',
chooseFile: 'Choose file',
confirmDelete: 'Confirm to delete this command?'
},
systemCommand: {
label: 'System command',
placeholder: 'Please select system command',
options: {
sleep: 'Enter sleep mode',
volumeAdd: 'Increase volume',
volumeReduce: 'Reduce volume',
broadcastDate: 'Broadcast date',
broadcastWeather: 'Broadcast weather',
backDesktop: 'Return to desktop',
shutdown: 'Shut down'
}
}
}
},
// First-level menu-Settings
settings: {
multiLanguage: {
title: 'Multilingual settings',
placeholder: 'Select language',
options: {
zhcn: 'Chinese-Simplified',
zhtw: 'Chinese-Traditional',
en: 'English'
}
},
version: {
title: 'Version number'
}
},
// First-level menu-Others
others: {
user: {
title: 'Hello, user,',
p1: 'The "voice key" of the intelligent voice mouse can be used for voice typing and voice control;',
p2: 'The "translate key" can be used for voice translation and word translation.'
}
}
}
export const lang = {
// 左侧菜单
quit: '退出助理',
menu: {
typing: '打字',
translate: '翻译',
subtitle: '字幕',
aiRui: '小瑞',
mouse: '鼠标',
MKey: 'M键',
control: '控制',
settings: '设置',
others: '其他'
},
// 一级菜单-打字
typing: {
modeSetting: {
title: '模式设置',
aiMode: '智能模式',
typingMode: '打字模式'
},
typingLanguage: {
title: '打字语言',
language: '中文'
},
typingTranslate: {
title: '打字翻译',
open: '开',
close: '关',
fromLabel: '识别语种',
fromValue: '中文',
toLabel: '翻译语种',
placeholder: '请选择语言'
},
typingMethod: {
title: '打字实现方式',
method: '1:动态修正打字(默认)',
method1_title: '长时间连续语音输入(短按模式)',
method1_subtitle: '语音键短按开始,再次短按停止',
method2_title: '说话过程中显示文字(动态修正)',
method2_subtitle: '支持普通话、粤语',
method3: '去除标点',
method4: '打字提示框固定在右下角'
},
tips: {
title: '打字提示框'
}
},
// 一级菜单-翻译
translate: {
// 截图翻译
capture: {
title: '截图翻译',
subtitle: '长按“翻译键”,进行语音翻译',
fromLabel: '识别语种',
toLabel: '翻译语种',
placeholder: '请选择语言'
},
// 划词翻译
cross: {
title: '划词翻译',
subtitle: '选中一段文字,短按"翻译键",进行划词翻译',
option1: '划词翻译 + AI助手',
option2: '中英互译',
fromLabel: '识别语种',
toLabel: '翻译语种',
placeholder: '请选择语言'
}
},
// 一级菜单-字幕
captions: {
voice: {
title: '语音字幕',
openLabel: '打开字幕'
},
tips: '语言请在“翻译设置”里进行设置'
},
// 一级菜单-鼠标
mouse: {
name: '鼠标名称',
power: '电量',
version: '固件版本'
},
// 一级菜单-M键
mSettins: {
title: 'M键设置',
tips: '为鼠标的M键设置为你常用的功能,按下“M键”,启用该功能',
openWeb: '一键打开网页(默认浏览器)',
placeholder: '请输入网址',
options: {
voiceTyping: '语音打字',
captureTranslate: '截图翻译',
translateTyping: '翻译打字',
enter: '回车',
back: '回退',
openBaidu: '一键百度',
voiceSearch: '语音搜索',
changeTab: '窗口切换'
},
engineOptions: {
baidu: '百度',
360: '360搜索',
sogou: '搜狗',
bing: '必应',
google: '谷歌'
}
},
// 一级菜单-控制
controls: {
command: {
title: '试一试这些口令',
tips: '提示',
addSuccessTips: '添加成功',
deletSuccessTips: '删除成功',
keywords: {
label: '指令词',
placeholder: '首先,请输入关键指令词',
tips: '指令词不能为空',
repeatTips: '已包含重复指令词,请重新输入'
},
type: {
label: '指令类型',
placeholder: '请选择指令类型',
options: {
exe: '应用/文件',
dir: '文件夹',
web: '网站',
command: '系统指令'
}
},
content: {
label: '指令内容',
placeholder: '其次,请选择文件,或者输入网址',
tips: '请输入网址',
selectTips: '请选择应用/文件、文件夹、系统命令'
},
table: {
type: '类型',
keywords: '设定指令词汇',
content: '内容',
action: '操作'
},
btn: {
add: '添加',
delet: '删除',
chooseFile: '选择文件',
confirmDelete: '确定删除该指令?'
},
systemCommand: {
label: '系统指令',
placeholder: '请选择系统指令',
options: {
sleep: '进入休眠',
volumeAdd: '音量增加',
volumeReduce: '音量减少',
broadcastDate: '播报日期',
broadcastWeather: '播报天气',
backDesktop: '返回桌面',
shutdown: '关机'
}
}
}
},
// 一级菜单-设置
settings: {
multiLanguage: {
title: '多语言设置',
placeholder: '请选择语言',
options: {
zhcn: '中文-简体',
zhtw: '中文-繁体',
en: '英文'
}
},
version: {
title: '版本号'
}
},
// 一级菜单-其他
others: {
user: {
title: '用户您好,',
p1: '智能语音鼠标的“语音键”可以进行语音打字、语音控制;',
p2: '“翻译键”可以进行语音翻译、划词翻译。'
}
}
}
export const lang = {
// 左側菜單
quit: '退出助理',
menu: {
typing: '打字',
translate: '翻譯',
subtitle: '字幕',
aiRui: '小瑞',
mouse: '鼠標',
MKey: 'M鍵',
control: '控制',
settings: '設置',
others: '其他'
},
// 一級菜單-打字
typing: {
modeSetting: {
title: '模式設置',
aiMode: '智能模式',
typingMode: '打字模式'
},
typingLanguage: {
title: '打字語言',
language: '中文'
},
typingTranslate: {
title: '打字翻譯',
open: '開',
close: '關',
fromLabel: '識別語種',
fromValue: '中文',
toLabel: '翻譯語種',
placeholder: '請選擇語言'
},
typingMethod: {
title: '打字實現方式',
method: '1:動態修正打字(默認)',
method1_title: '長時間連續語音輸入(短按模式)',
method1_subtitle: '語音鍵短按開始,再次短按停止',
method2_title: '說話過程中顯示文字(動態修正)',
method2_subtitle: '支持普通話、粵語',
method3: '去除標點',
method4: '打字提示框固定在右下角'
},
tips: {
title: '打字提示框'
}
},
// 一級菜單-翻譯
translate: {
// 截圖翻譯
capture: {
title: '截圖翻譯',
subtitle: '長按“翻譯鍵”,進行語音翻譯',
fromLabel: '識別語種',
toLabel: '翻譯語種',
placeholder: '請選擇語言'
},
// 劃詞翻譯
cross: {
title: '劃詞翻譯',
subtitle: '選中一段文字,短按"翻譯鍵",進行劃詞翻譯',
option1: '劃詞翻譯 + AI助手',
option2: '中英互譯',
fromLabel: '識別語種',
toLabel: '翻譯語種',
placeholder: '請選擇語言'
}
},
// 一級菜單-字幕
captions: {
voice: {
title: '語音字幕',
openLabel: '打開字幕'
},
tips: '語言請在“翻譯設置”裡進行設置'
},
// 一級菜單-鼠標
mouse: {
name: '鼠標名稱',
power: '電量',
version: '固件版本'
},
// 一級菜單-M鍵
mSettins: {
title: 'M鍵設置',
tips: '為鼠標的M鍵設置為你常用的功能,按下“M鍵”,啟用該功能',
openWeb: '一鍵打開網頁(默認瀏覽器)',
placeholder: '請輸入網址',
options: {
voiceTyping: '語音打字',
captureTranslate: '截圖翻譯',
translateTyping: '翻譯打字',
enter: '回車',
back: '回退',
openBaidu: '一鍵百度',
voiceSearch: '語音搜索',
changeTab: '窗口切換'
},
engineOptions: {
baidu: '百度',
360: '360搜索',
sogou: '搜狗',
bing: '必應',
google: '谷歌'
}
},
// 一級菜單-控制
controls: {
command: {
title: '試一試這些口令',
tips: '提示',
addSuccessTips: '添加成功',
deletSuccessTips: '刪除成功',
keywords: {
label: '指令詞',
placeholder: '首先,請輸入關鍵指令詞',
tips: '指令詞不能為空',
repeatTips: '已包含重複指令詞,請重新輸入'
},
type: {
label: '指令類型',
placeholder: '請選擇指令類型',
options: {
exe: '應用/文件',
dir: '文件夾',
web: '網站',
command: '系統指令'
}
},
content: {
label: '指令內容',
placeholder: '其次,請選擇文件,或者輸入網址',
tips: '請輸入網址',
selectTips: '請選擇應用/文件、文件夾、系統命令'
},
table: {
type: '類型',
keywords: '設定指令詞彙',
content: '內容',
action: '操作'
},
btn: {
add: '添加',
delet: '刪除',
chooseFile: '選擇文件',
confirmDelete: '確定刪除該指令?'
},
systemCommand: {
label: '系統指令',
placeholder: '請選擇系統指令',
options: {
sleep: '進入休眠',
volumeAdd: '音量增加',
volumeReduce: '音量減少',
broadcastDate: '播報日期',
broadcastWeather: '播報天氣',
backDesktop: '返回桌面',
shutdown: '關機'
}
}
}
},
// 一級菜單-设置
settings: {
multiLanguage: {
title: '多語言設置',
placeholder: '請選擇語言',
options: {
zhcn: '中文-简体',
zhtw: '中文-繁體',
en: '英文'
}
},
version: {
title: '版本號'
}
},
// 一級菜單-其他
others: {
user: {
title: '用戶您好,',
p1: '智能語音鼠標的“語音鍵”可以進行語音打字、語音控制;',
p2: '“翻譯鍵”可以進行語音翻譯、劃詞翻譯。'
}
}
}
......@@ -8,7 +8,6 @@ import Capturer from '../views/capturer/index.vue'
import CommandPanel from '../views/commandPanel/index.vue'
import AnswerPanel from '../views/answerPanel/index.vue'
import captions from '../views/captions/index.vue'
import appSetting from '../views/appSetting/index.vue'
const router = createRouter({
history: createWebHashHistory(),
......@@ -48,11 +47,7 @@ const router = createRouter({
{
path: '/captions',
component: captions
},
{
path: '/appSetting',
component: appSetting
},
}
]
})
......
import { HmacSHA256, enc } from 'crypto-js'
import dayjs from 'dayjs'
export function triggerEventInstance(vm) {
return async function (name, ...args) {
if (vm.has(name)) {
......
import axios from 'axios'
import { AXIOS_REQUEST } from '../../../eventCenter/constant'
export const translateLang = async () => {
try {
......@@ -51,62 +50,3 @@ export const translateText = async (text, from, to) => {
// return Promise.reject(error)
}
}
export const aliTranslateLang = async () => {
try {
const res = await RSEvent.call(AXIOS_REQUEST, {
method: 'get',
url: 'https://tran.5ai.top/translate/languages/?ss=1a6dafedc9a3415f8a5d5244e6f62c34'
})
// const res = await RSAxios.fecth("https://tran.5ai.top/translate/languages/?ss=1a6dafedc9a3415f8a5d5244e6f62c34")
// console.log(res)
const arr = res.data.map((v) => ({
label: v.name,
value: v.from
}))
return {
arr,
origin: res.data.reduce((pre, cur) => {
pre[cur.from] = cur.name
return pre
}, {})
}
} catch (error) {
return {
arr: [],
origin: {}
}
}
}
export const aliTranslateText = async (text, from, to) => {
const res = await RSEvent.call(AXIOS_REQUEST, {
method: 'post',
url: 'https://tran.5ai.top/translate/api/?ss=1a6dafedc9a3415f8a5d5244e6f62c34',
data: {
from,
to,
text
},
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
console.log(res)
}
export const getLangOptions = async () => {
try {
const res = await RSEvent.call(AXIOS_REQUEST, {
method: 'get',
url: 'https://tran.5ai.top/asr/get_languages/?ss=1a6dafedc9a3415f8a5d5244e6f62c34'
})
if (res && res.data && res.data.length > 0) {
return res.data
}
return []
} catch (error) {
return error
}
}
<template>
<div class="app-setting">
<a-tabs v-model:activeKey="activeKey" tab-position="left" animated>
<a-tab-pane key="1" tab="应用程序">
<a-divider orientation="left">启动</a-divider>
<div class="cell-con">
<!-- <div class="cell-left"></div> -->
<div class="cell-right">
<a-select
v-model:value="startValue"
size="small"
:options="startOption"
style="width: 200px"
>
</a-select>
</div>
</div>
<div class="cell-con">
<!-- <div class="cell-left">启用托盘</div> -->
<div class="cell-right">
<a-checkbox v-model:checked="isShowInTray">启动最小化到系统托盘</a-checkbox>
</div>
</div>
<a-divider orientation="left">应用程序主题</a-divider>
<div class="cell-con">
<div class="cell-left">配色方案:</div>
<div class="cell-right">
<a-select
v-model:value="themeValue"
size="small"
:options="themeOption"
style="width: 200px"
>
</a-select>
</div>
</div>
<a-divider orientation="left">系统托盘图标</a-divider>
<div class="cell-con">
<div class="cell-right">
<a-checkbox v-model:checked="isShowInTray"
>在系统托盘(通知区域)上显示应用程序</a-checkbox
>
</div>
</div>
<div class="func-con">
<a-button type="primary" size="small" style="width: 120px; height: 30px">确定</a-button>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="日志文件">
<a-divider orientation="left">日志</a-divider>
<a-table
:columns="columns"
:data-source="dataSource"
:pagination="pagination"
:loading="loading"
@change="handleTableChange"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'">
<a-space :size="size">
<a-button type="primary" size="small" @click="handleLogUpload(record)">上传</a-button>
<a-button type="default" size="small" @click="handleOpenLog(record)">打开</a-button>
</a-space>
</template>
</template>
</a-table>
<div class="func-con">
<a-button @click="handleOpenLogDir" type="primary" size="small" style="width: 160px; height: 30px"
>打开文件夹</a-button
>
</div>
</a-tab-pane>
<a-tab-pane key="3" tab="键盘快捷键">
<a-empty description="更新中..." style="margin-top: 160px" />
</a-tab-pane>
<a-tab-pane key="4" tab="语言">
<a-empty description="更新中..." style="margin-top: 160px" />
</a-tab-pane>
<a-tab-pane key="5" tab="关于">
<a-divider orientation="center">关于AI Hub</a-divider>
<div class="tab-content">
<p class="version-text">当前客户端版本号:{{ version }}</p>
<a-button @click="handleCheckVersion" type="primary" size="small" style="width: 160px; height: 30px"
>检查更新</a-button
>
</div>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script setup>
import { onMounted, ref, computed } from 'vue'
import { LOG_GET_LIST, LOG_OPEN_DIR, LOG_OPEN_FILE, LOG_UPLOAD, UPDATE_CHECK, UPDATE_DOWNLOAD, UPDATE_VERSION } from '../../../../eventCenter/constant';
import Logger from 'electron-log/renderer';
import { Modal, message } from 'ant-design-vue';
const activeKey = ref('1')
const startValue = ref('manual')
const version = ref('')
const startOption = ref([
{
label: '手动启动',
value: 'manual'
},
{
label: '开机启动',
value: 'auto'
}
])
const themeValue = ref('default')
const themeOption = ref([
{
label: '科技风',
value: 'default'
}
])
const isShowInTray = ref(true)
const columns = ref([
{
title: '日志名称、时间',
dataIndex: 'name'
},
{
title: '操作',
dataIndex: 'action',
width: '100px'
}
])
const pagination = ref({
total: 0,
current: 1,
pageSize: 5,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total) => `共 ${total} 条`,
size: 'small'
})
const loading = ref(false)
const dataSource = ref([])
onMounted(()=>{
getLogList()
getVersion()
})
const getLogList = async ()=>{
try {
const res = await RSEvent.call(LOG_GET_LIST)
dataSource.value = res
pagination.value.total = res.length
} catch (error) {
message.error('获取日志列表失败')
Logger.log("获取日志列表失败",error)
}
}
const handleOpenLog = (record)=>{
Logger.log("打开日志", record)
RSEvent.send(LOG_OPEN_FILE, record.path)
}
const handleOpenLogDir = () =>{
Logger.log("打开日志文件夹")
RSEvent.send(LOG_OPEN_DIR)
}
const handleLogUpload = async (record) =>{
try {
Logger.log("上传日志", record)
await RSEvent.send(LOG_UPLOAD, record.path)
message.success("上传成功")
} catch (error) {
message.error("上传失败")
}
}
const handleTableChange = (e)=>{
pagination.value.current = e.current
}
const getVersion = async () =>{
version.value = await RSEvent.call(UPDATE_VERSION)
}
const handleCheckVersion = async () =>{
const url = await RSEvent.call(UPDATE_CHECK)
if(url) {
Modal.confirm({
title:"更新提示",
content:"应用有新的版本可用,点击立即更新,下载最新版本",
okText:"立即更新",
onOk:async()=>{
RSEvent.send(UPDATE_DOWNLOAD, url)
}
})
}else {
Modal.info({
title:"更新提示",
content:"您当前应用已经是最新版本了",
okText:"我知道了",
})
}
}
</script>
<style lang="scss">
.app-setting {
background-color: #fff;
height: 100%;
width: 100%;
.ant-tabs {
height: 100%;
.ant-tabs-content {
padding-right: 20px;
box-sizing: border-box;
}
}
.cell-con {
display: flex;
align-items: center;
padding: 10px 0;
.cell-left {
width: 80px;
}
}
.func-con {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.tab-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 60px;
.version-text {
font-size: 18px;
}
}
}
</style>
......@@ -33,11 +33,11 @@
</div>
<div class="panel-item">
<div class="panel-title" style="padding-top: 0">
<span>语音字幕</span>
<span>{{ i18nt.captions.voice.title }}</span>
</div>
<div class="panel-content" style="height: 30px">
<div style="font-size: 14px" class="item-center">
<span>打开字幕</span
<span>{{ i18nt.captions.voice.openLabel }}</span
><a-switch v-model:checked="isOpen" @change="handleOpenCaptions"></a-switch>
</div>
</div>
......@@ -47,13 +47,15 @@
</div> -->
</div>
<div class="footer-text">语言请在“翻译设置”里进行设置</div>
<div class="footer-text">{{ i18nt.captions.tips }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { Button } from 'ant-design-vue'
import { i18nt } from '@renderer/i18n'
const isTranslateZhToEn = ref(false)
const props = defineProps({
deviceList: Array
......
......@@ -58,8 +58,8 @@
>
<Slider
v-model:value="dpi"
:min="sliderMin"
:max="sliderMax"
:min="400"
:max="3200"
:marks="sliderMaker"
:step="null"
style="width: 200px"
......@@ -79,16 +79,7 @@
<div class="device-status-title">
<span class="title-text">设备状态</span>
</div>
<div class="device-status-con-inner">
<div class="right-title">
<p>鼠标连接状态</p>
<p>{{isConnent ? '已连接': "未连接"}}</p>
</div>
<div class="right-title">
<p>鼠标SN</p>
<p>{{ info.sn }}</p>
</div>
</div>
<div class="device-status-con-inner"></div>
</div>
</div>
</template>
......@@ -97,35 +88,27 @@
import { Slider, Switch, message } from 'ant-design-vue'
import Logger from 'electron-log/renderer'
import { onMounted, ref } from 'vue'
import { MOUSE_GET_DEVICE_INFO, MOUSE_SET_DPI, MOUSE_STATUS } from '../../../../../eventCenter/constant'
import { MOUSE_GET_DEVICE_INFO, MOUSE_SET_DPI } from '../../../../../eventCenter/constant'
const isNavigatorTool = ref(false)
const sliderMaker = ref({})
const dpi = ref('')
const sliderMaker = ref({
400: '',
800: '',
1000: '',
1200: '',
1600: '',
3200: ''
})
const dpi = ref(800)
const info = ref({})
const sliderMin = ref(0)
const sliderMax = ref(0)
const isConnent = ref(false)
onMounted(() => {
getInfo()
})
const getInfo = async () => {
info.value = await RSEvent.call(MOUSE_GET_DEVICE_INFO)
isConnent.value = await RSEvent.call(MOUSE_STATUS)
dpi.value = info.value.CPI
// console.log()
const arr = info.value.CPI_list.split(',').map(v=>Number(v))
sliderMin.value = arr[0]
sliderMax.value = arr[arr.length - 1]
sliderMaker.value = arr.reduce((pre, cur)=>{
pre[cur] = ''
return pre
},{})
Logger.log('获取鼠标信息', info.value)
Logger.log('获取鼠标信息',sliderMin.value, sliderMax.value, sliderMaker.value)
// console.log('getInfo', res)
}
......@@ -363,31 +346,6 @@ const handleSetDpi = async () => {
border-radius: 6px;
height: 93px;
margin-top: 10px;
display: flex;
justify-content: center;
flex-direction: column;
.right-title {
padding: 0 30px;
display: flex;
align-items: center;
justify-content: space-between;
p {
margin: 0;
&:first-child {
font-size: 14px;
color: #fff;
margin-bottom: 4px;
}
&:last-child {
font-size: 14px;
color: #fff;
// font-size: 12px;
// color: rgba(255, 255, 255, 0.6);
}
}
}
}
}
}
......
......@@ -2,17 +2,19 @@
<div class="message-panel">
<perfect-scrollbar>
<div class="panel-item">
<div class="panel-title">用户您好,</div>
<div class="panel-title">{{ i18nt.others.user.title }}</div>
<div class="panel-content">
<p>智能语音鼠标的“语音键”可以进行语音打字、语音控制;</p>
<p>“翻译键”可以进行语音翻译、划词翻译。</p>
<p>{{ i18nt.others.user.p1 }}</p>
<p>{{ i18nt.others.user.p2 }}</p>
</div>
</div>
</perfect-scrollbar>
</div>
</template>
<script setup></script>
<script setup>
import { i18nt } from '@renderer/i18n'
</script>
<style lang="scss">
.message-panel {
......
......@@ -3,7 +3,7 @@
<perfect-scrollbar>
<div class="panel-item">
<div class="panel-title" style="padding-top: 0">
<span>鼠标名称</span>
<span>{{ i18nt.mouse.name }}</span>
</div>
<div class="panel-content" style="height: 30px">
<div style="font-size: 14px">{{ info.brand }}</div>
......@@ -11,7 +11,7 @@
</div>
<div class="panel-item">
<div class="panel-title">
<span>电量</span>
<span>{{ i18nt.mouse.power }}</span>
</div>
<div class="panel-content">
<div class="panel-content-inner">
......@@ -32,16 +32,16 @@
class="custom-select"
@change="handleSetDpi"
>
<a-select-option value="800">800</a-select-option>
<a-select-option value="1000">1000</a-select-option>
<a-select-option v-for="v in dpiList" :key="v" :value="v">{{ v }}</a-select-option>
<!-- <a-select-option value="1000">1000</a-select-option> -->
<!-- <a-select-option value="1400">1400</a-select-option> -->
<a-select-option value="1600">1600</a-select-option>
<!-- <a-select-option value="1600">1600</a-select-option> -->
</a-select>
</div>
</div>
<div class="panel-item">
<div class="panel-title">
<span>鼠标固件版本</span>
<span>{{ i18nt.mouse.version }}</span>
</div>
<div class="panel-content">
<div class="panel-content-inner">
......@@ -50,6 +50,17 @@
</div>
</div>
</div>
<div class="panel-item">
<div class="panel-title">
<span>MAC</span>
</div>
<div class="panel-content">
<div class="panel-content-inner">
<span>{{ info.MAC }}</span>
<span class="a-text"></span>
</div>
</div>
</div>
<!-- <div class="panel-item">
<div class="panel-title">
<span>接收器固件版本</span>
......@@ -74,8 +85,11 @@ import Logger from 'electron-log/renderer'
import Battery from './battery.vue'
import { message } from 'ant-design-vue'
import { i18nt } from '@renderer/i18n'
let info = ref({})
let dpi = ref('')
const dpiList = ref([])
onMounted(() => {
getInfo()
......@@ -84,6 +98,7 @@ onMounted(() => {
const getInfo = async () => {
info.value = await RSEvent.call(MOUSE_GET_DEVICE_INFO)
dpi.value = info.value.CPI
dpiList.value = info.value.CPI_list ? info.value.CPI_list.split(',') : []
Logger.log('鼠标信息', info.value)
// console.log('getInfo', res)
}
......
<template>
<div class="setting-page">
<perfect-scrollbar>
<div class="panel-item">
<div class="panel-title">使用设置</div>
<div class="panel-content" style="background-color: #f6f6f6">
<a-checkbox
v-model:checked="state.startAdmin"
class="custom-checkbox"
@change="handleRootRunChange"
>管理员权限运行</a-checkbox
>
<br />
<a-checkbox
v-model:checked="state.inStart"
class="custom-checkbox"
@change="handleFormChange($event, 'inStart')"
>设置开机启动</a-checkbox
>
<br />
<a-checkbox
v-model:checked="state.showTips"
class="custom-checkbox"
@change="handleFormChange($event, 'showTips')"
>关闭提示</a-checkbox
>
<br />
<a-checkbox
v-model:checked="state.checkNet"
class="custom-checkbox"
@change="handleFormChange($event, 'checkNet')"
>不检测网络</a-checkbox
>
<br />
<a-checkbox
v-model:checked="state.openScreenshot"
class="custom-checkbox"
@change="handleFormChange($event, 'openScreenshot')"
>开启截图快捷键(Alt+Ctrl+X)</a-checkbox
>
</div>
</div>
<!-- <div class="panel-item">
<div class="panel-title">
<span>代理上网</span>
<SettingOutlined style="font-size: 14px; color: #fff" />
</div>
<div class="panel-content">
<div style="font-size: 12px">使用企业内部网络时设置</div>
</div>
</div> -->
<div class="panel-item">
<div class="panel-title">
<span>日志信息</span>
<FileTextOutlined style="font-size: 14px; color: #fff" />
</div>
<div class="panel-content">
<div style="font-size: 14px">查询程序的工作记录</div>
</div>
</div>
<div class="panel-item">
<div class="panel-title"><span>文件管理</span></div>
<div class="panel-content" style="padding: 0px">
<div class="input-style" @click="handleFileClick">
{{ state.cacheDir }}
<!-- <a-input
v-model:value="state.cacheDir"
disabled
class="custom-input"
placeholder="请选择缓存文件夹"
></a-input> -->
</div>
<div class="tips-con">
<span>打开文件夹位置</span>
<FolderOpenOutlined style="font-size: 14px; color: #000" @click="handleOpenPath" />
</div>
</div>
</div>
</perfect-scrollbar>
</div>
</template>
<script setup>
import { SettingOutlined, FileTextOutlined, FolderOpenOutlined } from '@ant-design/icons-vue'
import { onMounted, reactive } from 'vue'
const state = reactive({
startAdmin: false,
inStart: true,
showTips: false,
checkNet: false,
openScreenshot: false,
cacheDir: ''
})
onMounted(async () => {
const res = await RSData.get('setting')
state.startAdmin = res.startAdmin
state.inStart = res.inStart
state.showTips = res.showTips
state.checkNet = res.checkNet
state.openScreenshot = res.openScreenshot
state.cacheDir = res.cacheDir
})
const handleFileClick = async () => {
const path = await rs.chooseDirectory()
if (path) {
state.cacheDir = path[0]
RSData.set('setting.cacheDir', state.cacheDir, true)
}
}
const handleOpenPath = () => {
rs.openDirectory(state.cacheDir)
}
const handleRootRunChange = async () => {
await RSData.set('setting.startAdmin', state.startAdmin)
// todo::以管理员身份重启,
}
const handleFormChange = async (e, key) => {
await RSData.set(`setting.${key}`, state[key])
}
</script>
<style lang="scss">
.setting-page {
box-sizing: border-box;
color: #000;
height: 100%;
.ps {
height: 100%;
.ps__rail-y {
&:hover {
width: 7px;
background-color: transparent;
.ps__thumb-y {
background-color: rgba($color: #aaa, $alpha: 0.5);
width: 7px;
}
}
}
.ps__thumb-y {
background-color: rgba($color: #aaa, $alpha: 0.4);
width: 7px;
}
}
.custom-select {
width: 100%;
.ant-select-selection-item {
color: var(--panel-text-color);
&::after {
color: var(--panel-text-color);
}
}
.ant-select-selector {
background-color: transparent;
}
.ant-select-arrow {
color: var(--panel-text-color);
}
.ant-select-selection-placeholder {
color: #999;
}
}
.custom-input {
background-color: transparent;
color: #fff;
cursor: default;
&::placeholder {
color: #fff;
}
}
.ant-select-disabled {
.ant-select-selector {
border-color: #666;
}
.ant-select-arrow {
color: #666;
}
}
.custom-checkbox {
color: var(--panel-text-color);
.ant-checkbox-inner {
background-color: transparent;
}
.ant-checkbox-checked {
.ant-checkbox-inner {
background-color: var(--primary-color);
}
}
}
.panel-item {
// margin-bottom: 20px;
cursor: default;
padding: 0 20px;
.panel-title {
font-size: 16px;
color: var(--panel-title-color);
padding: 20px 0;
display: flex;
justify-content: space-between;
}
.panel-content {
display: flex;
flex-direction: column;
// margin-top: 5px;
padding: 10px 20px;
border-radius: 6px;
.text-sup {
font-size: 14px;
padding: 5px 0;
color: #999;
padding-bottom: 10px;
}
.icon-con {
padding: 5px 0;
font-size: 20px;
color: #999;
display: flex;
align-items: center;
justify-content: center;
}
.tips-con {
display: flex;
justify-content: space-between;
font-size: 12px;
color: #999;
margin-top: 8px;
padding-left: 20px;
}
}
}
.input-style {
background-color: #f6f6f6;
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
width: calc(100% - 20px);
margin-left: 20px;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
padding: 8px 8px;
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment