@dataclouder/nest-vertex 0.0.37 → 0.0.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ import { type MulterFile } from '@webundsoehne/nest-fastify-file-upload';
2
+ import { GroqService } from '../services/whisper/groq.service';
3
+ export declare class GroqSttController {
4
+ private readonly groqService;
5
+ private readonly logger;
6
+ constructor(groqService: GroqService);
7
+ processAudio(file: MulterFile): Promise<any>;
8
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var GroqSttController_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.GroqSttController = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const nest_fastify_file_upload_1 = require("@webundsoehne/nest-fastify-file-upload");
19
+ const swagger_1 = require("@nestjs/swagger");
20
+ const groq_service_1 = require("../services/whisper/groq.service");
21
+ let GroqSttController = GroqSttController_1 = class GroqSttController {
22
+ groqService;
23
+ logger = new common_1.Logger(GroqSttController_1.name);
24
+ constructor(groqService) {
25
+ this.groqService = groqService;
26
+ }
27
+ async processAudio(file) {
28
+ console.log('Receive requests');
29
+ if (!file || !file.buffer) {
30
+ console.error('No file buffer received.');
31
+ return { error: 'No file uploaded or file buffer is missing.' };
32
+ }
33
+ console.log(`Received file: ${file.originalname}, mimetype: ${file.mimetype}, size: ${file.size}`);
34
+ try {
35
+ const result = await this.groqService.transcribeAudio(file.buffer, file.originalname, file.mimetype);
36
+ return result;
37
+ }
38
+ catch (error) {
39
+ console.error('Error during transcription process:', error);
40
+ return { error: 'Failed to transcribe audio.', details: error.message };
41
+ }
42
+ }
43
+ };
44
+ exports.GroqSttController = GroqSttController;
45
+ __decorate([
46
+ (0, common_1.Post)('transcribe-bytes'),
47
+ (0, common_1.UseInterceptors)((0, nest_fastify_file_upload_1.FileInterceptor)('file')),
48
+ (0, swagger_1.ApiConsumes)('multipart/form-data'),
49
+ (0, nest_fastify_file_upload_1.ApiFileBody)('file'),
50
+ __param(0, (0, common_1.UploadedFile)('file')),
51
+ __metadata("design:type", Function),
52
+ __metadata("design:paramtypes", [Object]),
53
+ __metadata("design:returntype", Promise)
54
+ ], GroqSttController.prototype, "processAudio", null);
55
+ exports.GroqSttController = GroqSttController = GroqSttController_1 = __decorate([
56
+ (0, swagger_1.ApiTags)('Speech-to-Text'),
57
+ (0, common_1.Controller)('api/groq-stt'),
58
+ __metadata("design:paramtypes", [groq_service_1.GroqService])
59
+ ], GroqSttController);
60
+ //# sourceMappingURL=groq-stt.controller.js.map
@@ -6,7 +6,8 @@ export declare enum TierType {
6
6
  export declare enum ModelType {
7
7
  LLM = "llm",
8
8
  IMAGE = "image",
9
- VIDEO = "video"
9
+ VIDEO = "video",
10
+ AUDIO = "audio"
10
11
  }
11
12
  export interface IKeyBalancer {
12
13
  _id?: string;
@@ -11,5 +11,6 @@ var ModelType;
11
11
  ModelType["LLM"] = "llm";
12
12
  ModelType["IMAGE"] = "image";
13
13
  ModelType["VIDEO"] = "video";
14
+ ModelType["AUDIO"] = "audio";
14
15
  })(ModelType || (exports.ModelType = ModelType = {}));
15
16
  //# sourceMappingURL=key-balancer.models.js.map
@@ -35,6 +35,8 @@ const comfyui_module_1 = require("./comfyui/comfyui.module");
35
35
  const vertex_veo_genai_service_1 = require("./services/vertex-veo-genai.service");
36
36
  const vertex_veo_video_controller_1 = require("./controllers/vertex-veo-video.controller");
37
37
  const google_genai_service_1 = require("./services/google-genai.service");
38
+ const groq_stt_controller_1 = require("./controllers/groq-stt.controller");
39
+ const groq_service_1 = require("./services/whisper/groq.service");
38
40
  let NestVertexModule = class NestVertexModule {
39
41
  };
40
42
  exports.NestVertexModule = NestVertexModule;
@@ -61,6 +63,7 @@ exports.NestVertexModule = NestVertexModule = __decorate([
61
63
  key_balancer_api_service_1.KeyBalancerApiService,
62
64
  vertex_veo_genai_service_1.VertexVeoGenaiService,
63
65
  google_genai_service_1.GoogleGenaiService,
66
+ groq_service_1.GroqService,
64
67
  ],
65
68
  exports: [
66
69
  vertex_image_video_service_1.VertexImageVideoService,
@@ -76,6 +79,7 @@ exports.NestVertexModule = NestVertexModule = __decorate([
76
79
  key_balancer_api_service_1.KeyBalancerApiService,
77
80
  vertex_veo_genai_service_1.VertexVeoGenaiService,
78
81
  google_genai_service_1.GoogleGenaiService,
82
+ groq_service_1.GroqService,
79
83
  comfyui_module_1.ComfyUIModule,
80
84
  ],
81
85
  controllers: [
@@ -87,6 +91,7 @@ exports.NestVertexModule = NestVertexModule = __decorate([
87
91
  generated_assets_controller_1.GeneratedAssetsController,
88
92
  vertex_comfy_controller_1.VertexComfyController,
89
93
  vertex_veo_video_controller_1.VertexVeoGenerationController,
94
+ groq_stt_controller_1.GroqSttController,
90
95
  ],
91
96
  })
92
97
  ], NestVertexModule);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataclouder/nest-vertex",
3
- "version": "0.0.37",
3
+ "version": "0.0.39",
4
4
  "description": "NestJS Vertex AI library for Dataclouder",
5
5
  "author": "dataclouder",
6
6
  "license": "MIT",
@@ -6,7 +6,7 @@ export declare class GoogleGenaiService {
6
6
  private readonly logger;
7
7
  private readonly defaultApiKey;
8
8
  constructor(keyBalancer: KeyBalancerApiService);
9
- getGoogleGenAIClient(modelName: string, keyTierType?: TierType, modelType?: ModelType): Promise<{
9
+ getGoogleGenAIClient(modelName: string, keyTierType?: TierType, aiType?: ModelType): Promise<{
10
10
  client: GoogleGenAI;
11
11
  balancedKey?: AvailableKeyResult;
12
12
  }>;
@@ -26,10 +26,15 @@ let GoogleGenaiService = GoogleGenaiService_1 = class GoogleGenaiService {
26
26
  this.logger.warn('GEMINI_API_KEY environment variable not set. This service will not work without available keys in the balancer.');
27
27
  }
28
28
  }
29
- async getGoogleGenAIClient(modelName, keyTierType, modelType) {
29
+ async getGoogleGenAIClient(modelName, keyTierType, aiType) {
30
30
  this.logger.warn('getGoogleGenAIClient() Getting key from redis');
31
- if (process.env.KEY_BALANCER_HOST && modelType) {
32
- const balancedKey = await this.keyBalancer.getKey(modelType, modelName, keyTierType);
31
+ if (process.env.KEY_BALANCER_HOST && aiType) {
32
+ const balancedKey = await this.keyBalancer.postQueryKey({
33
+ provider: 'google',
34
+ model: modelName,
35
+ tier: keyTierType,
36
+ aiType: aiType,
37
+ });
33
38
  if (balancedKey?.apiKey) {
34
39
  this.logger.debug(`Using balanced key: ${balancedKey.name} ${balancedKey.id}`);
35
40
  return { client: new genai_1.GoogleGenAI({ apiKey: balancedKey.apiKey }), balancedKey };
@@ -1,10 +1,17 @@
1
1
  import { HttpService } from '@nestjs/axios';
2
2
  import { AvailableKeyResult, ModelType, TierType } from '../models/key-balancer.models';
3
+ interface PostQueryKeyRequest {
4
+ provider: string;
5
+ model: string;
6
+ tier?: TierType;
7
+ aiType: ModelType;
8
+ }
3
9
  export declare class KeyBalancerApiService {
4
10
  private readonly httpService;
5
11
  private readonly logger;
6
12
  constructor(httpService: HttpService);
7
- getKey(modelType: ModelType, model: string, tier?: TierType): Promise<AvailableKeyResult>;
13
+ postQueryKey(request: PostQueryKeyRequest): Promise<AvailableKeyResult>;
8
14
  private getUnavailableServiceResult;
9
15
  recordFailedRequest(keyId: string, error: any, modelType: ModelType, model: string, ttlSeconds?: number): Promise<void>;
10
16
  }
17
+ export {};
@@ -20,20 +20,20 @@ let KeyBalancerApiService = KeyBalancerApiService_1 = class KeyBalancerApiServic
20
20
  constructor(httpService) {
21
21
  this.httpService = httpService;
22
22
  }
23
- async getKey(modelType, model, tier) {
23
+ async postQueryKey(request) {
24
24
  const keyBalancerHost = process.env.KEY_BALANCER_HOST;
25
25
  if (!keyBalancerHost) {
26
26
  this.logger.error('KEY_BALANCER_HOST environment variable not set.');
27
27
  return this.getUnavailableServiceResult();
28
28
  }
29
29
  try {
30
- const url = `${keyBalancerHost}/api/key-balancer/redis/key/${modelType.toLowerCase()}?model=${model}&tier=${tier || ''}`;
30
+ const url = `${keyBalancerHost}/api/key-balancer/redis/key`;
31
31
  this.logger.warn(`Request to: ${url}`);
32
- const { data } = await (0, rxjs_1.firstValueFrom)(this.httpService.get(url));
32
+ const { data } = await (0, rxjs_1.firstValueFrom)(this.httpService.post(url, request));
33
33
  return data;
34
34
  }
35
35
  catch (error) {
36
- this.logger.error(`Failed to get ${modelType} key for model ${model} from the external service.`, error.stack);
36
+ this.logger.error(`Failed to get ${request.aiType} key for model ${request.model} from the external service.`, error.stack);
37
37
  return this.getUnavailableServiceResult();
38
38
  }
39
39
  }
@@ -43,7 +43,12 @@ let ImageVertexService = ImageVertexService_1 = class ImageVertexService {
43
43
  keyId = 'local';
44
44
  }
45
45
  else {
46
- availableKey = (await this.keyBalancerApiService.getKey(key_balancer_models_1.ModelType.IMAGE, model, key_balancer_models_1.TierType.TIER_1));
46
+ availableKey = (await this.keyBalancerApiService.postQueryKey({
47
+ provider: 'google',
48
+ model: model,
49
+ tier: key_balancer_models_1.TierType.TIER_1,
50
+ aiType: key_balancer_models_1.ModelType.IMAGE,
51
+ }));
47
52
  if (availableKey === null) {
48
53
  this.logger.error('KEY BALANCER IS DOWN: :::: No available API key from key balancer.');
49
54
  }
@@ -0,0 +1,11 @@
1
+ import Groq from 'groq-sdk';
2
+ import { KeyBalancerApiService } from '../key-balancer-api.service';
3
+ export declare class GroqService {
4
+ private readonly keyBalancer;
5
+ private readonly logger;
6
+ private groq;
7
+ constructor(keyBalancer: KeyBalancerApiService);
8
+ private getClientWithKey;
9
+ private getExtensionFromMimeType;
10
+ transcribeAudio(fileBuffer: Buffer, originalFileName: string, mimeType: string): Promise<Groq.Audio.Transcriptions.Transcription>;
11
+ }
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ var __metadata = (this && this.__metadata) || function (k, v) {
42
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
43
+ };
44
+ var GroqService_1;
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.GroqService = void 0;
47
+ const common_1 = require("@nestjs/common");
48
+ const groq_sdk_1 = __importStar(require("groq-sdk"));
49
+ const path = __importStar(require("path"));
50
+ const key_balancer_api_service_1 = require("../key-balancer-api.service");
51
+ const key_balancer_models_1 = require("dataclouder/nest-vertex/models/key-balancer.models");
52
+ let GroqService = GroqService_1 = class GroqService {
53
+ keyBalancer;
54
+ logger = new common_1.Logger(GroqService_1.name);
55
+ groq;
56
+ constructor(keyBalancer) {
57
+ this.keyBalancer = keyBalancer;
58
+ }
59
+ getClientWithKey(key) {
60
+ return new groq_sdk_1.default({ apiKey: key });
61
+ }
62
+ getExtensionFromMimeType(mimeType) {
63
+ switch (mimeType?.toLowerCase()) {
64
+ case 'audio/wav':
65
+ case 'audio/x-wav':
66
+ return '.wav';
67
+ case 'audio/mpeg':
68
+ return '.mp3';
69
+ case 'audio/mp4':
70
+ case 'video/mp4':
71
+ return '.mp4';
72
+ case 'audio/flac':
73
+ return '.flac';
74
+ case 'audio/ogg':
75
+ return '.ogg';
76
+ case 'audio/opus':
77
+ return '.opus';
78
+ case 'audio/webm':
79
+ case 'video/webm':
80
+ return '.webm';
81
+ case 'audio/mpga':
82
+ return '.mpga';
83
+ case 'audio/m4a':
84
+ return '.m4a';
85
+ default:
86
+ this.logger.warn(`Unsupported or unknown mime type provided: ${mimeType}`);
87
+ return null;
88
+ }
89
+ }
90
+ async transcribeAudio(fileBuffer, originalFileName, mimeType) {
91
+ this.logger.log(`Attempting to transcribe file: ${originalFileName} (${mimeType})`);
92
+ const extension = this.getExtensionFromMimeType(mimeType);
93
+ let effectiveFileName = originalFileName;
94
+ if (extension) {
95
+ const currentExt = path.extname(originalFileName).toLowerCase();
96
+ if (currentExt !== extension) {
97
+ const baseName = path.basename(originalFileName, currentExt);
98
+ effectiveFileName = `${baseName}${extension}`;
99
+ this.logger.log(`Adjusted filename to: ${effectiveFileName} based on mime type: ${mimeType}`);
100
+ }
101
+ else {
102
+ this.logger.log(`Filename ${originalFileName} already has correct extension ${extension}`);
103
+ }
104
+ }
105
+ else {
106
+ this.logger.warn(`Could not determine valid extension for mime type ${mimeType}. Using original filename: ${originalFileName}. Transcription may fail if the filename lacks a supported extension.`);
107
+ }
108
+ try {
109
+ const file = await (0, groq_sdk_1.toFile)(fileBuffer, effectiveFileName, { type: mimeType });
110
+ const keyResult = await this.keyBalancer.postQueryKey({
111
+ provider: 'groq',
112
+ model: 'whisper-large-v3-turbo',
113
+ tier: key_balancer_models_1.TierType.FREE_TIER,
114
+ aiType: key_balancer_models_1.ModelType.AUDIO,
115
+ });
116
+ const transcription = await this.getClientWithKey(keyResult.apiKey).audio.transcriptions.create({
117
+ file: file,
118
+ model: 'whisper-large-v3-turbo',
119
+ response_format: 'verbose_json',
120
+ timestamp_granularities: ['word'],
121
+ });
122
+ this.logger.log(`Transcription successful for file: ${effectiveFileName}`);
123
+ return transcription;
124
+ }
125
+ catch (error) {
126
+ this.logger.error(`Error during transcription for file ${effectiveFileName}:`, error?.error || error);
127
+ const errorMessage = error?.error?.message || (error instanceof Error ? error.message : 'Unknown error during transcription');
128
+ throw new Error(`Failed to transcribe audio: ${errorMessage}`);
129
+ }
130
+ }
131
+ };
132
+ exports.GroqService = GroqService;
133
+ exports.GroqService = GroqService = GroqService_1 = __decorate([
134
+ (0, common_1.Injectable)(),
135
+ __metadata("design:paramtypes", [key_balancer_api_service_1.KeyBalancerApiService])
136
+ ], GroqService);
137
+ //# sourceMappingURL=groq.service.js.map