first
Deploy Iddaai Frontend / build-and-deploy (push) Successful in 4m0s

This commit is contained in:
2026-04-16 13:36:34 +03:00
parent de5e145c4e
commit fc7a1ba567
218 changed files with 32370 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
import { getPricing } from "@/lib/services/pricing-service";
import { GoogleGenAI, Modality } from "@google/genai";
/**
* Merkezi yapay zeka istemci örneği
* Tüm yapay zeka istekleri bu örneği kullanmalıdır
*/
export const ai = new GoogleGenAI({
vertexai: true,
apiKey: process.env.GOOGLE_API_KEY,
});
// Kalite artırıcı anahtar kelimeler
const QUALITY_BOOSTERS = [
"highly detailed",
"8k resolution",
"professional photography",
"studio lighting",
"sharp focus",
"cinematic composition",
"vibrant colors",
"masterpiece",
"masterpiece",
];
/**
* Yapay Zeka Model yapılandırmaları
*/
export const AI_MODELS = {
FLASH_LITE: "gemini-2.5-flash-lite",
FLASH: "gemini-2.5-flash",
FLASH_IMAGE: "gemini-2.5-flash-image",
} as const;
// ——————————————————————————————————————
// Type definitions for Gemini API responses
// ——————————————————————————————————————
/** Token usage metadata from Gemini API */
interface UsageMetadata {
promptTokenCount?: number;
candidatesTokenCount?: number;
totalTokenCount?: number;
}
/** Gemini content part (text or inline data) */
interface ContentPart {
text?: string;
inlineData?: { mimeType: string; data: string };
}
/** Generation config passed to Gemini */
interface GenerationConfig {
responseModalities?: Modality[];
temperature?: number;
maxOutputTokens?: number;
[key: string]: unknown;
}
/** Prompt content — can be a string, structured content array, or object */
type PromptContent =
| string
| Array<{ role: string; parts: ContentPart[] }>
| Record<string, unknown>;
/**
* Yapay zeka ile içerik oluştur
* Tüm yapay zeka içerik oluşturma işlemleri için merkezi fonksiyon
*
* @param model - Kullanılacak yapay zeka modeli
* @param prompt - Gönderilecek istem veya içerikler
* @param config - İsteğe bağlı yapılandırma
* @returns Yapay zeka yanıtı
*/
export async function generateAIContent(
model: string,
prompt: PromptContent,
config?: GenerationConfig
) {
try {
const response = await ai.models.generateContent({
model,
contents: prompt,
...(config && { config }),
});
return response;
} catch (error) {
console.error("AI generation error:", error);
throw error;
}
}
/**
* Yapay zeka ile metin içeriği oluştur
* @param model - Kullanılacak yapay zeka modeli
* @param prompt - Metin istemi
* @returns Oluşturulan metin
*/
export async function generateText(
model: string,
prompt: string
): Promise<{ text: string; usage?: UsageMetadata }> {
const response = await generateAIContent(model, prompt);
return {
text: (response.text || "").trim(),
usage: response.usageMetadata as UsageMetadata | undefined,
};
}
/**
* Görüntü girdisi ile içerik oluştur
* @param model - Kullanılacak yapay zeka modeli
* @param imageBase64 - Base64 kodlanmış görüntü
* @param textPrompt - Metin istemi
* @returns Yapay zeka yanıtı
*/
export async function generateWithImage(
model: string,
imageBase64: string,
textPrompt: string
) {
const response = await generateAIContent(model, [
{
role: "user",
parts: [
{ inlineData: { mimeType: "image/jpeg", data: imageBase64 } },
{ text: textPrompt },
],
},
]);
return {
text: (response.text || "").trim(),
usage: response.usageMetadata as UsageMetadata | undefined,
};
}
/**
* İstemden görüntü oluştur
* @param prompt - Görüntü oluşturma için metin istemi
* @param imageBase64 - Düzenleme için isteğe bağlı base64 görüntü
* @param suggestions - Görsel iyileştirme önerileri (Nano Banana için)
* @param model - Kullanılacak model (varsayılan: FLASH_IMAGE)
* @param aspectRatio - Hedef en boy oranı (örn: "16:9", "1:1")
* @returns Oluşturulan görüntü URL'si (base64)
*/
export async function generateImage(
prompt: string,
imageBase64?: string,
suggestions?: string[],
model: string = AI_MODELS.FLASH_IMAGE,
aspectRatio?: string
): Promise<{ imageUrl: string | null; usage?: UsageMetadata }> {
let parts: Array<
{ text: string } | { inlineData: { mimeType: string; data: string } }
> = [];
// En boy oranı talimatı oluştur
const ratioInstruction = aspectRatio
? `\n\nTarget Aspect Ratio: ${aspectRatio}\nEnsure the image strictly follows the ${aspectRatio} aspect ratio format.`
: "";
if (imageBase64) {
// Görüntü düzenleme modu
const cleanBase64 = imageBase64.replace(
/^data:image\/(png|jpeg|webp|jpg);base64,/,
""
);
// Eğer Nano Banana modeli ve öneriler varsa, prompt'u zenginleştir
let finalPrompt = prompt;
if (model === "nano-banana") {
let improvementInstructions = "";
if (suggestions && suggestions.length > 0) {
improvementInstructions = `\n\nApply these specific improvements based on platform analysis:\n${suggestions.map((s) => `- ${s}`).join("\n")}`;
}
finalPrompt = `${prompt}${improvementInstructions}\n\nStyle & Quality Instructions:\nRender in ${QUALITY_BOOSTERS.join(", ")}.\n\nCRITICAL OBJECTIVE: The result MUST achieve a perfect 10/10 score.\n- Clarity: 10/10 (Ultra-sharp, no blur)\n- Professionalism: 10/10 (High-end commercial look)\n- Engagement: 10/10 (Eye-catching contrast and lighting)\n- Platform Fit: 10/10 (Perfect aspect ratio and framing)\nEnsure the image is visually stunning and flawless.`;
}
parts.push({ inlineData: { mimeType: "image/png", data: cleanBase64 } });
parts.push({ text: finalPrompt + ratioInstruction });
} else {
parts.push({ text: prompt + ratioInstruction });
}
console.log("[AI-Helper] generateImage calling Gemini model", {
model: AI_MODELS.FLASH_IMAGE,
});
try {
const response = await ai.models.generateContent({
model,
contents: [{ role: "user", parts }],
config: {
responseModalities: [Modality.IMAGE],
},
});
const candidate = response.candidates?.[0];
const imagePart = candidate?.content?.parts?.find(
(p) => p.inlineData?.mimeType?.startsWith("image/")
);
if (imagePart?.inlineData?.data) {
return {
imageUrl: `data:${imagePart.inlineData.mimeType};base64,${imagePart.inlineData.data}`,
usage: response.usageMetadata as UsageMetadata | undefined,
};
}
console.warn("No image part found in response");
return { imageUrl: null, usage: response.usageMetadata as UsageMetadata | undefined };
} catch (error) {
console.error("generateImage error:", error);
return { imageUrl: null };
}
}
/**
* Token kullanımına dayalı Yapay Zeka Maliyetini hesapla
* Giriş Maliyeti = (Giriş Tokenları / 1.000.000) * Giriş Fiyatı
* Çıkış Maliyeti = (Çıkış Tokenları / 1.000.000) * Çıkış Fiyatı
* @param usage - Yapay zeka yanıtından kullanım meta verileri
* @returns Para birimi cinsinden toplam maliyet
*/
export async function calculateAICost(usage: UsageMetadata | null | undefined): Promise<number> {
if (!usage) return 0;
const pricing = await getPricing();
const inputTokens = usage.promptTokenCount || 0;
const outputTokens = usage.candidatesTokenCount || 0;
const inputCost = (inputTokens / 1_000_000) * pricing.inputCost;
const outputCost = (outputTokens / 1_000_000) * pricing.outputCost;
return inputCost + outputCost;
}
+52
View File
@@ -0,0 +1,52 @@
/**
* Language mapping utility for AI prompts
* Maps locale codes to full language names for AI instructions
*/
export const SUPPORTED_LOCALES = {
tr: 'Turkish',
en: 'English',
de: 'German',
ar: 'Arabic',
zh: 'Chinese',
es: 'Spanish',
fr: 'French',
it: 'Italian',
ja: 'Japanese',
ko: 'Korean',
pt: 'Portuguese',
ru: 'Russian',
} as const;
export type SupportedLocale = keyof typeof SUPPORTED_LOCALES;
/**
* Get the full language name for AI prompts
* @param locale - Locale code (e.g., 'tr', 'en')
* @returns Full language name (e.g., 'Turkish', 'English')
*/
export function getLanguageName(locale?: string): string {
if (!locale) return SUPPORTED_LOCALES.tr; // Default to Turkish
const normalizedLocale = locale.toLowerCase() as SupportedLocale;
return SUPPORTED_LOCALES[normalizedLocale] || SUPPORTED_LOCALES.en; // Fallback to English
}
/**
* Get language instruction for AI prompts
* @param locale - Locale code
* @returns Formatted instruction for AI (e.g., "Write in Turkish")
*/
export function getLanguageInstruction(locale?: string): string {
const language = getLanguageName(locale);
return `Write in ${language}.`;
}
/**
* Check if a locale is supported
* @param locale - Locale code to check
* @returns True if supported, false otherwise
*/
export function isSupportedLocale(locale: string): locale is SupportedLocale {
return locale.toLowerCase() in SUPPORTED_LOCALES;
}
+35
View File
@@ -0,0 +1,35 @@
/**
* Gemini için Fotoğrafçılık Taslağı (JSON Blueprint)
* Bu yapı modeli profesyonel bir fotoğrafçı gibi düşünmeye zorlar.
* Client-side güvenlidir.
*/
export const buildPhotorealisticPrompt = (corePrompt: string): string => {
const blueprint = {
subject_context: corePrompt,
style: {
direction: 'Professional Lifestyle Photography / Authentic Brand Content',
aesthetic: 'Modern, bright, engaging, premium but approachable',
lighting: 'Natural ambient daylight mixed with soft studio fill, warm tones',
},
camera_settings: {
sensor: 'Full-frame Digital Sensor (Sony Alpha / Canon R5)',
lens: '35mm or 50mm Prime (Standard Social Media View)',
depth_of_field: 'Moderate depth of field (sharp subject, slightly softened background)',
shutter: '1/125s natural motion freeze',
},
composition_rules: {
framing: 'Rule of thirds, center-weighted for social media engagement',
angle: 'Eye-level or 45-degree isometric (depending on subject)',
aspect_ratio_fit: 'Optimized for Instagram/LinkedIn',
},
quality_assurance: {
clarity: 'Perfect Focus',
noise_level: 'Minimal natural grain allowed for authenticity',
texture_detail: 'High fidelity materials',
render_engine: 'Photorealistic Photography Style (Not CGI looking)',
},
prohibited_elements: ['text watermarks', 'blurry', 'distorted', 'ugly', 'low resolution'],
};
return JSON.stringify(blueprint, null, 2);
};