Skip to content

Commit e1bf217

Browse files
committed
feat(lightspeed): add a new lightspeed plugin with basic implementation of chat
1 parent 8c327c7 commit e1bf217

20 files changed

+571
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ yarn.lock @janus-idp/maintainers-plugins
3838
/plugins/analytics-module-matomo @janus-idp/maintainers-plugins @janus-idp/devex-uxe
3939
/plugins/kiali @janus-idp/maintainers-plugins @janus-idp/kiali
4040
/plugins/kiali-backend @janus-idp/maintainers-plugins @janus-idp/kiali
41+
/plugins/lightspeed @janus-idp/maintainers-plugins @rohitkrai03
4142
/plugins/quay @janus-idp/rhtap
4243
/plugins/tekton @janus-idp/rhtap
4344
/plugins/argocd @janus-idp/rhtap

plugins/lightspeed/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);

plugins/lightspeed/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Lightspeed plugin for Backstage
2+
3+
The Lightspeed plugin enables you to interact with any LLM server running a model with OpenAI's API compatibility.
4+
5+
## For administrators
6+
7+
### Installation
8+
9+
1. Install the Topology plugin using the following command:
10+
11+
```console
12+
yarn workspace app add @janus-idp/backstage-plugin-lightspeed
13+
```
14+
15+
### Configuration
16+
17+
1. Set the proxy to the desired LLM server in the `app-config.yaml` file as follows:
18+
19+
```yaml title="app-config.yaml"
20+
proxy:
21+
'/lightspeed/api':
22+
target: http://localhost:11434/v1/
23+
headers:
24+
Authorization: Bearer <token>
25+
```
26+
27+
2. Add a new nav item **Lightspeed** in App `packages/app/src/App.tsx`:
28+
29+
```tsx title="packages/app/src/components/App.tsx"
30+
/* highlight-add-next-line */ import { LightspeedPage } from '@janus-idp/backstage-plugin-lightspeed';
31+
32+
<Route path="/lightspeed" element={<LightspeedPage />} />;
33+
```
34+
35+
3. Enable **Lightspeed** page in `packages/app/src/components/Root/Root.tsx`:
36+
37+
```tsx title="packages/app/src/components/Root/Root.tsx"
38+
/* highlight-add-next-line */ import { LightspeedIcon } from '@janus-idp/backstage-plugin-lightspeed';
39+
40+
<SidebarItem
41+
icon={LightspeedIcon as IconComponent}
42+
to="lightspeed"
43+
text="Lightspeed"
44+
/>;
45+
```
46+
47+
## For users
48+
49+
### Using the Lightspeed plugin in Backstage
50+
51+
Lightspeed is a front-end plugin that enables you to interact with any LLM server running a model with OpenAI's API compatibility.
52+
53+
#### Prerequisites
54+
55+
- Your Backstage application is installed and running.
56+
- You have installed the Lightspeed plugin. For installation process, see [Installation](#installation).
57+
58+
#### Procedure
59+
60+
1. Open your Backstage application and select a Lightspeed nav item from the **Navigation**.
61+
2. Ask you questions to the Lightspeed chatbot.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
dynamicPlugins:
2+
frontend:
3+
janus-idp.backstage-plugin-lightspeed:
4+
appIcons:
5+
- name: LightspeedIcon
6+
module: LightspeedPlugin
7+
importName: LightspeedIcon
8+
dynamicRoutes:
9+
- path: /lightspeed
10+
importName: LightspeedPage
11+
module: LightspeedPlugin
12+
menuItem:
13+
icon: LightspeedIcon
14+
text: Lightspeed

plugins/lightspeed/config.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export interface Config {}

plugins/lightspeed/dev/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
3+
import { createDevApp } from '@backstage/dev-utils';
4+
5+
import { LightspeedPage, lightspeedPlugin } from '../src/plugin';
6+
7+
createDevApp()
8+
.registerPlugin(lightspeedPlugin)
9+
.addPage({
10+
element: <LightspeedPage />,
11+
title: 'Lightspeed Page',
12+
path: '/lightspeed',
13+
})
14+
.render();

plugins/lightspeed/images/logo.svg

Lines changed: 1 addition & 0 deletions
Loading

plugins/lightspeed/package.json

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"name": "@janus-idp/backstage-plugin-lightspeed",
3+
"version": "0.1.0",
4+
"main": "src/index.ts",
5+
"types": "src/index.ts",
6+
"license": "Apache-2.0",
7+
"private": false,
8+
"publishConfig": {
9+
"access": "public",
10+
"main": "dist/index.esm.js",
11+
"types": "dist/index.d.ts"
12+
},
13+
"backstage": {
14+
"role": "frontend-plugin"
15+
},
16+
"sideEffects": false,
17+
"scripts": {
18+
"build": "backstage-cli package build",
19+
"clean": "backstage-cli package clean",
20+
"export-dynamic": "janus-cli package export-dynamic-plugin",
21+
"lint": "backstage-cli package lint",
22+
"postpack": "backstage-cli package postpack",
23+
"postversion": "yarn run export-dynamic",
24+
"prepack": "backstage-cli package prepack",
25+
"start": "backstage-cli package start",
26+
"test": "backstage-cli package test --passWithNoTests --coverage",
27+
"tsc": "tsc"
28+
},
29+
"dependencies": {
30+
"@backstage/core-components": "^0.14.4",
31+
"@backstage/core-plugin-api": "^1.9.2",
32+
"@backstage/theme": "^0.5.5",
33+
"@material-ui/core": "^4.9.13",
34+
"@material-ui/icons": "^4.9.1",
35+
"@material-ui/lab": "^4.0.0-alpha.61",
36+
"@mui/icons-material": "^5.15.18",
37+
"openai": "^4.52.6",
38+
"react-use": "^17.2.4"
39+
},
40+
"peerDependencies": {
41+
"react": "16.13.1 || ^17.0.0 || ^18.0.0"
42+
},
43+
"devDependencies": {
44+
"@backstage/cli": "0.26.6",
45+
"@backstage/core-app-api": "1.12.5",
46+
"@backstage/dev-utils": "1.0.32",
47+
"@backstage/test-utils": "1.5.5",
48+
"@janus-idp/cli": "1.11.1",
49+
"@testing-library/jest-dom": "6.0.0",
50+
"@testing-library/react": "14.0.0",
51+
"@testing-library/user-event": "14.0.0",
52+
"msw": "1.0.0"
53+
},
54+
"files": [
55+
"dist",
56+
"config.d.ts",
57+
"dist-scalprum",
58+
"app-config.janus-idp.yaml"
59+
],
60+
"scalprum": {
61+
"name": "janus-idp.backstage-plugin-lightspeed",
62+
"exposedModules": {
63+
"PluginRoot": "./src/index.ts"
64+
}
65+
},
66+
"configSchema": "config.d.ts",
67+
"repository": {
68+
"type": "git",
69+
"url": "https://github.com/janus-idp/backstage-plugins",
70+
"directory": "plugins/lightspeed"
71+
},
72+
"keywords": [
73+
"backstage",
74+
"plugin"
75+
],
76+
"homepage": "https://janus-idp.io/",
77+
"bugs": "https://github.com/janus-idp/backstage-plugins/issues"
78+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as React from 'react';
2+
3+
import logo from '../../images/logo.svg';
4+
5+
export const LightspeedIcon = () => {
6+
return (
7+
<img src={logo as any} alt="lightspeed icon" style={{ height: '25px' }} />
8+
);
9+
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import React from 'react';
2+
3+
import Button from '@material-ui/core/Button';
4+
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
5+
import TextField from '@material-ui/core/TextField';
6+
import SendIcon from '@material-ui/icons/Send';
7+
8+
const useStyles = makeStyles((theme: Theme) =>
9+
createStyles({
10+
wrapForm: {
11+
display: 'flex',
12+
justifyContent: 'center',
13+
width: '98%',
14+
margin: `${theme.spacing(0)} auto`,
15+
},
16+
wrapText: {
17+
width: '100%',
18+
},
19+
button: {
20+
margin: theme.spacing(0),
21+
},
22+
}),
23+
);
24+
25+
type LightspeedInputProps = {
26+
onSubmit: (prompt: string) => void;
27+
};
28+
29+
export const LightspeedInput: React.FC<LightspeedInputProps> = ({
30+
onSubmit,
31+
}) => {
32+
const classes = useStyles();
33+
34+
const [prompt, setPrompt] = React.useState('');
35+
36+
const handleInputChange = React.useCallback(
37+
(e: React.ChangeEvent<HTMLInputElement>) => {
38+
setPrompt(e.target.value);
39+
},
40+
[],
41+
);
42+
43+
const handleSubmit = React.useCallback(
44+
(e: React.FormEvent) => {
45+
e.preventDefault();
46+
onSubmit(prompt);
47+
setPrompt('');
48+
},
49+
[onSubmit, prompt],
50+
);
51+
52+
return (
53+
<form
54+
className={classes.wrapForm}
55+
noValidate
56+
autoComplete="off"
57+
onSubmit={handleSubmit}
58+
>
59+
<TextField
60+
id="standard-text"
61+
label="Ask Lightspeed"
62+
className={classes.wrapText}
63+
value={prompt}
64+
onChange={handleInputChange}
65+
/>
66+
<Button
67+
type="submit"
68+
variant="contained"
69+
color="primary"
70+
className={classes.button}
71+
onSubmit={handleSubmit}
72+
>
73+
<SendIcon />
74+
</Button>
75+
</form>
76+
);
77+
};

0 commit comments

Comments
 (0)