Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<groupId>com.sap.ai.sdk</groupId>
<artifactId>sdk-parent</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by change for all AI Core services
image

</parent>
<artifactId>document-grounding</artifactId>
<name>Document Grounding Client</name>
Expand All @@ -30,7 +31,7 @@
</developer>
</developers>
<properties>
<project.rootdir>${project.basedir}/../</project.rootdir>
<project.rootdir>${project.basedir}/../../</project.rootdir>
<coverage.complexity>80%</coverage.complexity>
<coverage.line>71%</coverage.line>
<coverage.instruction>85%</coverage.instruction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<groupId>com.sap.ai.sdk</groupId>
<artifactId>sdk-parent</artifactId>
<version>1.6.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>prompt-registry</artifactId>
<name>Prompt Registry client</name>
Expand All @@ -31,7 +32,7 @@
</developer>
</developers>
<properties>
<project.rootdir>${project.basedir}/../</project.rootdir>
<project.rootdir>${project.basedir}/../../</project.rootdir>
<coverage.complexity>75%</coverage.complexity>
<coverage.line>87%</coverage.line>
<coverage.instruction>89%</coverage.instruction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,18 @@
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

/** Client for the Prompt Registry service. */
/**
* Client for the Prompt Registry service.
*
* @since 1.6.0
*/
public class PromptClient extends DefaultApi {

/** Instantiates this a client to invoke operations on the Prompt Registry service. */
/**
* Instantiates this a client to invoke operations on the Prompt Registry service.
*
* @since 1.6.0
*/
public PromptClient() {
this(new AiCoreService());
}
Expand All @@ -33,6 +41,7 @@ public PromptClient() {
* Instantiates this a client to invoke operations on the Prompt Registry service.
*
* @param aiCoreService The configured connectivity instance to AI Core
* @since 1.6.0
*/
public PromptClient(@Nonnull final AiCoreService aiCoreService) {
super(addMixin(aiCoreService));
Expand Down
3 changes: 2 additions & 1 deletion docs/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

### ✨ New Functionality

-
- [Prompt Registry] [Add Prompt Registry client](https://sap.github.io/ai-sdk/docs/java/ai-core/prompt-registry)
- `com.sap.ai.sdk:prompt-registry:1.6.0`

### 📈 Improvements

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
<modules>
<module>core</module>
<module>orchestration</module>
<module>document-grounding</module>
<module>core-services/document-grounding</module>
<module>core-services/prompt-registry</module>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Released prompt-registry

<module>foundation-models/openai</module>
</modules>
<scm>
Expand Down Expand Up @@ -788,7 +789,6 @@ https://gitbox.apache.org/repos/asf?p=maven-pmd-plugin.git;a=blob_plain;f=src/ma
</activation>
<modules>
<module>sample-code/spring-app</module>
<module>prompt-registry</module>
</modules>
</profile>
<profile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,20 @@

import com.sap.ai.sdk.prompt.registry.PromptClient;
import com.sap.ai.sdk.prompt.registry.client.DefaultApi;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateDeleteResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateListResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplatePostRequest;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplatePostResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSpec;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionRequest;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionResponse;
import com.sap.ai.sdk.prompt.registry.model.SingleChatTemplate;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -12,10 +25,78 @@
@RestController
@RequestMapping("/prompt-registry")
class PromptRegistryController {
static final String NAME = "java-e2e-test";
private static final DefaultApi client = new PromptClient();

@GetMapping("/listTemplates")
PromptTemplateListResponse listTemplates() {
return client.listPromptTemplates();
}

@GetMapping("/createTemplate")
PromptTemplatePostResponse createTemplate() {
return client.createUpdatePromptTemplate(getTemplate("Finance, Tech, Sports"));
}

@GetMapping("/updateTemplate")
PromptTemplatePostResponse updateTemplate() {
// create template then update
client.createUpdatePromptTemplate(getTemplate("Finance, Tech, Sports"));
return client.createUpdatePromptTemplate(getTemplate("Finance, Tech, Sports, Politics"));
}

private PromptTemplatePostRequest getTemplate(final String categories) {
final var spec =
PromptTemplateSpec.create()
.template(
SingleChatTemplate.create()
.role("system")
.content(
"You classify input text into the two following categories: {{?categories}}"),
SingleChatTemplate.create().role("user").content("{{?inputExample}}"))
.defaults(Map.of("categories", categories));

return PromptTemplatePostRequest.create()
.name(NAME)
.version("0.0.1")
.scenario("categorization")
.spec(spec);
}

@GetMapping("/history")
PromptTemplateListResponse history() {
return client.listPromptTemplateHistory("categorization", "0.0.1", NAME);
}

@GetMapping("/importTemplate")
PromptTemplatePostResponse importTemplate() throws IOException {
final Resource template = new ClassPathResource("prompt-template.yaml");
return client.importPromptTemplate(template.getFile());
}

@GetMapping("/exportTemplate")
File exportTemplate() throws IOException {
final var template = importTemplate();
return client.exportPromptTemplate(template.getId());
}

@GetMapping("/useTemplate")
PromptTemplateSubstitutionResponse useTemplate() {
final var template = createTemplate();
return client.parsePromptTemplateById(
template.getId(),
false,
PromptTemplateSubstitutionRequest.create()
.inputParams(Map.of("inputExample", "I love football")));
}

@GetMapping("/deleteTemplate")
List<PromptTemplateDeleteResponse> deleteTemplate() {
final PromptTemplateListResponse templates = client.listPromptTemplates();

return templates.getResources().stream()
.filter(template -> NAME.equals(template.getName()))
.map(template -> client.deletePromptTemplate(template.getId()))
.toList();
}
}
11 changes: 11 additions & 0 deletions sample-code/spring-app/src/main/resources/prompt-template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: java-e2e-test
version: 0.0.1
scenario: categorization
spec:
template:
- role: 'system'
content: 'You classify input text into the two following categories: {{?categories}}'
- role: 'user'
content: '{{?inputExample}}'
defaults:
categories: Finance, Tech, Sports
72 changes: 72 additions & 0 deletions sample-code/spring-app/src/main/resources/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,78 @@ <h2>📚 Prompt Registry</h2>
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/createTemplate"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/createTemplate</code>
</button>
<div class="tooltip-content">
Create a template in the prompt registry.
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/updateTemplate"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/updateTemplate</code>
</button>
<div class="tooltip-content">
Create a template in the prompt registry then update it.
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/history"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/history</code>
</button>
<div class="tooltip-content">
Get the history of a template for a specific version only.
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/importTemplate"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/importTemplate</code>
</button>
<div class="tooltip-content">
Import a template from a YAML file.
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/useTemplate"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/useTemplate</code>
</button>
<div class="tooltip-content">
Substitute the user input param
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit"
formaction="/prompt-registry/deleteTemplate"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/prompt-registry/deleteTemplate</code>
</button>
<div class="tooltip-content">
Delete all Java templates in the prompt registry.
</div>
</div>
</li>
</ul>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.sap.ai.sdk.app.controllers;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.Assertions.assertThat;

import com.sap.ai.sdk.prompt.registry.model.PromptTemplateDeleteResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateListResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplatePostResponse;
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionResponse;
import com.sap.ai.sdk.prompt.registry.model.SingleChatTemplate;
import com.sap.ai.sdk.prompt.registry.model.Template;
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.Test;

public class PromptRegistryTest {
Expand All @@ -12,4 +20,68 @@ void listTemplates() {
var result = controller.listTemplates();
assertThat(result.getCount()).isGreaterThan(0);
}

@Test
void createDeleteTemplate() {
var controller = new PromptRegistryController();
// cleanup
controller.deleteTemplate();

// create
PromptTemplatePostResponse createdTemplate = controller.createTemplate();
assertThat(createdTemplate.getMessage()).contains("successful");
assertThat(createdTemplate.getName()).contains(PromptRegistryController.NAME);

// use template
PromptTemplateSubstitutionResponse template = controller.useTemplate();
List<Template> prompt = template.getParsedPrompt();
assertThat(prompt).hasSize(2);
SingleChatTemplate userMessage = (SingleChatTemplate) prompt.get(1);
assertThat(userMessage.getRole()).isEqualTo("user");
assertThat(userMessage.getContent()).isEqualTo("I love football");

// cleanup
List<PromptTemplateDeleteResponse> deletedTemplate = controller.deleteTemplate();
assertThat(deletedTemplate).hasSize(1);
assertThat(deletedTemplate.get(0).getMessage()).contains("successful");
}

@Test
void importExportTemplate() throws IOException {
var controller = new PromptRegistryController();
// cleanup
controller.deleteTemplate();

// import
PromptTemplatePostResponse template = controller.importTemplate();
assertThat(template.getMessage()).contains("successful");

// export TODO: NOT WORKING

// cleanup
List<PromptTemplateDeleteResponse> deletedTemplate = controller.deleteTemplate();
assertThat(deletedTemplate).hasSize(1);
assertThat(deletedTemplate.get(0).getMessage()).contains("successful");
}

@Test
void history() {
var controller = new PromptRegistryController();
// cleanup
controller.deleteTemplate();

// create + update
PromptTemplatePostResponse template = controller.updateTemplate();
assertThat(template.getMessage()).contains("successful");

// history
PromptTemplateListResponse history = controller.history();
assertThat(history.getCount()).isEqualTo(2);
assertThat(history.getResources()).hasSize(2);

// cleanup
List<PromptTemplateDeleteResponse> deletedTemplate = controller.deleteTemplate();
assertThat(deletedTemplate).hasSize(1);
assertThat(deletedTemplate.get(0).getMessage()).contains("successful");
}
}