Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Create sample CAP app #184

Merged
merged 34 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
35db8ef
feat: add cap app with openai chat completion
ZhongpinWang Sep 27, 2024
c8003ac
docs: add README
ZhongpinWang Sep 27, 2024
9e50c7d
refactor: entity and service name
ZhongpinWang Sep 27, 2024
5f09d1a
feat: add ai-api and orchestration
ZhongpinWang Sep 30, 2024
83646af
docs: add missing title
ZhongpinWang Sep 30, 2024
a7a5a7a
fix: use req.reply
ZhongpinWang Sep 30, 2024
65aa111
fix: remove cdsrc private
ZhongpinWang Oct 1, 2024
50a74a4
fix: deps
ZhongpinWang Oct 1, 2024
6fa1146
fix: lint
ZhongpinWang Oct 1, 2024
7f8c9f3
chore: small changes in cap gitignore
ZhongpinWang Oct 1, 2024
0b48529
docs: update README.md
ZhongpinWang Oct 1, 2024
03641d8
docs: add toc
ZhongpinWang Oct 1, 2024
dc5a3c5
docs: rename
ZhongpinWang Oct 1, 2024
9588531
fix: Changes from lint
Oct 1, 2024
efbd591
docs: small changes
ZhongpinWang Oct 1, 2024
9c3dfb0
chore: add changeset
ZhongpinWang Oct 1, 2024
50b2eab
refactor: use actions instead of entity projection
ZhongpinWang Oct 4, 2024
6bfaa16
chore: format cds
ZhongpinWang Oct 4, 2024
c86a07c
review
ZhongpinWang Oct 7, 2024
77f431b
Merge branch 'main' into feat-create-sample-cap-app
ZhongpinWang Oct 7, 2024
9b889f7
review
ZhongpinWang Oct 7, 2024
551d6b1
docs: update README.md
ZhongpinWang Oct 7, 2024
f4f71fa
fix: lint
ZhongpinWang Oct 7, 2024
88823d2
fix: lock
ZhongpinWang Oct 7, 2024
fd9b4bc
fix: remove changeset
ZhongpinWang Oct 7, 2024
e46f829
chore: remove db
ZhongpinWang Oct 7, 2024
cd0d20d
chore: return string
ZhongpinWang Oct 7, 2024
6814e8a
chore: move cap deps to sample-cap
ZhongpinWang Oct 7, 2024
c63aee9
chore: remove use less import
ZhongpinWang Oct 7, 2024
fd220a5
Merge branch 'main' into feat-create-sample-cap-app
ZhongpinWang Oct 7, 2024
dc62111
Merge branch 'main' into feat-create-sample-cap-app
ZhongpinWang Oct 8, 2024
58cdfb6
Merge branch 'main' into feat-create-sample-cap-app
ZhongpinWang Oct 9, 2024
81aa162
fix: move @cap-js/cds-types back to root package.json
ZhongpinWang Oct 9, 2024
9b1ef64
chore: remove sample cap from deps check
ZhongpinWang Oct 9, 2024
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
5 changes: 5 additions & 0 deletions .changeset/sweet-lies-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sap-ai-sdk/sample-cap': patch
---

[New Functionality] Introduce a new sample application based on SAP CAP framework.
ZhongpinWang marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"type-tests": "pnpm -F=@sap-ai-sdk/type-tests",
"smoke-tests": "pnpm -F=@sap-ai-sdk/smoke-tests",
"schema-tests": "pnpm -F=@sap-ai-sdk/schema-tests",
"sample-code": "pnpm -F=@sap-ai-sdk/sample-code",
"sample-cap": "pnpm -F=@sap-ai-sdk/sample-cap",
"check:public-api": "pnpm -r check:public-api",
"check:deps": "pnpm -r -F !./tests/smoke-tests -F !./tests/schema-tests exec depcheck --ignores=\"nock,@jest/globals\" --quiet"
},
Expand All @@ -44,6 +46,8 @@
"@sap-cloud-sdk/http-client": "^3.21.0",
"@sap-cloud-sdk/openapi-generator": "^3.21.0",
"@sap-cloud-sdk/util": "^3.21.0",
"@cap-js/cds-types": "^0.6",
ZhongpinWang marked this conversation as resolved.
Show resolved Hide resolved
"tsx": "^4.19.1",
"@types/jest": "^29.5.13",
"@types/jsonwebtoken": "^9.0.7",
"@types/mock-fs": "^4.13.4",
Expand Down
485 changes: 454 additions & 31 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
packages:
# all packages in direct subdirs of packages/
- 'packages/ai-api'
- 'packages/foundation-models'
- 'packages/orchestration'
- 'packages/core'
- 'packages/foundation-models'
- 'packages/langchain'
- 'packages/orchestration'
- 'sample-cap'
- 'sample-code'
- 'tests/e2e-tests'
- 'tests/type-tests'
- 'tests/smoke-tests'
- 'tests/schema-tests'
- 'tests/smoke-tests'
- 'tests/type-tests'
36 changes: 36 additions & 0 deletions sample-cap/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# CAP
_out
*.db
*.sqlite
connection.properties
default-*.json
.cdsrc-private.json
gen/
node_modules/
target/

# Web IDE, App Studio
.che/
.gen/

# MTA
*_mta_build_tmp
*.mtar
mta_archives/

# Other
.DS_Store
*.orig
*.log

*.iml
*.flattened-pom.xml

# IDEs
.vscode
.idea

# @cap-js/cds-typer
@cds-models

.cdsrc-private.json
85 changes: 85 additions & 0 deletions sample-cap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Sample CAP Application with SAP Cloud SDK for AI

Sample CAP application written in TypeScript to demonstrate the usage of SAP Cloud SDK for AI.

### Table of Contents

- [Local Deployment](#local-deployment)
- [Usage](#usage)
- [`ai-api`](#ai-api)
- [Deployment API](#deployment-api)
- [`foundation-models`](#foundation-models)
- [Azure OpenAI Chat Completion](#azure-openai-chat-completion)
- [`orchestration`](#orchestration)
- [Chat Completions with Templating](#chat-completions-with-templating)

## Local Deployment

1. Build the application with `pnpm install`.

2. Login using `cf login -a API_ENDPOINT -o ORG -s SPACE`.

3. Bind the application to your AI Core instance:

```bash
cds bind -2 AI_CORE_INSTANCE_NAME
```

4. Run the application with the binding:

```bash
pnpm watch:hybrid
```

## Usage

### `ai-api`

#### Deployment API

```bash
curl --request GET \
--url 'http://localhost:4004/odata/v4/ai-api/getDeployments'
```

### `foundation-models`

#### Azure OpenAI Chat Completion

```bash
curl --request POST \
--url 'http://localhost:4004/odata/v4/azure-openai/chatCompletion' \
--header 'Content-Type: application/json' \
--data '{
"messages": [
{
"role": "user",
"content": "Hello, how are you?"
}
]
}'
```

### `orchestration`

#### Chat Completions with Templating

```bash
curl --request POST \
--url 'http://localhost:4004/odata/v4/orchestration/chatCompletion' \
--header 'Content-Type: application/json' \
--data '{
"template": [
{
"role": "user",
"content": "What is the capital of {{?country}}"
}
],
"inputParams": [
{
"name": "country",
"value": "France"
}
]
}'
```
Empty file added sample-cap/db/.gitkeep
ZhongpinWang marked this conversation as resolved.
Show resolved Hide resolved
Empty file.
2 changes: 2 additions & 0 deletions sample-cap/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import cds from '@sap/cds/eslint.config.mjs';
export default [...cds.recommended];
8 changes: 8 additions & 0 deletions sample-cap/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"moduleResolution": "nodenext",
"paths": {
"#cds-models/*": ["./@cds-models/*"]
}
}
}
25 changes: 25 additions & 0 deletions sample-cap/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"type": "module",
"name": "@sap-ai-sdk/sample-cap",
"version": "1.0.0",
"description": "Sample CAP application with Cloud SDK for AI.",
"repository": "https://github.com/sap/ai-sdk-js",
"license": "UNLICENSED",
ZhongpinWang marked this conversation as resolved.
Show resolved Hide resolved
"private": true,
"dependencies": {
"@sap/cds": "^8",
"express": "^4",
"@sap-ai-sdk/ai-api": "workspace:^",
"@sap-ai-sdk/foundation-models": "workspace:^",
"@sap-ai-sdk/orchestration": "workspace:^"
},
"scripts": {
"watch": "cds-tsx watch",
"watch:hybrid": "cds-tsx watch --profile hybrid",
"lint": "eslint . && prettier . --config ../.prettierrc --ignore-path ../.prettierignore -c",
"lint:fix": "eslint . --fix && prettier . --config ../.prettierrc --ignore-path ../.prettierignore -w --log-level error"
},
"imports": {
"#cds-models/*": "./@cds-models/*/index.js"
}
}
5 changes: 5 additions & 0 deletions sample-cap/srv/ai-api/ai-api-service.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@path: 'ai-api'
service AiApiService {
// Technically, it should return an array of AiDeployment entity if we define it in the model.
ZhongpinWang marked this conversation as resolved.
Show resolved Hide resolved
action getDeployments() returns array of String;
}
11 changes: 11 additions & 0 deletions sample-cap/srv/ai-api/ai-api-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DeploymentApi } from '@sap-ai-sdk/ai-api';

export default class AiApiService {
async getDeployments() {
const response = await DeploymentApi.deploymentQuery(
{},
{ 'AI-Resource-Group': 'default' }
).execute();
return response.resources;
}
}
9 changes: 9 additions & 0 deletions sample-cap/srv/foundation-models/azure-openai-service.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@path: 'azure-openai'
service AzureOpenAiService {
action chatCompletion(messages : array of Message) returns String;
}

type Message {
role : String;
content : String;
}
12 changes: 12 additions & 0 deletions sample-cap/srv/foundation-models/azure-openai-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Request } from '@sap/cds';
import { AzureOpenAiChatClient } from '@sap-ai-sdk/foundation-models';

export default class AzureOpenAiService {
async chatCompletion(req: Request) {
const { messages } = req.data;
const response = await new AzureOpenAiChatClient('gpt-35-turbo').run({
messages
});
return response.getContent();
}
}
3 changes: 3 additions & 0 deletions sample-cap/srv/index.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using from './foundation-models/azure-openai-service';
using from './ai-api/ai-api-service';
using from './orchestration/orchestration-service';
14 changes: 14 additions & 0 deletions sample-cap/srv/orchestration/orchestration-service.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@path: 'orchestration'
service OrchestrationService {
action chatCompletion(template : array of Template, inputParams : array of InputParam) returns String;
}

type Template {
role : String;
content : String;
}

type InputParam {
name : String;
value : String;
}
51 changes: 51 additions & 0 deletions sample-cap/srv/orchestration/orchestration-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Request } from '@sap/cds';
import { OrchestrationClient } from '@sap-ai-sdk/orchestration';

export default class OrchestrationService {
async chatCompletion(req: Request) {
const { template, inputParams } = req.data;
const llm = {
model_name: 'gpt-4-32k',
model_params: {}
};
const templating = { template };

const response = await new OrchestrationClient({
llm,
templating
}).chatCompletion({
inputParams: mapInputParams(inputParams)
});

return response.getContent();
}
}

/**
* Map input parameters since CAP does not support dynamic object keys.
*
* For example:
*
* ```ts
* inputParams: [{
* name: 'param1',
* value: 'value1'
* }]
* ```
* =>
* ```ts
* mappedInputParams: {
* param1: 'value1'
* }
* ```
* @param inputParams - Array of `InputParam` entity.
* @returns Mapped input parameters for AI Core.
*/
function mapInputParams(
inputParams: { name: string; value: string }[]
): Record<string, string> {
return inputParams.reduce(
(acc, { name, value }) => ({ ...acc, [name]: value }),
{} as Record<string, string>
);
}