{"id":23647081,"url":"https://github.com/wey-gu/nebula-siwi","last_synced_at":"2025-06-18T13:36:35.565Z","repository":{"id":50655720,"uuid":"380489128","full_name":"wey-gu/nebula-siwi","owner":"wey-gu","description":"Siwi (/ˈsɪwi/) is a PoC of Dialog System With Graph Database Backed Knowledge Graph.","archived":false,"fork":false,"pushed_at":"2022-11-17T10:25:28.000Z","size":1229,"stargazers_count":87,"open_issues_count":2,"forks_count":16,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-12-20T12:48:11.511Z","etag":null,"topics":["chatbot","graphdatabase","nebula-graph"],"latest_commit_sha":null,"homepage":"https://siwei.io/nebula-siwi","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wey-gu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-26T11:49:07.000Z","updated_at":"2024-10-10T03:41:53.000Z","dependencies_parsed_at":"2023-01-22T16:15:23.326Z","dependency_job_id":null,"html_url":"https://github.com/wey-gu/nebula-siwi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wey-gu%2Fnebula-siwi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wey-gu%2Fnebula-siwi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wey-gu%2Fnebula-siwi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wey-gu%2Fnebula-siwi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wey-gu","download_url":"https://codeload.github.com/wey-gu/nebula-siwi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231633141,"owners_count":18403402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chatbot","graphdatabase","nebula-graph"],"created_at":"2024-12-28T13:49:15.454Z","updated_at":"2024-12-28T13:49:15.999Z","avatar_url":"https://github.com/wey-gu.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Siwi the voice assistant\n\nSiwi (/ˈsɪwi/) is a PoC of Dialog System With Graph Database Backed Knowledge Graph.\n\nFor now, it's a demo for task-driven(not general purpose) dialog bots with KG(Knowledge Graph) leveraging Nebula Graph with the minimal/sample dataset from [Nebula Graph Manual](https://docs.nebula-graph.io/2.0.1/3.ngql-guide/1.nGQL-overview/1.overview/#basketballplayer)/ [NG中文手册](https://docs.nebula-graph.com.cn/2.0.1/3.ngql-guide/1.nGQL-overview/1.overview/#basketballplayer).\n\n\u003e Tips: Now you can play with the graph online without installing yourself!\n\u003e\n\u003e [Nebula Playground](https://playground.nebula-graph.io) | [Nebula Playground - China Mainland](https://playground.nebula-graph.com.cn)\n\nSupported queries:\n\n`relation`:\n\n- What is the relationship between Yao Ming and Lakers?\n- How does Yao Ming and Lakers connected?\n\n`serving`:\n- Which team had Yao Ming served?\n\n`friendship`:\n- Whom does Tim Duncan follow?\n- Who are Yao Ming's friends?\n\n## Deploy and Try\n\nYou can try with it from scratch here: https://siwei.io/learn/nebula-101-siwi-kgqa/\n\n## How does it work?\n\nThis is one of the most naive pipeline for a specific domain/ single purpose chat bot built on a Knowledge Graph.\n\n### Backend\n\n![backend-demo](./images/backend-demo.webp)\n\nThe Backend(Siwi API) is a Flask based API server:\n\n- Flask API server takes questions in HTTP POST, and calls the bot API.\n\n- In bot API part there are classfier(Symentic Parsing, Intent Matching, Slot Filling), and question actors(Call corresponding actions to query Knowledge Graph with intents and slots).\n\n- Knowledge Graph is built on an Open-Source Graph Database: [Nebula Graph](https://github.com/vesoft-inc/nebula-graph)\n\n### Frontend\n\n![demo](./src/siwi_frontend/images/demo.webp)\n\nThe Frontend is a VueJS Single Page Applicaiton(SPA):\n\n- I reused a Vue Bot UI to showcase a chat window in this human-agent interaction, typing is supported.\n- In addtion, leverating Chrome's [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API), a button to listen to human voice is introduced\n\n### A Query Flow\n\n```asciiart\n┌────────────────┬──────────────────────────────────────┐\n│                │                                      │\n│                │  Speech                              │\n│     ┌──────────▼──────────┐                           │\n│     │            Frontend │   Siwi, /ˈsɪwi/           │\n│     │ Web_Speech_API      │   A PoC of                │\n│     │                     │   Dialog System           │\n│     │ Vue.JS              │   With Graph Database     │\n│     │                     │   Backed Knowledge Graph  │\n│     └──────────┬──────────┘                           │\n│                │  Sentence                            │\n│                │                                      │\n│   ┌────────────┼──────────────────────────────┐       │\n│   │            │                              │       │\n│   │            │              Backend         │       │\n│   │ ┌──────────▼──────────┐                   │       │\n│   │ │ Web API, Flask      │   ./app/          │       │\n│   │ └──────────┬──────────┘                   │       │\n│   │            │  Sentence    ./bot/          │       │\n│   │ ┌──────────▼──────────┐                   │       │\n│   │ │                     │                   │       │\n│   │ │ Intent matching,    │   ./bot/classifier│       │\n│   │ │ Symentic Processing │                   │       │\n│   │ │                     │                   │       │\n│   │ └──────────┬──────────┘                   │       │\n│   │            │  Intent, Entities            │       │\n│   │ ┌──────────▼──────────┐                   │       │\n│   │ │                     │                   │       │\n│   │ │ Intent Actor        │   ./bot/actions   │       │\n│   │ │                     │                   │       │\n│   └─┴──────────┬──────────┴───────────────────┘       │\n│                │  Graph Query                         │\n│     ┌──────────▼──────────┐                           │\n│     │                     │                           │\n│     │ Graph Database      │    Nebula Graph           │\n│     │                     │                           │\n│     └─────────────────────┘                           │\n│                                                       │\n│                                                       │\n│                                                       │\n└───────────────────────────────────────────────────────┘\n```\n\n### Source Code Tree\n\n```bash\n.\n├── README.md\n├── src\n│   ├── siwi                        # Siwi-API Backend\n│   │   ├── app                     # Web Server, take HTTP requests and calls Bot API\n│   │   └── bot                     # Bot API\n│   │       ├── actions             # Take Intent, Slots, Query Knowledge Graph here\n│   │       ├── bot                 # Entrypoint of the Bot API\n│   │       ├── classifier          # Symentic Parsing, Intent Matching, Slot Filling\n│   │       └── test                # Example Data Source as equivalent/mocked module\n│   └── siwi_frontend               # Browser End\n│       ├── README.md\n│       ├── package.json\n│       └── src\n│           ├── App.vue             # Listening to user and pass Questions to Siwi-API\n│           └── main.js\n└── wsgi.py\n```\n\n\n\n## Manually Run Components\n\n### Graph Database\n\nThe backend relis on the [Nebula Graph](https://github.com/vesoft-inc/nebula), an Open Source Distributed Graph Database.\n\nInstall Nebula Graph in oneliner:\n\n```bash\ncurl -fsSL nebula-up.siwei.io/install.sh | bash\n```\n\nLoad the [basketballplayer dataset](https://docs.nebula-graph.com.cn/2.6.2/3.ngql-guide/1.nGQL-overview/1.overview/#basketballplayer).\n\n```bash\n~/.nebula-up/console.sh\nnebula-console -addr graphd -port 9669 -user root -p nebula -e \":play basketballplayer\"\n```\n\n### Backend\n\nInstall and run.\n```bash\n# Install siwi backend\npython3 -m build\n\n# Configure Nebula Graph Endpoint\nexport NG_ENDPOINTS=127.0.0.1:9669\n\n# Run Backend API server\ngunicorn --bind :5000 wsgi --workers 1 --threads 1 --timeout 60\n```\n\n\u003e For OpenFunction/ KNative\n\n```bash\ndocker build -t weygu/siwi-api .\ndocker run --rm --name siwi-api \\\n     --env=PORT=5000 \\\n     --env=NG_ENDPOINTS=127.0.0.1:9669 \\\n     --net=host \\\n     weygu/siwi-api\n```\n\nTry it out Web API:\n```bash\n$ curl -s --header \"Content-Type: application/json\" \\\n       --request POST \\\n       --data '{\"question\": \"What is the relationship between Yao Ming and Lakers?\"}' \\\n       http://192.168.8.128:5000/query | jq\n\n{\n  \"answer\": \"There are at least 23 relations between Yao Ming and Lakers, one relation path is: Yao Ming follows Shaquille O'Neal serves Lakers.\"\n}\n```\n\nCall Bot Python API:\n\n```python\nfrom nebula3.gclient.net import ConnectionPool\nfrom nebula3.Config import Config\n\n# define a config\nconfig = Config()\nconfig.max_connection_pool_size = 10\n# init connection pool\nconnection_pool = ConnectionPool()\n# if the given servers are ok, return true, else return false\nok = connection_pool.init([('127.0.0.1', 9669)], config)\n\n# import siwi bot\nfrom siwi.bot import bot\n\n# instantiate a bot\nb = bot.SiwiBot(connection_pool)\n\n# make the question query\nb.query(\"Which team had Jonathon Simmons served?\")\n```\n\nThen a response will be like this:\n\n```python\nIn [4]: b.query(\"Which team had Jonathon Simmons serv\n   ...: ed?\")\n\n[DEBUG] ServeAction intent: {'entities': {'Jonathon Simmons': 'player'}, 'intents': ('serve',)}\n\n[DEBUG] query for RelationshipAction:\n\tUSE basketballplayer;\n  MATCH p=(v)-[e:serve*1]-\u003e(v1) WHERE id(v) == \"player112\"\n  RETURN p LIMIT 100;\n\n[2021-07-02 02:59:36,392]:Get connection to ('127.0.0.1', 9669)\n\nOut[4]: 'Jonathon Simmons had served 3 teams. Spurs from 2015 to 2015; 76ers from 2019 to 2019; Magic from 2017 to 2017; '\n```\n\n\n\n### Frontend\n\nReferring to [siwi_frontend](https://github.com/wey-gu/nebula-siwi/tree/main/src/siwi_frontend)\n\n\n\n## Deploy with K8s + OpenFunction\n\n\n\n```asciiarmor\n ┌─────────────────────────────┐\n │ kind: Ingress               │     ┌───────────────────┐\n │   path: /                   │     │ Pod               │\n │    -\u003e siwi-frontend     ────┼─────┤  siwi-frontend    │\n │                             │     │                   │\n │                             │     └───────────────────┘\n │                             │\n │   path: /query              │     ┌───────────────────────────────────┐\n │    -\u003e siwi-api          ────┼─────┤ KNative Service                   │\n │       KNative Serving       │     │  serving-xxxx                     │\n │                             │     │                                   │\n │                             │     │ apiVersion: serving.knative.dev/v1│\n │                             │     │ kind: Service                     │\n └─────────────────────────────┘     └─────────┬─────────────────────────┘\n                                               │\n                                               └────────────┐\n                                                            │\n ┌───────────────────────────────────────────────────────┐  │\n │apiVersion: core.openfunction.io/v1alpha1              │  │\n │kind: Function                                         │  │\n │spec:                                                  │  │\n │  version: \"v1.0.0\"                                    │  │\n │  image: \"weygu/siwi-api:latest\"                       │  │\n │  imageCredentials:                                    │  │\n │    name: push-secret                                  │  │\n │  port: 8080                                           │  │\n │  build:                                               │  │\n │    builder: openfunction/builder:v1                   │  │\n │    env:                                               │  │\n │      FUNC_NAME: \"siwi_api\"                            │  │\n │      FUNC_TYPE: \"http\"                                │  │\n │      FUNC_SRC: \"main.py\"                              │  │\n │    srcRepo:                                           │  │\n │      url: \"https://github.com/wey-gu/nebula-siwi.git\" │  │\n │      sourceSubPath: \"src\"                             │  │\n │  serving:                                             │  │\n │    runtime: Knative  ─────────────────────────────────┼──┘\n │    params:                                            │\n │      NG_ENDPOINTS: \"NEBULA_GRAPH_ENDPOINT\"            │\n │    template:                          │               │\n │      containers:                      │               │\n │        - name: function               │               │\n │          imagePullPolicy: Always      │               │\n └───────────────────────────────────────┼───────────────┘\n                                         │\n                              ┌──────────┘\n                              │\n ┌────────────────────────────┴───────────────────────────┐\n │apiVersion:lapps.nebula-graph.io/v1alpha1               │\n │kind: NebulaCluster                                     │\n │spec:                                                   │\n │  graphd:                                               │\n │    config:                                             │\n │      system_memory_high_watermark_ratio: \"1.0\"         │\n │    image: vesoft/nebula-graphd                         │\n │    replicas: 1                                         │\n │...                                                     │\n └────────────────────────────────────────────────────────┘\n```\n\n\u003e Assumed we have a k8s with OpenFunctions installed\n\n### Run it!\n\nInstall a Nebula Graph with `kubesphere-all-in-one` nebula installer on KubeSphere:\n\n```bash\ncurl -sL nebula-kind.siwei.io/install-ks-1.sh | bash\n```\n\nGet Nebula Graph NodePort:\n\n```bash\nNEBULA_GRAPH_ENDPOINT=$(kubectl get svc nebula-graphd-svc-nodeport -o yaml -o jsonpath='{.spec.clusterIP}:{.spec.ports[0].port}')\necho $NEBULA_GRAPH_ENDPOINT\n```\n\nLoad Dataset into the nebula cluster:\n\n```bash\nwget https://docs.nebula-graph.io/2.0/basketballplayer-2.X.ngql\n\n~/.nebula-kind/bin/console -u root -p password --address=\u003cnebula-graphd-svc-nodeport\u003e --port=32669 -f basketballplayer-2.X.ngql\n```\n\nCreate the siwi-api powered by Openfunction:\n\n```bash\ncat siwi-api-function.yaml | sed \"s/NEBULA_GRAPH_ENDPOINT/$NEBULA_GRAPH_ENDPOINT/g\" | kubectl apply -f -\n```\n\nGet the function nebula-siwi and the KNative Service:\n\n```bash\nkubectl get functions nebula-siwi\n\nFUNCTION=$(kubectl get functions nebula-siwi -o go-template='{{.status.serving.resourceRef}}')\n\nkubectl get ksvc -l openfunction.io/serving=$FUNCTION\n\nKSVC=$(kubectl get ksvc -l openfunction.io/serving=$FUNCTION -o=jsonpath='{.items[0].metadata.name}')\n\nkubectl get revision -l serving.knative.dev/service=$KSVC\n\nREVISION=$(kubectl get revision -l serving.knative.dev/service=$KSVC -o=jsonpath='{.items[0].metadata.name}')\n\necho $REVISION\n```\n\nVerify the function worked fine:\n\n```bash\ncurl -s --header \"Content-Type: application/json\" \\\n     --request POST \\\n     --data '{\"question\": \"What is the relationship between Yao Ming and Lakers ?\"}' \\\n     $(kubectl get ksvc -l openfunction.io/serving=$FUNCTION -o=jsonpath='{.items[0].status.url}')/query\n```\n\nCreate the siwi-app resources on K8s:\n\n```bash\ncat siwi-app.yaml | sed \"s/REVISION/$REVISION/g\" | kubectl apply -f -\n```\n\nVerify the function worked fine through the ingress:\n\n\u003e Here nodeport with http port 31059 was used as ingress controller endpoint.\n\n```bash\ncurl -s --header \"Content-Type: application/json\" \\\n     --request POST \\\n     --data '{\"question\": \"how does Tim Duncan and Lakers connected?\"}' \\\n     demo-siwi.local:31059/query\n```\n\nVerify the frontend:\n\n```bash\ncurl $(kubectl get svc -l app=siwi -o=jsonpath='{.items[0].spec.clusterIP}')\n```\n\nVerify the frontend beind the ingress:\n\n```bash\ncurl demo-siwi.local:31059\n```\n\nGet all resources in siwi-app:\n\n```bash\nkubectl get service,pod,ingress,function -l app=siwi\n```\n\nAnd it should be something like this:\n```bash\n[root@wey nebula-siwi]# kubectl get service,pod,ingress,function -l app=siwi\nNAME                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE\nservice/siwi-frontend-file   ClusterIP   10.233.60.81   \u003cnone\u003e        80/TCP    64m\n\nNAME                     READY   STATUS    RESTARTS   AGE\npod/siwi-frontend-file   1/1     Running   0          64m\n\nNAME                                     CLASS    HOSTS             ADDRESS   PORTS   AGE\ningress.networking.k8s.io/siwi-service   \u003cnone\u003e   demo-siwi.local             80      59m\n\nNAME                                        BUILDSTATE   SERVINGSTATE   BUILDER         SERVING         AGE\nfunction.core.openfunction.io/nebula-siwi   Succeeded    Running        builder-sbfz6   serving-vvjvl   26h\n[root@wey nebula-siwi]# kubectl get service,pod,ingress,function -l app=siwi\nNAME                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE\nservice/siwi-frontend-file   ClusterIP   10.233.60.81   \u003cnone\u003e        80/TCP    65m\n\nNAME                     READY   STATUS    RESTARTS   AGE\npod/siwi-frontend-file   1/1     Running   0          65m\n\nNAME                                     CLASS    HOSTS             ADDRESS   PORTS   AGE\ningress.networking.k8s.io/siwi-service   \u003cnone\u003e   demo-siwi.local             80      59m\n\nNAME                                        BUILDSTATE   SERVINGSTATE   BUILDER         SERVING         AGE\nfunction.core.openfunction.io/nebula-siwi   Succeeded    Running        builder-sbfz6   serving-vvjvl   26h\n```\n\n### How to Build the image\n\n```bash\ndocker build -t weygu/siwi-frontend . -f Dockerfile.froentend\ndocker push weygu/siwi-frontend\n```\n\n\n\n## Further work\n\n- [ ] Use [NBA-API](https://github.com/swar/nba_api) to fallback undefined pattern questions\n- [ ] Wrap and manage sessions instead of get and release session per request, this is somehow costly actually.\n- [ ] Use NLP methods to implement proper Symentic Parsing, Intent Matching, Slot Filling\n- [ ] Build Graph to help with Intent Matching, especially for a general purpose bot\n- [ ] Use larger Dataset i.e. from [wyattowalsh/basketball](https://www.kaggle.com/wyattowalsh/basketball)\n\n\n\n## Thanks to Upstream Projects ❤️\n\n### Backend\n\n- I learnt a lot from the [KGQA on MedicalKG](https://github.com/liuhuanyong/QASystemOnMedicalKG) created by [Huanyong Liu](https://liuhuanyong.github.io)\n- [Flask](https://github.com/pallets/flask)\n- [pyahocorasick](https://github.com/WojciechMula/pyahocorasick) created by [Wojciech Muła](http://0x80.pl/)\n- [PyYaml](https://pyyaml.org/)\n\n### Frontend\n\n- [VueJS](https://vuejs.org) for frontend framework\n- [Vue Bot UI](https://github.com/juzser/vue-bot-ui ), as a lovely bot UI in vue\n- [Vue Web Speech](https://github.com/Drackokacka/vue-web-speech ), for speech API vue wrapper\n- [Axios](https://github.com/axios/axios ) for browser http client\n- [Solarized](https://en.wikipedia.org/wiki/Solarized_(color_scheme)) for color scheme\n- [Vitesome](https://github.com/alvarosaburido/vitesome) for landing page design\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwey-gu%2Fnebula-siwi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwey-gu%2Fnebula-siwi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwey-gu%2Fnebula-siwi/lists"}