diff --git a/core/runtime/src/main/java/io/quarkiverse/langchain4j/auth/ModelAuthProvider.java b/core/runtime/src/main/java/io/quarkiverse/langchain4j/auth/ModelAuthProvider.java index da0aaeb76..2662eac49 100644 --- a/core/runtime/src/main/java/io/quarkiverse/langchain4j/auth/ModelAuthProvider.java +++ b/core/runtime/src/main/java/io/quarkiverse/langchain4j/auth/ModelAuthProvider.java @@ -22,15 +22,25 @@ interface Input { } static Optional resolve(String modelName) { - Instance beanInstance = modelName == null - ? CDI.current().select(ModelAuthProvider.class) - : CDI.current().select(ModelAuthProvider.class, ModelName.Literal.of(modelName)); - - //get the first one without causing a bean1 resolution exception + // This will likely need to be refactored again. + // ModelAuthProvider should return a set of supported models (empty by default), + // otherwise the resolution on the main branch does not work for more than one OIDC provider ModelAuthProvider authorizer = null; - for (var handle : beanInstance.handles()) { - authorizer = handle.get(); - break; + if (modelName != null) { + Instance beanInstance = CDI.current().select(ModelAuthProvider.class, + ModelName.Literal.of(modelName)); + + for (var handle : beanInstance.handles()) { + authorizer = handle.get(); + break; + } + } + if (authorizer == null) { + Instance beanInstance = CDI.current().select(ModelAuthProvider.class); + for (var handle : beanInstance.handles()) { + authorizer = handle.get(); + break; + } } return Optional.ofNullable(authorizer); } diff --git a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/DevServicesConfigBuilderCustomizer.java b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/DevServicesConfigBuilderCustomizer.java index b6d3c4ea8..832f99adc 100644 --- a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/DevServicesConfigBuilderCustomizer.java +++ b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/DevServicesConfigBuilderCustomizer.java @@ -12,9 +12,10 @@ public class DevServicesConfigBuilderCustomizer implements SmallRyeConfigBuilderCustomizer { @Override public void configBuilder(final SmallRyeConfigBuilder builder) { - // use a priority of 50 to make sure that this is overridable by any of the standard methods - builder.withSources( - new PropertiesConfigSource(Map.of("quarkus.datasource.devservices.image-name", "pgvector/pgvector:pg17"), - "quarkus-langchain4j-pgvector", 50)); + // use a priority of 50 to make sure that this is overridable by any of the + // standard methods + builder.withSources(new PropertiesConfigSource( + Map.of("quarkus.datasource.devservices.image-name", "pgvector/pgvector:pg17"), + "quarkus-langchain4j-pgvector", 50)); } } diff --git a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreBuildTimeConfig.java b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreBuildTimeConfig.java index 7d7185d6c..1756e7356 100644 --- a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreBuildTimeConfig.java +++ b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreBuildTimeConfig.java @@ -12,8 +12,8 @@ public interface PgVectorEmbeddingStoreBuildTimeConfig { /** - * The name of the configured Postgres datasource to use for this store. If not set, - * the default datasource from the Agroal extension will be used. + * The name of the configured Postgres datasource to use for this store. If not + * set, the default datasource from the Agroal extension will be used. */ Optional datasource(); diff --git a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreProcessor.java b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreProcessor.java index 350f2b3d5..49d498c29 100644 --- a/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreProcessor.java +++ b/embedding-stores/pgvector/deployment/src/main/java/io/quarkiverse/langchain4j/pgvector/deployment/PgVectorEmbeddingStoreProcessor.java @@ -33,7 +33,8 @@ class PgVectorEmbeddingStoreProcessor { private static final DotName PG_VECTOR_EMBEDDING_STORE = DotName.createSimple(PgVectorEmbeddingStore.class); private static final DotName AGROAL_POOL_INTERCEPTOR = DotName.createSimple(AgroalPoolInterceptor.class); - private static final DotName PG_VECTOR_AGROAL_POOL_INTERCEPTOR = DotName.createSimple(PgVectorAgroalPoolInterceptor.class); + private static final DotName PG_VECTOR_AGROAL_POOL_INTERCEPTOR = DotName + .createSimple(PgVectorAgroalPoolInterceptor.class); private static final String FEATURE = "langchain4j-pgvector"; @@ -50,39 +51,27 @@ void indexDependencies(BuildProducer producer) { @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - public void createBean( - BuildProducer beanProducer, - PgVectorEmbeddingStoreRecorder recorder, - PgVectorEmbeddingStoreConfig config, - PgVectorEmbeddingStoreBuildTimeConfig buildTimeConfig, + public void createBean(BuildProducer beanProducer, PgVectorEmbeddingStoreRecorder recorder, + PgVectorEmbeddingStoreConfig config, PgVectorEmbeddingStoreBuildTimeConfig buildTimeConfig, BuildProducer embeddingStoreProducer) { AnnotationInstance datasourceQualifier = buildTimeConfig.datasource() .map(dn -> AnnotationInstance.builder(DataSource.class).add("value", dn).build()) .orElse(AnnotationInstance.builder(Default.class).build()); - beanProducer.produce(SyntheticBeanBuildItem - .configure(PG_VECTOR_EMBEDDING_STORE) + beanProducer.produce(SyntheticBeanBuildItem.configure(PG_VECTOR_EMBEDDING_STORE) .types(ClassType.create(dev.langchain4j.store.embedding.pgvector.PgVectorEmbeddingStore.class), ClassType.create(EmbeddingStore.class), ParameterizedType.create(EmbeddingStore.class, ClassType.create(TextSegment.class))) - .setRuntimeInit() - .defaultBean() - .unremovable() - .scope(ApplicationScoped.class) + .setRuntimeInit().defaultBean().unremovable().scope(ApplicationScoped.class) .createWith(recorder.embeddingStoreFunction(config, buildTimeConfig.datasource().orElse(null))) .addInjectionPoint(ClassType.create(DotName.createSimple(AgroalDataSource.class)), datasourceQualifier) .done()); - beanProducer.produce(SyntheticBeanBuildItem - .configure(PG_VECTOR_AGROAL_POOL_INTERCEPTOR) - .types(ClassType.create(AGROAL_POOL_INTERCEPTOR)) - .setRuntimeInit() - .unremovable() - .scope(ApplicationScoped.class) - .supplier(recorder.pgVectorAgroalPoolInterceptor()) - .qualifiers(datasourceQualifier) - .done()); + beanProducer.produce(SyntheticBeanBuildItem.configure(PG_VECTOR_AGROAL_POOL_INTERCEPTOR) + .types(ClassType.create(AGROAL_POOL_INTERCEPTOR)).setRuntimeInit().unremovable() + .scope(ApplicationScoped.class).supplier(recorder.pgVectorAgroalPoolInterceptor()) + .qualifiers(datasourceQualifier).done()); embeddingStoreProducer.produce(new EmbeddingStoreBuildItem()); } diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/ColumnsTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/ColumnsTest.java index 9900ba044..0c0ab3aa3 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/ColumnsTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/ColumnsTest.java @@ -13,15 +13,14 @@ class ColumnsTest extends LangChain4jPgVectorBaseTest { @RegisterExtension static final QuarkusUnitTest test = new QuarkusUnitTest() .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource(new StringAsset( - "quarkus.langchain4j.pgvector.dimension=384\n" + - "quarkus.langchain4j.pgvector.drop-table-first=true\n" + - "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + - "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + - "quarkus.langchain4j.pgvector.metadata.storage-mode=COLUMN_PER_KEY\n" + - "quarkus.langchain4j.pgvector.metadata.column-definitions=key text NULL, name text NULL, " + - "age float NULL, city varchar null, country varchar null\n" + - "quarkus.langchain4j.pgvector.metadata.indexes=key, name, age"), + .addAsResource(new StringAsset("quarkus.langchain4j.pgvector.dimension=384\n" + + "quarkus.langchain4j.pgvector.drop-table-first=true\n" + + "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + + "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + + "quarkus.langchain4j.pgvector.metadata.storage-mode=COLUMN_PER_KEY\n" + + "quarkus.langchain4j.pgvector.metadata.column-definitions=key text NULL, name text NULL, " + + "age float NULL, city varchar null, country varchar null\n" + + "quarkus.langchain4j.pgvector.metadata.indexes=key, name, age"), "application.properties")); @Test diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBMultiIndexTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBMultiIndexTest.java index edd82cba6..4f70e6ff3 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBMultiIndexTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBMultiIndexTest.java @@ -10,18 +10,15 @@ public class JSONBMultiIndexTest extends LangChain4jPgVectorBaseTest { @RegisterExtension - static final QuarkusUnitTest test = new QuarkusUnitTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource(new StringAsset( - "quarkus.langchain4j.pgvector.dimension=384\n" + - "quarkus.langchain4j.pgvector.drop-table-first=true\n" + - "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + - "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + - "quarkus.langchain4j.pgvector.metadata.storage-mode=COMBINED_JSONB\n" + - "quarkus.langchain4j.pgvector.metadata.column-definitions=metadata_b JSONB NULL\n" + - "quarkus.langchain4j.pgvector.metadata.indexes=(metadata_b->'key'), (metadata_b->'name'), (metadata_b->'age')\n" - + - "quarkus.langchain4j.pgvector.metadata.index-type=GIN"), - "application.properties")); + static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap + .create(JavaArchive.class) + .addAsResource(new StringAsset("quarkus.langchain4j.pgvector.dimension=384\n" + + "quarkus.langchain4j.pgvector.drop-table-first=true\n" + + "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + + "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + + "quarkus.langchain4j.pgvector.metadata.storage-mode=COMBINED_JSONB\n" + + "quarkus.langchain4j.pgvector.metadata.column-definitions=metadata_b JSONB NULL\n" + + "quarkus.langchain4j.pgvector.metadata.indexes=(metadata_b->'key'), (metadata_b->'name'), (metadata_b->'age')\n" + + "quarkus.langchain4j.pgvector.metadata.index-type=GIN"), "application.properties")); } diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBTest.java index 944a0e93e..b13935d30 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONBTest.java @@ -10,16 +10,14 @@ public class JSONBTest extends LangChain4jPgVectorBaseTest { @RegisterExtension - static final QuarkusUnitTest test = new QuarkusUnitTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource(new StringAsset( - "quarkus.langchain4j.pgvector.dimension=384\n" + - "quarkus.langchain4j.pgvector.drop-table-first=true\n" + - "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + - "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + - "quarkus.langchain4j.pgvector.metadata.storage-mode=COMBINED_JSONB\n" + - "quarkus.langchain4j.pgvector.metadata.column-definitions=metadata JSONB NULL\n" + - "quarkus.langchain4j.pgvector.metadata.indexes=metadata"), - "application.properties")); + static final QuarkusUnitTest test = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap + .create(JavaArchive.class) + .addAsResource(new StringAsset("quarkus.langchain4j.pgvector.dimension=384\n" + + "quarkus.langchain4j.pgvector.drop-table-first=true\n" + + "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + + "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n" + + "quarkus.langchain4j.pgvector.metadata.storage-mode=COMBINED_JSONB\n" + + "quarkus.langchain4j.pgvector.metadata.column-definitions=metadata JSONB NULL\n" + + "quarkus.langchain4j.pgvector.metadata.indexes=metadata"), "application.properties")); } diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONTest.java index 05570a120..6e81e4aed 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/JSONTest.java @@ -11,13 +11,12 @@ public class JSONTest extends LangChain4jPgVectorBaseTest { @RegisterExtension static final QuarkusUnitTest test = new QuarkusUnitTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource(new StringAsset( - "quarkus.langchain4j.pgvector.dimension=384\n" + - "quarkus.langchain4j.pgvector.drop-table-first=true\n" + - "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + - "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n"), - "application.properties")); + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addAsResource( + new StringAsset("quarkus.langchain4j.pgvector.dimension=384\n" + + "quarkus.langchain4j.pgvector.drop-table-first=true\n" + + "quarkus.class-loading.parent-first-artifacts=ai.djl.huggingface:tokenizers\n" + + "quarkus.log.category.\"io.quarkiverse.langchain4j.pgvector\".level=DEBUG\n\n"), + "application.properties")); // Default behavior } diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/LangChain4jPgVectorBaseTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/LangChain4jPgVectorBaseTest.java index 5502411f3..7a3ede5b1 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/LangChain4jPgVectorBaseTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/LangChain4jPgVectorBaseTest.java @@ -47,9 +47,8 @@ protected EmbeddingStore embeddingStore() { } /** - * Just for information, not real benchmark. - * JSONTest: Ingesting time 50849 ms. Query average 10 ms - * JSONBTest: Ingesting time 56035 ms. Query average 6 ms. + * Just for information, not real benchmark. JSONTest: Ingesting time 50849 ms. + * Query average 10 ms JSONBTest: Ingesting time 56035 ms. Query average 6 ms. * JSONBMultiIndexTest: Ingesting time 47344 ms. Query average 6 ms. * ColumnsTest: Ingesting time 49752 ms. Query average 3 ms. */ diff --git a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/PgVectorDataSourceTest.java b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/PgVectorDataSourceTest.java index 3d32de58c..e10d98c0d 100644 --- a/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/PgVectorDataSourceTest.java +++ b/embedding-stores/pgvector/deployment/src/test/java/io/quarkiverse/langchain4j/pgvector/test/PgVectorDataSourceTest.java @@ -27,15 +27,14 @@ public class PgVectorDataSourceTest { @RegisterExtension static final QuarkusUnitTest test = new QuarkusUnitTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) - .addAsResource(new StringAsset( - // DevServicesConfigBuilderCustomizer overrides the image-name only - // for the default DS, so in this case we have to override it manually - "quarkus.datasource.embeddings-ds.devservices.image-name=pgvector/pgvector:pg16\n" + - "quarkus.langchain4j.pgvector.datasource=embeddings-ds\n" + - "quarkus.langchain4j.pgvector.dimension=1536\n" + - "quarkus.datasource.embeddings-ds.db-kind=postgresql\n"), - "application.properties")); + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class).addAsResource(new StringAsset( + // DevServicesConfigBuilderCustomizer overrides the image-name only + // for the default DS, so in this case we have to override it manually + "quarkus.datasource.embeddings-ds.devservices.image-name=pgvector/pgvector:pg16\n" + + "quarkus.langchain4j.pgvector.datasource=embeddings-ds\n" + + "quarkus.langchain4j.pgvector.dimension=1536\n" + + "quarkus.datasource.embeddings-ds.db-kind=postgresql\n"), + "application.properties")); @io.quarkus.agroal.DataSource("embeddings-ds") DataSource ds; diff --git a/model-providers/openai/azure-openai/runtime/src/main/java/io/quarkiverse/langchain4j/azure/openai/runtime/AzureOpenAiRecorder.java b/model-providers/openai/azure-openai/runtime/src/main/java/io/quarkiverse/langchain4j/azure/openai/runtime/AzureOpenAiRecorder.java index 3df60b147..c15f66d81 100644 --- a/model-providers/openai/azure-openai/runtime/src/main/java/io/quarkiverse/langchain4j/azure/openai/runtime/AzureOpenAiRecorder.java +++ b/model-providers/openai/azure-openai/runtime/src/main/java/io/quarkiverse/langchain4j/azure/openai/runtime/AzureOpenAiRecorder.java @@ -24,6 +24,7 @@ import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.image.DisabledImageModel; import dev.langchain4j.model.image.ImageModel; +import io.quarkiverse.langchain4j.auth.ModelAuthProvider; import io.quarkiverse.langchain4j.azure.openai.AzureOpenAiChatModel; import io.quarkiverse.langchain4j.azure.openai.AzureOpenAiEmbeddingModel; import io.quarkiverse.langchain4j.azure.openai.AzureOpenAiImageModel; @@ -35,6 +36,8 @@ import io.quarkiverse.langchain4j.openai.common.QuarkusOpenAiClient; import io.quarkiverse.langchain4j.openai.common.runtime.AdditionalPropertiesHack; import io.quarkiverse.langchain4j.runtime.NamedConfigUtil; +import io.quarkus.arc.Arc; +import io.quarkus.arc.ArcContainer; import io.quarkus.arc.SyntheticCreationalContext; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; @@ -295,6 +298,12 @@ private LangChain4jAzureOpenAiConfig.AzureAiConfig correspondingAzureOpenAiConfi private void throwIfApiKeysNotConfigured(String apiKey, String adToken, String configName) { if ((apiKey != null) == (adToken != null)) { + ArcContainer container = Arc.container(); + if (container != null && container.instance(ModelAuthProvider.class).isAvailable()) { + // Perhaps ModelAuthProvider can provide a method with a default implementation returning a value like `ALL` + // to indicate that it applies to all or a specific model only + return; + } throw new ConfigValidationException(createKeyMisconfigurationProblem(configName)); } } diff --git a/samples/pom.xml b/samples/pom.xml index 2084dbda7..401863018 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -19,7 +19,7 @@ fraud-detection review-triage secure-fraud-detection - secure-vertex-ai-gemini-poem + secure-poem sql-chatbot diff --git a/samples/secure-poem/README.md b/samples/secure-poem/README.md new file mode 100644 index 000000000..0ca1dce56 --- /dev/null +++ b/samples/secure-poem/README.md @@ -0,0 +1,164 @@ +# Secure Vertex AI Gemini and Azure OpenAI Poem Demo + +This advanced secure poem demo showcases how users authenticated with Google can request a poem from a Vertex AI Gemini model and users authenticated with Microsoft Entra ID can request a poem from an Azure OpenAI model. + +## The Demo + +Demo asks either Vertex AI Gemini or Azure OpenAI LLM to write a short 1 paragraph poem, using the access token acquired during the OIDC authorization code flow with either Google or Microsoft Entra ID OpenId Connect provider. + +### OpenId Connect authenticaion + +This demo requires users to authenticate with either Google or Microsoft Entra ID. + +#### Google authentication + +All you need to do is to register an application with Google, follow steps listed in the [Quarkus Google](https://quarkus.io/guides/security-openid-connect-providers#google) section. + +Name your Google application as `Quarkus LangChain4j AI`, and make sure an allowed callback URL is set to `http://localhost:8080/gemini`. +Google will generate a client id and secret, use them to set `quarkus.oidc.client-id` and `quarkus.oidc.credentials.secret` properties. +Set `GOOGLE_PROJECT_ID` to the id of your Google Cloud project. +You must also enable Vertex AI API in your Google Cloud project. + +```properties +# Named Google OIDC provider +quarkus.oidc.google.provider=google +quarkus.oidc.google.client-id=${GOOGLE_CLIENT_ID} +quarkus.oidc.google.credentials.secret=${GOOGLE_CLIENT_SECRET} +quarkus.oidc.google.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform +quarkus.oidc.google.authentication.redirect-path=/login/google + +vertex-ai-region=europe-west2 +quarkus.langchain4j.vertexai.gemini.location=${vertex-ai-region} +quarkus.langchain4j.vertexai.gemini.project-id=${GOOGLE_PROJECT_ID} +``` + +#### Microsoft Entra ID authentication + +TODO: Describe steps required to setup Microsoft Entra ID autentication + +```properties +# Named Microsoft Entra ID OIDC provider +quarkus.oidc.azure.auth-server-url=https://login.microsoftonline.com/${AZURE_TENANT_ID} +quarkus.oidc.azure.application-type=web-app +quarkus.oidc.azure.client-id=${AZURE_CLIENT_ID} +quarkus.oidc.azure.credentials.secret=${AZURE_CLIENT_SECRET} +quarkus.oidc.azure.authentication.extra-params.scope=${AZURE_OPENAI_SCOPES} +quarkus.oidc.azure.authentication.redirect-path=/login/entraid +quarkus.oidc.azure.token.principal-claim=name + +quarkus.langchain4j.azure-openai.resource-name=${AZURE_OPENAI_RESOURCE} +quarkus.langchain4j.azure-openai.deployment-name=${AZURE_OPENAI_DEPLOYMENT} +``` + +### Multiple models + +This demo enables both Vertex AI Gemini and Azure OpenAI models. +When more than one model is used, you must use `quarkus.langchain4j.chat-model.provider` to name the default model's provider + +#### Vertex AI Gemini + +Vertex AI Gemini is a default model and is configured as follows: + +```properties +# Default Vertex AI Gemini model is accessed after a user has authenticated with Google. +# See https://cloud.google.com/vertex-ai/docs/geeral/locations +vertex-ai-region=europe-west2 + +quarkus.langchain4j.chat-model.provider=vertexai-gemini +quarkus.langchain4j.vertexai.gemini.location=${vertex-ai-region} +quarkus.langchain4j.vertexai.gemini.project-id=${GOOGLE_PROJECT_ID} +quarkus.langchain4j.vertexai.gemini.log-requests=true +quarkus.langchain4j.vertexai.gemini.log-responses=true +``` + +#### Azure OpenAI + +Azure OpenAI model is configured using an `openai` named configuration: + +```properties +# Named Azure OpenAI model is accessed after a user has authenticated with Entra ID. +quarkus.langchain4j.openai.chat-model.provider=azure-openai +quarkus.langchain4j.azure-openai.openai.resource-name=${AZURE_OPENAI_RESOURCE} +quarkus.langchain4j.azure-openai.openai.deployment-name=${AZURE_OPENAI_DEPLOYMENT} +quarkus.langchain4j.azure-openai.openai.log-requests=true +quarkus.langchain4j.azure-openai.openai.log-responses=true +``` + +### ChatLanguageModel + +This demo leverages ChatLanguageModel instead of the the AI service abstraction to simplify managing multiple models, with the interaction between the LLM and the application handled through the ChatLanguageModel interface. + +```java +package io.quarkiverse.langchain4j.sample; + +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.output.Response; +import io.quarkiverse.langchain4j.ModelName; +import io.quarkus.security.Authenticated; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/poem") +@Authenticated +public class PoemResource { + + static final UserMessage USER_MESSAGE = + UserMessage.from("Write a short 1 paragraph poem about Java. Set an author name to the model name which created the poem."); + + @Inject + ChatLanguageModel vertexAiGemini; + + @Inject + @ModelName("openai") + ChatLanguageModel azureOpenAI; + + @GET + @Path("gemini") + public String getPoemGemini() { + Response response = vertexAiGemini.generate(USER_MESSAGE); + return response.content().text(); + } + + @GET + @Path("azureopenai") + public String getPoemAzureOpenAI() { + Response response = azureOpenAI.generate(USER_MESSAGE); + return response.content().text(); + } + +} + +`PoemResource` can only be accessed by authenticated users from an HTML page generated after a successful authentication. +It uses either Vertex AI Gemini or Azure OpenAI model to generate a poem. + +## Security Considerations + +This demo makes it possible to access Google Vertex Gemini or Azure OpenAI models only to users who have authenticated with either Google or Microsoft Entra ID and authorized the registered `Quarkus LangChain4j AI` application to access either of these models on behalf of the currently authenticated user. + +### Google Vertex AI Gemini + +Users authorize `Quarkus LangChain4j AI` application registered in the Google Cloud project to use the access token to access Google Generative API on behalf of the currently authentiicated user. This authorization is requested from users during the authentication process and is configured by adding additional `quarkus.oidc.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform` scopes in the application properties. +* Quarkus LangChain4j vertex-ai-gemini model provider uses this authorized token on behalf of the current user to access Google Vertex AI endpoint. + +### Azure OpenAI + +TODO + +## Running the Demo + +To run the demo, use the following commands: + +```shell +mvn quarkus:dev +``` + +Access `http://localhost:8080`, login to Quarkus PoemResource using either Google or Microsoft Entra ID, and follow a provided application link to read the poem. +Use the logout link to logout and try another OpenId Connect provider and model. For example, if you've started with Google and Vertex AI Gemini, try Microsoft Entra ID and Azure OpenAI next, or vice versa. + +You do not have to have both Google and Microsoft Entra ID accounts enabled in order to run this demo. + +Running it with only Google or Microsoft Entra ID authentication is sufficient in order to learn how a user authenticated to Quarkus with an OpenId Connect (OIDC) provider can authorize Quarkus AI service to access a remote LLM which is enabled in this user's account. + diff --git a/samples/secure-vertex-ai-gemini-poem/pom.xml b/samples/secure-poem/pom.xml similarity index 93% rename from samples/secure-vertex-ai-gemini-poem/pom.xml rename to samples/secure-poem/pom.xml index ef0ed0c28..320ae553e 100644 --- a/samples/secure-vertex-ai-gemini-poem/pom.xml +++ b/samples/secure-poem/pom.xml @@ -3,8 +3,8 @@ 4.0.0 io.quarkiverse.langchain4j - quarkus-langchain4j-sample-secure-vertex-ai-gemini-poem - Quarkus LangChain4j - Sample - Secure Vertex AI Gemini Poem + quarkus-langchain4j-sample-secure-poem + Quarkus LangChain4j - Sample - Secure Poem 1.0-SNAPSHOT @@ -18,7 +18,7 @@ 3.15.1 true 3.2.5 - 0.21.0.CR4 + 999-SNAPSHOT @@ -52,6 +52,11 @@ quarkus-langchain4j-vertex-ai-gemini ${quarkus-langchain4j.version} + + io.quarkiverse.langchain4j + quarkus-langchain4j-azure-openai + ${quarkus-langchain4j.version} + io.quarkus quarkus-rest-qute diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java similarity index 56% rename from samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java rename to samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java index c4fb929c2..77f4ea5cd 100644 --- a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java +++ b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LoginResource.java @@ -3,6 +3,7 @@ import org.eclipse.microprofile.jwt.JsonWebToken; import io.quarkus.oidc.IdToken; +import io.quarkus.oidc.Tenant; import io.quarkus.qute.Template; import io.quarkus.qute.TemplateInstance; import io.quarkus.security.Authenticated; @@ -12,7 +13,7 @@ import jakarta.ws.rs.Produces; /** - * Login resource which returns a poem welcome page to the authenticated user + * Login resource which returns a poem welcome page to the authenticated user */ @Path("/login") @Authenticated @@ -26,8 +27,18 @@ public class LoginResource { Template poem; @GET + @Path("google") @Produces("text/html") - public TemplateInstance poem() { - return poem.data("name", idToken.getName()); + @Tenant("google") + public TemplateInstance poemGoogle() { + return poem.data("name", idToken.getName()).data("model", "gemini").data("logout", "google"); + } + + @GET + @Path("entraid") + @Produces("text/html") + @Tenant("entraid") + public TemplateInstance poemEntraID() { + return poem.data("name", idToken.getName()).data("model", "azureopenai").data("logout", "entraid"); } } diff --git a/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java new file mode 100644 index 000000000..491593e5b --- /dev/null +++ b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java @@ -0,0 +1,40 @@ +package io.quarkiverse.langchain4j.sample; + +import io.quarkus.oidc.OidcSession; +import io.quarkus.security.Authenticated; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriInfo; + +/** + * Logout resource + */ +@Path("/logout") +@Authenticated +public class LogoutResource { + + @Inject + OidcSession session; + + @GET + @Path("/google") + public Response logoutGoogle(@Context UriInfo uriInfo) { + return getLogoutResponse(uriInfo, "google"); + } + + @GET + @Path("/entraid") + public Response logoutEntraID(@Context UriInfo uriInfo) { + return getLogoutResponse(uriInfo, "entraid"); + } + + private Response getLogoutResponse(@Context UriInfo uriInfo, String loginPath) { + // remove the local session cookie + session.logout().await().indefinitely(); + // redirect to the login page + return Response.seeOther(uriInfo.getBaseUriBuilder().path("login").path(loginPath).build()).build(); + } +} diff --git a/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java new file mode 100644 index 000000000..812264bd3 --- /dev/null +++ b/samples/secure-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java @@ -0,0 +1,41 @@ +package io.quarkiverse.langchain4j.sample; + +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.output.Response; +import io.quarkiverse.langchain4j.ModelName; +import io.quarkus.security.Authenticated; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/poem") +@Authenticated +public class PoemResource { + + static final UserMessage USER_MESSAGE = + UserMessage.from("Write a short 1 paragraph poem about Java. Set an author name to the model name which created the poem."); + + @Inject + ChatLanguageModel vertexAiGemini; + + @Inject + @ModelName("openai") + ChatLanguageModel azureOpenAI; + + @GET + @Path("gemini") + public String getPoemGemini() { + Response response = vertexAiGemini.generate(USER_MESSAGE); + return response.content().text(); + } + + @GET + @Path("azureopenai") + public String getPoemAzureOpenAI() { + Response response = azureOpenAI.generate(USER_MESSAGE); + return response.content().text(); + } + +} diff --git a/samples/secure-poem/src/main/resources/META-INF/resources/images/entraId.svg b/samples/secure-poem/src/main/resources/META-INF/resources/images/entraId.svg new file mode 100644 index 000000000..0ed35fb73 --- /dev/null +++ b/samples/secure-poem/src/main/resources/META-INF/resources/images/entraId.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/resources/META-INF/resources/images/google.png b/samples/secure-poem/src/main/resources/META-INF/resources/images/google.png similarity index 100% rename from samples/secure-vertex-ai-gemini-poem/src/main/resources/META-INF/resources/images/google.png rename to samples/secure-poem/src/main/resources/META-INF/resources/images/google.png diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/resources/META-INF/resources/index.html b/samples/secure-poem/src/main/resources/META-INF/resources/index.html similarity index 89% rename from samples/secure-vertex-ai-gemini-poem/src/main/resources/META-INF/resources/index.html rename to samples/secure-poem/src/main/resources/META-INF/resources/index.html index c5e900b81..522843e65 100644 --- a/samples/secure-vertex-ai-gemini-poem/src/main/resources/META-INF/resources/index.html +++ b/samples/secure-poem/src/main/resources/META-INF/resources/index.html @@ -116,7 +116,10 @@

Login

- + + + +
Login with GoogleLogin with Google
Login with Microsoft Entra ID
diff --git a/samples/secure-poem/src/main/resources/application.properties b/samples/secure-poem/src/main/resources/application.properties new file mode 100644 index 000000000..12b7bfc21 --- /dev/null +++ b/samples/secure-poem/src/main/resources/application.properties @@ -0,0 +1,36 @@ +# Named Google OpenID Connect provider + +quarkus.oidc.google.provider=google +quarkus.oidc.google.client-id=${GOOGLE_CLIENT_ID} +quarkus.oidc.google.credentials.secret=${GOOGLE_CLIENT_SECRET} +quarkus.oidc.google.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform +quarkus.oidc.google.authentication.redirect-path=/login/google + +# Default Vertex AI Gemini model is accessed after a user has authenticated with Google. +# See https://cloud.google.com/vertex-ai/docs/geeral/locations +vertex-ai-region=europe-west2 + +quarkus.langchain4j.chat-model.provider=vertexai-gemini +quarkus.langchain4j.vertexai.gemini.location=${vertex-ai-region} +quarkus.langchain4j.vertexai.gemini.project-id=${GOOGLE_PROJECT_ID} +quarkus.langchain4j.vertexai.gemini.log-requests=true +quarkus.langchain4j.vertexai.gemini.log-responses=true + +# Named Entra ID OpenID Connect provider + +quarkus.oidc.entraid.auth-server-url=https://login.microsoftonline.com/${AZURE_TENANT_ID}/v2.0 +quarkus.oidc.entraid.application-type=web-app +quarkus.oidc.entraid.client-id=${AZURE_CLIENT_ID} +quarkus.oidc.entraid.credentials.secret=${AZURE_CLIENT_SECRET} +quarkus.oidc.entraid.authentication.scopes=https://cognitiveservices.azure.com/.default +quarkus.oidc.entraid.authentication.redirect-path=/login/entraid +quarkus.oidc.entraid.token.principal-claim=name + +# Named Azure OpenAI model is accessed after a user has authenticated with Entra ID. +quarkus.langchain4j.openai.chat-model.provider=azure-openai +quarkus.langchain4j.azure-openai.openai.resource-name=${AZURE_OPENAI_RESOURCE} +quarkus.langchain4j.azure-openai.openai.log-requests=true +quarkus.langchain4j.azure-openai.openai.log-responses=true + +# Disable Keycloak devservice +quarkus.keycloak.devservices.enabled=false diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/resources/templates/poem.html b/samples/secure-poem/src/main/resources/templates/poem.html similarity index 70% rename from samples/secure-vertex-ai-gemini-poem/src/main/resources/templates/poem.html rename to samples/secure-poem/src/main/resources/templates/poem.html index 170d82875..31aee57c9 100644 --- a/samples/secure-vertex-ai-gemini-poem/src/main/resources/templates/poem.html +++ b/samples/secure-poem/src/main/resources/templates/poem.html @@ -9,10 +9,10 @@

Hello {name} !

- Read a poem + Read a poem
- Logout + Logout diff --git a/samples/secure-vertex-ai-gemini-poem/README.md b/samples/secure-vertex-ai-gemini-poem/README.md deleted file mode 100644 index bceb80462..000000000 --- a/samples/secure-vertex-ai-gemini-poem/README.md +++ /dev/null @@ -1,115 +0,0 @@ -# Secure Vertex AI Gemini Poem Demo - -This demo showcases the implementation of a secure Vertex AI Gemini Poem Demo which is available only to users authenticated with Google. - -## The Demo - -Demo asks Vertex AI Gemini LLM to write a short 1 paragraph poem, using the access token acquired during the OIDC authorization code flow - -### Setup - -This demo requires users to authenticate with Google. - -All you need to do is to register an application with Google, follow steps listed in the [Quarkus Google](https://quarkus.io/guides/security-openid-connect-providers#google) section. - -Name your Google application as `Quarkus LangChain4j AI`, and make sure an allowed callback URL is set to `http://localhost:8080/login`. -Google will generate a client id and secret, use them to set `quarkus.oidc.client-id` and `quarkus.oidc.credentials.secret` properties: - -```properties -quarkus.oidc.provider=google -quarkus.oidc.client-id=${GOOGLE_CLIENT_ID} -quarkus.oidc.credentials.secret=${GOOGLE_CLIENT_SECRET} -quarkus.oidc.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform -quarkus.oidc.authentication.redirect-path=/login - -# See https://cloud.google.com/vertex-ai/docs/geeral/locations -vertex-ai-region=europe-west2 - -quarkus.langchain4j.vertexai.gemini.location=${vertex-ai-region} -quarkus.langchain4j.vertexai.gemini.project-id=${GOOGLE_PROJECT_ID} -``` - -You must enable Vertex AI API in your Google Cloud project. - -Set `GOOGLE_PROJECT_ID` to the id of your Google Cloud project. - -### AI Service - -This demo leverages the AI service abstraction, with the interaction between the LLM and the application handled through the AIService interface. - -The `io.quarkiverse.langchain4j.sample.PoemAiService` interface uses specific annotations to define the LLM: - -```java -package io.quarkiverse.langchain4j.sample; - -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; -import io.quarkiverse.langchain4j.RegisterAiService; - -@RegisterAiService -public interface PoemAiService { - - /** - * Ask the LLM to create a poem about Enterprise Java. - * - * @return the poem - */ - @SystemMessage("You are a professional poet") - @UserMessage(""" - Write a short 1 paragraph poem about Java. Set an author name to the model name which created the poem. - """) - String writeAPoem(); - -} - -### Using the AI service - -Once defined, you can inject the AI service as a regular bean, and use it: - -```java -package io.quarkiverse.langchain4j.sample; - -import java.net.URISyntaxException; - -import io.quarkus.security.Authenticated; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -@Path("/poem") -@Authenticated -public class PoemResource { - - private final PoemAiService aiService; - - public PoemResource(PoemAiService aiService) throws URISyntaxException { - this.aiService = aiService; - } - - @GET - public String getPoem() { - return aiService.writeAPoem(); - } -} - -``` - -`PoemResource` can only be accessed by authenticated users. - -## Security Considerations - -This demo makes it possible to access Google Vertex AI API enabled in the Google Cloud project only to users who: - -* Authenticated to Quarkus REST PoemService with Google using OIDC authorization code flow. -* Authorized `Quarkus LangChain4j AI` application registered in the Google Cloud project to use the access token to access Google Generative API on behalf of the currently authentiicated user. This authorization is requested from users during the authentication process and is configured by adding additional `quarkus.oidc.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform` scopes in the application properties. -* Quarkus LangChain4j vertex-ai-gemini model provider uses this authorized token on behalf of the current user to access Google Vertex AI endpoint. - -## Running the Demo - -To run the demo, use the following commands: - -```shell -mvn quarkus:dev -``` - -Then, access `http://localhost:8080`, login to Google, and follow a provided application link to read the poem. - diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java b/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java deleted file mode 100644 index e2635772e..000000000 --- a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/LogoutResource.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.quarkiverse.langchain4j.sample; - -import io.quarkus.oidc.OidcSession; -import io.quarkus.security.Authenticated; -import jakarta.inject.Inject; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.core.Context; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.UriInfo; - -/** - * Logout resource - */ -@Path("/logout") -@Authenticated -public class LogoutResource { - - @Inject - OidcSession session; - - @GET - public Response logout(@Context UriInfo uriInfo) { - // remove the local session cookie - session.logout().await().indefinitely(); - // redirect to the login page - return Response.seeOther(uriInfo.getBaseUriBuilder().path("login").build()).build(); - } -} diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemAiService.java b/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemAiService.java deleted file mode 100644 index 3cf57b662..000000000 --- a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemAiService.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.quarkiverse.langchain4j.sample; - -import dev.langchain4j.service.SystemMessage; -import dev.langchain4j.service.UserMessage; -import io.quarkiverse.langchain4j.RegisterAiService; - -@RegisterAiService -public interface PoemAiService { - - /** - * Ask the LLM to create a poem about Enterprise Java. - * - * @return the poem - */ - @SystemMessage("You are a professional poet") - @UserMessage(""" - Write a short 1 paragraph poem about Java. Set an author name to the model name which created the poem. - """) - String writeAPoem(); - -} diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java b/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java deleted file mode 100644 index 1d3e05952..000000000 --- a/samples/secure-vertex-ai-gemini-poem/src/main/java/io/quarkiverse/langchain4j/sample/PoemResource.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.quarkiverse.langchain4j.sample; - -import java.net.URISyntaxException; - -import io.quarkus.security.Authenticated; -import jakarta.ws.rs.GET; -import jakarta.ws.rs.Path; - -@Path("/poem") -@Authenticated -public class PoemResource { - - private final PoemAiService aiService; - - public PoemResource(PoemAiService aiService) throws URISyntaxException { - this.aiService = aiService; - } - - @GET - public String getPoem() { - return aiService.writeAPoem(); - } -} diff --git a/samples/secure-vertex-ai-gemini-poem/src/main/resources/application.properties b/samples/secure-vertex-ai-gemini-poem/src/main/resources/application.properties deleted file mode 100644 index af8d30303..000000000 --- a/samples/secure-vertex-ai-gemini-poem/src/main/resources/application.properties +++ /dev/null @@ -1,14 +0,0 @@ -quarkus.oidc.provider=google -quarkus.oidc.client-id=${GOOGLE_CLIENT_ID} -quarkus.oidc.credentials.secret=${GOOGLE_CLIENT_SECRET} -quarkus.oidc.authentication.extra-params.scope=https://www.googleapis.com/auth/generative-language.retriever,https://www.googleapis.com/auth/cloud-platform -quarkus.oidc.authentication.redirect-path=/login - -# See https://cloud.google.com/vertex-ai/docs/geeral/locations -vertex-ai-region=europe-west2 - -quarkus.langchain4j.vertexai.gemini.location=${vertex-ai-region} -quarkus.langchain4j.vertexai.gemini.project-id=${GOOGLE_PROJECT_ID} - -quarkus.langchain4j.vertexai.gemini.log-requests=true -quarkus.langchain4j.vertexai.gemini.log-responses=true