mcp-duojie-image 0.4.0 → 0.5.0

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/dist/config.js CHANGED
@@ -12,7 +12,7 @@ export function loadConfig(overrides) {
12
12
  return {
13
13
  apiKey,
14
14
  baseUrl: overrides?.baseUrl ?? process.env.DUOJIE_BASE_URL ?? "https://api.duojie.games",
15
- model: overrides?.model ?? process.env.DUOJIE_IMAGE_MODEL ?? "gemini-3-pro-image-preview",
15
+ model: overrides?.model ?? process.env.DUOJIE_IMAGE_MODEL ?? "gemini-3.1-flash-image",
16
16
  timeoutMs: 300_000,
17
17
  };
18
18
  }
package/dist/provider.js CHANGED
@@ -24,35 +24,46 @@ async function fetchWithRetry(url, init, timeoutMs, retries = 0) {
24
24
  }
25
25
  throw new AppError("E_PROVIDER_BAD_REQUEST", `Network error: ${lastErr}`);
26
26
  }
27
- async function buildMessages(opts) {
27
+ async function buildParts(opts) {
28
28
  const { prompt, referenceImages, negativePrompt } = opts;
29
29
  const fullPrompt = negativePrompt ? `${prompt}\n\nAvoid: ${negativePrompt}` : prompt;
30
- if (!referenceImages || referenceImages.length === 0) {
31
- return [{ role: "user", content: fullPrompt }];
30
+ const parts = [];
31
+ if (referenceImages && referenceImages.length > 0) {
32
+ const imageParts = await Promise.all(referenceImages.map(async (imgPath) => {
33
+ const data = await resizeIfNeeded(imgPath);
34
+ return { inlineData: { mimeType: "image/png", data: data.toString("base64") } };
35
+ }));
36
+ parts.push(...imageParts);
32
37
  }
33
- const parts = await Promise.all(referenceImages.map(async (imgPath) => {
34
- const data = await resizeIfNeeded(imgPath);
35
- const b64 = data.toString("base64");
36
- return { type: "image_url", image_url: { url: `data:image/png;base64,${b64}` } };
37
- }));
38
- parts.push({ type: "text", text: fullPrompt });
39
- return [{ role: "user", content: parts }];
38
+ parts.push({ text: fullPrompt });
39
+ return parts;
40
+ }
41
+ function mapSize(size) {
42
+ if (size === "512px")
43
+ return "512";
44
+ return size; // "1K", "2K", "4K" are used as-is
40
45
  }
41
46
  export async function generateImage(config, opts) {
42
- const messages = await buildMessages(opts);
47
+ const parts = await buildParts(opts);
43
48
  const model = opts.model ?? config.model;
44
49
  const imageConfig = {
45
- image_size: opts.size ?? "1K",
50
+ imageSize: mapSize(opts.size ?? "1K"),
46
51
  };
47
52
  if (opts.aspectRatio) {
48
- imageConfig.aspect_ratio = opts.aspectRatio;
53
+ imageConfig.aspectRatio = opts.aspectRatio;
49
54
  }
50
- const body = JSON.stringify({ model, messages, image_config: imageConfig });
51
- const url = `${config.baseUrl}/v1/chat/completions`;
55
+ const body = JSON.stringify({
56
+ contents: [{ role: "user", parts }],
57
+ generationConfig: {
58
+ responseModalities: ["IMAGE"],
59
+ imageConfig,
60
+ },
61
+ });
62
+ const url = `${config.baseUrl}/v1beta/models/${model}:generateContent`;
52
63
  const res = await fetchWithRetry(url, {
53
64
  method: "POST",
54
65
  headers: {
55
- "Authorization": `Bearer ${config.apiKey}`,
66
+ "x-goog-api-key": config.apiKey,
56
67
  "Content-Type": "application/json",
57
68
  },
58
69
  body,
@@ -68,14 +79,9 @@ export async function generateImage(config, opts) {
68
79
  throw new AppError("E_PROVIDER_BAD_REQUEST", `Upstream error ${res.status}: ${text.slice(0, 200)}`);
69
80
  }
70
81
  const data = (await res.json());
71
- const imageUrl = data.choices?.[0]?.message?.images?.[0]?.image_url?.url;
72
- if (!imageUrl) {
82
+ const imagePart = data.candidates?.[0]?.content?.parts?.find((p) => p.inlineData);
83
+ if (!imagePart?.inlineData?.data) {
73
84
  throw new AppError("E_PROVIDER_BAD_REQUEST", "No image in response");
74
85
  }
75
- // data:image/png;base64,<data>
76
- const comma = imageUrl.indexOf(",");
77
- if (comma === -1) {
78
- throw new AppError("E_PROVIDER_BAD_REQUEST", "Unexpected image_url format");
79
- }
80
- return Buffer.from(imageUrl.slice(comma + 1), "base64");
86
+ return Buffer.from(imagePart.inlineData.data, "base64");
81
87
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-duojie-image",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "MCP server for image generation via duojie.games",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",