Skip to content

Commit e498bbf

Browse files
committed
merged main and fix issues of semantic kernel 0.2.8-ALPHA
2 parents e978100 + d8b2b18 commit e498bbf

File tree

23 files changed

+332
-106
lines changed

23 files changed

+332
-106
lines changed

.devcontainer/devcontainer.json

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
{
22
"name": "Java 17 and maven 3.8.8 DevContainer to build Java RAG example with Azure AI",
3-
"image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye",
3+
"image": "mcr.microsoft.com/devcontainers/python:0-3.10",
44
"features": {
55
"azure-cli": "latest",
66
"ghcr.io/azure/azure-dev/azd:latest": {},
77
"ghcr.io/devcontainers/features/java:1": {
8-
"version": "none",
8+
"version": "17",
99
"installMaven": true,
1010
"mavenVersion": "3.8.8"
1111
},
1212
"ghcr.io/devcontainers/features/node:1": {
1313
"version": "20.5.0"
1414
},
15+
16+
"ghcr.io/devcontainers/features/git:1": {
17+
"version": "2.39.1"
18+
},
1519
"ghcr.io/devcontainers-contrib/features/typescript:2": {}
1620
},
1721
"customizations": {
@@ -21,16 +25,9 @@
2125
"ms-azuretools.azure-dev",
2226
"ms-azuretools.vscode-bicep",
2327
"vscjava.vscode-java-pack",
28+
"ms-python.python",
2429
"amodio.tsl-problem-matcher"
2530
]
2631
}
27-
},
28-
"forwardPorts": [
29-
// Forward ports if needed for local development
30-
],
31-
"postCreateCommand": "",
32-
"remoteUser": "vscode",
33-
"hostRequirements": {
34-
"memory": "8gb"
3532
}
3633
}

.github/workflows/app-ci.yaml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
2+
# More GitHub Actions for Azure: https://github.com/Azure/actions
3+
# More info on Python, GitHub Actions, and Azure App Service: https://aka.ms/python-webapps-actions
4+
5+
name: App Continuous Integration pipeline
6+
7+
on:
8+
push:
9+
branches:
10+
- app-ci-github-actions
11+
- main
12+
workflow_dispatch:
13+
14+
jobs:
15+
build:
16+
runs-on: ubuntu-latest
17+
outputs:
18+
env-name: ${{steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT}}
19+
steps:
20+
- uses: actions/checkout@v2
21+
22+
- name: Set up Java version
23+
uses: actions/setup-java@v2
24+
with:
25+
distribution: 'temurin'
26+
java-version: '17'
27+
cache: 'maven'
28+
29+
- name: Set environment for branch
30+
id: set-deploy-env
31+
run: |
32+
if [[ $GITHUB_REF_NAME == 'refs/heads/main' ]]; then
33+
echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT"
34+
elif [[ $GITHUB_REF_NAME == 'refs/heads/develop' ]]; then
35+
echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT"
36+
elif [[ $GITHUB_REF_NAME == 'refs/heads/release' ]]; then
37+
echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT"
38+
else
39+
echo "DEPLOY_ENVIRONMENT=Development" >> "$GITHUB_OUTPUT"
40+
fi
41+
- name: Build React Frontend
42+
run: |
43+
echo "Building frontend and merge into spring boot static folder. Environment [${{ steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT }}]"
44+
cd ./app/frontend
45+
npm install
46+
npm run build
47+
48+
- name: Build Spring Boot App
49+
run: |
50+
echo "Building spring boot app. Environment [${{ steps.set-deploy-env.outputs.DEPLOY_ENVIRONMENT }}]"
51+
cd ./app/backend
52+
mvn package
53+
artifactid=$(mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout)
54+
jarversion=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
55+
originaljarname="$artifactid-$jarversion.jar"
56+
echo "Renaming $originaljarname to app.jar"
57+
# Renaming jas so it is auto detected by app service
58+
mv ./target/$originaljarname ./target/app.jar
59+
60+
- name: Upload artifacts for backend deployment jobs
61+
uses: actions/upload-artifact@v2
62+
with:
63+
name: spring-boot-app
64+
path: |
65+
./app/backend/target/app.jar
66+
67+
68+
deploy:
69+
runs-on: ubuntu-latest
70+
needs: build
71+
environment:
72+
name: ${{ needs.build.outputs.env-name}}
73+
url: ${{ steps.deploy-app.outputs.webapp-url }}
74+
75+
steps:
76+
- name: Download backend artifact from build job
77+
uses: actions/download-artifact@v2
78+
with:
79+
name: spring-boot-app
80+
path: ./backend
81+
82+
- name: 'Deploy backend to Azure Web App'
83+
uses: azure/webapps-deploy@v2
84+
id: deploy-app
85+
with:
86+
app-name: ${{ vars.AZUREAPPSERVICE_APP_NAME }}
87+
package: ./backend
88+
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE}}

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# ChatGPT + Enterprise data with Azure OpenAI and Cognitive Search - Java Version
2+
[![Open in GitHub Codespaces](https://img.shields.io/static/v1?style=for-the-badge&label=GitHub+Codespaces&message=Open&color=brightgreen&logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=599293758&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestUs2)
3+
[![Open in VS Code Dev - Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Remote%20-%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/dantelmomsft/azure-search-openai-demo-java/)
4+
25
This repo is the java conversion of the well known [chatGPT + Enterprise data code sample](https://github.com/Azure-Samples/azure-search-openai-demo) originally written in python.
36
It demonstrates a few approaches for creating ChatGPT-like experiences over your own data using the Retrieval Augmented Generation pattern. It uses Azure OpenAI Service to access the ChatGPT model (gpt-35-turbo), and Azure Cognitive Search for data indexing and retrieval.
47

@@ -55,6 +58,7 @@ ReadDecomposeAsk | :x: | :soon:
5558

5659
Execute the following command, if you don't have any pre-existing Azure services and want to start from a fresh deployment.
5760

61+
1. Run `azd auth login`
5862
1. Run `azd up` - This will provision Azure resources and deploy this sample to those resources, including building the search index based on the files found in the `./data` folder.
5963
* For the target location, the regions that currently support the models used in this sample are **East US**, **France Central**, **South Central US**, **UK South**, and **West Europe**. For an up-to-date list of regions and models, check [here](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/concepts/models)
6064
1. After the application has been successfully deployed you will see a URL printed to the console. Click that URL to interact with the application in your browser.
@@ -82,6 +86,13 @@ It will look like the following:
8286
3. Run `./start.ps1` or `./start.sh` or run the "VS Code Task: Start App" to start the project locally.
8387
4. Wait for the spring boot server to start and refresh your browser to localhost:8080
8488

89+
### To Run in GitHub Codespaces or VS Code Remote Containers
90+
91+
You can run this repo virtually by using GitHub Codespaces or VS Code Remote Containers. Click on one of the buttons below to open this repo in one of those options.
92+
93+
[![Open in GitHub Codespaces](https://img.shields.io/static/v1?style=for-the-badge&label=GitHub+Codespaces&message=Open&color=brightgreen&logo=github)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=599293758&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&location=WestUs2)
94+
[![Open in VS Code Dev - Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Remote%20-%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/dantelmomsft/azure-search-openai-demo-java/)
95+
8596
### UI Navigation
8697

8798
* In Azure: navigate to the Azure WebApp deployed by azd. The URL is printed out when azd completes (as "Endpoint"), or you can find it in the Azure portal.
@@ -93,6 +104,35 @@ Once in the web app:
93104
* Explore citations and sources
94105
* Click on "settings" to try different options, tweak prompts, etc.
95106

107+
## App Continuous Integration
108+
if you don't want to use azd to build and deploy the app, a GitHub automated CI pipeline is provided in `.github/workflows/app-ci.yml`. Some notes about the CI pipeline design:
109+
- It uses a "branch per environment approach". The deploy environment name is computed at 'runtime' based on a git branch. You can check branch/env-name mapping logic in the "set environment for branch" step (line 29). The current implemented logic maps everything to a dev like environment. Therefore on each git push on the `main branch` the pipeline is triggered trying to deploy to an environment called `Development`. For more info about GitHub environments and how to set specific env variables and secrets read [here](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment).
110+
- GitHub environment variables and secrets are used to configure development environment specific configuration. They need to be configured manually in github repository settings:
111+
- `AZUREAPPSERVICE_PUBLISHPROFILE` is used to store the azure app service publish profile configuration securely.
112+
- `AZUREAPPSERVICE_APP_NAME` is used to store the azure web app resource name generated during infra arm deployment.
113+
114+
To properly configure automated build and deploy for both backend and frontend components follow below steps:
115+
116+
1. Go to your forked repository in GitHub and create an [environment]((https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment)) called 'Development' (yes this is the exact name; don't change it). If you want to change the environment name (also adding new branches and environments, change the current branch/env mapping) you can do that, but make sure to change the pipeline code accordingly in `.github/workflows/app-ci.yml` (starting line 29)
117+
2. Create 'Development' environment [secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) for the azure web app hosting both frontend and backend [publish profiles]((https://learn.microsoft.com/en-us/visualstudio/azure/how-to-get-publish-profile-from-azure-app-service?view=vs-2022)). You'll need to copy paste the xml content from the .PublishSettings file into the secret value:
118+
- Create a secret with name `AZUREAPPSERVICE_PUBLISHPROFILE` and set the Value field to publish profile of the azure web app
119+
3. Create 'Development' environment [variables](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-an-environment) for azure web app resource name:
120+
- Create a variable with name `AZUREAPPSERVICE_APP_NAME` and set the Value field to the azure web app resource name
121+
4. For each commit you push check the status of the triggered pipeline in the GitHub Actions tab, you should see a pipeline has been triggered for the specific commit. If everything is ok you should see green checkmark on both build and deploy jobs in the pipeline detail like below:
122+
123+
![pipeline success](./docs/github-actions-pipeline-success.png)
124+
125+
## Custom Data Ingestion and Indexing
126+
The repo includes sample pdf documents in the data folder. They are ingested in blob container and indexed in azure cognitive search during infra provisioning by azure developer cli post provision hooks (see line 23 in [azure.yaml](azure.yaml))
127+
128+
If you want to chat with your custom documents you can:
129+
1. Add your pdf documents in the [data folder](./data/).
130+
2. Open a terminal and cd to repo root folder. Example `cd path/to/your/custom/dir/azure-search-openai-demo-java`
131+
3. Run `./scripts/prepdocs.ps1` if you are on windows or `./scripts/prepdocs.sh` on linux
132+
4. Wait the script to complete. This is not a 'delta' process, it's not updating **only** the new files you've added. Instead on each run all documents in data folder will be ingested.Feel free to add new files you want to ingest and delete/move the old documents from the data folder. Once you've run the script and it completes successfully, cognitive search index have been updated and stored (until you want to manually delete it from your azure cognitive search instance)
133+
5. if ingestion and indexing is completed successfully you should see a message like this
134+
![prepdocs success](./docs/prepdocs-success.png)
135+
96136
## Resources
97137

98138
* [Revolutionize your Enterprise Data with ChatGPT: Next-gen Apps w/ Azure OpenAI and Cognitive Search](https://aka.ms/entgptsearchblog)

app/backend/pom.xml

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
<spring-cloud-azure.version>4.9.0</spring-cloud-azure.version>
1919
<azure-search.version>11.6.0-beta.6</azure-search.version>
2020
<azure-openai.version>1.0.0-beta.2</azure-openai.version>
21-
<semantic-kernel.version>0.2.8-alpha-SNAPSHOT</semantic-kernel.version>
21+
<semantic-kernel.version>0.2.8-alpha</semantic-kernel.version>
22+
<mockito-inline.version>4.5.1</mockito-inline.version>
2223
</properties>
2324

2425
<dependencyManagement>
@@ -30,6 +31,13 @@
3031
<type>pom</type>
3132
<scope>import</scope>
3233
</dependency>
34+
<dependency>
35+
<groupId>com.microsoft.semantic-kernel</groupId>
36+
<artifactId>semantickernel-bom</artifactId>
37+
<version>${semantic-kernel.version}</version>
38+
<scope>import</scope>
39+
<type>pom</type>
40+
</dependency>
3341
</dependencies>
3442
</dependencyManagement>
3543

@@ -44,6 +52,12 @@
4452
<artifactId>spring-boot-starter-test</artifactId>
4553
<scope>test</scope>
4654
</dependency>
55+
<dependency>
56+
<groupId>org.mockito</groupId>
57+
<artifactId>mockito-inline</artifactId>
58+
<version>${mockito-inline.version}</version>
59+
<scope>test</scope>
60+
</dependency>
4761

4862
<dependency>
4963
<groupId>com.azure</groupId>
@@ -66,6 +80,28 @@
6680
<groupId>com.azure</groupId>
6781
<artifactId>azure-storage-blob</artifactId>
6882
</dependency>
83+
84+
<!-- Semantic Kernel start-->
85+
<dependency>
86+
<groupId>com.microsoft.semantic-kernel</groupId>
87+
<artifactId>semantickernel-api</artifactId>
88+
</dependency>
89+
<dependency>
90+
<groupId>com.microsoft.semantic-kernel</groupId>
91+
<artifactId>semantickernel-core</artifactId>
92+
<!-- TODO: scope should be runtime, but VolatileMemoryStore is an issue -->
93+
<!-- <scope>runtime</scope> -->
94+
</dependency>
95+
<dependency>
96+
<groupId>com.microsoft.semantic-kernel</groupId>
97+
<artifactId>semantickernel-connectors-ai-openai</artifactId>
98+
</dependency>
99+
100+
<dependency>
101+
<groupId>com.microsoft.semantic-kernel</groupId>
102+
<artifactId>semantickernel-planners</artifactId>
103+
</dependency>
104+
<!-- Semantic Kernel end -->
69105
</dependencies>
70106

71107
<build>
@@ -77,4 +113,4 @@
77113
</plugins>
78114
</build>
79115

80-
</project>
116+
</project>

app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGApproachFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
public interface RAGApproachFactory<I,O> {
44

5-
RAGApproach<I,O> createApproach(String approachName);
5+
RAGApproach<I,O> createApproach(String approachName,RAGType ragType);
66
}

app/backend/src/main/java/com/microsoft/openai/samples/rag/approaches/RAGApproachFactorySpringBootImpl.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
@Component
1111
public class RAGApproachFactorySpringBootImpl implements RAGApproachFactory, ApplicationContextAware {
1212
private ApplicationContext applicationContext;
13-
private static String CHAT_READ_RETRIEVE_READ = "crrr";
13+
1414
private static String READ_RETRIEVE_READ = "rrr";
1515
private static String RETRIEVE_THEN_READ = "rtr";
1616

@@ -23,16 +23,18 @@ public void setApplicationContext(ApplicationContext applicationContext) {
2323
* @return
2424
*/
2525
@Override
26-
public RAGApproach createApproach(String approachName) {
26+
public RAGApproach createApproach(String approachName, RAGType ragType) {
2727

28-
if(RETRIEVE_THEN_READ.equals(approachName)) {
29-
return applicationContext.getBean(RetrieveThenReadApproach.class);
30-
} else if(CHAT_READ_RETRIEVE_READ.equals(approachName)) {
28+
if (ragType.equals(RAGType.CHAT) && READ_RETRIEVE_READ.equals(approachName)) {
3129
return applicationContext.getBean(ChatReadRetrieveReadApproach.class);
32-
} else if(READ_RETRIEVE_READ.equals(approachName)) {
33-
return applicationContext.getBean(ReadRetrieveReadApproach.class);}
34-
else {
35-
throw new IllegalArgumentException("Invalid approach name: " + approachName);
30+
31+
} else if (ragType.equals(RAGType.ASK)) {
32+
if (RETRIEVE_THEN_READ.equals(approachName))
33+
return applicationContext.getBean(RetrieveThenReadApproach.class);
34+
else if (READ_RETRIEVE_READ.equals(approachName))
35+
return applicationContext.getBean(ReadRetrieveReadApproach.class);
3636
}
37+
//if this point is reached then the combination of approach and rag type is not supported
38+
throw new IllegalArgumentException("Invalid combination for approach[%s] and rag type[%s]: ".formatted(approachName, ragType));
3739
}
3840
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.microsoft.openai.samples.rag.approaches;
2+
3+
public enum RAGType {
4+
CHAT, ASK;
5+
6+
7+
}

app/backend/src/main/java/com/microsoft/openai/samples/rag/ask/approaches/RetrieveThenReadApproach.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
import com.azure.ai.openai.models.Completions;
44
import com.azure.ai.openai.models.CompletionsOptions;
5+
import com.azure.core.util.Context;
56
import com.azure.search.documents.SearchDocument;
67
import com.azure.search.documents.models.*;
7-
import com.azure.core.util.Context;
88
import com.azure.search.documents.util.SearchPagedIterable;
99
import com.microsoft.openai.samples.rag.approaches.ContentSource;
1010
import com.microsoft.openai.samples.rag.approaches.RAGApproach;
1111
import com.microsoft.openai.samples.rag.approaches.RAGOptions;
1212
import com.microsoft.openai.samples.rag.approaches.RAGResponse;
13-
import com.microsoft.openai.samples.rag.chat.approaches.ChatReadRetrieveReadApproach;
1413
import com.microsoft.openai.samples.rag.proxy.CognitiveSearchProxy;
1514
import com.microsoft.openai.samples.rag.proxy.OpenAIProxy;
1615
import org.slf4j.Logger;
@@ -27,7 +26,6 @@
2726
@Component
2827
public class RetrieveThenReadApproach implements RAGApproach<String, RAGResponse> {
2928
private static final Logger logger = LoggerFactory.getLogger(RetrieveThenReadApproach.class);
30-
3129
private CognitiveSearchProxy cognitiveSearchProxy;
3230
private OpenAIProxy openAIProxy;
3331
public RetrieveThenReadApproach(CognitiveSearchProxy cognitiveSearchProxy, OpenAIProxy openAIProxy) {

app/backend/src/main/java/com/microsoft/openai/samples/rag/ask/approaches/semantickernel/ReadRetrieveReadApproach.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import com.microsoft.openai.samples.rag.proxy.CognitiveSearchProxy;
99
import com.microsoft.semantickernel.Kernel;
1010
import com.microsoft.semantickernel.KernelConfig;
11-
import com.microsoft.semantickernel.builders.SKBuilders;
11+
import com.microsoft.semantickernel.SKBuilders;
1212
import com.microsoft.semantickernel.orchestration.SKContext;
1313
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlanner;
1414
import com.microsoft.semantickernel.planner.sequentialplanner.SequentialPlannerRequestSettings;
@@ -90,13 +90,11 @@ public RAGResponse run(String question, RAGOptions options) {
9090

9191

9292
private Kernel buildSemanticKernel( RAGOptions options) {
93-
KernelConfig config = SKBuilders.kernelConfig()
94-
.addTextCompletionService("davinci",
95-
kernel -> SKBuilders.textCompletionService().build(this.openAIAsyncClient, gptDeploymentModelId))
96-
.build();
97-
9893
Kernel kernel = SKBuilders.kernel()
99-
.withKernelConfig(config)
94+
.withDefaultAIService(SKBuilders.textCompletionService()
95+
.setModelId(gptDeploymentModelId)
96+
.withOpenAIClient(this.openAIAsyncClient)
97+
.build())
10098
.build();
10199

102100
kernel.importSkill(new CognitiveSearchPlugin(this.cognitiveSearchProxy, buildSearchOptions(options),options), "CognitiveSearchPlugin");

0 commit comments

Comments
 (0)