Skip to content

Commit

Permalink
Merge pull request #11273 from anunnakian/langchain4j
Browse files Browse the repository at this point in the history
Allow using langchain4j module
  • Loading branch information
pascalgrimaud authored Nov 7, 2024
2 parents e6b38b7 + 243ca32 commit 10966ba
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tech.jhipster.lite.generator.server.springboot.langchain4j.application;

import org.springframework.stereotype.Service;
import tech.jhipster.lite.generator.server.springboot.langchain4j.domain.LangChain4JModuleFactory;
import tech.jhipster.lite.module.domain.JHipsterModule;
import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;

@Service
public class LangChain4JApplicationService {

private final LangChain4JModuleFactory factory;

public LangChain4JApplicationService() {
factory = new LangChain4JModuleFactory();
}

public JHipsterModule buildModule(JHipsterModuleProperties properties) {
return factory.buildModule(properties);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package tech.jhipster.lite.generator.server.springboot.langchain4j.domain;

import static tech.jhipster.lite.module.domain.JHipsterModule.*;

import tech.jhipster.lite.module.domain.JHipsterModule;
import tech.jhipster.lite.module.domain.file.JHipsterSource;
import tech.jhipster.lite.module.domain.javabuild.ArtifactId;
import tech.jhipster.lite.module.domain.javabuild.GroupId;
import tech.jhipster.lite.module.domain.javabuild.VersionSlug;
import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;
import tech.jhipster.lite.shared.error.domain.Assert;

public class LangChain4JModuleFactory {

private static final String API_KEY_DEMO_COMMENT =
"You can temporarily use 'demo' key, which is provided for free for demonstration purposes";

private static final JHipsterSource SOURCE = from("server/springboot/langchain4j");
private static final GroupId GROUP_ID = groupId("dev.langchain4j");
private static final ArtifactId ARTIFACT_ID = artifactId("langchain4j-spring-boot-starter");
private static final ArtifactId OPEN_AI_ARTIFACT_ID = artifactId("langchain4j-open-ai-spring-boot-starter");
private static final VersionSlug VERSION_SLUG = versionSlug("langchain4j");

private static final String PROPERTIES = "properties";

public JHipsterModule buildModule(JHipsterModuleProperties properties) {
Assert.notNull(PROPERTIES, properties);

//@formatter:off
return moduleBuilder(properties)
.documentation(documentationTitle("Dev tools"), SOURCE.template("langchain4j.md"))
.javaDependencies()
.addDependency(GROUP_ID, ARTIFACT_ID, VERSION_SLUG)
.addDependency(GROUP_ID, OPEN_AI_ARTIFACT_ID, VERSION_SLUG)
.and()
.springMainProperties()
.set(propertyKey("langchain4j.open-ai.chat-model.api-key"), propertyValue("${OPENAI_API_KEY}"))
.comment(propertyKey("langchain4j.open-ai.chat-model.api-key"), comment(API_KEY_DEMO_COMMENT))
.set(propertyKey("langchain4j.open-ai.chat-model.model-name"), propertyValue("gpt-4o-mini"))
.set(propertyKey("langchain4j.open-ai.chat-model.log-requests"), propertyValue("true"))
.set(propertyKey("langchain4j.open-ai.chat-model.log-responses"), propertyValue("true"))
.and()
.build();
//@formatter:on
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tech.jhipster.lite.generator.server.springboot.langchain4j.infrastructure.primary;

import static tech.jhipster.lite.shared.slug.domain.JHLiteModuleSlug.LANGCHAIN4J;
import static tech.jhipster.lite.shared.slug.domain.JHLiteModuleSlug.SPRING_BOOT;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tech.jhipster.lite.generator.server.springboot.langchain4j.application.LangChain4JApplicationService;
import tech.jhipster.lite.module.domain.resource.JHipsterModuleOrganization;
import tech.jhipster.lite.module.domain.resource.JHipsterModulePropertiesDefinition;
import tech.jhipster.lite.module.domain.resource.JHipsterModuleResource;

@Configuration
class LangChain4JModuleConfiguration {

@Bean
JHipsterModuleResource langChain4JModule(LangChain4JApplicationService langChain4J) {
return JHipsterModuleResource.builder()
.slug(LANGCHAIN4J)
.propertiesDefinition(JHipsterModulePropertiesDefinition.builder().addProjectBaseName().addIndentation().build())
.apiDoc("LangChain4J", "Add LangChain4j")
.organization(JHipsterModuleOrganization.builder().addDependency(SPRING_BOOT).build())
.tags("server", "spring", "spring-boot", "langchain4j")
.factory(langChain4J::buildModule);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@tech.jhipster.lite.BusinessContext
package tech.jhipster.lite.generator.server.springboot.langchain4j;
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ public enum JHLiteModuleSlug implements JHipsterModuleSlugFactory {
VUE_OAUTH2_KEYCLOAK("vue-oauth2-keycloak"),
VUE_PINIA("vue-pinia"),
TS_PAGINATION_DOMAIN("ts-pagination-domain"),
TS_REST_PAGINATION("ts-rest-pagination");
TS_REST_PAGINATION("ts-rest-pagination"),
LANGCHAIN4J("langchain4j");

private static final Map<String, JHLiteModuleSlug> moduleSlugMap = Stream.of(values()).collect(
Collectors.toMap(JHLiteModuleSlug::get, Function.identity())
Expand Down
11 changes: 11 additions & 0 deletions src/main/resources/generator/dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<asciidoctor-maven-plugin.version>3.1.0</asciidoctor-maven-plugin.version>
<openapi-maven-plugin.version>0.0.21</openapi-maven-plugin.version>
<openapi-backwards-compat-maven-plugin.version>1.0.3</openapi-backwards-compat-maven-plugin.version>
<langchain4j.version>0.35.0</langchain4j.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -400,6 +401,16 @@
<artifactId>openapi-backwards-compat-maven-plugin</artifactId>
<version>${openapi-backwards-compat-maven-plugin.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# LangChain4j

How to use it:

[Official documentation](https://docs.langchain4j.dev/tutorials/spring-boot-integration/)
10 changes: 10 additions & 0 deletions src/test/features/server/springboot/langchain4j.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Feature: LangChain4j module

Scenario: Should add Spring Boot LangChain4j Starter
When I apply modules to default project
| maven-java |
| spring-boot |
| langchain4j |
Then I should have entries in "src/main/resources/config/application.yml"
| open-ai |
| langchain4j |
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package tech.jhipster.lite.generator.server.springboot.langchain4j.domain;

import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.assertThatModuleWithFiles;
import static tech.jhipster.lite.module.infrastructure.secondary.JHipsterModulesAssertions.pomFile;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import tech.jhipster.lite.TestFileUtils;
import tech.jhipster.lite.UnitTest;
import tech.jhipster.lite.module.domain.JHipsterModule;
import tech.jhipster.lite.module.domain.JHipsterModulesFixture;
import tech.jhipster.lite.module.domain.properties.JHipsterModuleProperties;

@UnitTest
@ExtendWith(MockitoExtension.class)
class LangChain4JModuleFactoryTest {

@InjectMocks
private LangChain4JModuleFactory factory;

@Test
void shouldCreateModule() {
JHipsterModuleProperties properties = JHipsterModulesFixture.propertiesBuilder(TestFileUtils.tmpDirForTest())
.projectBaseName("myApp")
.build();

JHipsterModule module = factory.buildModule(properties);

assertThatModuleWithFiles(module, pomFile())
.hasFile("pom.xml")
.containing("<langchain4j.version>")
.containing(
"""
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
"""
)
.containing(
"""
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
"""
)
.and()
.hasFile("src/main/resources/config/application.yml")
.containing(
"""
langchain4j:
open-ai:
chat-model:
# You can temporarily use 'demo' key, which is provided for free for demonstration purposes
api-key: ${OPENAI_API_KEY}
log-requests: 'true'
log-responses: 'true'
model-name: gpt-4o-mini
"""
);
}
}

0 comments on commit 10966ba

Please sign in to comment.