mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-03 02:59:07 +08:00
冲突
This commit is contained in:
parent
fc77db3b91
commit
4e5e7f6248
@ -64,6 +64,11 @@ export enum IpcChannel {
|
||||
Aes_Encrypt = 'aes:encrypt',
|
||||
Aes_Decrypt = 'aes:decrypt',
|
||||
|
||||
// search window
|
||||
SearchWindow_Open = 'search-window:open',
|
||||
SearchWindow_Close = 'search-window:close',
|
||||
SearchWindow_OpenUrl = 'search-window:open-url',
|
||||
|
||||
Gemini_UploadFile = 'gemini:upload-file',
|
||||
Gemini_Base64File = 'gemini:base64-file',
|
||||
Gemini_RetrieveFile = 'gemini:retrieve-file',
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edge ASR (External)</title>
|
||||
<title>Browser ASR (External)</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
@ -28,8 +28,8 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Edge ASR 中继页面</h1>
|
||||
<p>这个页面需要在 Edge 浏览器中保持打开,以便 Electron 应用使用其语音识别功能。</p>
|
||||
<h1>浏览器语音识别中继页面</h1>
|
||||
<p>这个页面需要在浏览器中保持打开,以便应用使用其语音识别功能。</p>
|
||||
<div id="status">正在连接到服务器...</div>
|
||||
<div id="result"></div>
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ const path = require('path') // Need path module
|
||||
const app = express()
|
||||
const port = 8080 // Define the port
|
||||
|
||||
// 提供网页给 Edge 浏览器
|
||||
// 提供网页给浏览器
|
||||
app.get('/', (req, res) => {
|
||||
// Use path.join for cross-platform compatibility
|
||||
res.sendFile(path.join(__dirname, 'index.html'))
|
||||
|
||||
@ -24,6 +24,7 @@ import * as NutstoreService from './services/NutstoreService'
|
||||
import ObsidianVaultService from './services/ObsidianVaultService'
|
||||
import { ProxyConfig, proxyManager } from './services/ProxyManager'
|
||||
import { registerShortcuts, unregisterAllShortcuts } from './services/ShortcutService'
|
||||
import { searchService } from './services/SearchService'
|
||||
import { TrayService } from './services/TrayService'
|
||||
import { windowService } from './services/WindowService'
|
||||
import { getResourcePath } from './utils'
|
||||
@ -297,6 +298,17 @@ export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
|
||||
NutstoreService.getDirectoryContents(token, path)
|
||||
)
|
||||
|
||||
// search window
|
||||
ipcMain.handle(IpcChannel.SearchWindow_Open, async (_, uid: string) => {
|
||||
await searchService.openSearchWindow(uid)
|
||||
})
|
||||
ipcMain.handle(IpcChannel.SearchWindow_Close, async (_, uid: string) => {
|
||||
await searchService.closeSearchWindow(uid)
|
||||
})
|
||||
ipcMain.handle(IpcChannel.SearchWindow_OpenUrl, async (_, uid: string, url: string) => {
|
||||
return await searchService.openUrlInSearchWindow(uid, url)
|
||||
})
|
||||
|
||||
// 启动ASR服务器
|
||||
ipcMain.handle('start-asr-server', async () => {
|
||||
try {
|
||||
|
||||
100
src/main/services/SearchService.ts
Normal file
100
src/main/services/SearchService.ts
Normal file
@ -0,0 +1,100 @@
|
||||
import { BrowserWindow } from 'electron'
|
||||
import { join } from 'path'
|
||||
import { is } from '@electron-toolkit/utils'
|
||||
import { isMac } from '@main/constant'
|
||||
|
||||
class SearchService {
|
||||
private searchWindows: Map<string, BrowserWindow> = new Map()
|
||||
|
||||
/**
|
||||
* 打开搜索窗口
|
||||
* @param uid 窗口唯一标识符
|
||||
*/
|
||||
public async openSearchWindow(uid: string): Promise<void> {
|
||||
// 如果窗口已经存在,则激活它
|
||||
if (this.searchWindows.has(uid)) {
|
||||
const existingWindow = this.searchWindows.get(uid)
|
||||
if (existingWindow && !existingWindow.isDestroyed()) {
|
||||
if (existingWindow.isMinimized()) {
|
||||
existingWindow.restore()
|
||||
}
|
||||
existingWindow.focus()
|
||||
return
|
||||
}
|
||||
// 如果窗口已销毁,则从Map中移除
|
||||
this.searchWindows.delete(uid)
|
||||
}
|
||||
|
||||
// 创建新窗口
|
||||
const searchWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
...(isMac ? { titleBarStyle: 'hidden' } : {}),
|
||||
webPreferences: {
|
||||
preload: join(__dirname, '../preload/index.js'),
|
||||
sandbox: false,
|
||||
webSecurity: false
|
||||
}
|
||||
})
|
||||
|
||||
// 设置窗口标题
|
||||
searchWindow.setTitle(`搜索窗口 - ${uid}`)
|
||||
|
||||
// 加载搜索页面
|
||||
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
||||
searchWindow.loadURL(`${process.env['ELECTRON_RENDERER_URL']}/#/search?uid=${uid}`)
|
||||
} else {
|
||||
searchWindow.loadFile(join(__dirname, '../renderer/index.html'), {
|
||||
hash: `/search?uid=${uid}`
|
||||
})
|
||||
}
|
||||
|
||||
// 窗口准备好后显示
|
||||
searchWindow.once('ready-to-show', () => {
|
||||
searchWindow.show()
|
||||
})
|
||||
|
||||
// 窗口关闭时从Map中移除
|
||||
searchWindow.on('closed', () => {
|
||||
this.searchWindows.delete(uid)
|
||||
})
|
||||
|
||||
// 存储窗口引用
|
||||
this.searchWindows.set(uid, searchWindow)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭搜索窗口
|
||||
* @param uid 窗口唯一标识符
|
||||
*/
|
||||
public async closeSearchWindow(uid: string): Promise<void> {
|
||||
const window = this.searchWindows.get(uid)
|
||||
if (window && !window.isDestroyed()) {
|
||||
window.close()
|
||||
}
|
||||
this.searchWindows.delete(uid)
|
||||
}
|
||||
|
||||
/**
|
||||
* 在搜索窗口中打开URL
|
||||
* @param uid 窗口唯一标识符
|
||||
* @param url 要打开的URL
|
||||
*/
|
||||
public async openUrlInSearchWindow(uid: string, url: string): Promise<boolean> {
|
||||
const window = this.searchWindows.get(uid)
|
||||
if (window && !window.isDestroyed()) {
|
||||
try {
|
||||
await window.loadURL(url)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error(`Failed to load URL in search window: ${error}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export const searchService = new SearchService()
|
||||
5
src/preload/index.d.ts
vendored
5
src/preload/index.d.ts
vendored
@ -175,6 +175,11 @@ declare global {
|
||||
decryptToken: (token: string) => Promise<{ username: string; access_token: string }>
|
||||
getDirectoryContents: (token: string, path: string) => Promise<any>
|
||||
}
|
||||
searchWindow: {
|
||||
open: (uid: string) => Promise<void>
|
||||
close: (uid: string) => Promise<void>
|
||||
openUrl: (uid: string, url: string) => Promise<boolean>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,6 +169,11 @@ const api = {
|
||||
decryptToken: (token: string) => ipcRenderer.invoke(IpcChannel.Nutstore_DecryptToken, token),
|
||||
getDirectoryContents: (token: string, path: string) =>
|
||||
ipcRenderer.invoke(IpcChannel.Nutstore_GetDirectoryContents, token, path)
|
||||
},
|
||||
searchWindow: {
|
||||
open: (uid: string) => ipcRenderer.invoke(IpcChannel.SearchWindow_Open, uid),
|
||||
close: (uid: string) => ipcRenderer.invoke(IpcChannel.SearchWindow_Close, uid),
|
||||
openUrl: (uid: string, url: string) => ipcRenderer.invoke(IpcChannel.SearchWindow_OpenUrl, uid, url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Edge ASR (External)</title>
|
||||
<title>Browser ASR (External)</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
@ -28,8 +28,8 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Edge ASR 中继页面</h1>
|
||||
<p>这个页面需要在 Edge 浏览器中保持打开,以便 Electron 应用使用其语音识别功能。</p>
|
||||
<h1>浏览器语音识别中继页面</h1>
|
||||
<p>这个页面需要在浏览器中保持打开,以便应用使用其语音识别功能。</p>
|
||||
<div id="status">正在连接到服务器...</div>
|
||||
<div id="result"></div>
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ function getIndexHtmlPath() {
|
||||
return path.join(process.cwd(), 'index.html');
|
||||
}
|
||||
|
||||
// 提供网页给 Edge 浏览器
|
||||
// 提供网页给浏览器
|
||||
app.get('/', (req, res) => {
|
||||
const indexPath = getIndexHtmlPath();
|
||||
console.log(`Serving index.html from: ${indexPath}`);
|
||||
|
||||
@ -1347,7 +1347,7 @@
|
||||
"api_settings": "API Settings",
|
||||
"service_type": "Service Type",
|
||||
"service_type.openai": "OpenAI",
|
||||
"service_type.edge": "Edge TTS",
|
||||
"service_type.edge": "Browser TTS",
|
||||
"service_type.refresh": "Refresh TTS service type settings",
|
||||
"service_type.refreshed": "TTS service type settings refreshed",
|
||||
"api_key": "API Key",
|
||||
@ -1393,7 +1393,7 @@
|
||||
"model": "Model",
|
||||
"browser.info": "Use the browser's built-in speech recognition feature, no additional setup required",
|
||||
"local.info": "Use local server and browser for speech recognition, need to start the server and open the browser page first",
|
||||
"local.browser_tip": "Please open this page in Edge browser and keep the browser window open",
|
||||
"local.browser_tip": "Please open this page in your browser and keep the browser window open",
|
||||
"local.test_connection": "Test Connection",
|
||||
"local.connection_success": "Connection successful",
|
||||
"local.connection_failed": "Connection failed, please make sure the server is running",
|
||||
|
||||
@ -1347,14 +1347,14 @@
|
||||
"api_settings": "API設定",
|
||||
"service_type": "サービスタイプ",
|
||||
"service_type.openai": "OpenAI",
|
||||
"service_type.edge": "Edge TTS",
|
||||
"service_type.edge": "ブラウザ TTS",
|
||||
"test": "テスト",
|
||||
"error": {
|
||||
"failed": "音声合成に失敗しました",
|
||||
"not_enabled": "音声合成が有効になっていません",
|
||||
"no_edge_voice": "Edge TTSの音声が選択されていません"
|
||||
"no_edge_voice": "ブラウザ TTSの音声が選択されていません"
|
||||
},
|
||||
"help": "OpenAIのTTS APIを使用するには、APIキーが必要です。Edge TTSはブラウザの機能を使用するため、APIキーは不要です。",
|
||||
"help": "OpenAIのTTS APIを使用するには、APIキーが必要です。ブラウザ TTSはブラウザの機能を使用するため、APIキーは不要です。",
|
||||
"learn_more": "詳細はこちら"
|
||||
},
|
||||
"asr": {
|
||||
@ -1372,7 +1372,7 @@
|
||||
"model": "モデル",
|
||||
"browser.info": "ブラウザの内蔵音声認識機能を使用します。追加設定は不要です",
|
||||
"local.info": "ローカルサーバーとブラウザを使用して音声認識を行います。サーバーを起動してブラウザページを開く必要があります",
|
||||
"local.browser_tip": "このページをEdgeブラウザで開き、ブラウザウィンドウを開いたままにしてください",
|
||||
"local.browser_tip": "このページをブラウザで開き、ブラウザウィンドウを開いたままにしてください",
|
||||
"local.test_connection": "接続テスト",
|
||||
"local.connection_success": "接続成功",
|
||||
"local.connection_failed": "接続失敗。サーバーが起動していることを確認してください",
|
||||
|
||||
@ -1353,14 +1353,14 @@
|
||||
"api_settings": "API设置",
|
||||
"service_type": "服务类型",
|
||||
"service_type.openai": "OpenAI",
|
||||
"service_type.edge": "Edge TTS",
|
||||
"service_type.edge": "浏览器 TTS",
|
||||
"service_type.refresh": "刷新TTS服务类型设置",
|
||||
"service_type.refreshed": "已刷新TTS服务类型设置",
|
||||
"api_key": "API密钥",
|
||||
"api_key.placeholder": "请输入OpenAI API密钥",
|
||||
"api_url": "API地址",
|
||||
"api_url.placeholder": "例如:https://api.openai.com/v1/audio/speech",
|
||||
"edge_voice": "Edge TTS音色",
|
||||
"edge_voice": "浏览器 TTS音色",
|
||||
"edge_voice.loading": "加载中...",
|
||||
"edge_voice.refresh": "刷新可用音色列表",
|
||||
"edge_voice.not_found": "未找到匹配的音色",
|
||||
@ -1386,7 +1386,7 @@
|
||||
"error": {
|
||||
"not_enabled": "语音合成功能未启用",
|
||||
"no_api_key": "未设置API密钥",
|
||||
"no_edge_voice": "未选择Edge TTS音色",
|
||||
"no_edge_voice": "未选择浏览器 TTS音色",
|
||||
"browser_not_support": "浏览器不支持语音合成"
|
||||
}
|
||||
},
|
||||
@ -1405,7 +1405,7 @@
|
||||
"model": "模型",
|
||||
"browser.info": "使用浏览器内置的语音识别功能,无需额外设置",
|
||||
"local.info": "使用本地服务器和浏览器进行语音识别,需要先启动服务器并打开浏览器页面",
|
||||
"local.browser_tip": "请在Edge浏览器中打开此页面,并保持浏览器窗口打开",
|
||||
"local.browser_tip": "请在浏览器中打开此页面,并保持浏览器窗口打开",
|
||||
"local.test_connection": "测试连接",
|
||||
"local.connection_success": "连接成功",
|
||||
"local.connection_failed": "连接失败,请确保服务器已启动",
|
||||
|
||||
@ -121,7 +121,7 @@ const TTSSettings: FC = () => {
|
||||
// 浏览器可用的语音列表
|
||||
const [availableVoices, setAvailableVoices] = useState<{ label: string; value: string }[]>([])
|
||||
|
||||
// 预定义的Edge TTS音色列表
|
||||
// 预定义的浏览器 TTS音色列表
|
||||
const predefinedVoices = [
|
||||
{ label: '小晓 (女声, 中文)', value: 'zh-CN-XiaoxiaoNeural' },
|
||||
{ label: '云扬 (男声, 中文)', value: 'zh-CN-YunyangNeural' },
|
||||
@ -494,7 +494,7 @@ const TTSSettings: FC = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Edge TTS设置 */}
|
||||
{/* 浏览器 TTS设置 */}
|
||||
{ttsServiceType === 'edge' && (
|
||||
<Form.Item label={t('settings.tts.edge_voice')} style={{ marginBottom: 16 }}>
|
||||
<VoiceSelectContainer>
|
||||
|
||||
@ -112,14 +112,14 @@ export interface SettingsState {
|
||||
enableDataCollection: boolean
|
||||
// TTS配置
|
||||
ttsEnabled: boolean
|
||||
ttsServiceType: string // TTS服务类型:openai或edge
|
||||
ttsServiceType: string // TTS服务类型:openai或浏览器
|
||||
ttsApiKey: string
|
||||
ttsApiUrl: string
|
||||
ttsVoice: string
|
||||
ttsModel: string
|
||||
ttsCustomVoices: string[]
|
||||
ttsCustomModels: string[]
|
||||
// Edge TTS配置
|
||||
// 浏览器 TTS配置
|
||||
ttsEdgeVoice: string
|
||||
// TTS过滤选项
|
||||
ttsFilterOptions: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user