diff --git a/apps/picture/apps/backend/src/db/schema/models.schema.ts b/apps/picture/apps/backend/src/db/schema/models.schema.ts index 7b7ad27e5..8aee0ec73 100644 --- a/apps/picture/apps/backend/src/db/schema/models.schema.ts +++ b/apps/picture/apps/backend/src/db/schema/models.schema.ts @@ -2,7 +2,7 @@ import { pgTable, uuid, text, timestamp, boolean, integer, real } from 'drizzle- export const models = pgTable('models', { id: uuid('id').primaryKey().defaultRandom(), - name: text('name').notNull(), + name: text('name').notNull().unique(), displayName: text('display_name').notNull(), description: text('description'), replicateId: text('replicate_id').notNull(), diff --git a/apps/picture/apps/backend/src/db/seed.ts b/apps/picture/apps/backend/src/db/seed.ts index ba3c79631..0514a4fc5 100644 --- a/apps/picture/apps/backend/src/db/seed.ts +++ b/apps/picture/apps/backend/src/db/seed.ts @@ -1,63 +1,85 @@ import * as dotenv from 'dotenv'; +import { eq } from 'drizzle-orm'; import { getDb, closeConnection } from './connection'; import { models } from './schema'; dotenv.config(); const defaultModels = [ - { - name: 'sdxl', - displayName: 'Stable Diffusion XL', - description: 'High-quality image generation with excellent prompt adherence', - replicateId: 'stability-ai/sdxl', - version: '39ed52f2a78e934b3ba6e2a89f5b1c712de7dfea535525255b1aa35c5565e08b', - defaultWidth: 1024, - defaultHeight: 1024, - defaultSteps: 25, - defaultGuidanceScale: 7.5, - supportsNegativePrompt: true, - supportsImg2Img: true, - supportsSeed: true, - isActive: true, - isDefault: true, - sortOrder: 0, - estimatedTimeSeconds: 15, - }, { name: 'flux-schnell', displayName: 'FLUX Schnell', - description: 'Fast image generation with good quality', + description: + 'Schnellstes Modell von Black Forest Labs - generiert hochwertige Bilder in nur 1-4 Schritten. Ideal für schnelle Iterationen.', replicateId: 'black-forest-labs/flux-schnell', - version: 'f2ab8a5bfe79f02f0789a146cf5e73d2a4ff2684a98c2b303d1e1ff3814271db', + version: 'c846a69991daf4c0e5d016514849d14ee5b2e6846ce6b9d6f21369e564cfe51e', defaultWidth: 1024, defaultHeight: 1024, defaultSteps: 4, defaultGuidanceScale: 0, + minWidth: 256, + minHeight: 256, + maxWidth: 1440, + maxHeight: 1440, + maxSteps: 4, + supportsNegativePrompt: false, + supportsImg2Img: false, + supportsSeed: true, + isActive: true, + isDefault: true, + sortOrder: 0, + costPerGeneration: 0.003, + estimatedTimeSeconds: 3, + }, + { + name: 'seedream-3', + displayName: 'Seedream 3', + description: + 'ByteDances hochauflösendes Modell mit nativer 2K-Ausgabe. Exzellente Text-Darstellung und fotorealistische Portraits.', + replicateId: 'bytedance/seedream-3', + version: 'ed344813bc9f4996be6de4febd8b9c14c7849ad7b21ab047572e3620ee374ee7', + defaultWidth: 2048, + defaultHeight: 2048, + defaultSteps: 1, // Model handles steps internally + defaultGuidanceScale: 2.5, + minWidth: 512, + minHeight: 512, + maxWidth: 2048, + maxHeight: 2048, + maxSteps: 1, supportsNegativePrompt: false, supportsImg2Img: false, supportsSeed: true, isActive: true, isDefault: false, sortOrder: 1, + costPerGeneration: 0.03, estimatedTimeSeconds: 5, }, { - name: 'flux-pro', - displayName: 'FLUX Pro', - description: 'Professional quality image generation', - replicateId: 'black-forest-labs/flux-pro', - version: '7d6fbcd3da3f4e1c1c08d8ab0e7a4c2e0e5e3c9e8f8e8e8e8e8e8e8e8e8e8e8e', + name: 'nano-banana', + displayName: 'Nano Banana', + description: + 'Googles multimodales Gemini-Modell für Bildgenerierung und -bearbeitung. Beste Textdarstellung in Bildern und Charakter-Konsistenz.', + replicateId: 'google/nano-banana', + version: 'd05a591283da31be3eea28d5634ef9e26989b351718b6489bd308426ebd0a3e8', defaultWidth: 1024, defaultHeight: 1024, - defaultSteps: 25, - defaultGuidanceScale: 3.5, + defaultSteps: 1, // Model handles steps internally + defaultGuidanceScale: 0, + minWidth: 512, + minHeight: 512, + maxWidth: 2048, + maxHeight: 2048, + maxSteps: 1, supportsNegativePrompt: false, - supportsImg2Img: false, - supportsSeed: true, + supportsImg2Img: true, // Supports image editing + supportsSeed: false, // No seed parameter exposed isActive: true, isDefault: false, sortOrder: 2, - estimatedTimeSeconds: 20, + costPerGeneration: 0.039, + estimatedTimeSeconds: 3, }, ]; @@ -69,12 +91,58 @@ async function seed() { const db = getDb(databaseUrl); + console.log('Clearing old models...'); + // Remove old models that are not in the new list + const oldModelNames = ['sdxl', 'flux-pro']; + for (const name of oldModelNames) { + try { + await db.delete(models).where(eq(models.name, name)); + console.log(` - Removed: ${name}`); + } catch (error) { + console.error(` - Error removing ${name}:`, error); + } + } + console.log('Seeding models...'); for (const model of defaultModels) { try { - await db.insert(models).values(model).onConflictDoNothing(); - console.log(` - ${model.displayName}`); + // Check if model exists + const existing = await db.select().from(models).where(eq(models.name, model.name)); + if (existing.length > 0) { + // Update existing + await db + .update(models) + .set({ + displayName: model.displayName, + description: model.description, + replicateId: model.replicateId, + version: model.version, + defaultWidth: model.defaultWidth, + defaultHeight: model.defaultHeight, + defaultSteps: model.defaultSteps, + defaultGuidanceScale: model.defaultGuidanceScale, + minWidth: model.minWidth, + minHeight: model.minHeight, + maxWidth: model.maxWidth, + maxHeight: model.maxHeight, + maxSteps: model.maxSteps, + supportsNegativePrompt: model.supportsNegativePrompt, + supportsImg2Img: model.supportsImg2Img, + supportsSeed: model.supportsSeed, + isActive: model.isActive, + isDefault: model.isDefault, + sortOrder: model.sortOrder, + costPerGeneration: model.costPerGeneration, + estimatedTimeSeconds: model.estimatedTimeSeconds, + }) + .where(eq(models.name, model.name)); + console.log(` - Updated: ${model.displayName}`); + } else { + // Insert new + await db.insert(models).values(model); + console.log(` - Added: ${model.displayName}`); + } } catch (error) { console.error(` - Error seeding ${model.displayName}:`, error); } diff --git a/apps/picture/apps/backend/src/model/model.controller.ts b/apps/picture/apps/backend/src/model/model.controller.ts index 392f164b5..ebe73b6ea 100644 --- a/apps/picture/apps/backend/src/model/model.controller.ts +++ b/apps/picture/apps/backend/src/model/model.controller.ts @@ -1,12 +1,11 @@ -import { Controller, Get, Param, UseGuards } from '@nestjs/common'; +import { Controller, Get, Param } from '@nestjs/common'; import { ModelService } from './model.service'; -import { JwtAuthGuard } from '../common/guards/jwt-auth.guard'; @Controller('models') -@UseGuards(JwtAuthGuard) export class ModelController { constructor(private readonly modelService: ModelService) {} + // Models are public - no auth required @Get() async getActiveModels() { return this.modelService.getActiveModels(); diff --git a/apps/picture/apps/web/package.json b/apps/picture/apps/web/package.json index b7e1935f6..f4fc2eccd 100644 --- a/apps/picture/apps/web/package.json +++ b/apps/picture/apps/web/package.json @@ -16,6 +16,7 @@ "clean": "rm -rf .svelte-kit build node_modules" }, "dependencies": { + "@manacore/shared-auth": "workspace:*", "@manacore/shared-auth-ui": "workspace:*", "@manacore/shared-branding": "workspace:*", "@manacore/shared-i18n": "workspace:*", @@ -26,7 +27,6 @@ "@manacore/shared-ui": "workspace:*", "@picture/design-tokens": "workspace:*", "@picture/shared": "workspace:*", - "@supabase/supabase-js": "^2.38.4", "konva": "^10.0.2", "posthog-js": "^1.273.1", "svelte-i18n": "^4.0.1" diff --git a/apps/picture/apps/web/src/lib/components/auth/LoginForm.svelte b/apps/picture/apps/web/src/lib/components/auth/LoginForm.svelte deleted file mode 100644 index ca08074bd..000000000 --- a/apps/picture/apps/web/src/lib/components/auth/LoginForm.svelte +++ /dev/null @@ -1,140 +0,0 @@ - - - -
-

Welcome back

-

Sign in to your account

-
- - {#if error} -
-

{error}

-
- {/if} - -
{ - e.preventDefault(); - handleLogin(); - }} - class="space-y-4" - > -
- -
- -
- -
- - - - -
- -
-
-
-
-
- Or continue with -
-
- - - -

- Don't have an account? - Sign up -

-
diff --git a/apps/picture/apps/web/src/lib/components/auth/SignupForm.svelte b/apps/picture/apps/web/src/lib/components/auth/SignupForm.svelte deleted file mode 100644 index 1b2de8a13..000000000 --- a/apps/picture/apps/web/src/lib/components/auth/SignupForm.svelte +++ /dev/null @@ -1,126 +0,0 @@ - - - -
-

Create account

-

Start generating AI images today

-
- - {#if success} -
-

Check your email

-

- We've sent you a confirmation link. Please check your email to verify your account. -

-
- {:else} - {#if error} -
-

{error}

-
- {/if} - -
{ - e.preventDefault(); - handleSignup(); - }} - class="space-y-4" - > -
- -
- -
- -
- -
- -
- - -
- -

- Already have an account? - Sign in -

- {/if} -
diff --git a/apps/picture/apps/web/src/lib/components/board/ImagePickerModal.svelte b/apps/picture/apps/web/src/lib/components/board/ImagePickerModal.svelte index cda73e59d..8f66abfe2 100644 --- a/apps/picture/apps/web/src/lib/components/board/ImagePickerModal.svelte +++ b/apps/picture/apps/web/src/lib/components/board/ImagePickerModal.svelte @@ -1,7 +1,7 @@ diff --git a/apps/picture/apps/web/src/routes/app/archive/+page.svelte b/apps/picture/apps/web/src/routes/app/archive/+page.svelte index 32d6cc154..a63d383f5 100644 --- a/apps/picture/apps/web/src/routes/app/archive/+page.svelte +++ b/apps/picture/apps/web/src/routes/app/archive/+page.svelte @@ -1,5 +1,5 @@ diff --git a/apps/picture/apps/web/src/routes/auth/login/+page.svelte b/apps/picture/apps/web/src/routes/auth/login/+page.svelte index e17e19d81..88aeb68ba 100644 --- a/apps/picture/apps/web/src/routes/auth/login/+page.svelte +++ b/apps/picture/apps/web/src/routes/auth/login/+page.svelte @@ -6,7 +6,7 @@ import PictureLogo from '$lib/components/branding/PictureLogo.svelte'; import AppSlider from '$lib/components/AppSlider.svelte'; import LanguageSelector from '$lib/components/LanguageSelector.svelte'; - import { authService } from '$lib/services/authService'; + import { authStore } from '$lib/stores/auth.svelte'; import { onMount } from 'svelte'; import { PUBLIC_GOOGLE_CLIENT_ID, PUBLIC_APPLE_CLIENT_ID } from '$env/static/public'; @@ -20,15 +20,17 @@ }); async function handleSignIn(email: string, password: string) { - return authService.signIn(email, password); + return authStore.signIn(email, password); } async function handleSignInWithGoogle() { - return authService.signInWithGoogle(); + // TODO: Implement OAuth with Mana Core Auth when ready + return { success: false, error: 'Google Sign-In not yet implemented' }; } async function handleSignInWithApple() { - return authService.signInWithApple(); + // TODO: Implement OAuth with Mana Core Auth when ready + return { success: false, error: 'Apple Sign-In not yet implemented' }; } diff --git a/apps/picture/apps/web/src/routes/auth/signup/+page.svelte b/apps/picture/apps/web/src/routes/auth/signup/+page.svelte index 012b0fa9c..257507c7b 100644 --- a/apps/picture/apps/web/src/routes/auth/signup/+page.svelte +++ b/apps/picture/apps/web/src/routes/auth/signup/+page.svelte @@ -3,7 +3,7 @@ import { RegisterPage, setGoogleClientId } from '@manacore/shared-auth-ui'; import { getRegisterTranslations } from '@manacore/shared-i18n'; import PictureLogo from '$lib/components/branding/PictureLogo.svelte'; - import { authService } from '$lib/services/authService'; + import { authStore } from '$lib/stores/auth.svelte'; import { onMount } from 'svelte'; import { PUBLIC_GOOGLE_CLIENT_ID, PUBLIC_APPLE_CLIENT_ID } from '$env/static/public'; @@ -17,15 +17,17 @@ }); async function handleSignUp(email: string, password: string) { - return authService.signUp(email, password); + return authStore.signUp(email, password); } async function handleSignUpWithGoogle() { - return authService.signInWithGoogle(); + // TODO: Implement OAuth with Mana Core Auth when ready + return { success: false, error: 'Google Sign-Up not yet implemented' }; } async function handleSignUpWithApple() { - return authService.signInWithApple(); + // TODO: Implement OAuth with Mana Core Auth when ready + return { success: false, error: 'Apple Sign-Up not yet implemented' }; }