/***
@ Base: https://play.google.com/store/apps/details?id=xyz.thingapps.banana
@ Author: Shannz
@ Note: 이미지 편집 및 이미지 생성을 간편하게.
***/
import axios from 'axios';
import fs from 'fs';
import crypto from 'crypto';
const 설정 = {
베이스_엔드: "https://dydkrpmnafsnivjxmipj.supabase.co",
비밀키: "sb_publishable_W_1Ofv9769iYEEn9dfyAHQ_OhuCER6g",
경로: {
회원가입: "/auth/v1/signup",
새로_고침: "/auth/v1/token",
편집: "/functions/v1/edit-image",
생성: "/functions/v1/generate-image"
},
헤더: {
"User-Agent": "Dart/3.9 (dart:io)",
"Accept-Encoding": "gzip",
"x-supabase-client-platform": "android",
"x-client-info": "supabase-flutter/2.10.3",
"x-supabase-client-platform-version": "15 A15.0.2.0.VGWIDXM",
"Content-Type": "application/json; charset=utf-8",
"x-supabase-api-version": "2024-01-01"
}
};
let 세션 = {
액세스_토큰: null,
리프레시_토큰: null,
만료일: 0
};
const 클라우드_업로드 = async (buffer, ext = '.png') => {
try {
const 파일_이름 = `flux-${crypto.randomUUID()}${ext}`;
const 콘텐츠_유형 = 'image/png';
const 파일_크기 = buffer.length;
const { data } = await axios.post('https://api.cloudsky.biz.id/get-upload-url', {
fileKey: 파일_이름,
contentType: 콘텐츠_유형,
fileSize: 파일_크기
});
await axios.put(data.uploadUrl, buffer, {
headers: {
'Content-Type': 콘텐츠_유형,
'Content-Length': 파일_크기,
'x-amz-server-side-encryption': 'AES256'
},
maxBodyLength: Infinity,
maxContentLength: Infinity
});
return `https://api.cloudsky.biz.id/file?key=${encodeURIComponent(파일_이름)}`;
} catch (에러) {
console.error(`[Upload Cloud Error]: ${에러.message}`);
return null;
}
};
const Base64로_변환 = async (입력_데이터) => {
try {
let 완충기;
if (Buffer.isBuffer(입력_데이터)) {
완충기 = 입력_데이터;
} else if (typeof 입력_데이터 === 'string' && 입력_데이터.startsWith('http')) {
const 응답 = await axios.get(입력_데이터, { responseType: 'arraybuffer' });
완충기 = Buffer.from(응답.data);
} else if (fs.existsSync(입력_데이터)) {
완충기 = fs.readFileSync(입력_데이터);
} else {
return null;
}
return 완충기.toString('base64');
} catch (e) { return null; }
};
export const fluxAi = {
signup: async () => {
try {
const 유효_탑재량 = { data: {}, gotrue_meta_security: { captcha_token: null } };
const 헤더 = { ...설정.헤더, "apikey": 설정.비밀키, "Authorization": `Bearer ${설정.비밀키}` };
const 응답 = await axios.post(설정.베이스_엔드 + 설정.경로.회원가입, 유효_탑재량, { headers: 헤더 });
if (응답.data?.access_token) {
세션.액세스_토큰 = 응답.data.access_token;
세션.리프레시_토큰 = 응답.data.refresh_token;
return 세션.액세스_토큰;
}
return null;
} catch (e) {
console.error("Signup Error:", e.message);
return null;
}
},
editImage: async (imageInput, prompt) => {
try {
if (!세션.액세스_토큰) await fluxAi.signup();
if (!세션.액세스_토큰) return { success: false, msg: 'Auth failed' };
const base64이미지 = await Base64로_변환(imageInput);
if (!base64이미지) return { success: false, msg: 'Invalid input image' };
const 유효_탑재량 = {
image: base64이미지,
mimeType: "image/png",
prompt: prompt,
model: "auto",
isFirstAttempt: true
};
const 헤더 = { ...설정.헤더, "apikey": 설정.비밀키, "Authorization": `Bearer ${세션.액세스_토큰}` };
const 응답 = await axios.post(설정.베이스_엔드 + 설정.경로.편집, 유효_탑재량, { headers: 헤더 });
if (응답.data && 응답.data.image) {
const 결과_버퍼 = Buffer.from(응답.data.image, 'base64');
const 클라우드_URL = await 클라우드_업로드(결과_버퍼);
return {
success: true,
prompt: 응답.data.prompt,
model: 응답.data.model,
url: 클라우드_URL
};
}
return { success: false, msg: 'No image data returned' };
} catch (에러) {
return { success: false, msg: 에러.message };
}
},
generateImage: async (prompt, model = "fal-ai/flux-2") => {
try {
if (!세션.액세스_토큰) await fluxAi.signup();
if (!세션.액세스_토큰) return { success: false, msg: 'Auth failed' };
const 유효_탑재량 = { prompt: prompt, model: model };
const 헤더 = { ...설정.헤더, "apikey": 설정.비밀키, "Authorization": `Bearer ${세션.액세스_토큰}` };
const 응답 = await axios.post(설정.베이스_엔드 + 설정.경로.생성, 유효_탑재량, { headers: 헤더 });
if (응답.data && 응답.data.image) {
const 결과_버퍼 = Buffer.from(응답.data.image, 'base64');
const 클라우드_URL = await 클라우드_업로드(결과_버퍼);
return {
success: true,
prompt: 응답.data.prompt,
model: 응답.data.model,
url: 클라우드_URL
};
}
return { success: false, msg: 'No image data returned' };
} catch (에러) {
return { success: false, msg: 에러.message };
}
}
};