Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export const THREE_ZERO_TWO_AI: string = '302ai';
export const MESHY: string = 'meshy';
export const TRIPO3D: string = 'tripo3d';
export const NEXTBIT: string = 'nextbit';
export const VEENA_MAX: string = 'veenamax';

export const VALID_PROVIDERS = [
ANTHROPIC,
Expand Down Expand Up @@ -173,6 +174,7 @@ export const VALID_PROVIDERS = [
MESHY,
TRIPO3D,
NEXTBIT,
VEENA_MAX,
];

export const CONTENT_TYPES = {
Expand Down
2 changes: 2 additions & 0 deletions src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import AI302Config from './302ai';
import MeshyConfig from './meshy';
import Tripo3DConfig from './tripo3d';
import { NextBitConfig } from './nextbit';
import VeenaMaxConfig from './veenamax';

const Providers: { [key: string]: ProviderConfigs } = {
openai: OpenAIConfig,
Expand Down Expand Up @@ -132,6 +133,7 @@ const Providers: { [key: string]: ProviderConfigs } = {
meshy: MeshyConfig,
nextbit: NextBitConfig,
tripo3d: Tripo3DConfig,
veenamax: VeenaMaxConfig,
};

export default Providers;
22 changes: 22 additions & 0 deletions src/providers/veenamax/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ProviderAPIConfig } from '../types';

const VeenaMaxAPIConfig: ProviderAPIConfig = {
getBaseURL: () => 'https://flash.mayaresearch.ai',
headers: ({ providerOptions }) => {
const headersObj: Record<string, string> = {
Authorization: `Bearer ${providerOptions.apiKey}`,
'Content-Type': 'application/json',
};
return headersObj;
},
getEndpoint: ({ fn }) => {
switch (fn) {
case 'createSpeech':
return '/generate';
default:
return '';
}
},
};

export default VeenaMaxAPIConfig;
136 changes: 136 additions & 0 deletions src/providers/veenamax/createSpeech.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { VEENA_MAX } from '../../globals';
import { ErrorResponse, ProviderConfig } from '../types';
import {
generateErrorResponse,
generateInvalidProviderResponseError,
} from '../utils';

// VeenaMAX API request interface
export interface VeenaMaxTTSRequest {
text: string;
speaker_id: string;
streaming?: boolean;
normalize?: boolean;
}

// VeenaMAX API response interface
export interface VeenaMaxTTSResponse {
// VeenaMAX returns audio data directly as Response
}

// VeenaMAX API error response interface
export interface VeenaMaxErrorResponse {
error: {
message: string;
code: number;
type: string;
};
}

// Parameter configuration mapping OpenAI format to VeenaMAX format
export const VeenaMaxCreateSpeechConfig: ProviderConfig = {
model: {
param: 'model',
required: false,
default: 'veenamax-1',
},
input: {
param: 'text',
required: true,
},
voice: {
param: 'speaker_id',
required: true,
default: 'charu_soft',
},
response_format: {
param: 'response_format',
required: false,
default: 'wav',
},
speed: {
param: 'speed',
required: false,
default: 1,
min: 0.25,
max: 4.0,
},

streaming: {
param: 'streaming',
required: false,
default: false,
},
normalize: {
param: 'normalize',
required: false,
default: true,
},
};

export const VeenaMaxCreateSpeechResponseTransform = (
response: VeenaMaxTTSResponse | VeenaMaxErrorResponse | Response,
responseStatus: number
) => {
if (responseStatus !== 200) {
if (response && typeof response === 'object' && 'error' in response) {
const errorResponse = response as VeenaMaxErrorResponse;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Code Refactor

Issue: Redundant type assertion after in operator check
Fix: Remove unnecessary type assertion since in operator already confirms type
Impact: Cleaner code without runtime impact

Suggested change
const errorResponse = response as VeenaMaxErrorResponse;
const errorResponse = response;

return generateErrorResponse(
{
message: errorResponse.error.message,
type: errorResponse.error.type,
param: null,
code:
errorResponse.error.code?.toString() || responseStatus.toString(),
Comment on lines +83 to +84
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐛 Bug Fix

Issue: Error response handling fails when errorResponse.error.code is 0 (falsy), causing undefined in error code
Fix: Use nullish coalescing to handle 0 correctly
Impact: Prevents incorrect error codes in API responses

Suggested change
code:
errorResponse.error.code?.toString() || responseStatus.toString(),
code:
errorResponse.error.code ?? responseStatus.toString(),

},
VEENA_MAX
);
}

let errorMessage = 'TTS request failed';
let errorType = 'api_error';

switch (responseStatus) {
case 400:
errorMessage =
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @saicherry93479 I would not recommend keeping a map of the error messages here in the gateway, please forward whatever error message is returned from the upstream provider in the https response

'Invalid request format. Check JSON syntax and required fields.';
errorType = 'invalid_request_error';
break;
case 401:
errorMessage =
'Authentication failed. Verify API key and Bearer token format.';
errorType = 'authentication_error';
break;
case 403:
errorMessage = 'Access denied. Check API permissions and quotas.';
errorType = 'permission_error';
break;
case 429:
errorMessage = 'Rate limit exceeded. Implement exponential backoff.';
errorType = 'rate_limit_error';
break;
case 500:
errorMessage = 'Internal server error. Contact support if persistent.';
errorType = 'api_error';
break;
default:
errorMessage = `VeenaMAX TTS request failed with status ${responseStatus}`;
}

return generateErrorResponse(
{
message: errorMessage,
type: errorType,
param: null,
code: responseStatus.toString(),
},
VEENA_MAX
);
}

if (response instanceof Response) {
return response;
}

return generateInvalidProviderResponseError(response, VEENA_MAX);
};
16 changes: 16 additions & 0 deletions src/providers/veenamax/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ProviderConfigs } from '../types';
import VeenaMaxAPIConfig from './api';
import {
VeenaMaxCreateSpeechConfig,
VeenaMaxCreateSpeechResponseTransform,
} from './createSpeech';

const VeenaMaxConfig: ProviderConfigs = {
api: VeenaMaxAPIConfig,
createSpeech: VeenaMaxCreateSpeechConfig,
responseTransforms: {
createSpeech: VeenaMaxCreateSpeechResponseTransform,
},
};

export default VeenaMaxConfig;