@contentgrowth/llm-service 0.6.7 → 0.6.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/llm-service",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "description": "Unified LLM Service for Content Growth",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -46,4 +46,26 @@ export class BaseLLMProvider {
46
46
  async imageGeneration(prompt, modelName, systemPrompt, options) {
47
47
  throw new Error('Image generation not supported by this provider');
48
48
  }
49
+
50
+ /**
51
+ * Start video generation (returns operation name for polling)
52
+ * @param {string} prompt
53
+ * @param {Array} images
54
+ * @param {string} modelName
55
+ * @param {string} systemPrompt
56
+ * @param {Object} options
57
+ * @returns {Promise<{operationName: string}>}
58
+ */
59
+ async startVideoGeneration(prompt, images, modelName, systemPrompt, options) {
60
+ throw new Error('Video generation not supported by this provider');
61
+ }
62
+
63
+ /**
64
+ * Get video generation status (poll operation)
65
+ * @param {string} operationName
66
+ * @returns {Promise<{done: boolean, progress: number, state: string, videoUri?: string, error?: object}>}
67
+ */
68
+ async getVideoGenerationStatus(operationName) {
69
+ throw new Error('Video generation not supported by this provider');
70
+ }
49
71
  }
@@ -354,47 +354,45 @@ export class GeminiProvider extends BaseLLMProvider {
354
354
  return this.models[tier] || this.models.default;
355
355
  }
356
356
 
357
- async videoGeneration(prompt, images, modelName, systemPrompt, options = {}) {
358
- const model = this.client.getGenerativeModel({
357
+ async startVideoGeneration(prompt, images, modelName, systemPrompt, options = {}) {
358
+ // 1. Initiate the request
359
+ const operation = await this.client.models.generateVideos({
359
360
  model: modelName,
360
- systemInstruction: systemPrompt,
361
- });
362
-
363
- // Prepare image parts
364
- const imageParts = images.map(img => ({
365
- inlineData: {
366
- data: img.data, // Base64 string
367
- mimeType: img.mimeType
361
+ prompt: prompt,
362
+ config: {
363
+ referenceImages: images,
368
364
  }
369
- }));
370
-
371
- const result = await model.generateContent({
372
- contents: [{
373
- role: "user",
374
- parts: [
375
- { text: prompt },
376
- ...imageParts
377
- ]
378
- }]
379
365
  });
380
366
 
381
- const response = result.response;
382
-
383
- // Check for video attachment/URI in the response
384
- // This structure depends on the specific API response for Veo
385
- // Assuming it might return a file URI or a specific part type
367
+ return { operationName: operation.name };
368
+ }
386
369
 
387
- // Fallback: Return text if no specific video part is found,
388
- // but try to find a URI in the text if possible.
389
- const text = response.text();
370
+ async getVideoGenerationStatus(operationName) {
371
+ // 2. Get operation status
372
+ // Assuming the SDK supports retrieving operation by name via this.client.models.getOperation
373
+ // If not, we might need to adjust based on the specific SDK version.
374
+ const operation = await this.client.models.getOperation(operationName);
390
375
 
391
- // TODO: Update this once Veo API response structure is fully documented/available
392
- // For now, we return the text which might contain the URI or status.
376
+ // Refresh status
377
+ await operation.get();
393
378
 
394
- return {
395
- content: text,
396
- // potential video URI extraction
397
- videoUri: text.match(/https?:\/\/[^\s]+/) ? text.match(/https?:\/\/[^\s]+/)[0] : null
379
+ const result = {
380
+ done: operation.done,
381
+ // Extract progress if available in metadata
382
+ progress: operation.metadata?.progressPercent || 0,
383
+ state: operation.metadata?.state || (operation.done ? 'COMPLETED' : 'PROCESSING'),
398
384
  };
385
+
386
+ if (operation.done) {
387
+ if (operation.error) {
388
+ result.error = operation.error;
389
+ } else {
390
+ const videoResult = operation.response;
391
+ result.videoUri = videoResult.uri || (videoResult.generatedAssets && videoResult.generatedAssets[0] && videoResult.generatedAssets[0].uri);
392
+ result.content = "Video generation completed.";
393
+ }
394
+ }
395
+
396
+ return result;
399
397
  }
400
398
  }
@@ -205,11 +205,43 @@ export class LLMService {
205
205
  }
206
206
 
207
207
  /**
208
- * Generate a video
208
+ * Generate a video (async wrapper with polling - backward compatibility)
209
209
  */
210
210
  async videoGeneration(prompt, images, tenantId, modelName, systemPrompt, options = {}) {
211
+ const { operationName } = await this.startVideoGeneration(prompt, images, tenantId, modelName, systemPrompt, options);
212
+
213
+ let status = await this.getVideoGenerationStatus(operationName, tenantId);
214
+
215
+ while (!status.done) {
216
+ console.log(`Waiting for video generation... Progress: ${status.progress}%`);
217
+ await new Promise(resolve => setTimeout(resolve, 10000)); // Wait 10 seconds
218
+ status = await this.getVideoGenerationStatus(operationName, tenantId);
219
+ }
220
+
221
+ if (status.error) {
222
+ throw new Error(`Video generation failed: ${status.error.message || JSON.stringify(status.error)}`);
223
+ }
224
+
225
+ return {
226
+ content: status.content || "Video generation completed.",
227
+ videoUri: status.videoUri
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Start video generation (returns operation name for polling)
233
+ */
234
+ async startVideoGeneration(prompt, images, tenantId, modelName, systemPrompt, options = {}) {
235
+ const provider = await this._getProvider(tenantId);
236
+ return provider.startVideoGeneration(prompt, images, modelName, systemPrompt, options);
237
+ }
238
+
239
+ /**
240
+ * Get video generation status
241
+ */
242
+ async getVideoGenerationStatus(operationName, tenantId) {
211
243
  const provider = await this._getProvider(tenantId);
212
- return provider.videoGeneration(prompt, images, modelName, systemPrompt, options);
244
+ return provider.getVideoGenerationStatus(operationName);
213
245
  }
214
246
 
215
247
  /**