feat: integrate learning module
This commit is contained in:
52
electron/services/learning-speech-client.ts
Normal file
52
electron/services/learning-speech-client.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { WORKS_SQUARE_CONFIG } from '../api/works-config';
|
||||
import { proxyAwareFetch } from '../utils/proxy-fetch';
|
||||
import { getValidWorksSquareAccessToken } from './works-square-session';
|
||||
|
||||
const MAX_AUDIO_BYTES = 26_214_400;
|
||||
|
||||
export type LearningSpeechRequest = {
|
||||
audio: Uint8Array;
|
||||
fileName: string;
|
||||
mimeType: string;
|
||||
language?: string;
|
||||
};
|
||||
|
||||
type Dependencies = {
|
||||
fetchImpl?: typeof fetch;
|
||||
getAccessToken?: typeof getValidWorksSquareAccessToken;
|
||||
apiBaseUrl?: string;
|
||||
};
|
||||
|
||||
export function createLearningSpeechClient(dependencies: Dependencies = {}) {
|
||||
const fetchImpl = dependencies.fetchImpl ?? proxyAwareFetch;
|
||||
const getAccessToken = dependencies.getAccessToken ?? getValidWorksSquareAccessToken;
|
||||
const apiBaseUrl = (dependencies.apiBaseUrl ?? WORKS_SQUARE_CONFIG.apiBaseUrl).replace(/\/+$/, '');
|
||||
|
||||
async function transcribe(input: LearningSpeechRequest): Promise<{ text: string }> {
|
||||
const audio = input.audio instanceof Uint8Array ? input.audio : new Uint8Array(input.audio);
|
||||
if (!audio.byteLength || audio.byteLength > MAX_AUDIO_BYTES) throw new Error('语音长度不符合要求');
|
||||
const token = await getAccessToken({ fetchImpl });
|
||||
if (!token) throw new Error('请先登录');
|
||||
const form = new FormData();
|
||||
form.set('audio', new Blob([audio], { type: input.mimeType || 'audio/webm' }), input.fileName || 'voice.webm');
|
||||
if (input.language?.trim()) form.set('language', input.language.trim());
|
||||
const request = (accessToken: string) => fetchImpl(`${apiBaseUrl}/api/speech/transcriptions`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
body: form,
|
||||
});
|
||||
let response = await request(token);
|
||||
if (response.status === 401) {
|
||||
await response.body?.cancel().catch(() => undefined);
|
||||
const refreshed = await getAccessToken({ fetchImpl, forceRefresh: true });
|
||||
if (refreshed) response = await request(refreshed);
|
||||
}
|
||||
const payload = await response.json().catch(() => null) as { text?: unknown; detail?: unknown } | null;
|
||||
if (!response.ok || typeof payload?.text !== 'string' || !payload.text.trim()) {
|
||||
throw new Error(typeof payload?.detail === 'string' ? payload.detail : '语音识别失败');
|
||||
}
|
||||
return { text: payload.text.trim() };
|
||||
}
|
||||
|
||||
return { transcribe };
|
||||
}
|
||||
Reference in New Issue
Block a user