File size: 4,136 Bytes
66e3a81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
 * Image Service
 * Handles communication with Image Generation APIs.
 */

const axios = require('axios'); // Assuming axios might be used

// Placeholder for API Key configuration
const API_KEY = process.env.IMG_API_KEY || process.env.LLM_API_KEY || '';
const MODEL = 'gemini-3-pro-image-preview';
const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/${MODEL}:generateContent`;

/**
 * Generates an image based on the text prompt.
 * @param {string} prompt - The text description for the image.
 * @param {Object} options - Optional parameters (aspectRatio, etc.)
 * @returns {Promise<string>} - The base64 string of the generated image.
 */
async function generateImage(prompt, options = {}) {
  if (!API_KEY) {
    throw new Error("IMG_API_KEY or LLM_API_KEY is not defined in environment variables.");
  }

  try {
    console.log(`[Image Service] Sending request to ${MODEL}...`, prompt);

    const url = `${API_URL}?key=${API_KEY}`;

    const payload = {
      contents: [{
        parts: [{
          text: prompt
        }]
      }]
    };

    // Add optional configuration if supported by the model and needed
    /*
    if (options.aspectRatio) {
        payload.generationConfig = {
            aspectRatio: options.aspectRatio // e.g., "1:1", "4:3", "16:9"
        };
    }
    */

    const response = await axios.post(url, payload, {
      headers: {
        'Content-Type': 'application/json'
      },
      timeout: 120000 // 2 minutes timeout
    });

    // Extract base64 image data from Gemini response structure
    if (response.data && response.data.candidates && response.data.candidates.length > 0) {
      const candidate = response.data.candidates[0];
      if (candidate.content && candidate.content.parts) {
        const imagePart = candidate.content.parts.find(p => p.inlineData);
        if (imagePart && imagePart.inlineData) {
          return imagePart.inlineData.data; // This is the base64 string
        }
      }
    }

    console.warn("[Image Service] Unexpected response structure:", JSON.stringify(response.data));
    throw new Error("Empty or invalid response from Image Generation API.");

  } catch (error) {
    console.error('[Image Service] Error generating image:', error.response ? JSON.stringify(error.response.data) : error.message);
    throw error;
  }
}

/**
 * Regenerates/Edits an image based on a text prompt and an existing image.
 * 
 * @param {string} prompt - The text instruction.
 * @param {string} imageBase64 - The base64 string of the previous image.
 * @returns {Promise<string>} - The base64 string of the new image.
 */
async function regenerateImage(prompt, imageBase64) {
  if (!API_KEY) {
    throw new Error("IMG_API_KEY or LLM_API_KEY is not defined.");
  }

  try {
    console.log(`[Image Service] Regenerating image with prompt: ${prompt}`);

    const url = `${API_URL}?key=${API_KEY}`;

    const payload = {
      contents: [{
        parts: [
          { text: prompt },
          {
            inline_data: {
              mime_type: "image/png", // Assuming PNG for now, simplest for base64
              data: imageBase64
            }
          }
        ]
      }]
    };

    const response = await axios.post(url, payload, {
      headers: { 'Content-Type': 'application/json' },
      timeout: 120000
    });

    if (response.data && response.data.candidates && response.data.candidates.length > 0) {
      const candidate = response.data.candidates[0];
      if (candidate.content && candidate.content.parts) {
        const imagePart = candidate.content.parts.find(p => p.inlineData);
        if (imagePart && imagePart.inlineData) {
          return imagePart.inlineData.data;
        }
      }
    }

    console.warn("[Image Service] Unexpected response structure:", JSON.stringify(response.data));
    throw new Error("Empty or invalid response from Image Generation API.");

  } catch (error) {
    console.error('[Image Service] Error regenerating image:', error.response ? JSON.stringify(error.response.data) : error.message);
    throw error;
  }
}

module.exports = {
  generateImage,
  regenerateImage
};