generated from fahricansecer/boilerplate-be
@@ -36,3 +36,4 @@ junit.xml
|
|||||||
dist
|
dist
|
||||||
|
|
||||||
cli-tool
|
cli-tool
|
||||||
|
.pnpm-store
|
||||||
@@ -13,8 +13,10 @@ RUN dotnet publish -c Release -o /app/publish --no-restore
|
|||||||
FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS runtime
|
FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine AS runtime
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# FFmpeg kurulumu (ARM64 native Alpine paketi)
|
# FFmpeg ve Globalization kurulumu (ARM64 native Alpine paketi)
|
||||||
RUN apk add --no-cache ffmpeg font-dejavu
|
RUN apk add --no-cache ffmpeg font-dejavu icu-libs
|
||||||
|
|
||||||
|
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
|
||||||
|
|
||||||
# Temp dizin oluştur
|
# Temp dizin oluştur
|
||||||
RUN mkdir -p /tmp/contgen-render
|
RUN mkdir -p /tmp/contgen-render
|
||||||
|
|||||||
@@ -33,9 +33,7 @@ public class S3StorageService
|
|||||||
var config = new AmazonS3Config
|
var config = new AmazonS3Config
|
||||||
{
|
{
|
||||||
ServiceURL = _settings.Endpoint,
|
ServiceURL = _settings.Endpoint,
|
||||||
ForcePathStyle = true,
|
ForcePathStyle = true
|
||||||
RequestChecksumCalculation = RequestChecksumCalculation.WHEN_REQUIRED,
|
|
||||||
ResponseChecksumValidation = ResponseChecksumValidation.WHEN_REQUIRED,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_s3Client = new AmazonS3Client(
|
_s3Client = new AmazonS3Client(
|
||||||
|
|||||||
@@ -39,12 +39,15 @@
|
|||||||
"@nestjs/websockets": "^11.1.17",
|
"@nestjs/websockets": "^11.1.17",
|
||||||
"@prisma/client": "^5.22.0",
|
"@prisma/client": "^5.22.0",
|
||||||
"@types/sharp": "^0.32.0",
|
"@types/sharp": "^0.32.0",
|
||||||
|
"axios": "^1.15.0",
|
||||||
"bcrypt": "^6.0.0",
|
"bcrypt": "^6.0.0",
|
||||||
"bullmq": "^5.66.4",
|
"bullmq": "^5.66.4",
|
||||||
"cache-manager": "^7.2.7",
|
"cache-manager": "^7.2.7",
|
||||||
"cache-manager-redis-yet": "^5.1.5",
|
"cache-manager-redis-yet": "^5.1.5",
|
||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.3",
|
"class-validator": "^0.14.3",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"form-data": "^4.0.5",
|
||||||
"helmet": "^8.1.0",
|
"helmet": "^8.1.0",
|
||||||
"ioredis": "^5.9.0",
|
"ioredis": "^5.9.0",
|
||||||
"nestjs-i18n": "^10.6.0",
|
"nestjs-i18n": "^10.6.0",
|
||||||
@@ -70,7 +73,9 @@
|
|||||||
"@nestjs/testing": "^11.0.1",
|
"@nestjs/testing": "^11.0.1",
|
||||||
"@types/bcrypt": "^6.0.0",
|
"@types/bcrypt": "^6.0.0",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
|
"@types/form-data": "^2.5.2",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/multer": "^2.1.0",
|
||||||
"@types/node": "^22.10.7",
|
"@types/node": "^22.10.7",
|
||||||
"@types/nodemailer": "^7.0.4",
|
"@types/nodemailer": "^7.0.4",
|
||||||
"@types/passport-jwt": "^4.0.1",
|
"@types/passport-jwt": "^4.0.1",
|
||||||
|
|||||||
Generated
+58
@@ -59,6 +59,9 @@ importers:
|
|||||||
'@types/sharp':
|
'@types/sharp':
|
||||||
specifier: ^0.32.0
|
specifier: ^0.32.0
|
||||||
version: 0.32.0
|
version: 0.32.0
|
||||||
|
axios:
|
||||||
|
specifier: ^1.15.0
|
||||||
|
version: 1.15.0
|
||||||
bcrypt:
|
bcrypt:
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
@@ -77,6 +80,12 @@ importers:
|
|||||||
class-validator:
|
class-validator:
|
||||||
specifier: ^0.14.3
|
specifier: ^0.14.3
|
||||||
version: 0.14.4
|
version: 0.14.4
|
||||||
|
express:
|
||||||
|
specifier: ^5.2.1
|
||||||
|
version: 5.2.1
|
||||||
|
form-data:
|
||||||
|
specifier: ^4.0.5
|
||||||
|
version: 4.0.5
|
||||||
helmet:
|
helmet:
|
||||||
specifier: ^8.1.0
|
specifier: ^8.1.0
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
@@ -147,9 +156,15 @@ importers:
|
|||||||
'@types/express':
|
'@types/express':
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.6
|
version: 5.0.6
|
||||||
|
'@types/form-data':
|
||||||
|
specifier: ^2.5.2
|
||||||
|
version: 2.5.2
|
||||||
'@types/jest':
|
'@types/jest':
|
||||||
specifier: ^30.0.0
|
specifier: ^30.0.0
|
||||||
version: 30.0.0
|
version: 30.0.0
|
||||||
|
'@types/multer':
|
||||||
|
specifier: ^2.1.0
|
||||||
|
version: 2.1.0
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.10.7
|
specifier: ^22.10.7
|
||||||
version: 22.19.15
|
version: 22.19.15
|
||||||
@@ -1721,6 +1736,10 @@ packages:
|
|||||||
'@types/express@5.0.6':
|
'@types/express@5.0.6':
|
||||||
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
||||||
|
|
||||||
|
'@types/form-data@2.5.2':
|
||||||
|
resolution: {integrity: sha512-tfmcyHn1Pp9YHAO5r40+UuZUPAZbUEgqTel3EuEKpmF9hPkXgR4l41853raliXnb4gwyPNoQOfvgGGlHN5WSog==}
|
||||||
|
deprecated: This is a stub types definition. form-data provides its own type definitions, so you do not need this installed.
|
||||||
|
|
||||||
'@types/http-errors@2.0.5':
|
'@types/http-errors@2.0.5':
|
||||||
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
|
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
|
||||||
|
|
||||||
@@ -1748,6 +1767,9 @@ packages:
|
|||||||
'@types/ms@2.1.0':
|
'@types/ms@2.1.0':
|
||||||
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
|
||||||
|
|
||||||
|
'@types/multer@2.1.0':
|
||||||
|
resolution: {integrity: sha512-zYZb0+nJhOHtPpGDb3vqPjwpdeGlGC157VpkqNQL+UU2qwoacoQ7MpsAmUptI/0Oa127X32JzWDqQVEXp2RcIA==}
|
||||||
|
|
||||||
'@types/node@22.19.15':
|
'@types/node@22.19.15':
|
||||||
resolution: {integrity: sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==}
|
resolution: {integrity: sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==}
|
||||||
|
|
||||||
@@ -2153,6 +2175,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
|
resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
|
axios@1.15.0:
|
||||||
|
resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==}
|
||||||
|
|
||||||
babel-jest@30.3.0:
|
babel-jest@30.3.0:
|
||||||
resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==}
|
resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==}
|
||||||
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
|
engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
|
||||||
@@ -2809,6 +2834,15 @@ packages:
|
|||||||
flatted@3.4.2:
|
flatted@3.4.2:
|
||||||
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
|
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
|
||||||
|
|
||||||
|
follow-redirects@1.15.11:
|
||||||
|
resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -3780,6 +3814,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
proxy-from-env@2.1.0:
|
||||||
|
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
pump@3.0.4:
|
pump@3.0.4:
|
||||||
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
|
resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==}
|
||||||
|
|
||||||
@@ -6449,6 +6487,10 @@ snapshots:
|
|||||||
'@types/express-serve-static-core': 5.1.1
|
'@types/express-serve-static-core': 5.1.1
|
||||||
'@types/serve-static': 2.2.0
|
'@types/serve-static': 2.2.0
|
||||||
|
|
||||||
|
'@types/form-data@2.5.2':
|
||||||
|
dependencies:
|
||||||
|
form-data: 4.0.5
|
||||||
|
|
||||||
'@types/http-errors@2.0.5': {}
|
'@types/http-errors@2.0.5': {}
|
||||||
|
|
||||||
'@types/istanbul-lib-coverage@2.0.6': {}
|
'@types/istanbul-lib-coverage@2.0.6': {}
|
||||||
@@ -6477,6 +6519,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/ms@2.1.0': {}
|
'@types/ms@2.1.0': {}
|
||||||
|
|
||||||
|
'@types/multer@2.1.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/express': 5.0.6
|
||||||
|
|
||||||
'@types/node@22.19.15':
|
'@types/node@22.19.15':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
@@ -6889,6 +6935,14 @@ snapshots:
|
|||||||
|
|
||||||
atomic-sleep@1.0.0: {}
|
atomic-sleep@1.0.0: {}
|
||||||
|
|
||||||
|
axios@1.15.0:
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.15.11
|
||||||
|
form-data: 4.0.5
|
||||||
|
proxy-from-env: 2.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
|
||||||
babel-jest@30.3.0(@babel/core@7.29.0):
|
babel-jest@30.3.0(@babel/core@7.29.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.29.0
|
'@babel/core': 7.29.0
|
||||||
@@ -7601,6 +7655,8 @@ snapshots:
|
|||||||
|
|
||||||
flatted@3.4.2: {}
|
flatted@3.4.2: {}
|
||||||
|
|
||||||
|
follow-redirects@1.15.11: {}
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@@ -8753,6 +8809,8 @@ snapshots:
|
|||||||
forwarded: 0.2.0
|
forwarded: 0.2.0
|
||||||
ipaddr.js: 1.9.1
|
ipaddr.js: 1.9.1
|
||||||
|
|
||||||
|
proxy-from-env@2.1.0: {}
|
||||||
|
|
||||||
pump@3.0.4:
|
pump@3.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
end-of-stream: 1.4.5
|
end-of-stream: 1.4.5
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ enum SourceType {
|
|||||||
MANUAL
|
MANUAL
|
||||||
X_TWEET
|
X_TWEET
|
||||||
YOUTUBE
|
YOUTUBE
|
||||||
|
DOCUMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
+1
-1
@@ -118,7 +118,7 @@ import {
|
|||||||
useFactory: (configService: ConfigService) => ({
|
useFactory: (configService: ConfigService) => ({
|
||||||
fallbackLanguage: configService.get('i18n.fallbackLanguage', 'en'),
|
fallbackLanguage: configService.get('i18n.fallbackLanguage', 'en'),
|
||||||
loaderOptions: {
|
loaderOptions: {
|
||||||
path: path.join(__dirname, '..', 'i18n'),
|
path: path.join(__dirname, 'i18n'),
|
||||||
watch: configService.get('app.isDevelopment', true),
|
watch: configService.get('app.isDevelopment', true),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -242,6 +242,11 @@ IMPORTANT: Only output valid JSON, no markdown code blocks or other text.`;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gemini Image Generation API ile görsel üret.
|
* Gemini Image Generation API ile görsel üret.
|
||||||
|
* 3 katmanlı fallback mimarisi:
|
||||||
|
* 1) gemini-2.5-flash-image (Nano Banana — hızlı, stabil)
|
||||||
|
* 2) gemini-3.1-flash-image-preview (Nano Banana 2 — en yeni)
|
||||||
|
* 3) Imagen 4 Fast (generateImages API)
|
||||||
|
*
|
||||||
* Raspberry Pi 5 bellek koruması için buffer olarak döner.
|
* Raspberry Pi 5 bellek koruması için buffer olarak döner.
|
||||||
*
|
*
|
||||||
* @param prompt - İngilizce görsel açıklaması
|
* @param prompt - İngilizce görsel açıklaması
|
||||||
@@ -256,18 +261,44 @@ IMPORTANT: Only output valid JSON, no markdown code blocks or other text.`;
|
|||||||
throw new Error('Gemini AI is not available. Check your configuration.');
|
throw new Error('Gemini AI is not available. Check your configuration.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageModel = this.configService.get<string>(
|
// Güncel model sıralaması (Nisan 2026):
|
||||||
'gemini.imageModel',
|
// - gemini-2.5-flash-image: Nano Banana — stabil, hızlı
|
||||||
'gemini-2.0-flash-preview-image-generation',
|
// - gemini-3.1-flash-image-preview: Nano Banana 2 — en yeni, yüksek kalite
|
||||||
);
|
const primaryModel = 'gemini-2.5-flash-image';
|
||||||
|
const fallbackModel = 'gemini-3.1-flash-image-preview';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.logger.debug(`🎨 Görsel üretiliyor: "${prompt.substring(0, 80)}..." [${aspectRatio}]`);
|
this.logger.debug(`🎨 Görsel üretiliyor: "${prompt.substring(0, 80)}..." [${aspectRatio}]`);
|
||||||
|
|
||||||
const enhancedPrompt = `Generate a high-quality image for this description: ${prompt}. Style: photorealistic, cinematic lighting, detailed. Aspect ratio: ${aspectRatio}.`;
|
const enhancedPrompt = `Generate a high-quality image for this description: ${prompt}. Style: photorealistic, cinematic lighting, detailed. Aspect ratio: ${aspectRatio}. IMPORTANT: Generate only the image, no text response needed.`;
|
||||||
|
|
||||||
// 1) First try the stable Imagen-4 Fast API
|
// ── Katman 1: gemini-2.5-flash-image (Nano Banana) ──
|
||||||
try {
|
try {
|
||||||
|
this.logger.debug(`🔄 Katman 1: ${primaryModel} deneniyor...`);
|
||||||
|
const result = await this.tryGenerateContentImage(primaryModel, enhancedPrompt);
|
||||||
|
if (result) {
|
||||||
|
this.logger.log(`✅ Görsel üretildi (${primaryModel}): ${(result.buffer.length / 1024).toFixed(1)} KB`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} catch (err1: any) {
|
||||||
|
this.logger.warn(`⚠️ ${primaryModel} başarısız: ${err1.message?.substring(0, 120)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Katman 2: gemini-3.1-flash-image-preview (Nano Banana 2) ──
|
||||||
|
try {
|
||||||
|
this.logger.debug(`🔄 Katman 2: ${fallbackModel} deneniyor...`);
|
||||||
|
const result = await this.tryGenerateContentImage(fallbackModel, enhancedPrompt);
|
||||||
|
if (result) {
|
||||||
|
this.logger.log(`✅ Görsel üretildi (${fallbackModel}): ${(result.buffer.length / 1024).toFixed(1)} KB`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} catch (err2: any) {
|
||||||
|
this.logger.warn(`⚠️ ${fallbackModel} başarısız: ${err2.message?.substring(0, 120)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Katman 3: Imagen 4 Fast (generateImages API) ──
|
||||||
|
try {
|
||||||
|
this.logger.debug(`🔄 Katman 3: Imagen 4 Fast deneniyor...`);
|
||||||
const response = await this.client!.models.generateImages({
|
const response = await this.client!.models.generateImages({
|
||||||
model: 'imagen-4.0-fast-generate-001',
|
model: 'imagen-4.0-fast-generate-001',
|
||||||
prompt: enhancedPrompt,
|
prompt: enhancedPrompt,
|
||||||
@@ -275,30 +306,44 @@ IMPORTANT: Only output valid JSON, no markdown code blocks or other text.`;
|
|||||||
numberOfImages: 1,
|
numberOfImages: 1,
|
||||||
aspectRatio: aspectRatio,
|
aspectRatio: aspectRatio,
|
||||||
outputMimeType: 'image/jpeg',
|
outputMimeType: 'image/jpeg',
|
||||||
personGeneration: 'ALLOW_ALL' as any
|
personGeneration: 'ALLOW_ALL' as any,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.generatedImages?.[0]?.image?.imageBytes) {
|
if (response.generatedImages?.[0]?.image?.imageBytes) {
|
||||||
const buffer = Buffer.from(response.generatedImages[0].image.imageBytes, 'base64');
|
const buffer = Buffer.from(response.generatedImages[0].image.imageBytes, 'base64');
|
||||||
const mimeType = 'image/jpeg';
|
const mimeType = 'image/jpeg';
|
||||||
this.logger.log(`✅ Görsel üretildi (Imagen): ${(buffer.length / 1024).toFixed(1)} KB [${mimeType}]`);
|
this.logger.log(`✅ Görsel üretildi (Imagen 4): ${(buffer.length / 1024).toFixed(1)} KB`);
|
||||||
return { buffer, mimeType };
|
return { buffer, mimeType };
|
||||||
}
|
}
|
||||||
} catch (imagenError: any) {
|
} catch (err3: any) {
|
||||||
this.logger.warn(`Imagen API error, falling back to generateContent... ${imagenError.message}`);
|
this.logger.warn(`⚠️ Imagen 4 başarısız: ${err3.message?.substring(0, 120)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Fallback to Gemini Flash image modalities (experimental feature)
|
this.logger.error('❌ Tüm görsel üretim katmanları başarısız oldu');
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`Gemini görsel üretim hatası: ${error instanceof Error ? error.message : error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generateContent API ile görsel üretim denemesi.
|
||||||
|
* responseModalities: ['IMAGE', 'TEXT'] kullanarak inlineData içinden resim çıkarır.
|
||||||
|
*/
|
||||||
|
private async tryGenerateContentImage(
|
||||||
|
model: string,
|
||||||
|
prompt: string,
|
||||||
|
): Promise<{ buffer: Buffer; mimeType: string } | null> {
|
||||||
const response = await this.client!.models.generateContent({
|
const response = await this.client!.models.generateContent({
|
||||||
model: imageModel,
|
model,
|
||||||
contents: enhancedPrompt,
|
contents: prompt,
|
||||||
config: {
|
config: {
|
||||||
responseModalities: ['IMAGE', 'TEXT'],
|
responseModalities: ['IMAGE', 'TEXT'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Gemini image generation modeli, inlineData olarak görsel döner
|
|
||||||
const candidate = response.candidates?.[0];
|
const candidate = response.candidates?.[0];
|
||||||
const imagePart = candidate?.content?.parts?.find(
|
const imagePart = candidate?.content?.parts?.find(
|
||||||
(p: any) => p.inlineData?.mimeType?.startsWith('image/'),
|
(p: any) => p.inlineData?.mimeType?.startsWith('image/'),
|
||||||
@@ -307,17 +352,10 @@ IMPORTANT: Only output valid JSON, no markdown code blocks or other text.`;
|
|||||||
if (imagePart?.inlineData?.data) {
|
if (imagePart?.inlineData?.data) {
|
||||||
const buffer = Buffer.from(imagePart.inlineData.data, 'base64');
|
const buffer = Buffer.from(imagePart.inlineData.data, 'base64');
|
||||||
const mimeType = imagePart.inlineData.mimeType || 'image/png';
|
const mimeType = imagePart.inlineData.mimeType || 'image/png';
|
||||||
|
|
||||||
this.logger.log(`✅ Görsel üretildi (Flash): ${(buffer.length / 1024).toFixed(1)} KB [${mimeType}]`);
|
|
||||||
return { buffer, mimeType };
|
return { buffer, mimeType };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warn('Gemini görsel üretemedi — response içinde image part bulunamadı');
|
|
||||||
return null;
|
return null;
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(`Gemini görsel üretim hatası: ${error instanceof Error ? error.message : error}`);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ApiResponse,
|
ApiResponse,
|
||||||
createSuccessResponse,
|
createSuccessResponse,
|
||||||
} from '../../common/types/api-response.type';
|
} from '../../common/types/api-response.type';
|
||||||
import { User } from '@prisma/client/wasm';
|
import { User } from '@prisma/client';
|
||||||
|
|
||||||
import { plainToInstance } from 'class-transformer';
|
import { plainToInstance } from 'class-transformer';
|
||||||
import { UserResponseDto } from './dto/user.dto';
|
import { UserResponseDto } from './dto/user.dto';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as bcrypt from 'bcrypt';
|
|||||||
import { PrismaService } from '../../database/prisma.service';
|
import { PrismaService } from '../../database/prisma.service';
|
||||||
import { BaseService } from '../../common/base';
|
import { BaseService } from '../../common/base';
|
||||||
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
|
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
|
||||||
import { User } from '@prisma/client/wasm';
|
import { User } from '@prisma/client';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersService extends BaseService<
|
export class UsersService extends BaseService<
|
||||||
|
|||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
const db = new PrismaClient();
|
|
||||||
async function run() {
|
|
||||||
const adminUser = await db.user.findUnique({ where: { email: 'admin@contentgen.ai' } });
|
|
||||||
console.log("Admin ID:", adminUser?.id);
|
|
||||||
|
|
||||||
const projects = await db.project.findMany({
|
|
||||||
orderBy: { createdAt: 'desc' },
|
|
||||||
take: 5,
|
|
||||||
select: { id: true, title: true, createdAt: true, userId: true }
|
|
||||||
});
|
|
||||||
console.log("Last 5 projects:", projects);
|
|
||||||
await db.$disconnect();
|
|
||||||
}
|
|
||||||
run();
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "prisma"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user