awesome-gpt-image-2/scripts/utils/image-uploader.ts
Jared Liu a00a14c74f feat: scaffold awesome-gpt-image-2 from nano-banana-pro template
Mirror of awesome-nano-banana-pro-prompts tuned for OpenAI's upcoming
GPT Image 2 (codename "duct-tape"):

- Swap CMS model filter to gpt-image-2 + campaign gpt-image-2-prompts
- i18n.ts: all 16 languages rebranded; rewrite seedancePromo to
  cross-promote nano-banana-pro, and whatIs content to reflect
  GPT Image 2's actual strengths:
    * Pixel-perfect multi-language text rendering (zh/en/ja)
    * Cross-image pixel-level consistency
    * Commercial-ready illustration quality
    * True art style induction
  Primary languages (en, zh, zh-TW, ja, ko) hand-translated;
  others fall back to English copy (will be refined later)
- markdown-generator: cover image path switched to
  gpt-image-2-prompts-cover-{en,zh}.png, arenaUrl points at the
  gallery page (the side-by-side arena page doesn't exist yet)
- GitHub Actions:
    * update-readme.yml runs on cron 0 0,12 * * * (twice daily
      per product request, instead of every 4 hours)
    * sync-approved-to-cms.yml wired to gpt-image-2 model
- Cover images, issue templates, docs, LICENSE (year 2026) updated
- Initial 16 README_*.md files generated from live CMS (78 prompts,
  44 categories) so the repo renders immediately without waiting
  for the first Action run

Secrets the repo needs before the Action runs on the remote:
  - CMS_HOST
  - CMS_API_KEY

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 14:42:24 +08:00

56 lines
1.7 KiB
TypeScript

import fetch from 'node-fetch';
import type { Media } from './cms-client.js';
const CMS_HOST = process.env.CMS_HOST;
const CMS_API_KEY = process.env.CMS_API_KEY;
/**
* Upload image to CMS
* @param imageUrl Original image URL
* @returns CMS media object
*/
export async function uploadImageToCMS(imageUrl: string): Promise<Media> {
try {
// Download image
const imageResponse = await fetch(imageUrl);
if (!imageResponse.ok) {
throw new Error(`Failed to fetch image: ${imageResponse.statusText}`);
}
const imageBuffer = await imageResponse.arrayBuffer();
const contentType = imageResponse.headers.get('content-type') || 'image/jpeg';
// Extract filename from URL
const urlParts = imageUrl.split('/');
const filename = urlParts[urlParts.length - 1].split('?')[0] || 'image.jpg';
// Create FormData
const formData = new FormData();
const blob = new Blob([imageBuffer], { type: contentType });
formData.append('file', blob, filename);
// Upload to CMS
const uploadResponse = await fetch(`${CMS_HOST}/api/media`, {
method: 'POST',
headers: {
'Authorization': `users API-Key ${CMS_API_KEY}`,
},
body: formData as any,
});
if (!uploadResponse.ok) {
const errorText = await uploadResponse.text();
throw new Error(`Failed to upload image: ${uploadResponse.statusText} - ${errorText}`);
}
const data = await uploadResponse.json() as { doc: Media };
const media = data.doc;
return media;
} catch (error) {
console.error('Error uploading image to CMS:', error);
// If upload fails, throw error instead of returning original URL
// The caller should handle the error
throw error;
}
}