img2img.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. const fs = require('fs');
  2. const path = require('path');
  3. const config = require('../config');
  4. const PATH = 'images/edits';
  5. const TIMEOUT_MS = 180000;
  6. /**
  7. * @param {string} imageUrl data:image/...;base64,... 或本地绝对/相对路径
  8. */
  9. function parseImageInput (imageUrl) {
  10. const s = String(imageUrl || '').trim();
  11. const m = s.match(/^data:([^;]+);base64,([\s\S]+)$/i);
  12. if (m) {
  13. return {
  14. buffer: Buffer.from(m[2], 'base64'),
  15. filename: 'image.png',
  16. mime: (m[1] || 'image/png').split(';')[0].trim() || 'image/png',
  17. };
  18. }
  19. if (fs.existsSync(s)) {
  20. const buf = fs.readFileSync(s);
  21. const base = path.basename(s) || 'image.png';
  22. return { buffer: buf, filename: base, mime: 'image/png' };
  23. }
  24. throw new Error('img2img: image 需为 data URL 或存在的本地图片路径');
  25. }
  26. /**
  27. * OpenAI 官方 /v1/images/edits 要求 multipart/form-data(非 JSON)
  28. * 字段:prompt, image(文件), n, size;可选 model
  29. */
  30. function buildFormData (prompt, imageUrl, modelOverride) {
  31. const form = new FormData();
  32. form.append('prompt', String(prompt || ''));
  33. form.append('n', '1');
  34. form.append('size', '1024x1024');
  35. const { buffer, filename, mime } = parseImageInput(imageUrl);
  36. const blob = new Blob([buffer], { type: mime });
  37. form.append('image', blob, filename.endsWith('.png') || filename.endsWith('.jpg') || filename.endsWith('.webp') ? filename : `${filename}.png`);
  38. if (modelOverride && String(modelOverride).trim()) {
  39. form.append('model', String(modelOverride).trim());
  40. }
  41. return form;
  42. }
  43. /** @deprecated 仅结构占位;真实请求请用 buildFormData + multipart */
  44. function getBody (prompt, imageUrl) {
  45. return {
  46. prompt,
  47. image: typeof imageUrl === 'string' && imageUrl.length > 80 ? `${imageUrl.slice(0, 40)}…` : imageUrl,
  48. n: 1,
  49. size: '1024x1024',
  50. };
  51. }
  52. function getDoubaoBody (prompt, imageUrl, modelOverride) {
  53. const model =
  54. (modelOverride && String(modelOverride).trim()) || config.DOUBAO_MODEL;
  55. return {
  56. model,
  57. prompt,
  58. image: imageUrl,
  59. n: 1,
  60. size: '1024x1024',
  61. };
  62. }
  63. module.exports = {
  64. path: PATH,
  65. getBody,
  66. getDoubaoBody,
  67. buildFormData,
  68. timeoutMs: TIMEOUT_MS,
  69. };