diff --git a/examples/creative-studio/README.md b/examples/creative-studio/README.md index 7888ef9664f..4924f1eb1e3 100644 --- a/examples/creative-studio/README.md +++ b/examples/creative-studio/README.md @@ -47,8 +47,13 @@ Just run this script which has a step by step approach for you to deploy the inf curl https://raw.githubusercontent.com/GoogleCloudPlatform/professional-services/refs/heads/main/examples/creative-studio/bootstrap.sh | bash ``` -For better guidance, we recorded a video to showcase how to deploy Creative Studio in a completely new and fresh GCP Account: -https://the-deploy-example-video +For better guidance, [we recorded a video](./screenshots/how_to_deploy_creative_studio.mp4) to showcase how to deploy Creative Studio in a completely new and fresh GCP Account. + + + > **IMPORTANT:** In order to run this app, you will have to enable the [Vertex AI API](https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview) and the [IAM Service Account Credentials API](https://console.developers.google.com/apis/api/iamcredentials.googleapis.com/overview). diff --git a/examples/creative-studio/backend/src/auth/auth_guard.py b/examples/creative-studio/backend/src/auth/auth_guard.py index 745b66b893a..c8fee5e57e3 100644 --- a/examples/creative-studio/backend/src/auth/auth_guard.py +++ b/examples/creative-studio/backend/src/auth/auth_guard.py @@ -101,6 +101,10 @@ def get_current_user(token: str = Depends(oauth2_scheme)) -> UserModel: detail="Could not create or retrieve user profile.", ) + if not user_doc.picture: + user_doc.picture = picture + user_service.user_repo.update(user_doc.id, user_doc.model_dump()) + return user_doc except auth.ExpiredIdTokenError: diff --git a/examples/creative-studio/backend/src/common/base_dto.py b/examples/creative-studio/backend/src/common/base_dto.py index cd8755f44cf..5d791181193 100644 --- a/examples/creative-studio/backend/src/common/base_dto.py +++ b/examples/creative-studio/backend/src/common/base_dto.py @@ -47,6 +47,7 @@ class GenerationModelEnum(str, Enum): VTO = "virtual-try-on-preview-08-04" # Video-Specific Models + VEO_3_1_PREVIEW = "veo-3.1-generate-preview" VEO_3_FAST = "veo-3.0-fast-generate-001" VEO_3_QUALITY = "veo-3.0-generate-001" VEO_3_FAST_PREVIEW = "veo-3.0-fast-generate-preview" diff --git a/examples/creative-studio/backend/src/videos/dto/create_veo_dto.py b/examples/creative-studio/backend/src/videos/dto/create_veo_dto.py index 77587dc3f2a..69134dd82f5 100644 --- a/examples/creative-studio/backend/src/videos/dto/create_veo_dto.py +++ b/examples/creative-studio/backend/src/videos/dto/create_veo_dto.py @@ -58,7 +58,7 @@ class CreateVeoDto(BaseDto): min_length=1, description="The ID of the workspace for this generation." ) generation_model: GenerationModelEnum = Field( - default=GenerationModelEnum.VEO_3_FAST, + default=GenerationModelEnum.VEO_3_1_PREVIEW, description="Model used for image generation.", ) aspect_ratio: AspectRatioEnum = Field( @@ -213,6 +213,7 @@ def validate_video_generation_model( ) -> GenerationModelEnum: """Ensures that only supported generation models for video are used.""" valid_video_ratios = [ + GenerationModelEnum.VEO_3_1_PREVIEW, GenerationModelEnum.VEO_3_FAST, GenerationModelEnum.VEO_3_QUALITY, GenerationModelEnum.VEO_3_FAST_PREVIEW, diff --git a/examples/creative-studio/frontend/package-lock.json b/examples/creative-studio/frontend/package-lock.json index 79b2997f1f2..c19803aac6e 100644 --- a/examples/creative-studio/frontend/package-lock.json +++ b/examples/creative-studio/frontend/package-lock.json @@ -18,9 +18,9 @@ "@angular/material": "^18.2.1", "@angular/platform-browser": "^18.1.0", "@angular/platform-browser-dynamic": "^18.1.0", - "@angular/platform-server": "^18.2.14", + "@angular/platform-server": "^18.1.0", "@angular/router": "^18.1.0", - "@angular/ssr": "^18.2.21", + "@angular/ssr": "^18.1.2", "express": "^4.18.2", "file-saver": "^2.0.5", "ngx-image-cropper": "^9.1.5", @@ -676,10 +676,9 @@ } }, "node_modules/@angular/platform-server": { - "version": "18.2.14", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-18.2.14.tgz", - "integrity": "sha512-XUErL0mOPvua5EtlmSOFllSM+Ts1wHzNIv0WNV5FJxWI3Pe6Xxs29xneKDOImC9ErYWuQqK7sQ/hyIaHO5fhOw==", - "license": "MIT", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-18.2.1.tgz", + "integrity": "sha512-xU/7EGYk/HXAY2V7VEzBx4YcVQe3rPuojXPubdgKJ8ueQ7XVtwumv/LHM72/Yn8ChvYYaoGLtM7nI2rG1MVAag==", "dependencies": { "tslib": "^2.3.0", "xhr2": "^0.2.0" @@ -688,11 +687,11 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.2.14", - "@angular/common": "18.2.14", - "@angular/compiler": "18.2.14", - "@angular/core": "18.2.14", - "@angular/platform-browser": "18.2.14" + "@angular/animations": "18.2.1", + "@angular/common": "18.2.1", + "@angular/compiler": "18.2.1", + "@angular/core": "18.2.1", + "@angular/platform-browser": "18.2.1" } }, "node_modules/@angular/router": { @@ -713,10 +712,9 @@ } }, "node_modules/@angular/ssr": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-18.2.21.tgz", - "integrity": "sha512-0euH/xxVLv12xVPf1WkfVVmteFccsObjcomCQg/wwu6U4pp5BVqtXpLgA6kAyJByhwbjJWnJJwxovHcVMsRoig==", - "license": "MIT", + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-18.2.1.tgz", + "integrity": "sha512-e+/RZZmUAUVv22JpOQ64z7RzzlCbyx2spDoKJgopp+LmfWqdR99LEvZ6H01yd8ZzynOEQtFIilPcrEWKQ1kSXg==", "dependencies": { "critters": "0.0.24", "tslib": "^2.3.0" @@ -5487,16 +5485,15 @@ } }, "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", - "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.3.tgz", + "integrity": "sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==", "devOptional": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" }, @@ -7980,24 +7977,32 @@ } }, "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "devOptional": true, - "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", "vary": "~1.1.2" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "devOptional": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compression/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -8013,15 +8018,11 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "devOptional": true }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "devOptional": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -11549,9 +11550,9 @@ } }, "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -16175,9 +16176,9 @@ "license": "BSD-3-Clause" }, "node_modules/morgan": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", - "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -16185,7 +16186,7 @@ "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.1.0" + "on-headers": "~1.0.2" }, "engines": { "node": ">= 0.8.0" @@ -16888,11 +16889,10 @@ } }, "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "devOptional": true, - "license": "MIT", "engines": { "node": ">= 0.8" } diff --git a/examples/creative-studio/frontend/package.json b/examples/creative-studio/frontend/package.json index a3cc2d9b167..6f35f90f82f 100644 --- a/examples/creative-studio/frontend/package.json +++ b/examples/creative-studio/frontend/package.json @@ -33,9 +33,9 @@ "@angular/material": "^18.2.1", "@angular/platform-browser": "^18.1.0", "@angular/platform-browser-dynamic": "^18.1.0", - "@angular/platform-server": "^18.2.14", + "@angular/platform-server": "^18.1.0", "@angular/router": "^18.1.0", - "@angular/ssr": "^18.2.21", + "@angular/ssr": "^18.1.2", "express": "^4.18.2", "file-saver": "^2.0.5", "ngx-image-cropper": "^9.1.5", diff --git a/examples/creative-studio/frontend/src/app/fun-templates/media-template.model.ts b/examples/creative-studio/frontend/src/app/fun-templates/media-template.model.ts index 922527db00a..48448f51797 100644 --- a/examples/creative-studio/frontend/src/app/fun-templates/media-template.model.ts +++ b/examples/creative-studio/frontend/src/app/fun-templates/media-template.model.ts @@ -101,6 +101,7 @@ export enum GenerationModelEnum { IMAGEN_4_FAST = 'imagen-4.0-fast-generate-001', // Video-Specific Models + VEO_3_1_PREVIEW = 'veo-3.1-generate-preview', VEO_3_FAST = 'veo-3.0-fast-generate-001', VEO_3_QUALITY = 'veo-3.0-generate-001', VEO_2_FAST = 'veo-2.0-fast-generate-001', diff --git a/examples/creative-studio/frontend/src/app/home/home.component.html b/examples/creative-studio/frontend/src/app/home/home.component.html index 9b52b4da93c..39ee9fb7caa 100644 --- a/examples/creative-studio/frontend/src/app/home/home.component.html +++ b/examples/creative-studio/frontend/src/app/home/home.component.html @@ -442,7 +442,7 @@
-
+
m.value === 'veo-2.0-generate-001', + const veo31Model = this.generationModels.find( + m => m.value === 'veo-3.1-generate-preview', ); - if (veo2Model) { - this.selectModel(veo2Model); + if (veo31Model) { + this.selectModel(veo31Model); this._snackBar.openFromComponent(ToastMessageComponent, { panelClass: ['green-toast'], duration: 8000, data: { - text: "Veo 3 Fast doesn't support images as input, so we've switched to Veo 2 for you.", + text: "Veo 3 doesn't support images as input, so we've switched to Veo 3.1 for you.", matIcon: 'info_outline', }, }); @@ -1166,16 +1170,16 @@ export class VideoComponent implements AfterViewInit { this._snackBar.open(snackbarMessage, 'OK', {duration: 5000}); } - const expModel = this.generationModels.find( - m => m.value === 'veo-2.0-generate-exp', + const veo31Model = this.generationModels.find( + m => m.value === 'veo-3.1-generate-preview', ); - if (expModel) { - this.selectModel(expModel); + if (veo31Model) { + this.selectModel(veo31Model); this._snackBar.openFromComponent(ToastMessageComponent, { panelClass: ['green-toast'], duration: 8000, data: { - text: "We've switched to the Veo 2 Exp model for you, as it's the only one that supports reference images.", + text: "We've switched to the Veo 3.1 model for you, as this one supports reference images.", matIcon: 'info_outline', }, }); diff --git a/examples/creative-studio/infra/modules/platform/main.tf b/examples/creative-studio/infra/modules/platform/main.tf index 2b63188148d..d8d257adb26 100644 --- a/examples/creative-studio/infra/modules/platform/main.tf +++ b/examples/creative-studio/infra/modules/platform/main.tf @@ -595,7 +595,7 @@ module "frontend_service" { resource_prefix = "cs-fe" github_branch_name = var.github_branch_name cloudbuild_yaml_path = "examples/creative-studio/frontend/cloudbuild-deploy.yaml" - included_files_glob = ["**/creative-studio/backend/**"] + included_files_glob = ["**/creative-studio/frontend/**"] build_substitutions = merge( var.fe_build_substitutions, diff --git a/examples/creative-studio/screenshots/how_to_deploy_creative_studio.mp4 b/examples/creative-studio/screenshots/how_to_deploy_creative_studio.mp4 new file mode 100644 index 00000000000..a467e2f2644 Binary files /dev/null and b/examples/creative-studio/screenshots/how_to_deploy_creative_studio.mp4 differ