56 lines
1.2 KiB
TypeScript
56 lines
1.2 KiB
TypeScript
|
|
import {
|
||
|
|
IsBase64,
|
||
|
|
IsIn,
|
||
|
|
IsInt,
|
||
|
|
IsString,
|
||
|
|
MaxLength,
|
||
|
|
Min,
|
||
|
|
} from 'class-validator';
|
||
|
|
|
||
|
|
/** Containers OpenRouter's transcription endpoint accepts, and MediaRecorder can produce. */
|
||
|
|
export const VOICE_AUDIO_FORMATS = [
|
||
|
|
'webm',
|
||
|
|
'mp4',
|
||
|
|
'm4a',
|
||
|
|
'aac',
|
||
|
|
'ogg',
|
||
|
|
'wav',
|
||
|
|
'mp3',
|
||
|
|
'flac',
|
||
|
|
] as const;
|
||
|
|
|
||
|
|
export type VoiceAudioFormat = (typeof VOICE_AUDIO_FORMATS)[number];
|
||
|
|
|
||
|
|
export class ExtractVoiceDto {
|
||
|
|
/**
|
||
|
|
* Base64 audio, no data: prefix. Capped well above a 2-minute opus clip (~400 KB) but
|
||
|
|
* far below OpenRouter's 25 MB ceiling, so an oversized upload is rejected before it
|
||
|
|
* costs a vendor call.
|
||
|
|
*/
|
||
|
|
@IsString()
|
||
|
|
@IsBase64()
|
||
|
|
@MaxLength(8_000_000)
|
||
|
|
audio: string;
|
||
|
|
|
||
|
|
@IsIn(VOICE_AUDIO_FORMATS)
|
||
|
|
format: VoiceAudioFormat;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The clinician's IANA zone. The server derives "today" from it rather than trusting a
|
||
|
|
* client-supplied date, which is what relative deadlines resolve against.
|
||
|
|
*/
|
||
|
|
@IsString()
|
||
|
|
@MaxLength(64)
|
||
|
|
timeZone: string;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Recording length as measured by the client.
|
||
|
|
*
|
||
|
|
* Required, not optional: an optional value means omitting it bypasses
|
||
|
|
* VOICE_MAX_RECORDING_MS entirely, which would make the cap advisory.
|
||
|
|
*/
|
||
|
|
@IsInt()
|
||
|
|
@Min(0)
|
||
|
|
durationMs: number;
|
||
|
|
}
|