code-gen-react-ui (#417)

* CodeGen: Manifest to deploy CodeGen with ReactUI into Kubernetes

Include manifest to deploy CodeGen pipeline with ReactUI into
Kubernetes. Include as well README file for the steps.

Signed-off-by: Yeoh, Hoong Tee <hoong.tee.yeoh@intel.com>

* code-gen-react-ui

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* made changes as per PR suggestions

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* updated readme

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* update base image

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* updated codegn dockerfile react

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* updated wait time

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* updated as per PR comments

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* aded react ui in gaudi test file

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* fixed PR comments

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* added docker pull for text-generation-model

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

* removed unused files

Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>

---------

Signed-off-by: Yeoh, Hoong Tee <hoong.tee.yeoh@intel.com>
Signed-off-by: jaswanth8888 <karani.jaswanth@gmail.com>
Co-authored-by: Yeoh, Hoong Tee <hoong.tee.yeoh@intel.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: chen, suyue <suyue.chen@intel.com>
This commit is contained in:
Jaswanth Karani
2024-07-24 21:31:16 +05:30
committed by GitHub
parent 8c4a2534c1
commit 1b48e54a3d
51 changed files with 1513 additions and 4 deletions

View File

@@ -55,6 +55,9 @@ for MEGA_SVC in $1; do
if [ "$MEGA_SVC" == "ChatQnA" ];then if [ "$MEGA_SVC" == "ChatQnA" ];then
docker_build ${IMAGE_NAME}-conversation-ui docker/Dockerfile.react docker_build ${IMAGE_NAME}-conversation-ui docker/Dockerfile.react
fi fi
if [ "$MEGA_SVC" == "CodeGen" ];then
docker_build ${IMAGE_NAME}-react-ui docker/Dockerfile.react
fi
;; ;;
"VisualQnA") "VisualQnA")
echo "Not supported yet" echo "Not supported yet"

View File

@@ -1,4 +1,8 @@
FROM node as vite-app # Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Use node 20.11.1 as the base image
FROM node:20.11.1 as vite-app
COPY . /usr/app COPY . /usr/app
WORKDIR /usr/app/react WORKDIR /usr/app/react

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -38,11 +38,21 @@ cd GenAIExamples/CodeGen/docker/ui/
docker build -t opea/codegen-ui:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f ./docker/Dockerfile . docker build -t opea/codegen-ui:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f ./docker/Dockerfile .
``` ```
### 5. Build the React UI Docker Image
Construct the React frontend Docker image via the command below:
```bash
cd GenAIExamples/CodeGen/docker/ui/
docker build -t opea/codegen-react-ui:latest --build-arg BACKEND_SERVICE_ENDPOINT=$BACKEND_SERVICE_ENDPOINT -f ./docker/Dockerfile.react .
```
Then run the command `docker images`, you will have the following 3 Docker images: Then run the command `docker images`, you will have the following 3 Docker images:
- `opea/llm-tgi:latest` - `opea/llm-tgi:latest`
- `opea/codegen:latest` - `opea/codegen:latest`
- `opea/codegen-ui:latest` - `opea/codegen-ui:latest`
- `opea/codegen-react-ui:latest`
## 🚀 Start MicroServices and MegaService ## 🚀 Start MicroServices and MegaService
@@ -143,12 +153,12 @@ export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY=ls_... export LANGCHAIN_API_KEY=ls_...
``` ```
## 🚀 Launch the UI ## 🚀 Launch the Svelte Based UI
To access the frontend, open the following URL in your browser: `http://{host_ip}:5173`. By default, the UI runs on port 5173 internally. If you prefer to use a different host port to access the frontend, you can modify the port mapping in the `docker_compose.yaml` file as shown below: To access the frontend, open the following URL in your browser: `http://{host_ip}:5173`. By default, the UI runs on port 5173 internally. If you prefer to use a different host port to access the frontend, you can modify the port mapping in the `docker_compose.yaml` file as shown below:
```yaml ```yaml
codegen-xeon-ui-server: codegen-gaudi-ui-server:
image: opea/codegen-ui:latest image: opea/codegen-ui:latest
... ...
ports: ports:
@@ -157,6 +167,20 @@ To access the frontend, open the following URL in your browser: `http://{host_ip
![project-screenshot](../../assets/img/codeGen_ui_init.jpg) ![project-screenshot](../../assets/img/codeGen_ui_init.jpg)
## 🚀 Launch the React Based UI
To access the frontend, open the following URL in your browser: `http://{host_ip}:5174`. By default, the UI runs on port 5174 internally. If you prefer to use a different host port to access the frontend, you can modify the port mapping in the `docker_compose.yaml` file as shown below:
```yaml
codegen-gaudi-react-ui-server:
image: opea/codegen-react-ui:latest
...
ports:
- "80:5174"
```
![project-screenshot](../../assets/img/codegen_react.png)
## Install Copilot VSCode extension from Plugin Marketplace as the frontend ## Install Copilot VSCode extension from Plugin Marketplace as the frontend
In addition to the Svelte UI, users can also install the Copilot VSCode extension from the Plugin Marketplace as the frontend. In addition to the Svelte UI, users can also install the Copilot VSCode extension from the Plugin Marketplace as the frontend.

View File

@@ -72,6 +72,19 @@ services:
ipc: host ipc: host
restart: always restart: always
codegen-gaudi-react-ui-server:
image: opea/codegen-react-ui:latest
container_name: codegen-gaudi-react-ui-server
depends_on:
- codegen-gaudi-backend-server
ports:
- "5174:80"
build:
args:
- BACKEND_SERVICE_ENDPOINT=${BACKEND_SERVICE_ENDPOINT}
ipc: host
restart: always
networks: networks:
default: default:
driver: bridge driver: bridge

View File

@@ -0,0 +1,24 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Use node 20.11.1 as the base image
FROM node:20.11.1 as vite-app
COPY . /usr/app
WORKDIR /usr/app/react
ARG BACKEND_SERVICE_ENDPOINT
ENV VITE_CODE_GEN_URL=$BACKEND_SERVICE_ENDPOINT
RUN ["npm", "install"]
RUN ["npm", "run", "build"]
FROM nginx:alpine
EXPOSE 80
COPY --from=vite-app /usr/app/react/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=vite-app /usr/app/react/dist /usr/share/nginx/html
ENTRYPOINT ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1 @@
VITE_CODE_GEN_URL=http://ip_address:7778/v1/codegen

View File

@@ -0,0 +1,11 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react-hooks/recommended"],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
},
};

24
CodeGen/docker/ui/react/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,25 @@
<h1 align="center" id="title">Code Gen</h1>
### 📸 Project Screenshots
![project-screenshot](../../../assets/img/codegen_ui_react.png)
<h2>🧐 Features</h2>
Here're some of the project's features:
- Generate code: generate the corresponding code based on the current user's input.
<h2>🛠️ Get it Running:</h2>
1. Clone the repo.
2. cd command to the current folder.
3. Modify the required .env variables.
```
VITE_CODE_GEN_URL = ''
```
4. Execute `npm install` to install the corresponding dependencies.
5. Execute `npm run dev` in both environments

View File

@@ -0,0 +1,18 @@
<!--
Copyright (C) 2024 Intel Corporation
SPDX-License-Identifier: Apache-2.0
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/opea-icon-color.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Conversations UI</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -0,0 +1,20 @@
server {
listen 80;
gzip on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types font/woff2 text/css application/javascript application/json application/font-woff application/font-tff image/gif image/png image/svg+xml application/octet-stream;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
location ~* \.(gif|jpe?g|png|webp|ico|svg|css|js|mp4|woff2)$ {
expires 1d;
}
}
}

View File

@@ -0,0 +1,51 @@
{
"name": "ui",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"test": "vitest"
},
"dependencies": {
"@mantine/core": "^7.10.0",
"@mantine/hooks": "^7.10.0",
"@mantine/notifications": "^7.10.2",
"@microsoft/fetch-event-source": "^2.0.1",
"@reduxjs/toolkit": "^2.2.5",
"@tabler/icons-react": "^3.5.0",
"axios": "^1.7.2",
"luxon": "^3.4.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0",
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.0"
},
"devDependencies": {
"@testing-library/react": "^16.0.0",
"@types/luxon": "^3.4.2",
"@types/node": "^20.12.12",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react-syntax-highlighter": "^15.5.13",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"jsdom": "^24.1.0",
"postcss": "^8.4.38",
"postcss-preset-mantine": "^1.15.0",
"postcss-simple-vars": "^7.0.1",
"sass": "1.64.2",
"typescript": "^5.2.2",
"vite": "^5.2.13",
"vitest": "^1.6.0"
}
}

View File

@@ -0,0 +1,14 @@
module.exports = {
plugins: {
"postcss-preset-mantine": {},
"postcss-simple-vars": {
variables: {
"mantine-breakpoint-xs": "36em",
"mantine-breakpoint-sm": "48em",
"mantine-breakpoint-md": "62em",
"mantine-breakpoint-lg": "75em",
"mantine-breakpoint-xl": "88em",
},
},
},
};

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "./styles/styles";
.root {
@include flex(row, nowrap, flex-start, flex-start);
}
.layout-wrapper {
@include absolutes;
display: grid;
width: 100%;
height: 100%;
grid-template-columns: 80px auto;
grid-template-rows: 1fr;
}
/* ===== Scrollbar CSS ===== */
/* Firefox */
* {
scrollbar-width: thin;
scrollbar-color: #d6d6d6 #ffffff;
}
/* Chrome, Edge, and Safari */
*::-webkit-scrollbar {
width: 8px;
}
*::-webkit-scrollbar-track {
background: #ffffff;
}
*::-webkit-scrollbar-thumb {
background-color: #d6d6d6;
border-radius: 16px;
border: 4px double #dedede;
}

View File

@@ -0,0 +1,32 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import "./App.scss"
import { MantineProvider } from "@mantine/core"
import '@mantine/notifications/styles.css';
import { SideNavbar, SidebarNavList } from "./components/sidebar/sidebar"
import { IconMessages } from "@tabler/icons-react"
import { Notifications } from '@mantine/notifications';
import CodeGen from "./components/CodeGen/CodeGen";
const title = "Code Gen"
const navList: SidebarNavList = [
{ icon: IconMessages, label: title }
]
function App() {
return (
<MantineProvider>
<Notifications position="top-right" />
<div className="layout-wrapper">
<SideNavbar navList={navList} />
<div className="content">
<CodeGen />
</div>
</div>
</MantineProvider>
)
}
export default App

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import { describe, expect, test } from "vitest";
import { getCurrentTimeStamp, uuidv4 } from "../common/util";
describe("unit tests", () => {
test("check UUID is of length 36", () => {
expect(uuidv4()).toHaveLength(36);
});
test("check TimeStamp generated is of unix", () => {
expect(getCurrentTimeStamp()).toBe(Math.floor(Date.now() / 1000));
});
});

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="800px" height="800px" viewBox="0 0 800 800" style="enable-background:new 0 0 800 800;" xml:space="preserve">
<style type="text/css">
.Drop_x0020_Shadow{fill:none;}
.Outer_x0020_Glow_x0020_5_x0020_pt{fill:none;}
.Blue_x0020_Neon{fill:none;stroke:#8AACDA;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;}
.Chrome_x0020_Highlight{fill:url(#SVGID_1_);stroke:#FFFFFF;stroke-width:0.3629;stroke-miterlimit:1;}
.Jive_GS{fill:#FFDD00;}
.Alyssa_GS{fill:#A6D0E4;}
.st0{fill:#FF6900;}
.st1{fill:#FFB500;}
.st2{fill:#FFFFFF;}
</style>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-1640" y1="-1640" x2="-1640" y2="-1641">
<stop offset="0" style="stop-color:#656565"/>
<stop offset="0.618" style="stop-color:#1B1B1B"/>
<stop offset="0.6292" style="stop-color:#545454"/>
<stop offset="0.9831" style="stop-color:#3E3E3E"/>
</linearGradient>
<g>
<polygon points="400,0 737.5,181.7 607.3,252.8 269.7,71.1 "/>
<path d="M708.3,414.7l29.2,15.7l-130.3,71.1l-44.9-24.2v-31.7l40,21.5c1.5,0.8,3.2,1.2,4.9,1.2c1.7,0,3.4-0.4,5-1.3l0,0
L708.3,414.7z"/>
<path d="M557.3,532.1c-0.1-0.1-0.3-0.1-0.4-0.2l0,0l-34.2-18.4l31.2-17l42.9,23.1v169.9l-34.5-18.6V541
C562.4,537.3,560.4,533.9,557.3,532.1z"/>
<polygon points="410.4,381.3 541.6,309.7 541.6,479.5 410.4,551.2 "/>
<path d="M258.4,88.5l338.6,182.3v169.9l-34.5-18.6V292.2c0-3.7-1.9-7-5.1-8.9c-0.1-0.1-0.3-0.1-0.4-0.2l0,0L258.4,122.3V88.5z"/>
<polygon points="192.7,110.6 530.3,292.3 400,363.4 62.5,181.6 "/>
<polygon points="51.1,369 51.1,199 389.6,381.3 389.6,551.3 96.6,393.5 "/>
<path d="M91.7,414.4l303.4,163.3c1.5,0.8,3.2,1.2,4.9,1.2c1.7,0,3.4-0.4,5-1.3l0,0l96.1-52.4l29.2,15.7L400,612.1L62.5,430.4
L91.7,414.4z"/>
<polygon points="51.1,447.8 389.6,630.1 389.6,800 51.1,617.7 "/>
<polygon points="541.6,728.3 410.4,799.9 410.4,630 541.6,558.4 "/>
<polygon points="748.9,617.7 617.6,689.3 617.6,519.5 748.9,447.9 "/>
<polygon points="748.9,369 617.6,440.6 617.6,270.7 748.9,199.1 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 28.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="800px" height="800px" viewBox="0 0 800 800" style="enable-background:new 0 0 800 800;" xml:space="preserve">
<style type="text/css">
.Drop_x0020_Shadow{fill:none;}
.Outer_x0020_Glow_x0020_5_x0020_pt{fill:none;}
.Blue_x0020_Neon{fill:none;stroke:#8AACDA;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;}
.Chrome_x0020_Highlight{fill:url(#SVGID_1_);stroke:#FFFFFF;stroke-width:0.3629;stroke-miterlimit:1;}
.Jive_GS{fill:#FFDD00;}
.Alyssa_GS{fill:#A6D0E4;}
.st0{fill:#FF6900;}
.st1{fill:#FFB500;}
.st2{fill:#FFFFFF;}
</style>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-820" y1="-1640" x2="-820" y2="-1641">
<stop offset="0" style="stop-color:#656565"/>
<stop offset="0.618" style="stop-color:#1B1B1B"/>
<stop offset="0.6292" style="stop-color:#545454"/>
<stop offset="0.9831" style="stop-color:#3E3E3E"/>
</linearGradient>
<g>
<polygon class="st0" points="400,0 737.5,181.7 607.3,252.8 269.7,71.1 "/>
<path class="st1" d="M708.3,414.7l29.2,15.7l-130.3,71.1l-44.9-24.2v-31.7l40,21.5c1.5,0.8,3.2,1.2,4.9,1.2c1.7,0,3.4-0.4,5-1.3
l0,0L708.3,414.7z"/>
<path class="st1" d="M557.3,532.1c-0.1-0.1-0.3-0.1-0.4-0.2l0,0l-34.2-18.4l31.2-17l42.9,23.1v169.9l-34.5-18.6V541
C562.4,537.3,560.4,533.9,557.3,532.1z"/>
<polygon class="st1" points="410.4,381.3 541.6,309.7 541.6,479.5 410.4,551.2 "/>
<path class="st0" d="M258.4,88.5l338.6,182.3v169.9l-34.5-18.6V292.2c0-3.7-1.9-7-5.1-8.9c-0.1-0.1-0.3-0.1-0.4-0.2l0,0
L258.4,122.3V88.5z"/>
<polygon class="st1" points="192.7,110.6 530.3,292.3 400,363.4 62.5,181.6 "/>
<polygon class="st1" points="51.1,369 51.1,199 389.6,381.3 389.6,551.3 96.6,393.5 "/>
<path class="st0" d="M91.7,414.4l303.4,163.3c1.5,0.8,3.2,1.2,4.9,1.2c1.7,0,3.4-0.4,5-1.3l0,0l96.1-52.4l29.2,15.7L400,612.1
L62.5,430.4L91.7,414.4z"/>
<polygon class="st0" points="51.1,447.8 389.6,630.1 389.6,800 51.1,617.7 "/>
<polygon class="st0" points="541.6,728.3 410.4,799.9 410.4,630 541.6,558.4 "/>
<polygon class="st1" points="748.9,617.7 617.6,689.3 617.6,519.5 748.9,447.9 "/>
<polygon class="st0" points="748.9,369 617.6,440.6 617.6,270.7 748.9,199.1 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,8 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import axios from "axios";
//add iterceptors to add any request headers
export default axios;

View File

@@ -0,0 +1,12 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
export const getCurrentTimeStamp = () => {
return Math.floor(Date.now() / 1000);
};
export const uuidv4 = () => {
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) =>
(+c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))).toString(16),
);
};

View File

@@ -0,0 +1,135 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import { KeyboardEventHandler, SyntheticEvent, useEffect, useRef, useState } from 'react'
import styleClasses from "./codeGen.module.scss"
import { ActionIcon, Textarea, Title, rem } from '@mantine/core'
import { IconArrowRight } from '@tabler/icons-react'
import { ConversationMessage } from '../Message/conversationMessage'
import { fetchEventSource } from '@microsoft/fetch-event-source'
import { CODE_GEN_URL } from '../../config'
const CodeGen = () => {
const [prompt, setPrompt] = useState<string>("")
const [submittedPrompt, setSubmittedPrompt] = useState<string>("")
const [response,setResponse] = useState<string>("");
const promptInputRef = useRef<HTMLTextAreaElement>(null)
const scrollViewport = useRef<HTMLDivElement>(null)
const toSend = "Enter"
const handleSubmit = async () => {
setResponse("")
setSubmittedPrompt(prompt)
const body = {
messages:prompt
}
fetchEventSource(CODE_GEN_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept":"*/*"
},
body: JSON.stringify(body),
openWhenHidden: true,
async onopen(response) {
if (response.ok) {
return;
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
const e = await response.json();
console.log(e);
throw Error(e.error.message);
} else {
console.log("error", response);
}
},
onmessage(msg) {
if (msg?.data != "[DONE]") {
try {
const match = msg.data.match(/b'([^']*)'/);
if (match && match[1] != "</s>") {
const extractedText = match[1].replace(/\\n/g, "\n");
setResponse(prev=>prev+extractedText);
}
} catch (e) {
console.log("something wrong in msg", e);
throw e;
}
}
},
onerror(err) {
console.log("error", err);
setResponse("")
throw err;
},
onclose() {
setPrompt("")
},
});
}
const scrollToBottom = () => {
scrollViewport.current!.scrollTo({ top: scrollViewport.current!.scrollHeight })
}
useEffect(() => {
scrollToBottom()
}, [response])
const handleKeyDown: KeyboardEventHandler = (event) => {
if (!event.shiftKey && event.key === toSend) {
handleSubmit()
setTimeout(() => {
setPrompt("")
}, 1)
}
}
const handleChange = (event: SyntheticEvent) => {
event.preventDefault()
setPrompt((event.target as HTMLTextAreaElement).value)
}
return (
<div className={styleClasses.codeGenWrapper}>
<div className={styleClasses.codeGenContent}>
<div className={styleClasses.codeGenContentMessages}>
<div className={styleClasses.codeGenTitle}>
<Title order={3}>CodeGen</Title>
</div>
<div className={styleClasses.historyContainer} ref={scrollViewport}>
{submittedPrompt && (
<ConversationMessage key={`_ai`} date={Date.now()} human={true} message={submittedPrompt} />
)}
{response && (
<ConversationMessage key={`_ai`} date={Date.now()} human={false} message={response} />
)}
</div>
<div className={styleClasses.codeGenActions}>
<Textarea
radius="xl"
size="md"
placeholder="Ask a question"
ref={promptInputRef}
onKeyDown={handleKeyDown}
onChange={handleChange}
value={prompt}
rightSectionWidth={42}
rightSection={
<ActionIcon onClick={handleSubmit} size={32} radius="xl" variant="filled">
<IconArrowRight style={{ width: rem(18), height: rem(18) }} stroke={1.5} />
</ActionIcon>
}
// {...props}
/>
</div>
</div>
</div>
</div >
)
}
export default CodeGen;

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "../../styles/styles";
.spacer {
flex: 1 1 auto;
}
.codeGenWrapper {
@include flex(row, nowrap, flex-start, flex-start);
flex: 1 1 auto;
height: 100%;
& > * {
height: 100%;
}
.codeGenContent {
flex: 1 1 auto;
position: relative;
.codeGenContentMessages {
@include absolutes;
// @include flex(column, nowrap, flex-start, flex-start);
display: grid;
grid-template-areas:
"header"
"messages"
"inputs";
grid-template-columns: auto;
grid-template-rows: 60px auto 100px;
.codeGenTitle {
grid-area: header;
@include flex(row, nowrap, center, flex-start);
height: 60px;
padding: 8px 24px;
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
.historyContainer {
grid-area: messages;
overflow: auto;
width: 100%;
padding: 16px 32px;
& > * {
width: 100%;
}
}
.codeGenActions {
// padding: --var()
grid-area: inputs;
padding: 18px;
border-top: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
}
}
}

View File

@@ -0,0 +1,15 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "../../styles/styles";
.conversationMessage {
@include flex(column, nowrap, flex-start, flex-start);
margin-top: 16px;
padding: 0 32px;
width: 100%;
& > * {
width: 100%;
}
}

View File

@@ -0,0 +1,41 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import { IconAi, IconUser } from "@tabler/icons-react"
import style from "./conversationMessage.module.scss"
import { Group, Text } from "@mantine/core"
import { DateTime } from "luxon"
import Markdown from "../Shared/Markdown/Markdown"
export interface ConversationMessageProps {
message: string
human: boolean
date: number
}
export function ConversationMessage({ human, message, date }: ConversationMessageProps) {
const dateFormat = () => {
return DateTime.fromJSDate(new Date(date)).toLocaleString(DateTime.DATETIME_MED)
}
return (
<div className={style.conversationMessage}>
<Group>
{human && <IconUser />}
{!human && <IconAi />}
<div>
<Text size="sm">
{human && "You"} {!human && "Assistant"}
</Text>
<Text size="xs" c="dimmed">
{dateFormat()}
</Text>
</div>
</Group>
<Text pl={54} pt="sm" size="sm">
{human? message : (<Markdown content={message}/>)}
</Text>
</div>
)
}

View File

@@ -0,0 +1,52 @@
import styles from './codeRender.module.scss'
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism";
import { IconCopy } from '@tabler/icons-react';
import { Button, CopyButton } from '@mantine/core';
type CodeRenderProps = {
cleanCode: React.ReactNode,
language: string,
inline: boolean
}
const CodeRender = ({ cleanCode, language, inline }:CodeRenderProps) => {
cleanCode = String(cleanCode).replace(/\n$/, '').replace(/^\s*[\r\n]/gm, '') //right trim and remove empty lines from the input
console.log(styles)
try {
return inline ? (<code className='inline-code'><i>{cleanCode}</i></code>) : (
<div className={styles.code}>
<div className={styles.codeHead}>
<div className='code-title'>
{language || "language not detected"}
</div>
<div className={styles.codeActionGroup} >
<CopyButton value={cleanCode.toString()}>
{({ copied, copy }) => (
<Button color={copied ? 'teal' : 'blue'} styles={{root:{border:"none"}}} leftSection={<IconCopy size={12} />} onClick={copy}>
{copied ? 'Copied' : 'Copy'}
</Button>
)}
</CopyButton>
</div>
</div>
<SyntaxHighlighter
className={styles.codeHighlighterDiv}
children={cleanCode.toString()}
wrapLongLines={true}
style={tomorrow}
language={language}
PreTag="div"
/>
</div>)
} catch (err) {
return (
<pre>
{cleanCode}
</pre>
)
}
}
export default CodeRender;

View File

@@ -0,0 +1,23 @@
@import "../../../styles/styles";
.code {
margin: 7px 0px;
.codeHead {
background: #379af1;
padding: 0px 10px !important;
@include flex(row, nowrap, center, space-between);
.codeTitle {
}
.codeActionGroup {
@include flex(row, nowrap, center, flex-start);
}
}
.codeHighlighterDiv {
margin: 0px !important;
}
}
.inlineCode {
background: #d7d7d7;
}

View File

@@ -0,0 +1,62 @@
import markdownStyles from './markdown.module.scss'
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import remarkFrontmatter from 'remark-frontmatter';
// import Mermaid from '../../shared/Mermaid/Mermaid';
import CodeRender from '../CodeRender/CodeRender';
type MarkdownProps = {
content: string
}
const Markdown = ({ content }: MarkdownProps) => {
return (
<ReactMarkdown
children={content}
className={markdownStyles.md}
remarkPlugins={[remarkGfm, remarkFrontmatter]}
components={{
p: ({ children, ...props }) => {
return (
<p {...props} style={{ whiteSpace: "pre-wrap" }}>
{children}
</p>
);
},
a: ({ children, ...props }) => {
return (
<a
href={props.href}
target="_blank"
rel="noopener noreferrer"
{...props}
>
{children}
</a>
);
},
table: ({ children, ...props }) => {
return (
<div
className={markdownStyles.tableDiv}
style={{
overflowX: "auto",
padding: "10px",
}}
>
<table {...props}>{children}</table>
</div>
);
},
//@ts-expect-error inline can undefined sometimes
code({ inline, className, children, }) {
const lang = /language-(\w+)/.exec(className || '')
// if (lang && lang[1] === "mermaid") {
// return <Mermaid content={String(children).replace(/\n$/, '')} key={"id"} />
// }
return <CodeRender cleanCode={children} inline={inline} language={(lang && lang[1]) || ""} />
}
}}
/>)
}
export default Markdown;

View File

@@ -0,0 +1,14 @@
.tableDiv {
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
}
.md {
li {
margin-left: 35px; /* Adjust the value based on your preference */
}
}

View File

@@ -0,0 +1,84 @@
/**
Copyright (c) 2024 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
@import "../../styles/styles";
.navbar {
width: 100%;
@include flex(column, nowrap, center, flex-start);
padding: var(--mantine-spacing-md);
background-color: var(--mantine-color-blue-filled);
// background-color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-6));
// border-right: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
}
.navbarMain {
flex: 1;
}
.navbarLogo {
width: 100%;
display: flex;
justify-content: center;
padding-top: var(--mantine-spacing-md);
margin-bottom: var(--mantine-spacing-xl);
}
.link {
width: 44px;
height: 44px;
border-radius: var(--mantine-radius-md);
display: flex;
align-items: center;
justify-content: center;
color: var(--mantine-color-white);
&:hover {
background-color: var(--mantine-color-blue-7);
}
&[data-active] {
&,
&:hover {
box-shadow: var(--mantine-shadow-sm);
background-color: var(--mantine-color-white);
color: var(--mantine-color-blue-6);
}
}
}
.aside {
flex: 0 0 60px;
background-color: var(--mantine-color-body);
display: flex;
flex-direction: column;
align-items: center;
border-right: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
}
.logo {
width: 100%;
display: flex;
justify-content: center;
height: 60px;
padding-top: var(--mantine-spacing-s);
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
margin-bottom: var(--mantine-spacing-xl);
}
.logoImg {
width: 30px;
}

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import { useState } from "react"
import { Tooltip, UnstyledButton, Stack, rem } from "@mantine/core"
import { IconHome2 } from "@tabler/icons-react"
import classes from "./sidebar.module.scss"
import OpeaLogo from "../../assets/opea-icon-color.svg"
interface NavbarLinkProps {
icon: typeof IconHome2
label: string
active?: boolean
onClick?(): void
}
function NavbarLink({ icon: Icon, label, active, onClick }: NavbarLinkProps) {
return (
<Tooltip label={label} position="right" transitionProps={{ duration: 0 }}>
<UnstyledButton onClick={onClick} className={classes.link} data-active={active || undefined}>
<Icon style={{ width: rem(20), height: rem(20) }} stroke={1.5} />
</UnstyledButton>
</Tooltip>
)
}
export interface SidebarNavItem {
icon: typeof IconHome2
label: string
}
export type SidebarNavList = SidebarNavItem[]
export interface SideNavbarProps {
navList: SidebarNavList
}
export function SideNavbar({ navList }: SideNavbarProps) {
const [active, setActive] = useState(0)
const links = navList.map((link, index) => (
<NavbarLink {...link} key={link.label} active={index === active} onClick={() => setActive(index)} />
))
return (
<nav className={classes.navbar}>
<div className={classes.navbarLogo}>
<img className={classes.logoImg} src={OpeaLogo} alt="opea logo" />
</div>
<div className={classes.navbarMain}>
<Stack justify="center" gap={0}>
{links}
</Stack>
</div>
</nav>
)
}

View File

@@ -0,0 +1,4 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
export const CODE_GEN_URL = import.meta.env.VITE_CODE_GEN_URL;

View File

@@ -0,0 +1,20 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "@mantine/core/styles.css";
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
html,
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}

View File

@@ -0,0 +1,13 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import React from "react"
import ReactDOM from "react-dom/client"
import App from "./App.tsx"
import "./index.scss"
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<App />
</React.StrictMode>
)

View File

@@ -0,0 +1,8 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "../layout/flex";
@mixin sidebar {
@include flex(column, nowrap, flex-start, flex-start);
}

View File

@@ -0,0 +1,5 @@
@mixin textWrapEllipsis {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}

View File

@@ -0,0 +1,66 @@
@import "../layout/flex";
@import "../components/content.scss";
.contextWrapper {
background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
border-right: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
width: 180px;
overflow-y: hidden;
overflow-x: hidden;
// overflow-y: auto;
.contextTitle {
position: sticky;
top: 0;
font-family:
Greycliff CF,
var(--mantine-font-family);
margin-bottom: var(--mantine-spacing-xl);
background-color: var(--mantine-color-body);
padding: var(--mantine-spacing-md);
padding-top: 18px;
width: 100%;
height: 60px;
border-bottom: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-7));
}
.contextList {
height: 70vh;
// display: flex();
.contextListItem {
display: block;
text-decoration: none;
border-top-right-radius: var(--mantine-radius-md);
border-bottom-right-radius: var(--mantine-radius-md);
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
padding: 0 var(--mantine-spacing-md);
font-size: var(--mantine-font-size-sm);
margin-right: var(--mantine-spacing-md);
font-weight: 500;
height: 44px;
width: 100%;
line-height: 44px;
cursor: pointer;
.contextItemName {
flex: 1 1 auto;
width: 130px;
@include textWrapEllipsis;
}
&:hover {
background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-5));
color: light-dark(var(--mantine-color-dark), var(--mantine-color-light));
}
&[data-active] {
&,
&:hover {
border-left-color: var(--mantine-color-blue-filled);
background-color: var(--mantine-color-blue-filled);
color: var(--mantine-color-white);
}
}
}
}
}

View File

@@ -0,0 +1,7 @@
@mixin absolutes {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}

View File

@@ -0,0 +1,6 @@
@mixin flex($direction: row, $wrap: nowrap, $alignItems: center, $justifyContent: center) {
display: flex;
flex-flow: $direction $wrap;
align-items: $alignItems;
justify-content: $justifyContent;
}

View File

@@ -0,0 +1,5 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
@import "layout/flex";
@import "layout/basics";

View File

@@ -0,0 +1,4 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
/// <reference types="vite/client" />

View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -0,0 +1,11 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true
},
"include": ["vite.config.ts"]
}

View File

@@ -0,0 +1,27 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "./src/styles/styles.scss";`,
},
},
},
plugins: [react()],
server: {
port: 3000,
},
test: {
globals: true,
environment: "jsdom",
},
define: {
"import.meta.env": process.env,
},
});

View File

@@ -174,6 +174,20 @@ Here is an example of running CodeGen in the UI:
![project-screenshot](../../assets/img/codeGen_ui_response.png) ![project-screenshot](../../assets/img/codeGen_ui_response.png)
## 🚀 Launch the React Based UI
To access the frontend, open the following URL in your browser: `http://{host_ip}:5174`. By default, the UI runs on port 5174 internally. If you prefer to use a different host port to access the frontend, you can modify the port mapping in the `docker_compose.yaml` file as shown below:
```yaml
codegen-xeon-react-ui-server:
image: opea/codegen-react-ui:latest
...
ports:
- "80:5174"
```
![project-screenshot](../../assets/img/codegen_react.png)
## Install Copilot VSCode extension from Plugin Marketplace as the frontend ## Install Copilot VSCode extension from Plugin Marketplace as the frontend
In addition to the Svelte UI, users can also install the Copilot VSCode extension from the Plugin Marketplace as the frontend. In addition to the Svelte UI, users can also install the Copilot VSCode extension from the Plugin Marketplace as the frontend.

View File

@@ -66,6 +66,18 @@ services:
- BASIC_URL=${BACKEND_SERVICE_ENDPOINT} - BASIC_URL=${BACKEND_SERVICE_ENDPOINT}
ipc: host ipc: host
restart: always restart: always
codegen-xeon-react-ui-server:
image: opea/codegen-react-ui:latest
container_name: codegen-xeon-react-ui-server
depends_on:
- codegen-xeon-backend-server
ports:
- "5174:80"
build:
args:
- BACKEND_SERVICE_ENDPOINT=${BACKEND_SERVICE_ENDPOINT}
ipc: host
restart: always
networks: networks:
default: default:

View File

@@ -0,0 +1,36 @@
# Deploy CodeGen with ReactUI
The README provides a step-by-step guide on how to deploy CodeGen with ReactUI, a popular React-based user interface library in Kubernetes cluster.
You can use react-codegen.yaml to deploy CodeGen with reactUI.
```
kubectl apply -f react-codegen.yaml
```
## Prerequisites for Deploying CodeGen with ReactUI:
Before deploying the react-codegen.yaml file, ensure that you have the following prerequisites in place:
1. Kubernetes installation: Make sure that you have Kubernetes installed.
2. Configuration Values: Set the following values in react-codegen.yaml before proceeding with the deployment:
#### a. HUGGINGFACEHUB_API_TOKEN (Your HuggingFace token to download your desired model from HuggingFace):
```
# You may set the HUGGINGFACEHUB_API_TOKEN via method:
export HUGGINGFACEHUB_API_TOKEN="YourOwnToken"
cd GenAIExamples/CodeGen/kubernetes/manifests/xeon/ui/
sed -i "s/insert-your-huggingface-token-here/${HUGGINGFACEHUB_API_TOKEN}/g" react-codegen.yaml
```
#### b. Set the proxies based on your network configuration
```
# Look for http_proxy, https_proxy, no_proxy key and fill up the value with your proxy configuration.
```
3. MODEL_ID and model-volume (OPTIONAL): You may as well customize the "MODEL_ID" to use different model and model-volume for the volume to be mounted.
4. After completing these, you can proceed with the deployment of the react-codegen.yaml file.
## Verify Services:
Make sure all the pods are running, you should see total of 4 pods running:
1. codegen
2. codegen-llm-uservice
3. codegen-react-ui
4. codegen-tgi
You may open up the UI by using the codegen-react-ui endpoint in the browser.

View File

@@ -0,0 +1,280 @@
---
# Source: codegen/charts/llm-uservice/charts/tgi/templates/service.yaml
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
apiVersion: v1
kind: Service
metadata:
name: codegen-tgi
labels:
helm.sh/chart: tgi-0.1.0
app.kubernetes.io/name: tgi
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.4"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: tgi
selector:
app.kubernetes.io/name: tgi
app.kubernetes.io/instance: codegen
---
apiVersion: v1
kind: Service
metadata:
name: codegen-llm-uservice
labels:
helm.sh/chart: llm-uservice-0.1.0
app.kubernetes.io/name: llm-uservice
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 9000
targetPort: 9000
protocol: TCP
name: llm-uservice
selector:
app.kubernetes.io/name: llm-uservice
app.kubernetes.io/instance: codegen
---
apiVersion: v1
kind: Service
metadata:
name: codegen
labels:
helm.sh/chart: codegen-0.1.0
app.kubernetes.io/name: codegen
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 7778
targetPort: 7778
protocol: TCP
name: codegen
selector:
app.kubernetes.io/name: codegen
app.kubernetes.io/instance: codegen
---
apiVersion: v1
kind: Service
metadata:
name: codegen-react-ui
labels:
helm.sh/chart: codegen-react-ui-0.1.0
app.kubernetes.io/name: react-ui
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: react-ui
selector:
app.kubernetes.io/name: react-ui
app.kubernetes.io/instance: codegen
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: codegen-tgi
labels:
helm.sh/chart: tgi-0.1.0
app.kubernetes.io/name: tgi
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.4"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: tgi
app.kubernetes.io/instance: codegen
template:
metadata:
labels:
app.kubernetes.io/name: tgi
app.kubernetes.io/instance: codegen
spec:
securityContext: {}
containers:
- name: tgi
env:
- name: MODEL_ID
value: ise-uiuc/Magicoder-S-DS-6.7B
- name: PORT
value: "80"
- name: http_proxy
value:
- name: https_proxy
value:
- name: no_proxy
value:
securityContext: {}
image: "ghcr.io/huggingface/text-generation-inference:1.4"
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /data
name: model-volume
ports:
- name: http
containerPort: 80
protocol: TCP
resources: {}
volumes:
- name: model-volume
hostPath:
path: /mnt
type: Directory
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: codegen-llm-uservice
labels:
helm.sh/chart: llm-uservice-0.1.0
app.kubernetes.io/name: llm-uservice
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: llm-uservice
app.kubernetes.io/instance: codegen
template:
metadata:
labels:
app.kubernetes.io/name: llm-uservice
app.kubernetes.io/instance: codegen
spec:
securityContext: {}
containers:
- name: codegen
env:
- name: TGI_LLM_ENDPOINT
value: "http://codegen-tgi:80"
- name: HUGGINGFACEHUB_API_TOKEN
value: "insert-your-huggingface-token-here"
- name: http_proxy
value:
- name: https_proxy
value:
- name: no_proxy
value:
securityContext: {}
image: "opea/llm-tgi:latest"
imagePullPolicy: IfNotPresent
ports:
- name: llm-uservice
containerPort: 9000
protocol: TCP
startupProbe:
exec:
command:
- curl
- http://codegen-tgi:80
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 120
resources: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: codegen
labels:
helm.sh/chart: codegen-0.1.0
app.kubernetes.io/name: codegen
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: codegen
app.kubernetes.io/instance: codegen
template:
metadata:
labels:
app.kubernetes.io/name: codegen
app.kubernetes.io/instance: codegen
spec:
securityContext: null
containers:
- name: codegen
env:
- name: LLM_SERVICE_HOST_IP
value: codegen-llm-uservice
- name: http_proxy
value:
- name: https_proxy
value:
- name: no_proxy
value:
securityContext: null
image: "opea/codegen:latest"
imagePullPolicy: IfNotPresent
ports:
- name: codegen
containerPort: 7778
protocol: TCP
resources: null
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: codegen-react-ui
labels:
helm.sh/chart: codegen-react-ui-0.1.0
app.kubernetes.io/name: react-ui
app.kubernetes.io/instance: codegen
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/managed-by: Helm
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: react-ui
app.kubernetes.io/instance: codegen
template:
metadata:
labels:
app.kubernetes.io/name: react-ui
app.kubernetes.io/instance: codegen
spec:
securityContext: null
containers:
- name: codegen-react-ui
env:
- name: BASIC_URL
value: "http://codegen:7778/v1/codegen"
- name: http_proxy
value:
- name: https_proxy
value:
- name: no_proxy
value:
securityContext: null
image: "opea/codegen-react-ui:latest"
imagePullPolicy: IfNotPresent
ports:
- name: react-ui
containerPort: 80
protocol: TCP
resources: null

View File

@@ -22,6 +22,7 @@ function build_docker_images() {
cd $WORKPATH/docker/ui cd $WORKPATH/docker/ui
docker build --no-cache -t opea/codegen-ui:latest -f docker/Dockerfile . docker build --no-cache -t opea/codegen-ui:latest -f docker/Dockerfile .
docker build --no-cache --build-arg BACKEND_SERVICE_ENDPOINT=http://${ip_address}:7778/v1/codegen -t opea/codegen--react-ui:latest -f docker/Dockerfile.react .
docker images docker images
} }
@@ -43,6 +44,7 @@ function start_services() {
echo "using image repository $IMAGE_REPO and image tag $IMAGE_TAG" echo "using image repository $IMAGE_REPO and image tag $IMAGE_TAG"
sed -i "s#image: opea/codegen:latest#image: opea/codegen:${IMAGE_TAG}#g" docker_compose.yaml sed -i "s#image: opea/codegen:latest#image: opea/codegen:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/codegen-ui:latest#image: opea/codegen-ui:${IMAGE_TAG}#g" docker_compose.yaml sed -i "s#image: opea/codegen-ui:latest#image: opea/codegen-ui:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/codegen-react-ui:latest#image: opea/codegen-react-ui:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/*#image: ${IMAGE_REPO}opea/#g" docker_compose.yaml sed -i "s#image: opea/*#image: ${IMAGE_REPO}opea/#g" docker_compose.yaml
echo "cat docker_compose.yaml" echo "cat docker_compose.yaml"
cat docker_compose.yaml cat docker_compose.yaml
@@ -51,7 +53,7 @@ function start_services() {
# Start Docker Containers # Start Docker Containers
docker compose -f docker_compose.yaml up -d docker compose -f docker_compose.yaml up -d
sleep 2m # Waits 2 minutes sleep 5m # Waits 5 minutes
} }
function validate_services() { function validate_services() {

View File

@@ -15,11 +15,14 @@ function build_docker_images() {
docker build -t opea/llm-tgi:latest -f comps/llms/text-generation/tgi/Dockerfile . docker build -t opea/llm-tgi:latest -f comps/llms/text-generation/tgi/Dockerfile .
docker pull ghcr.io/huggingface/text-generation-inference:1.4
cd $WORKPATH/docker cd $WORKPATH/docker
docker build --no-cache -t opea/codegen:latest -f Dockerfile . docker build --no-cache -t opea/codegen:latest -f Dockerfile .
cd $WORKPATH/docker/ui cd $WORKPATH/docker/ui
docker build --no-cache -t opea/codegen-ui:latest -f docker/Dockerfile . docker build --no-cache -t opea/codegen-ui:latest -f docker/Dockerfile .
docker build --no-cache --build-arg BACKEND_SERVICE_ENDPOINT=http://${ip_address}:7778/v1/codegen -t opea/codegen-react-ui:latest -f docker/Dockerfile.react .
docker images docker images
} }
@@ -41,6 +44,7 @@ function start_services() {
echo "using image repository $IMAGE_REPO and image tag $IMAGE_TAG" echo "using image repository $IMAGE_REPO and image tag $IMAGE_TAG"
sed -i "s#image: opea/codegen:latest#image: opea/codegen:${IMAGE_TAG}#g" docker_compose.yaml sed -i "s#image: opea/codegen:latest#image: opea/codegen:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/codegen-ui:latest#image: opea/codegen-ui:${IMAGE_TAG}#g" docker_compose.yaml sed -i "s#image: opea/codegen-ui:latest#image: opea/codegen-ui:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/codegen-react-ui:latest#image: opea/codegen-react-ui:${IMAGE_TAG}#g" docker_compose.yaml
sed -i "s#image: opea/*#image: ${IMAGE_REPO}opea/#g" docker_compose.yaml sed -i "s#image: opea/*#image: ${IMAGE_REPO}opea/#g" docker_compose.yaml
echo "cat docker_compose.yaml" echo "cat docker_compose.yaml"
cat docker_compose.yaml cat docker_compose.yaml