Skip to content

Commit c7bc0f1

Browse files
committed
0.4.5: NebulaGraph AI Suite added
1 parent 6378477 commit c7bc0f1

File tree

3 files changed

+229
-8
lines changed

3 files changed

+229
-8
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ LABEL org.opencontainers.image.title="NebulaGraph" \
3131
com.docker.extension.detailed-description="NebulaGraph is a popular Open-Source, distributed Cloud Native Graph Database for trillion edges graph data volume." \
3232
com.docker.extension.publisher-url="https://github.com/vesoft-inc/nebula" \
3333
com.docker.extension.additional-urls='[{"title":"WebSite","url":"https://www.nebula-graph.io/"}, {"title":"GitHub","url":"https://github.com/vesoft-inc/nebula"}, {"title":"Slack","url":"http://community-chat.nebula-graph.io/"}, {"title":"Docker Extension Feedback","url":"https://github.com/nebula-contrib/nebulagraph-docker-ext/issues/new/choose"}]' \
34-
com.docker.extension.changelog="Introduced data intelegence suite\nSee https://github.com/nebula-contrib/nebulagraph-docker-ext/" \
34+
com.docker.extension.changelog="Introduced NebulaGraph AI Suite\nSee https://github.com/nebula-contrib/nebulagraph-docker-ext/" \
3535
com.docker.desktop.extension.icon="https://user-images.githubusercontent.com/1651790/213339618-107d0e59-1b8b-4c89-bbae-5529aa4e2666.svg" \
3636
com.docker.extension.categories="database"
3737

optional_workload/docker-compose-ngai.yaml

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ services:
99
- '18888:8888'
1010
volumes:
1111
- ~/.nebulagraph/:/root
12-
1312
networks:
1413
- weygu_nebulagraph-dd-ext-desktop-extension_nebula-net
1514
healthcheck:

ui/src/components/TabPanel/index.tsx

+228-6
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
Step,
2121
StepLabel,
2222
} from "@mui/material";
23-
import { Help, Insights, Refresh } from '@mui/icons-material';
23+
import { Help, Insights, Refresh, Psychology } from '@mui/icons-material';
2424
import { createDockerDesktopClient } from '@docker/extension-api-client';
2525
import Confetti from 'react-confetti'
2626

@@ -208,8 +208,12 @@ export default function NebulaGraphTabs() {
208208

209209
const [coreContainers, setCoreContainers] = React.useState<any[]>([]);
210210
const [utilsContainers, setUtilsContainers] = React.useState<any[]>([]);
211+
const [ngaiContainers, setNgaiContainers] = React.useState<any[]>([]);
211212

212213
const [storageActivated, setStorageActivated] = React.useState(false);
214+
const [ngaiDeployed, setNgaiDeployed] = React.useState(false);
215+
const [isNgaiDeploying, setNgaiIsDeploying] = React.useState(false);
216+
const [isNgaiUndeploying, setNgaiIsUndeploying] = React.useState(false);
213217

214218
const openExternalUrl = (url: string) => {
215219
ddClient.host.openExternal(url);
@@ -270,13 +274,15 @@ export default function NebulaGraphTabs() {
270274
// get started stepper tab end
271275

272276
const fetchContainerList = async () => {
273-
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', 'label=com.vesoft.scope=core']).then((result) => {
277+
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', 'label=com.vesoft.scope=core']).then((result: any) => {
274278
setCoreContainers(result.parseJsonLines());
275279
});
276-
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', 'label=com.vesoft.scope=utils']).then((result) => {
280+
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', 'label=com.vesoft.scope=utils']).then((result: any) => {
277281
setUtilsContainers(result.parseJsonLines());
278282
});
279-
283+
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"', '--filter', 'label=com.vesoft.scope=ngai']).then((result: any) => {
284+
setNgaiContainers(result.parseJsonLines());
285+
});
280286
setTimeout(fetchContainerList, 60000);
281287
addHostsIfStorageUnhealthy();
282288
};
@@ -298,7 +304,7 @@ export default function NebulaGraphTabs() {
298304
}
299305
const networkName = unhealthyStoragedContainers[0]["Networks"]
300306
if (networkName) {
301-
ddClient.docker.cli.exec('run', ['--net', networkName, '--rm', 'vesoft/nebula-console:v3', '-addr', 'graphd', '-port', '9669', '-u', 'root', '-p', 'nebula', '-e', '\'ADD HOSTS "storaged0":9779,"storaged1":9779,"storaged2":9779\'']).then((result) => {
307+
ddClient.docker.cli.exec('run', ['--net', networkName, '--rm', 'vesoft/nebula-console:v3', '-addr', 'graphd', '-port', '9669', '-u', 'root', '-p', 'nebula', '-e', '\'ADD HOSTS "storaged0":9779,"storaged1":9779,"storaged2":9779\'']).then((result: any) => {
302308
console.log("the result of adding hosts: ", result);
303309
if (result.stdout.includes("existed")) {
304310
setStorageActivated(true);
@@ -307,6 +313,86 @@ export default function NebulaGraphTabs() {
307313
}
308314
};
309315

316+
// Deploy NebulaGraph ngai Playground
317+
// 0.1 run docker exec nebulagraph_webshell mkdir -p /host_data/ngai
318+
// 0.2 run docker exec nebulagraph_webshell mkdir -p /host_data/download
319+
// 0.3 run docker exec nebulagraph_webshell mkdir -p /host_data/udf
320+
// 1. run docker exec nebulagraph_webshell wget -O /host_data/ngai/docker-compose.yaml https://raw.githubusercontent.com/nebula-contrib/nebulagraph-docker-ext/main/optional_workload/docker-compose-ngai.yaml
321+
// 2. run docker exec nebulagraph_webshell wget -O /host_data/download/nebula-algo.jar https://repo1.maven.org/maven2/com/vesoft/nebula-algorithm/$ALGO_VERSION/nebula-algorithm-$ALGO_VERSION.jar
322+
// 3. run docker exec nebulagraph_webshell wget -O /host_data/download/nebula-spark-connector.jar https://repo1.maven.org/maven2/com/vesoft/nebula-spark-connector/$SPARK_C_VERSION/nebula-spark-connector-$SPARK_C_VERSION.jar
323+
// 4. run docker exec nebulagraph_webshell wget -O /host_data/udf/ng_ai.so https://github.com/wey-gu/nebulagraph-ai/releases/download/0.2.9/ng_ai-ubuntu-2004-nebulagraph-nightly-2023.03.13.so
324+
// 5. run docker exec nebulagraph_webshell chmod +x /host_data/udf/ng_ai.so
325+
// 6. run docker-compose -f ~/.nebulagraph/ngai/docker-compose.yaml up -d --remove-orphans
326+
// 7. run docker exec nebulagraph_webshell wget -O /host_data/ngai/AI_suite_demo.ipynb https://raw.githubusercontent.com/wey-gu/nebula-up/main/spark/AI_suite_demo.ipynb
327+
// 8. run docker exec nebulagraph_webshell wget -O /host_data/ngai/AI_suite_nGQL_UDF.ipynb https://raw.githubusercontent.com/wey-gu/nebula-up/main/spark/AI_suite_nGQL_UDF.ipynb
328+
329+
const deployNgai = async () => {
330+
if (isNgaiDeploying) {
331+
console.log("Ngai is deploying, please wait...");
332+
return;
333+
}
334+
setNgaiIsDeploying(true);
335+
console.log("Start deploying Ngai...");
336+
const mkdirPromises = [
337+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'mkdir', '-p', '/host_data/ngai']).catch((error: any) => {
338+
console.error("Error creating directory /host_data/ngai: ", error);
339+
}),
340+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'mkdir', '-p', '/host_data/download']).catch((error: any) => {
341+
console.error("Error creating directory /host_data/download: ", error);
342+
}),
343+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'mkdir', '-p', '/host_data/udf']).catch((error: any) => {
344+
console.error("Error creating directory /host_data/udf: ", error);
345+
}),
346+
];
347+
await Promise.all(mkdirPromises);
348+
349+
const downloadPromises = [
350+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/download/nebula-algo.jar', 'https://repo1.maven.org/maven2/com/vesoft/nebula-algorithm/3.1.0/nebula-algorithm-3.1.0.jar']).catch((error: any) => {
351+
console.error("Error downloading nebula-algo.jar: ", error);
352+
}),
353+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/ngai/docker-compose.yaml', 'https://raw.githubusercontent.com/nebula-contrib/nebulagraph-docker-ext/main/optional_workload/docker-compose-ngai.yaml']).catch((error: any) => {
354+
console.error("Error downloading docker-compose.yaml: ", error);
355+
}),
356+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/udf/ng_ai.so', 'https://github.com/wey-gu/nebulagraph-ai/releases/download/0.2.9/ng_ai-ubuntu-2004-nebulagraph-nightly-2023.03.13.so']).catch((error: any) => {
357+
console.error("Error downloading ng_ai.so: ", error);
358+
}),
359+
ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/download/nebula-spark-connector.jar', 'https://repo1.maven.org/maven2/com/vesoft/nebula-spark-connector/3.4.0/nebula-spark-connector-3.4.0.jar']).catch((error: any) => {
360+
console.error("Error downloading nebula-spark-connector.jar: ", error);
361+
}),
362+
];
363+
const results = await Promise.all(downloadPromises);
364+
results.forEach((result: any) => {
365+
console.log("the result of wget: ", result);
366+
});
367+
368+
await ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'chmod', '+x', '/host_data/udf/ng_ai.so']);
369+
console.log("the result of chmod ng_ai.so");
370+
371+
await ddClient.docker.cli.exec('compose', ['-f', '~/.nebulagraph/ngai/docker-compose.yaml', 'up', '-d', '--remove-orphans']);
372+
console.log("the result of docker-compose up");
373+
374+
await ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/ngai/AI_suite_demo.ipynb', 'https://raw.githubusercontent.com/wey-gu/nebula-up/main/spark/AI_suite_demo.ipynb']);
375+
console.log("the result of wget AI_suite_demo.ipynb");
376+
377+
await ddClient.docker.cli.exec('exec', ['nebulagraph_webshell', 'wget', '-O', '/host_data/ngai/AI_suite_nGQL_UDF.ipynb', 'https://raw.githubusercontent.com/wey-gu/nebula-up/main/spark/AI_suite_nGQL_UDF.ipynb']);
378+
console.log("the result of wget AI_suite_nGQL_UDF.ipynb");
379+
380+
setNgaiDeployed(true);
381+
setNgaiIsDeploying(false);
382+
};
383+
384+
// Undeploy NebulaGraph AI
385+
const undeployNgai = async () => {
386+
if (isNgaiUndeploying) {
387+
return;
388+
}
389+
await ddClient.docker.cli.exec('compose', ['-f', '~/.nebulagraph/ngai/docker-compose.yaml', 'down']);
390+
console.log("the result of docker-compose down");
391+
392+
setNgaiDeployed(false);
393+
setNgaiIsUndeploying(false);
394+
};
395+
310396
return (
311397
<Box sx={{ width: '100%' }}>
312398
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
@@ -316,6 +402,7 @@ export default function NebulaGraphTabs() {
316402
<Tab label="Get Started" {...a11yProps(2)} />
317403
<Tab label="Docs" {...a11yProps(3)} />
318404
<Tab label="Console" {...a11yProps(4)} />
405+
<Tab label="NebulaGraph AI" {...a11yProps(5)} />
319406
</Tabs>
320407
</Box>
321408
<TabPanel value={value} index={0}>
@@ -399,6 +486,45 @@ export default function NebulaGraphTabs() {
399486
</Table>
400487
</TableContainer>
401488

489+
490+
491+
<Box sx={{ display: 'flex', alignItems: 'center' }}>
492+
<Typography variant="h6" color={(theme) => theme.palette.text.primary} sx={{ my: 2, width: '95%' }}>
493+
NebulaGraph AI Suite Resources
494+
</Typography>
495+
<Fab onClick={fetchContainerList}>
496+
<Refresh />
497+
</Fab>
498+
</Box>
499+
500+
501+
502+
<TableContainer sx={{mt:-1}}>
503+
<Table>
504+
<TableHead>
505+
<TableRow>
506+
<TableCell sx={{ width: '15%' }}>Container id</TableCell>
507+
<TableCell sx={{ width: '25%' }}>Image</TableCell>
508+
<TableCell sx={{ width: '35%' }}>Created</TableCell>
509+
<TableCell sx={{ width: '25%' }}>Status</TableCell>
510+
</TableRow>
511+
</TableHead>
512+
<TableBody>
513+
{ngaiContainers.map((container) => (
514+
<TableRow
515+
key={container.ID}
516+
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
517+
>
518+
<TableCell>{container.ID}</TableCell>
519+
<TableCell>{container.Image}</TableCell>
520+
<TableCell>{container.CreatedAt}</TableCell>
521+
<TableCell>{container.Status}</TableCell>
522+
</TableRow>
523+
))}
524+
</TableBody>
525+
</Table>
526+
</TableContainer>
527+
402528
</TabPanel>
403529

404530
<TabPanel value={value} index={2}>
@@ -711,7 +837,103 @@ export default function NebulaGraphTabs() {
711837
</TabPanel>
712838

713839
<TabPanel value={value} index={5}>
714-
{/* TBD */}
840+
<Box sx={{ display: 'flex' }}>
841+
<Box sx={{ width: '80%' }}>
842+
<img
843+
src="https://user-images.githubusercontent.com/1651790/226272763-61be3f05-e4f2-4108-a3f8-eb01462a8605.png"
844+
alt="celebrate"
845+
width="100%"
846+
/>
847+
</Box>
848+
849+
<Box sx={{ width: '20%', display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'flex-end' }}>
850+
<Button
851+
variant="contained"
852+
color="primary"
853+
onClick={deployNgai}
854+
disabled={isNgaiDeploying}
855+
sx={{ mb: 1, width: '70%' }}
856+
>
857+
Install
858+
</Button>
859+
<Button
860+
variant="contained"
861+
color="secondary"
862+
onClick={undeployNgai}
863+
disabled={isNgaiUndeploying}
864+
sx={{ width: '70%' }}
865+
>
866+
Uninstall
867+
</Button>
868+
</Box>
869+
870+
</Box>
871+
872+
{/* Description of NebulaGraph AI Suite */}
873+
<Typography variant="body1" color={(theme) => theme.palette.text.primary} sx={{ my: 2, mr: 6 }}>
874+
<List component="div">
875+
<ListItem>
876+
<b>NebulaGraph AI Suite</b> &nbsp; (<a href="#" onClick={() => openExternalUrl("https://github.com/wey-gu/nebulagraph-ai")}>GitHub</a>)
877+
is a Python library to run Analytics, Algo & GNN on NebulaGraph.
878+
</ListItem>
879+
<ListItem>
880+
<b>Step 1 Install:</b> &nbsp; It's not by default installed in NebulaGraph This Docker Extension, to install it, click the Install button.
881+
</ListItem>
882+
<ListItem>
883+
<b>Step 2 Run:</b> &nbsp; After installation, you go to
884+
<Box sx={{ display: 'inline-block', ml: 2, mr: 2 }}>
885+
<Button
886+
variant="outlined"
887+
onClick={() => openExternalUrl("http://127.0.0.1:18888/notebooks/ngai/AI_suite_demo.ipynb")}
888+
endIcon={<Psychology />}
889+
>
890+
Jupyter Notebook
891+
</Button>
892+
</Box>
893+
and its password is nebula.
894+
</ListItem>
895+
<ListItem>
896+
<b>Step 3 ng_ai API Gateway:</b> Follow &nbsp;<a href="#" onClick={() => openExternalUrl("http://127.0.0.1:18888/notebooks/ngai/AI_suite_nGQL_UDF.ipynb")}> this </a>&nbsp; to run ng_ai API Gateway and call ng_ai from nGQL.
897+
</ListItem>
898+
</List>
899+
</Typography>
900+
901+
902+
<Box sx={{ display: 'flex', alignItems: 'center' }}>
903+
<Typography variant="h6" color={(theme) => theme.palette.text.primary} sx={{ my: 2, width: '95%' }}>
904+
NebulaGraph AI Suite Resources
905+
</Typography>
906+
<Fab onClick={fetchContainerList}>
907+
<Refresh />
908+
</Fab>
909+
</Box>
910+
911+
<TableContainer sx={{mt:-1}}>
912+
<Table>
913+
<TableHead>
914+
<TableRow>
915+
<TableCell sx={{ width: '15%' }}>Container id</TableCell>
916+
<TableCell sx={{ width: '25%' }}>Image</TableCell>
917+
<TableCell sx={{ width: '35%' }}>Created</TableCell>
918+
<TableCell sx={{ width: '25%' }}>Status</TableCell>
919+
</TableRow>
920+
</TableHead>
921+
<TableBody>
922+
{ngaiContainers.map((container) => (
923+
<TableRow
924+
key={container.ID}
925+
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
926+
>
927+
<TableCell>{container.ID}</TableCell>
928+
<TableCell>{container.Image}</TableCell>
929+
<TableCell>{container.CreatedAt}</TableCell>
930+
<TableCell>{container.Status}</TableCell>
931+
</TableRow>
932+
))}
933+
</TableBody>
934+
</Table>
935+
</TableContainer>
936+
715937
</TabPanel>
716938
</Box>
717939
);

0 commit comments

Comments
 (0)