Files
CRM_Montzar/apps/api/src/ai/ai-stt.service.ts
T

84 lines
2.5 KiB
TypeScript

import {
BadRequestException,
Injectable,
ServiceUnavailableException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
const MAX_AUDIO_BYTES = 8 * 1024 * 1024;
@Injectable()
export class AiSttService {
constructor(private readonly config: ConfigService) {}
isEnabled(): boolean {
return (
this.config.get<string>('STT_ENABLED') === 'true' &&
Boolean(this.sttUrl())
);
}
async transcribe(file: Express.Multer.File | undefined) {
if (!this.isEnabled()) {
throw new ServiceUnavailableException('تبدیل صوت به متن فعال نیست');
}
if (!file?.buffer?.length) {
throw new BadRequestException('فایل صوتی ارسال نشده است');
}
if (file.size > MAX_AUDIO_BYTES) {
throw new BadRequestException('حجم فایل صوتی بیش از حد مجاز است');
}
const form = new FormData();
form.append(
'audio',
new Blob([new Uint8Array(file.buffer)], {
type: file.mimetype || 'audio/wav',
}),
file.originalname || 'audio.wav',
);
const timeoutMs = Number(this.config.get<string>('STT_TIMEOUT_MS') || 180000);
const headers: Record<string, string> = {};
const token = this.config.get<string>('STT_INTERNAL_TOKEN')?.trim();
if (token) headers['X-STT-Token'] = token;
let res: Response;
try {
res = await fetch(`${this.sttUrl()}/transcribe`, {
method: 'POST',
headers,
body: form,
signal: AbortSignal.timeout(timeoutMs),
});
} catch {
throw new ServiceUnavailableException(
'سرویس تبدیل صوت در دسترس نیست. Pipecat STT را اجرا کنید.',
);
}
const payload = (await res.json().catch(() => ({}))) as {
text?: string;
detail?: string | Array<{ msg?: string }>;
};
if (!res.ok) {
const detail = Array.isArray(payload.detail)
? payload.detail.map((item) => item.msg).filter(Boolean).join('، ')
: payload.detail;
const raw = String(detail || '').trim();
let message = raw || 'تبدیل صوت به متن ناموفق بود';
if (raw.length > 220) {
message = 'تبدیل صوت به متن ناموفق بود. سرویس STT محلی را بررسی کنید.';
}
throw new ServiceUnavailableException(message);
}
return { text: (payload.text ?? '').trim() };
}
private sttUrl(): string {
return (this.config.get<string>('STT_URL') ?? '').trim().replace(/\/$/, '');
}
}