Siwi (/ˈsɪwi/) es una prueba de concepto de sistema de diálogo con gráfico de conocimiento respaldado por una base de datos gráfica.
Por ahora, es una demostración para robots de diálogo basados en tareas (no de propósito general) con KG (Knowledge Graph) que aprovecha Nebula Graph con el conjunto de datos mínimo/de muestra de Nebula Graph Manual/NG中文手册.
Consejos: ¡Ahora puedes jugar con el gráfico en línea sin instalarte!
Zona de juegos nebulosa | Parque infantil Nebula - China continental
Consultas admitidas:
relation
:
serving
:
friendship
:
Puedes probarlo desde cero aquí: https://siwei.io/learn/nebula-101-siwi-kgqa/
Este es uno de los procesos más ingenuos para un dominio específico/bot de chat de un solo propósito creado en un Gráfico de conocimiento.
El Backend (Siwi API) es un servidor API basado en Flask:
El servidor Flask API responde preguntas en HTTP POST y llama a la API del bot.
En la parte de la API del bot hay clasificadores (análisis siméntico, coincidencia de intenciones, llenado de espacios) y actores de preguntas (llame a las acciones correspondientes para consultar el gráfico de conocimiento con intenciones y espacios).
Knowledge Graph se basa en una base de datos de gráficos de código abierto: Nebula Graph
El frontend es una aplicación de página única (SPA) de VueJS:
┌────────────────┬──────────────────────────────────────┐
│ │ │
│ │ Speech │
│ ┌──────────▼──────────┐ │
│ │ Frontend │ Siwi, /ˈsɪwi/ │
│ │ Web_Speech_API │ A PoC of │
│ │ │ Dialog System │
│ │ Vue.JS │ With Graph Database │
│ │ │ Backed Knowledge Graph │
│ └──────────┬──────────┘ │
│ │ Sentence │
│ │ │
│ ┌────────────┼──────────────────────────────┐ │
│ │ │ │ │
│ │ │ Backend │ │
│ │ ┌──────────▼──────────┐ │ │
│ │ │ Web API, Flask │ ./app/ │ │
│ │ └──────────┬──────────┘ │ │
│ │ │ Sentence ./bot/ │ │
│ │ ┌──────────▼──────────┐ │ │
│ │ │ │ │ │
│ │ │ Intent matching, │ ./bot/classifier│ │
│ │ │ Symentic Processing │ │ │
│ │ │ │ │ │
│ │ └──────────┬──────────┘ │ │
│ │ │ Intent, Entities │ │
│ │ ┌──────────▼──────────┐ │ │
│ │ │ │ │ │
│ │ │ Intent Actor │ ./bot/actions │ │
│ │ │ │ │ │
│ └─┴──────────┬──────────┴───────────────────┘ │
│ │ Graph Query │
│ ┌──────────▼──────────┐ │
│ │ │ │
│ │ Graph Database │ Nebula Graph │
│ │ │ │
│ └─────────────────────┘ │
│ │
│ │
│ │
└───────────────────────────────────────────────────────┘
.
├── README.md
├── src
│ ├── siwi # Siwi-API Backend
│ │ ├── app # Web Server, take HTTP requests and calls Bot API
│ │ └── bot # Bot API
│ │ ├── actions # Take Intent, Slots, Query Knowledge Graph here
│ │ ├── bot # Entrypoint of the Bot API
│ │ ├── classifier # Symentic Parsing, Intent Matching, Slot Filling
│ │ └── test # Example Data Source as equivalent/mocked module
│ └── siwi_frontend # Browser End
│ ├── README.md
│ ├── package.json
│ └── src
│ ├── App.vue # Listening to user and pass Questions to Siwi-API
│ └── main.js
└── wsgi.py
El backend se basa en Nebula Graph, una base de datos de gráficos distribuidos de código abierto.
Instale Nebula Graph en oneliner:
curl -fsSL nebula-up.siwei.io/install.sh | bash
Cargue el conjunto de datos del jugador de baloncesto.
~ /.nebula-up/console.sh
nebula-console -addr graphd -port 9669 -user root -p nebula -e " :play basketballplayer "
Instalar y ejecutar.
# Install siwi backend
python3 -m build
# Configure Nebula Graph Endpoint
export NG_ENDPOINTS=127.0.0.1:9669
# Run Backend API server
gunicorn --bind :5000 wsgi --workers 1 --threads 1 --timeout 60
Para función abierta/KNative
docker build -t weygu/siwi-api .
docker run --rm --name siwi-api
--env=PORT=5000
--env=NG_ENDPOINTS=127.0.0.1:9669
--net=host
weygu/siwi-api
Pruébelo API web:
$ curl -s --header " Content-Type: application/json "
--request POST
--data ' {"question": "What is the relationship between Yao Ming and Lakers?"} '
http://192.168.8.128:5000/query | jq
{
" answer " : " There are at least 23 relations between Yao Ming and Lakers, one relation path is: Yao Ming follows Shaquille O'Neal serves Lakers. "
}
Llame a la API de Bot Python:
from nebula3 . gclient . net import ConnectionPool
from nebula3 . Config import Config
# define a config
config = Config ()
config . max_connection_pool_size = 10
# init connection pool
connection_pool = ConnectionPool ()
# if the given servers are ok, return true, else return false
ok = connection_pool . init ([( '127.0.0.1' , 9669 )], config )
# import siwi bot
from siwi . bot import bot
# instantiate a bot
b = bot . SiwiBot ( connection_pool )
# make the question query
b . query ( "Which team had Jonathon Simmons served?" )
Entonces una respuesta será así:
In [ 4 ]: b . query (" Which team had Jonathon Simmons serv
...: ed ?")
[ DEBUG ] ServeAction intent : { 'entities' : { 'Jonathon Simmons' : 'player' }, 'intents' : ( 'serve' ,)}
[ DEBUG ] query for RelationshipAction :
USE basketballplayer ;
MATCH p = ( v ) - [ e : serve * 1 ] - > ( v1 ) WHERE id ( v ) == "player112"
RETURN p LIMIT 100 ;
[ 2021 - 07 - 02 02 : 59 : 36 , 392 ]: Get connection to ( '127.0.0.1' , 9669 )
Out [ 4 ]: 'Jonathon Simmons had served 3 teams. Spurs from 2015 to 2015; 76ers from 2019 to 2019; Magic from 2017 to 2017; '
Refiriéndose a siwi_frontend
┌─────────────────────────────┐
│ kind: Ingress │ ┌───────────────────┐
│ path: / │ │ Pod │
│ -> siwi-frontend ────┼─────┤ siwi-frontend │
│ │ │ │
│ │ └───────────────────┘
│ │
│ path: /query │ ┌───────────────────────────────────┐
│ -> siwi-api ────┼─────┤ KNative Service │
│ KNative Serving │ │ serving-xxxx │
│ │ │ │
│ │ │ apiVersion: serving.knative.dev/v1│
│ │ │ kind: Service │
└─────────────────────────────┘ └─────────┬─────────────────────────┘
│
└────────────┐
│
┌───────────────────────────────────────────────────────┐ │
│apiVersion: core.openfunction.io/v1alpha1 │ │
│kind: Function │ │
│spec: │ │
│ version: "v1.0.0" │ │
│ image: "weygu/siwi-api:latest" │ │
│ imageCredentials: │ │
│ name: push-secret │ │
│ port: 8080 │ │
│ build: │ │
│ builder: openfunction/builder:v1 │ │
│ env: │ │
│ FUNC_NAME: "siwi_api" │ │
│ FUNC_TYPE: "http" │ │
│ FUNC_SRC: "main.py" │ │
│ srcRepo: │ │
│ url: "https://github.com/wey-gu/nebula-siwi.git" │ │
│ sourceSubPath: "src" │ │
│ serving: │ │
│ runtime: Knative ─────────────────────────────────┼──┘
│ params: │
│ NG_ENDPOINTS: "NEBULA_GRAPH_ENDPOINT" │
│ template: │ │
│ containers: │ │
│ - name: function │ │
│ imagePullPolicy: Always │ │
└───────────────────────────────────────┼───────────────┘
│
┌──────────┘
│
┌────────────────────────────┴───────────────────────────┐
│apiVersion:lapps.nebula-graph.io/v1alpha1 │
│kind: NebulaCluster │
│spec: │
│ graphd: │
│ config: │
│ system_memory_high_watermark_ratio: "1.0" │
│ image: vesoft/nebula-graphd │
│ replicas: 1 │
│... │
└────────────────────────────────────────────────────────┘
Supongamos que tenemos un k8s con OpenFunctions instalado
Instale un Nebula Graph con el instalador de nebulosa kubesphere-all-in-one
en KubeSphere:
curl -sL nebula-kind.siwei.io/install-ks-1.sh | bash
Obtenga el puerto de nodo del gráfico de nebulosa:
NEBULA_GRAPH_ENDPOINT= $( kubectl get svc nebula-graphd-svc-nodeport -o yaml -o jsonpath= ' {.spec.clusterIP}:{.spec.ports[0].port} ' )
echo $NEBULA_GRAPH_ENDPOINT
Cargue el conjunto de datos en el grupo de nebulosas:
wget https://docs.nebula-graph.io/2.0/basketballplayer-2.X.ngql
~ /.nebula-kind/bin/console -u root -p password --address= < nebula-graphd-svc-nodeport > --port=32669 -f basketballplayer-2.X.ngql
Cree la siwi-api impulsada por Openfunction:
cat siwi-api-function.yaml | sed " s/NEBULA_GRAPH_ENDPOINT/ $NEBULA_GRAPH_ENDPOINT /g " | kubectl apply -f -
Obtenga la función nebula-siwi y el servicio KNative:
kubectl get functions nebula-siwi
FUNCTION= $( kubectl get functions nebula-siwi -o go-template= ' {{.status.serving.resourceRef}} ' )
kubectl get ksvc -l openfunction.io/serving= $FUNCTION
KSVC= $( kubectl get ksvc -l openfunction.io/serving= $FUNCTION -o=jsonpath= ' {.items[0].metadata.name} ' )
kubectl get revision -l serving.knative.dev/service= $KSVC
REVISION= $( kubectl get revision -l serving.knative.dev/service= $KSVC -o=jsonpath= ' {.items[0].metadata.name} ' )
echo $REVISION
Verifique que la función funcionó bien:
curl -s --header " Content-Type: application/json "
--request POST
--data ' {"question": "What is the relationship between Yao Ming and Lakers ?"} '
$( kubectl get ksvc -l openfunction.io/serving= $FUNCTION -o=jsonpath= ' {.items[0].status.url} ' ) /query
Cree los recursos de la aplicación siwi en K8:
cat siwi-app.yaml | sed " s/REVISION/ $REVISION /g " | kubectl apply -f -
Verifique que la función funcionó bien a través del ingreso:
Aquí se utilizó nodeport con el puerto http 31059 como punto final del controlador de ingreso.
curl -s --header " Content-Type: application/json "
--request POST
--data ' {"question": "how does Tim Duncan and Lakers connected?"} '
demo-siwi.local:31059/query
Verifique la interfaz:
curl $( kubectl get svc -l app=siwi -o=jsonpath= ' {.items[0].spec.clusterIP} ' )
Verifique la interfaz detrás de la entrada:
curl demo-siwi.local:31059
Obtenga todos los recursos en siwi-app:
kubectl get service,pod,ingress,function -l app=siwi
Y debería ser algo como esto:
[root@wey nebula-siwi] # kubectl get service,pod,ingress,function -l app=siwi
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/siwi-frontend-file ClusterIP 10.233.60.81 < none > 80/TCP 64m
NAME READY STATUS RESTARTS AGE
pod/siwi-frontend-file 1/1 Running 0 64m
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/siwi-service < none > demo-siwi.local 80 59m
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING AGE
function.core.openfunction.io/nebula-siwi Succeeded Running builder-sbfz6 serving-vvjvl 26h
[root@wey nebula-siwi] # kubectl get service,pod,ingress,function -l app=siwi
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/siwi-frontend-file ClusterIP 10.233.60.81 < none > 80/TCP 65m
NAME READY STATUS RESTARTS AGE
pod/siwi-frontend-file 1/1 Running 0 65m
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/siwi-service < none > demo-siwi.local 80 59m
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING AGE
function.core.openfunction.io/nebula-siwi Succeeded Running builder-sbfz6 serving-vvjvl 26h
docker build -t weygu/siwi-frontend . -f Dockerfile.froentend
docker push weygu/siwi-frontend