feat: add reader.json endpoint for TTS link generation and implement UI button for fetching reader link

This commit is contained in:
王锦强
2025-03-16 23:50:08 +08:00
parent ebb7e2b292
commit 660d3ba5f5

View File

@@ -98,6 +98,66 @@ async function handleRequest(request) {
return response; return response;
} }
// 添加 reader.json 路径处理
if (path === '/reader.json') {
// 从请求参数获取 API 密钥
const apiKey = requestUrl.searchParams.get('api_key');
// 验证 API 密钥
if (!validateApiKey(apiKey)) {
return new Response(JSON.stringify({
error: 'Unauthorized',
message: '无效的 API 密钥,请确保您提供了正确的密钥。',
status: 401
}), {
status: 401,
headers: { 'Content-Type': 'application/json; charset=utf-8' }
});
}
// 从URL参数获取
const voice = requestUrl.searchParams.get('v') || '';
const rate = requestUrl.searchParams.get('r') || '';
const pitch = requestUrl.searchParams.get('p') || '';
const style = requestUrl.searchParams.get('s') || '';
const displayName = requestUrl.searchParams.get('n') || 'Microsoft TTS';
// 构建基本URL
const baseUrl = `${requestUrl.protocol}//${requestUrl.host}`;
// 构建URL参数
const urlParams = ["t={{java.encodeURI(speakText)}}", "r={{speakSpeed*4}}"];
// 只有有值的参数才添加
if (voice) {
urlParams.push(`v=${voice}`);
}
if (pitch) {
urlParams.push(`p=${pitch}`);
}
if (style) {
urlParams.push(`s=${style}`);
}
if (apiKey) {
urlParams.push(`api_key=${apiKey}`);
}
const url = `${baseUrl}/tts?${urlParams.join('&')}`;
// 返回 reader 响应
return new Response(JSON.stringify({
id: Date.now(),
name: displayName,
url: url
}), {
status: 200,
headers: { 'Content-Type': 'application/json; charset=utf-8' }
});
}
// 添加 OpenAI 兼容接口路由 // 添加 OpenAI 兼容接口路由
if (path === '/v1/audio/speech' || path === '/audio/speech') { if (path === '/v1/audio/speech' || path === '/audio/speech') {
return await handleOpenAITTS(request); return await handleOpenAITTS(request);
@@ -305,6 +365,10 @@ async function handleRequest(request) {
class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500"> class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
下载音频 下载音频
</button> </button>
<button type="button" id="getReaderLinkBtn"
class="inline-flex justify-center py-2 px-4 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-ms-blue">
导入阅读
</button>
</div> </div>
<div id="voiceLoadError" role="alert" class="mt-4 rounded-md bg-red-50 p-4" style="display: none;"> <div id="voiceLoadError" role="alert" class="mt-4 rounded-md bg-red-50 p-4" style="display: none;">
@@ -557,10 +621,10 @@ curl ${baseUrl}/v1/audio/speech \\
// 清空现有选项 // 清空现有选项
styleSelect.innerHTML = ''; styleSelect.innerHTML = '';
// 默认添加标准风格 // 默认风格
const defaultOption = document.createElement('option'); const defaultOption = document.createElement('option');
defaultOption.value = 'general'; defaultOption.value = '';
defaultOption.text = '标准'; defaultOption.text = '无风格';
styleSelect.appendChild(defaultOption); styleSelect.appendChild(defaultOption);
// 查找选定的语音对象 // 查找选定的语音对象
@@ -750,6 +814,28 @@ curl ${baseUrl}/v1/audio/speech \\
const apiKeyInputGroup = document.getElementById('apiKeyInputGroup'); const apiKeyInputGroup = document.getElementById('apiKeyInputGroup');
const toggleApiKeyVisibilityBtn = document.getElementById('toggleApiKeyVisibility'); const toggleApiKeyVisibilityBtn = document.getElementById('toggleApiKeyVisibility');
// 添加获取Reader链接按钮的事件监听
document.getElementById('getReaderLinkBtn').addEventListener('click', function() {
const apiKey = document.getElementById('apiKey').value || localStorage.getItem('tts_api_key') || '';
const voice = document.getElementById('voice').value;
const rate = document.getElementById('rate').value;
const pitch = document.getElementById('pitch').value;
const style = document.getElementById('style').value;
const displayName = document.getElementById('voice').options[document.getElementById('voice').selectedIndex].text || '微软TTS';
// 构建URL参数
const params = new URLSearchParams();
if (apiKey) params.append('api_key', apiKey);
if (voice) params.append('v', voice);
if (rate) params.append('r', rate);
if (pitch) params.append('p', pitch);
if (style) params.append('s', style);
params.append('n', displayName);
// 打开新标签页
window.open(\`\${window.location.origin}/reader.json?\${params.toString()}\`, '_blank');
});
// 显示/隐藏API Key // 显示/隐藏API Key
toggleApiKeyVisibilityBtn.addEventListener('click', function() { toggleApiKeyVisibilityBtn.addEventListener('click', function() {
const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password'; const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password';