mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-06-09 14:55:13 +02:00
Merge branch 'release/v0.18'
This commit is contained in:
commit
b026590e76
35 changed files with 1490 additions and 167 deletions
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- v0.17.*
|
||||
- v0.18.*
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
username: ${{ vars.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_SECRET }}
|
||||
|
||||
- name: Install build dependencies
|
||||
|
|
|
|||
|
|
@ -164,9 +164,13 @@ tg-invoke-agent -v -q "Write a blog post about the 5 key takeaways from SB1047 a
|
|||
> [!TIP]
|
||||
> Adding `-v` to the agent request will return all of the agent manager's thoughts and observations that led to the final response.
|
||||
|
||||
## API documentation
|
||||
|
||||
[Developing on TrustGraph using APIs](docs/api/README.md)
|
||||
|
||||
## Deploy and Manage TrustGraph
|
||||
|
||||
[🚀 Full Deployment Guide 🚀](https://trustgraph.ai/docs/getstarted)
|
||||
[🚀🙏 Full Deployment Guide 🚀🙏](https://trustgraph.ai/docs/getstarted)
|
||||
|
||||
## TrustGraph Developer's Guide
|
||||
|
||||
|
|
|
|||
72
docs/apis/README.md
Normal file
72
docs/apis/README.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
# TrustGraph APIs
|
||||
|
||||
## Overview
|
||||
|
||||
If you want to interact with TrustGraph through APIs, there are 3
|
||||
forms of API which may be of interest to you:
|
||||
|
||||
### Pulsar APIs
|
||||
|
||||
Apache Pulsar is a pub/sub system used to deliver messages between TrustGraph
|
||||
components. Using Pulsar, you can communicate with TrustGraph components.
|
||||
|
||||
Pros:
|
||||
- Provides complete access to all TrustGraph functionality
|
||||
- Simple integration with metrics and observability
|
||||
|
||||
Cons:
|
||||
- Integration is non-trivial, requires a special-purpose Pulsar client
|
||||
library
|
||||
- The Pulsar interfaces are likely something that you would not want to
|
||||
expose outside of the processing cluster in a production or well-secured
|
||||
deployment
|
||||
|
||||
### REST APIs
|
||||
|
||||
A component, `api-gateway`, provides a bridge between Pulsar internals and
|
||||
the REST API which allows many services to be invoked using REST APIs.
|
||||
|
||||
Pros:
|
||||
- Uses standard REST approach can be easily integrated into many kinds
|
||||
of technology
|
||||
- Can be easily protected with authentication and TLS for production-grade
|
||||
or secure deployments
|
||||
|
||||
Cons:
|
||||
- For a complex application, a long series of REST invocations has
|
||||
latency and performance overheads - HTTP has limits on the number
|
||||
of concurrent service invocations
|
||||
- Lower coverage of functionality - service interfaces need to be added to
|
||||
`api-gateway` to permit REST invocation
|
||||
|
||||
### Websocket API
|
||||
|
||||
The `api-gateway` component also provides access to services through a
|
||||
websocket API.
|
||||
|
||||
Pros:
|
||||
- Usable through a standard websocket library
|
||||
- Can be easily protected with authentication and TLS for production-grade
|
||||
or secure deployments
|
||||
- Supports concurrent service invocations
|
||||
|
||||
Cons:
|
||||
- Websocket service invocation is a little more complex to develop than
|
||||
using a basic REST API, particular if you want to cover all of the error
|
||||
scenarios well
|
||||
|
||||
## See also
|
||||
|
||||
- [TrustGraph websocket overview](websocket.md)
|
||||
- [TrustGraph Pulsar overview](pulsar.md)
|
||||
- API details
|
||||
- [Text completion](api-text-completion.md)
|
||||
- [Prompt completion](api-prompt.md)
|
||||
- [Graph RAG](api-graph-rag.md)
|
||||
- [Agent](api-agent.md)
|
||||
- [Embeddings](api-embeddings.md)
|
||||
- [Graph embeddings](api-graph-embeddings.md)
|
||||
- [Triples query](api-triples-query.md)
|
||||
- [Document load](api-document-load.md)
|
||||
|
||||
135
docs/apis/api-agent.md
Normal file
135
docs/apis/api-agent.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
# TrustGraph Agent API
|
||||
|
||||
The REST service provides incomplete functionality: The agent service
|
||||
is able to provide multi-part responses containing 'thought' and
|
||||
'observation' messages as the agent manager iterates over resolution of the
|
||||
question. These responses are provided in the websocket, but not the REST
|
||||
API.
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `question`: A string, the question which the agent API must resolve
|
||||
- `plan`: Optional, not used
|
||||
- `state`: Optional, not used
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `thought`: Optional, a string, provides an interim agent thought
|
||||
- `observation`: Optional, a string, provides an interim agent thought
|
||||
- `answer`: Optional, a string, provides the final answer
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the question field.
|
||||
The response is a JSON object containing the `answer` field. Interim
|
||||
responses are not provided.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"question": "What does NASA stand for?"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"answer": "National Aeronautics and Space Administration"
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Agent requests have a `request` object containing the `question` field.
|
||||
Responses have a `response` object containing `thought`, `observation`
|
||||
and `answer` fields in multi-part responses. The final `answer` response
|
||||
has `complete` set to `true`.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"service": "agent",
|
||||
"request": {
|
||||
"question": "What does NASA stand for?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Responses:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"thought": "I need to query a knowledge base"
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"observation": "National Aeronautics and Space Administration."
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"thought": "I now know the final answer"
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"answer": "National Aeronautics and Space Administration"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Agent API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/agent.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/agent`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/agent`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.AgentRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.AgentResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.AgentClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/agent_client.py
|
||||
3
docs/apis/api-document-load.md
Normal file
3
docs/apis/api-document-load.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
Coming soon
|
||||
|
||||
106
docs/apis/api-embeddings.md
Normal file
106
docs/apis/api-embeddings.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
# TrustGraph Embeddings API
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `text`: A string, the text to apply the embedding to
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `vectors`: Embeddings response, an array of arrays. An embedding is
|
||||
an array of floating-point numbers. As multiple embeddings may be
|
||||
returned, an array of embeddings is returned, hence an array
|
||||
of arrays.
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the question field.
|
||||
The response is a JSON object containing the `answer` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"text": "What does NASA stand for?"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"vectors": [ 0.231341245, ... ]
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Embeddings requests have a `request` object containing the `text` field.
|
||||
Responses have a `response` object containing `vectors` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-2",
|
||||
"service": "embeddings",
|
||||
"request": {
|
||||
"text": "What is a cat?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Responses:
|
||||
|
||||
```
|
||||
|
||||
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-2",
|
||||
"response": {
|
||||
"vectors": [
|
||||
[
|
||||
0.04013510048389435,
|
||||
0.07536131888628006,
|
||||
...
|
||||
-0.023531345650553703,
|
||||
0.03591292351484299
|
||||
]
|
||||
]
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Embeddings API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/models.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/embeddings`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/embeddings`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.EmbeddingsRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.EmbeddingsResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.EmbeddingsClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/embeddings_client.py
|
||||
|
||||
155
docs/apis/api-graph-embeddings.md
Normal file
155
docs/apis/api-graph-embeddings.md
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
|
||||
# TrustGraph Graph Embeddings API
|
||||
|
||||
The purpose of this API is to search for knowledge graph entities
|
||||
by embeddings. The request is a list of embeddings, the response is
|
||||
a list of knowledge graph entities. The search is performed using a
|
||||
vector store.
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `vectors`: An array of embeddings. Each embedding is itself an array
|
||||
of numbers.
|
||||
- `limit`: Optional: a limit on the number of graph entities to return.
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `entities`: An array of graph entities. The entity type is described here:
|
||||
|
||||
TrustGraph uses the same schema for knowledge graph elements:
|
||||
- `value`: the entity URI or literal value depending on whether this is
|
||||
graph entity or literal value.
|
||||
- `is_uri`: A boolean value which is true if this is a graph entity i.e.
|
||||
`value` is a URI, not a literal value.
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the `vectors` field.
|
||||
The response is a JSON object containing the `entities` field.
|
||||
|
||||
To reduce the size of the JSON, the graph entities are encoded as an
|
||||
object with `value` and `is_uri` mapped to `v` and `e` respectively.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"vectors": [
|
||||
[
|
||||
0.04013510048389435,
|
||||
0.07536131888628006,
|
||||
...
|
||||
-0.10790473222732544,
|
||||
0.03591292351484299
|
||||
]
|
||||
],
|
||||
"limit": 15
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
{
|
||||
"v": "http://trustgraph.ai/e/rocket-propellants",
|
||||
"e": true
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
The websocket service accepts a request object containing the `vectors` field.
|
||||
The response is a JSON object containing the `entities` field.
|
||||
|
||||
To reduce the size of the JSON, the graph entities are encoded as an
|
||||
object with `value` and `is_uri` mapped to `v` and `e` respectively.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-3",
|
||||
"service": "graph-embeddings-query",
|
||||
"request": {
|
||||
"vectors": [
|
||||
[
|
||||
0.04013510048389435,
|
||||
0.07536131888628006,
|
||||
...
|
||||
-0.10790473222732544,
|
||||
0.03591292351484299
|
||||
]
|
||||
],
|
||||
"limit": 15
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-3",
|
||||
"response": {
|
||||
"entities": [
|
||||
{
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
{
|
||||
"v": "http://trustgraph.ai/e/rocket-propellants",
|
||||
"e": true
|
||||
},
|
||||
]
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Graph Embeddings API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/graph.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/graph-embeddings`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/graph-embeddings`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.GraphEmbeddingsRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.GraphEmbeddingsResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.GraphEmbeddingsClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/graph_embeddings.py
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
97
docs/apis/api-graph-rag.md
Normal file
97
docs/apis/api-graph-rag.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
# TrustGraph Graph RAG API
|
||||
|
||||
This presents a prompt to the Graph RAG service and retrieves the answer.
|
||||
This makes use of a number of the other APIs behind the scenes:
|
||||
Embeddings, Graph Embeddings, Prompt, TextCompletion, Triples Query.
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `query`: The question to answer
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `response`: LLM response
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the `query` field.
|
||||
The response is a JSON object containing the `response` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"query": "What does NASA stand for?"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"response": "National Aeronautics and Space Administration"
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Requests have a `request` object containing the `query` field.
|
||||
Responses have a `response` object containing `response` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-14",
|
||||
"service": "graph-rag",
|
||||
"request": {
|
||||
"query": "What does NASA stand for?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-14",
|
||||
"response": {
|
||||
"response": "National Aeronautics and Space Administration"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Graph RAG API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/retrieval.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/graph-rag`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/graph-rag`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.GraphRagRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.GraphRagResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.GraphRagClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/graph_rag_client.py
|
||||
|
||||
140
docs/apis/api-prompt.md
Normal file
140
docs/apis/api-prompt.md
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
# TrustGraph Prompt API
|
||||
|
||||
This is a higher-level interface to the LLM service. The input
|
||||
specifies a prompt template by ID and some variables to include in the
|
||||
template.
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `id`: A prompt template ID
|
||||
- `variables`: A set of key/values describing the variables
|
||||
|
||||
### Response
|
||||
|
||||
The request contains either of these fields:
|
||||
- `text`: A plain text response
|
||||
- `object`: A structured object, JSON-encoded
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts `id` and `variables` fields, the variables are
|
||||
encoded as a JSON object.
|
||||
|
||||
e.g.
|
||||
|
||||
In this example, the template takes a `text` variable and returns an
|
||||
array of entity definitions in t he `object` field. The value is
|
||||
JSON-encoded.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"id": "extract-definitions",
|
||||
"variables": {
|
||||
"text": "A cat is a domesticated Felidae animal"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"object": "[{\"entity\": \"cat\", \"definition\": \"a domesticated Felidae animal\"}]"
|
||||
},
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Requests have `id` and `variables` fields.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "akshfkiehfkseffh-142",
|
||||
"service": "prompt",
|
||||
"request": {
|
||||
"id": "extract-definitions",
|
||||
"variables": {
|
||||
"text": "A cat is a domesticated Felidae animal"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Responses:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "akshfkiehfkseffh-142",
|
||||
"response": {
|
||||
"object": "[{\"entity\": \"cat\", \"definition\": \"a domesticated Felidae animal\"}]"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
e.g.
|
||||
|
||||
An example which returns plain text
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "akshfkiehfkseffh-141",
|
||||
"service": "prompt",
|
||||
"request": {
|
||||
"id": "question",
|
||||
"variables": {
|
||||
"question": "What is 2 + 2?"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "akshfkiehfkseffh-141",
|
||||
"response": {
|
||||
"text": "2 + 2 = 4"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Prompt API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/prompt.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/prompt`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/prompt`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.PromptRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.PromptResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.PromptClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/prompt_client.py
|
||||
|
||||
105
docs/apis/api-text-completion.md
Normal file
105
docs/apis/api-text-completion.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
# TrustGraph Text Completion API
|
||||
|
||||
This is a low-level interface to the LLM service. For a higher-level
|
||||
interface with template management, consider the
|
||||
[Prompt API](api-prompt.md).
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
Some LLM system permit specifying a separate `system` prompt. When
|
||||
the same system prompt is used repeatedly, this can result in lower
|
||||
token costs for the system part or quicker LLM response.
|
||||
|
||||
The request contains the following fields:
|
||||
- `system`: A string, the system part
|
||||
- `prompt`: A string, the user part
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `response`: LLM response
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the question field.
|
||||
The response is a JSON object containing the `answer` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"system": "You are a helpful agent",
|
||||
"prompt": "What does NASA stand for?"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"response": "National Aeronautics and Space Administration"
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Requests have a `request` object containing the `system` and
|
||||
`prompt` fields.
|
||||
Responses have a `response` object containing `response` field.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-1",
|
||||
"service": "text-completion",
|
||||
"request": {
|
||||
"system": "You are a helpful agent",
|
||||
"prompt": "What does NASA stand for?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-1",
|
||||
"response": {
|
||||
"response": "National Aeronautics and Space Administration"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Text Completion API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/models.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/text-completion`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/text-completion`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.TextCompletionRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.TextCompletionResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.LlmClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/llm_client.py
|
||||
|
||||
187
docs/apis/api-triples-query.md
Normal file
187
docs/apis/api-triples-query.md
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
|
||||
# TrustGraph Triples Query API
|
||||
|
||||
This is a service which queries the knowledge graph for triples ("facts").
|
||||
|
||||
## Request/response
|
||||
|
||||
### Request
|
||||
|
||||
The request contains the following fields:
|
||||
- `s`: Optional, if included specifies a match for the subject part of a
|
||||
triple.
|
||||
- `p`: Optional, if included specifies a match for the subject part of a
|
||||
triple.
|
||||
- `o`: Optional, if included specifies a match for the subject part of a
|
||||
triple.
|
||||
- `limit`: Optional, if included specifies the maximum number of triples to
|
||||
return. If not specified, an arbitrary value is used.
|
||||
|
||||
Returned triples will match all of `s`, `p` and `o` where provided.
|
||||
|
||||
### Response
|
||||
|
||||
The request contains the following fields:
|
||||
- `response`: A list of triples.
|
||||
|
||||
Each triple contains `s`, `p` and `o` fields describing the
|
||||
subject, predicate and object part of each triple.
|
||||
|
||||
Each triple element uses the same schema:
|
||||
- `value`: the entity URI or literal value depending on whether this is
|
||||
graph entity or literal value.
|
||||
- `is_uri`: A boolean value which is true if this is a graph entity i.e.
|
||||
`value` is a URI, not a literal value.
|
||||
|
||||
## REST service
|
||||
|
||||
The REST service accepts a request object containing the `s`, `p`, `o`
|
||||
and `limit` fields.
|
||||
The response is a JSON object containing the `response` field.
|
||||
|
||||
To reduce the size of the JSON, the graph entities are encoded as an
|
||||
object with `value` and `is_uri` mapped to `v` and `e` respectively.
|
||||
|
||||
e.g.
|
||||
|
||||
This example query matches triples with a subject of
|
||||
`http://trustgraph.ai/e/space-station-modules` and a predicate of
|
||||
`http://www.w3.org/2000/01/rdf-schema#label`. This predicate
|
||||
represents the RDF schema 'label' relationship.
|
||||
|
||||
The response is a single triple - the `o` element contains the
|
||||
literal "space station modules" which is the label for
|
||||
`http://trustgraph.ai/e/space-station-modules`.
|
||||
|
||||
Request:
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-4",
|
||||
"service": "triples-query",
|
||||
"request": {
|
||||
"s": {
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
"p": {
|
||||
"v": "http://www.w3.org/2000/01/rdf-schema#label",
|
||||
"e": true
|
||||
},
|
||||
"limit": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```
|
||||
{
|
||||
"response": [
|
||||
{
|
||||
"s": {
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
"p": {
|
||||
"v": "http://www.w3.org/2000/01/rdf-schema#label",
|
||||
"e": true
|
||||
},
|
||||
"o": {
|
||||
"v": "space station modules",
|
||||
"e": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Websocket
|
||||
|
||||
Requests have a `request` object containing the `system` and
|
||||
`prompt` fields.
|
||||
Responses have a `response` object containing `response` field.
|
||||
|
||||
To reduce the size of the JSON, the graph entities are encoded as an
|
||||
object with `value` and `is_uri` mapped to `v` and `e` respectively.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-4",
|
||||
"service": "triples-query",
|
||||
"request": {
|
||||
"s": {
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
"p": {
|
||||
"v": "http://www.w3.org/2000/01/rdf-schema#label",
|
||||
"e": true
|
||||
},
|
||||
"limit": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Responses:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-4",
|
||||
"response": {
|
||||
"response": [
|
||||
{
|
||||
"s": {
|
||||
"v": "http://trustgraph.ai/e/space-station-modules",
|
||||
"e": true
|
||||
},
|
||||
"p": {
|
||||
"v": "http://www.w3.org/2000/01/rdf-schema#label",
|
||||
"e": true
|
||||
},
|
||||
"o": {
|
||||
"v": "space station modules",
|
||||
"e": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Pulsar
|
||||
|
||||
The Pulsar schema for the Triples Query API is defined in Python code here:
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/schema/graph.py
|
||||
|
||||
Default request queue:
|
||||
`non-persistent://tg/request/triples-query`
|
||||
|
||||
Default response queue:
|
||||
`non-persistent://tg/response/triples-query`
|
||||
|
||||
Request schema:
|
||||
`trustgraph.schema.TriplesQueryRequest`
|
||||
|
||||
Response schema:
|
||||
`trustgraph.schema.TriplesQueryResponse`
|
||||
|
||||
## Pulsar Python client
|
||||
|
||||
The client class is
|
||||
`trustgraph.clients.TriplesQueryClient`
|
||||
|
||||
https://github.com/trustgraph-ai/trustgraph/blob/master/trustgraph-base/trustgraph/clients/triples_query_client.py
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3
docs/apis/pulsar.md
Normal file
3
docs/apis/pulsar.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
Coming soon
|
||||
|
||||
136
docs/apis/websocket.md
Normal file
136
docs/apis/websocket.md
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
# TrustGraph websocket overview
|
||||
|
||||
The websocket service is provided by the `api-gateway` service on port
|
||||
8088.
|
||||
|
||||
## URL
|
||||
|
||||
Depending on how the service is hosted, the websocket is invoked on this
|
||||
URL on `api-gateway`:
|
||||
|
||||
```
|
||||
/api/v1/socket
|
||||
```
|
||||
|
||||
When hosted using docker compose, you can access the service at
|
||||
`ws://localhost:8088/api/v1/socket`
|
||||
|
||||
## Request
|
||||
|
||||
A request message is a JSON message containing 3 fields:
|
||||
|
||||
- `id`: A unique ID which is used to correlate requests and responses.
|
||||
You should make sure it is unique.
|
||||
- `service`: The name of the service to invoke.
|
||||
- `request`: The request body which is passed to the service - this is
|
||||
defined in the API documentation for that service.
|
||||
|
||||
e.g.
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-1",
|
||||
"service": "graph-rag",
|
||||
"request": {
|
||||
"query": "What does NASA stand for?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
A response message is JSON encoded, and may contain the following fields:
|
||||
|
||||
- `id`: This is the same value provided on the request and shows which
|
||||
request this response is returned for.
|
||||
- `error`: If an error occured, this field is provided, and provides an
|
||||
error message.
|
||||
- `response`: For a non-error case, this provides a response from the
|
||||
service - the response structure depends on the service invoked. It is
|
||||
not provided if the `error` field is provided.
|
||||
- `complete`: A boolean value indicating whether this response is the
|
||||
final response from the service. If set to false, the response values
|
||||
are intermediate values. It is not provided if the `error` field is
|
||||
provided.
|
||||
|
||||
An error response completes a request - no further responses
|
||||
will be provided.
|
||||
|
||||
e.g.
|
||||
|
||||
```
|
||||
{
|
||||
"id": "qgzw1287vfjc8wsk-1",
|
||||
"response": {
|
||||
"response": "National Aeronautics and Space Administration."
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
## Multi-part response
|
||||
|
||||
For a multi-part response, a number of responses are provided with the
|
||||
same ID until the final message which has the `complete` field set to
|
||||
true.
|
||||
|
||||
Note that multi-part responses are a feature of the websocket API which
|
||||
the request/response nature of the REST API is not able to provide.
|
||||
|
||||
e.g.
|
||||
|
||||
Request:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"service": "agent",
|
||||
"request": {
|
||||
"question": "What does NASA stand for?"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Responses:
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"thought": "I need to query a knowledge base"
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"observation": "National Aeronautics and Space Administration."
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"thought": "I now know the final answer"
|
||||
},
|
||||
"complete": false
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
{
|
||||
"id": "blrqotfefnmnh7de-20",
|
||||
"response": {
|
||||
"answer": "National Aeronautics and Space Administration"
|
||||
},
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -14,6 +14,12 @@ scrape_configs:
|
|||
# The job name is added as a label `job=<job_name>` to any timeseries
|
||||
# scraped from this config.
|
||||
|
||||
- job_name: 'pulsar'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'pulsar:8080'
|
||||
|
||||
- job_name: 'pdf-decoder'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
|
|
@ -26,122 +32,116 @@ scrape_configs:
|
|||
- targets:
|
||||
- 'chunker:8000'
|
||||
|
||||
|
||||
- job_name: 'vectorize'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'vectorize:8000'
|
||||
|
||||
|
||||
- job_name: 'embeddings'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'embeddings:8000'
|
||||
|
||||
|
||||
- job_name: 'kg-extract-definitions'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'kg-extract-definitions:8000'
|
||||
|
||||
|
||||
- job_name: 'kg-extract-topics'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'kg-extract-topics:8000'
|
||||
|
||||
|
||||
- job_name: 'kg-extract-relationships'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'kg-extract-relationships:8000'
|
||||
|
||||
|
||||
- job_name: 'metering'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'metering:8000'
|
||||
|
||||
|
||||
- job_name: 'metering-rag'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'metering-rag:8000'
|
||||
|
||||
|
||||
- job_name: 'store-graph-embeddings'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'store-graph-embeddings:8000'
|
||||
|
||||
|
||||
- job_name: 'store-triples'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'store-triples:8000'
|
||||
|
||||
|
||||
- job_name: 'text-completion'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'text-completion:8000'
|
||||
|
||||
|
||||
- job_name: 'text-completion-rag'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'text-completion-rag:8000'
|
||||
|
||||
|
||||
- job_name: 'graph-rag'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'graph-rag:8000'
|
||||
|
||||
|
||||
- job_name: 'prompt'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'prompt:8000'
|
||||
|
||||
|
||||
- job_name: 'prompt-rag'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'prompt-rag:8000'
|
||||
|
||||
|
||||
- job_name: 'query-graph-embeddings'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'query-graph-embeddings:8000'
|
||||
|
||||
|
||||
- job_name: 'query-triples'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'query-triples:8000'
|
||||
|
||||
|
||||
- job_name: 'pulsar'
|
||||
- job_name: 'agent-manager'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'pulsar:8080'
|
||||
- 'agent-manager:8000'
|
||||
|
||||
- job_name: 'api-gateway'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'api-gateway:8000'
|
||||
|
||||
- job_name: 'workbench-ui'
|
||||
scrape_interval: 5s
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'workbench-ui:8000'
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
"vector-store-qdrant": import "components/qdrant.jsonnet",
|
||||
"vector-store-pinecone": import "components/pinecone.jsonnet",
|
||||
"vertexai": import "components/vertexai.jsonnet",
|
||||
"workbench-ui": import "components/workbench-ui.jsonnet",
|
||||
"null": {},
|
||||
|
||||
"agent-manager-react": import "components/agent-manager-react.jsonnet",
|
||||
|
|
|
|||
32
templates/components/workbench-ui.jsonnet
Normal file
32
templates/components/workbench-ui.jsonnet
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
local images = import "values/images.jsonnet";
|
||||
|
||||
{
|
||||
|
||||
"workbench-ui" +: {
|
||||
|
||||
create:: function(engine)
|
||||
|
||||
local container =
|
||||
engine.container("workbench-ui")
|
||||
.with_image(images["workbench-ui"])
|
||||
.with_limits("0.1", "256M")
|
||||
.with_reservations("0.1", "256M")
|
||||
.with_port(8888, 8888, "ui");
|
||||
|
||||
local containerSet = engine.containers(
|
||||
"workbench-ui", [ container ]
|
||||
);
|
||||
|
||||
local service =
|
||||
engine.internalService(containerSet)
|
||||
.with_port(8888, 8888, "ui");
|
||||
|
||||
engine.resources([
|
||||
containerSet,
|
||||
service,
|
||||
])
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ local images = import "values/images.jsonnet";
|
|||
.with_limits("1.0", "768M")
|
||||
.with_reservations("0.5", "768M")
|
||||
.with_port(6379, 6379, "api")
|
||||
.with_port(3000, 3000, "ui")
|
||||
.with_port(3010, 3000, "ui")
|
||||
.with_volume_mount(vol, "/data");
|
||||
|
||||
local containerSet = engine.containers(
|
||||
|
|
@ -25,7 +25,7 @@ local images = import "values/images.jsonnet";
|
|||
local service =
|
||||
engine.service(containerSet)
|
||||
.with_port(6379, 6379, "api")
|
||||
.with_port(3000, 3000, "ui");
|
||||
.with_port(3010, 3010, "ui");
|
||||
|
||||
engine.resources([
|
||||
vol,
|
||||
|
|
|
|||
|
|
@ -13,5 +13,6 @@ local version = import "version.jsonnet";
|
|||
qdrant: "docker.io/qdrant/qdrant:v1.11.1",
|
||||
memgraph_mage: "docker.io/memgraph/memgraph-mage:1.22-memgraph-2.22",
|
||||
memgraph_lab: "docker.io/memgraph/lab:2.19.1",
|
||||
falkordb: "falkordb/falkordb:latest"
|
||||
falkordb: "docker.io/falkordb/falkordb:latest",
|
||||
"workbench-ui": "docker.io/trustgraph/workbench-ui:0.1.6",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"pulsar-client",
|
||||
"prometheus-client",
|
||||
"boto3",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"requests",
|
||||
"pulsar-client",
|
||||
"rdflib",
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-flow>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"trustgraph-flow>=0.18,<0.19",
|
||||
"torch",
|
||||
"urllib3",
|
||||
"transformers",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"urllib3",
|
||||
"rdflib",
|
||||
"pymilvus",
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@ class ServiceEndpoint:
|
|||
|
||||
print(data)
|
||||
|
||||
def responder(x, fin):
|
||||
async def responder(x, fin):
|
||||
print(x)
|
||||
|
||||
resp, fin = await self.requestor.process(data, responder)
|
||||
resp = await self.requestor.process(data, responder)
|
||||
|
||||
return web.json_response(resp)
|
||||
|
||||
|
|
|
|||
40
trustgraph-flow/trustgraph/gateway/graph_embeddings_query.py
Normal file
40
trustgraph-flow/trustgraph/gateway/graph_embeddings_query.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
from .. schema import GraphEmbeddingsRequest, GraphEmbeddingsResponse
|
||||
from .. schema import graph_embeddings_request_queue
|
||||
from .. schema import graph_embeddings_response_queue
|
||||
|
||||
from . endpoint import ServiceEndpoint
|
||||
from . requestor import ServiceRequestor
|
||||
from . serialize import serialize_value
|
||||
|
||||
class GraphEmbeddingsQueryRequestor(ServiceRequestor):
|
||||
def __init__(self, pulsar_host, timeout, auth):
|
||||
|
||||
super(GraphEmbeddingsQueryRequestor, self).__init__(
|
||||
pulsar_host=pulsar_host,
|
||||
request_queue=graph_embeddings_request_queue,
|
||||
response_queue=graph_embeddings_response_queue,
|
||||
request_schema=GraphEmbeddingsRequest,
|
||||
response_schema=GraphEmbeddingsResponse,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
def to_request(self, body):
|
||||
|
||||
limit = int(body.get("limit", 20))
|
||||
|
||||
return GraphEmbeddingsRequest(
|
||||
vectors = body["vectors"],
|
||||
limit = limit,
|
||||
user = body.get("user", "trustgraph"),
|
||||
collection = body.get("collection", "default"),
|
||||
)
|
||||
|
||||
def from_response(self, message):
|
||||
|
||||
return {
|
||||
"entities": [
|
||||
serialize_value(ent) for ent in message.entities
|
||||
]
|
||||
}, True
|
||||
|
||||
|
|
@ -8,65 +8,132 @@ from aiohttp import web, WSMsgType
|
|||
from . socket import SocketEndpoint
|
||||
from . text_completion import TextCompletionRequestor
|
||||
|
||||
MAX_OUTSTANDING_REQUESTS = 15
|
||||
WORKER_CLOSE_WAIT = 0.01
|
||||
START_REQUEST_WAIT = 0.1
|
||||
|
||||
# This buffers requests until task start, so short-lived
|
||||
MAX_QUEUE_SIZE = 10
|
||||
|
||||
class MuxEndpoint(SocketEndpoint):
|
||||
|
||||
def __init__(
|
||||
self, pulsar_host, auth,
|
||||
services,
|
||||
path="/api/v1/mux",
|
||||
path="/api/v1/socket",
|
||||
):
|
||||
|
||||
super(MuxEndpoint, self).__init__(
|
||||
endpoint_path=path, auth=auth,
|
||||
)
|
||||
|
||||
self.q = asyncio.Queue(maxsize=10)
|
||||
|
||||
self.services = services
|
||||
|
||||
async def start(self):
|
||||
pass
|
||||
|
||||
async def async_thread(self, ws, running):
|
||||
async def maybe_tidy_workers(self, workers):
|
||||
|
||||
while True:
|
||||
|
||||
try:
|
||||
|
||||
await asyncio.wait_for(
|
||||
asyncio.shield(workers[0]),
|
||||
WORKER_CLOSE_WAIT
|
||||
)
|
||||
|
||||
# worker[0] now stopped
|
||||
# FIXME: Delete reference???
|
||||
|
||||
workers.pop(0)
|
||||
|
||||
if len(workers) == 0:
|
||||
break
|
||||
|
||||
# Loop iterates to try the next worker
|
||||
|
||||
except TimeoutError:
|
||||
# worker[0] still running, move on
|
||||
break
|
||||
|
||||
async def start_request_task(self, ws, id, svc, request, workers):
|
||||
|
||||
if svc not in self.services:
|
||||
await ws.send_json({"id": id, "error": "Service not recognised"})
|
||||
return
|
||||
|
||||
requestor = self.services[svc]
|
||||
|
||||
async def responder(resp, fin):
|
||||
await ws.send_json({
|
||||
"id": id,
|
||||
"response": resp,
|
||||
"complete": fin,
|
||||
})
|
||||
|
||||
# Wait for outstanding requests to go below MAX_OUTSTANDING_REQUESTS
|
||||
while len(workers) > MAX_OUTSTANDING_REQUESTS:
|
||||
|
||||
# Fixes deadlock
|
||||
# FIXME: Put it in its own loop
|
||||
await asyncio.sleep(START_REQUEST_WAIT)
|
||||
|
||||
await self.maybe_tidy_workers(workers)
|
||||
|
||||
worker = asyncio.create_task(
|
||||
requestor.process(request, responder)
|
||||
)
|
||||
|
||||
workers.append(worker)
|
||||
|
||||
async def async_thread(self, ws, running, q):
|
||||
|
||||
# Worker threads, servicing
|
||||
workers = []
|
||||
|
||||
while running.get():
|
||||
|
||||
try:
|
||||
id, svc, request = await asyncio.wait_for(self.q.get(), 1)
|
||||
|
||||
if len(workers) > 0:
|
||||
await self.maybe_tidy_workers(workers)
|
||||
|
||||
# Get next request on queue
|
||||
id, svc, request = await asyncio.wait_for(q.get(), 1)
|
||||
|
||||
except TimeoutError:
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
# This is an internal working error, may not be recoverable
|
||||
print("Exception:", e)
|
||||
await ws.send_json({"id": id, "error": str(e)})
|
||||
break
|
||||
|
||||
try:
|
||||
|
||||
print(svc, request)
|
||||
|
||||
requestor = self.services[svc]
|
||||
|
||||
async def responder(resp, fin):
|
||||
await ws.send_json({
|
||||
"id": id,
|
||||
"response": resp,
|
||||
"complete": fin,
|
||||
})
|
||||
|
||||
resp = await requestor.process(request, responder)
|
||||
print(id, svc, request)
|
||||
await self.start_request_task(ws, id, svc, request, workers)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
print("Exception2:", e)
|
||||
await ws.send_json({"error": str(e)})
|
||||
|
||||
running.stop()
|
||||
|
||||
async def listener(self, ws, running):
|
||||
|
||||
# The outstanding request queue, max size is MAX_QUEUE_SIZE
|
||||
q = asyncio.Queue(maxsize=MAX_QUEUE_SIZE)
|
||||
|
||||
async_task = asyncio.create_task(self.async_thread(
|
||||
ws, running, q
|
||||
))
|
||||
|
||||
async for msg in ws:
|
||||
|
||||
# On error, finish
|
||||
if msg.type == WSMsgType.ERROR:
|
||||
break
|
||||
else:
|
||||
if msg.type == WSMsgType.TEXT:
|
||||
|
||||
try:
|
||||
|
||||
|
|
@ -81,7 +148,7 @@ class MuxEndpoint(SocketEndpoint):
|
|||
if "id" not in data:
|
||||
raise RuntimeError("Bad message")
|
||||
|
||||
await self.q.put(
|
||||
await q.put(
|
||||
(data["id"], data["service"], data["request"])
|
||||
)
|
||||
|
||||
|
|
@ -90,5 +157,13 @@ class MuxEndpoint(SocketEndpoint):
|
|||
await ws.send_json({"error": str(e)})
|
||||
continue
|
||||
|
||||
elif msg.type == WSMsgType.ERROR:
|
||||
break
|
||||
elif msg.type == WSMsgType.CLOSE:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
running.stop()
|
||||
|
||||
await async_task
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from . text_completion import TextCompletionRequestor
|
|||
from . prompt import PromptRequestor
|
||||
from . graph_rag import GraphRagRequestor
|
||||
from . triples_query import TriplesQueryRequestor
|
||||
from . graph_embeddings_query import GraphEmbeddingsQueryRequestor
|
||||
from . embeddings import EmbeddingsRequestor
|
||||
from . encyclopedia import EncyclopediaRequestor
|
||||
from . agent import AgentRequestor
|
||||
|
|
@ -95,6 +96,10 @@ class Api:
|
|||
pulsar_host=self.pulsar_host, timeout=self.timeout,
|
||||
auth = self.auth,
|
||||
),
|
||||
"graph-embeddings-query": GraphEmbeddingsQueryRequestor(
|
||||
pulsar_host=self.pulsar_host, timeout=self.timeout,
|
||||
auth = self.auth,
|
||||
),
|
||||
"embeddings": EmbeddingsRequestor(
|
||||
pulsar_host=self.pulsar_host, timeout=self.timeout,
|
||||
auth = self.auth,
|
||||
|
|
@ -134,6 +139,11 @@ class Api:
|
|||
endpoint_path = "/api/v1/triples-query", auth=self.auth,
|
||||
requestor = self.services["triples-query"],
|
||||
),
|
||||
ServiceEndpoint(
|
||||
endpoint_path = "/api/v1/graph-embeddings-query",
|
||||
auth=self.auth,
|
||||
requestor = self.services["graph-embeddings-query"],
|
||||
),
|
||||
ServiceEndpoint(
|
||||
endpoint_path = "/api/v1/embeddings", auth=self.auth,
|
||||
requestor = self.services["embeddings"],
|
||||
|
|
|
|||
|
|
@ -22,25 +22,16 @@ class SocketEndpoint:
|
|||
|
||||
async for msg in ws:
|
||||
# On error, finish
|
||||
if msg.type == WSMsgType.ERROR:
|
||||
break
|
||||
if msg.type == WSMsgType.TEXT:
|
||||
# Ignore incoming message
|
||||
continue
|
||||
elif msg.type == WSMsgType.BINARY:
|
||||
# Ignore incoming message
|
||||
continue
|
||||
else:
|
||||
# Ignore incoming messages
|
||||
pass
|
||||
break
|
||||
|
||||
running.stop()
|
||||
|
||||
async def async_thread(self, ws, running):
|
||||
|
||||
while running.get():
|
||||
try:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
except TimeoutError:
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"Exception: {str(e)}", flush=True)
|
||||
|
||||
async def handle(self, request):
|
||||
|
||||
|
|
@ -56,12 +47,8 @@ class SocketEndpoint:
|
|||
ws = web.WebSocketResponse()
|
||||
await ws.prepare(request)
|
||||
|
||||
task = asyncio.create_task(self.async_thread(ws, running))
|
||||
|
||||
try:
|
||||
|
||||
await self.listener(ws, running)
|
||||
|
||||
except Exception as e:
|
||||
print(e, flush=True)
|
||||
|
||||
|
|
@ -69,8 +56,6 @@ class SocketEndpoint:
|
|||
|
||||
await ws.close()
|
||||
|
||||
await task
|
||||
|
||||
return ws
|
||||
|
||||
async def start(self):
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ class Processor(ConsumerProducer):
|
|||
|
||||
print(f"Handling input {id}...", flush=True)
|
||||
|
||||
entities = set()
|
||||
entity_set = set()
|
||||
entities = []
|
||||
|
||||
for vec in v.vectors:
|
||||
|
||||
|
|
@ -85,20 +86,30 @@ class Processor(ConsumerProducer):
|
|||
|
||||
index = self.pinecone.Index(index_name)
|
||||
|
||||
# Heuristic hack, get (2*limit), so that we have more chance
|
||||
# of getting (limit) entities
|
||||
results = index.query(
|
||||
namespace=v.collection,
|
||||
vector=vec,
|
||||
top_k=v.limit,
|
||||
top_k=v.limit * 2,
|
||||
include_values=False,
|
||||
include_metadata=True
|
||||
)
|
||||
|
||||
for r in results.matches:
|
||||
ent = r.metadata["entity"]
|
||||
entities.add(ent)
|
||||
|
||||
# Convert set to list
|
||||
entities = list(entities)
|
||||
ent = r.metadata["entity"]
|
||||
|
||||
# De-dupe entities
|
||||
if ent not in entity_set:
|
||||
entity_set.add(ent)
|
||||
entities.append(ent)
|
||||
|
||||
# Keep adding entities until limit
|
||||
if len(entity_set) >= v.limit: break
|
||||
|
||||
# Keep adding entities until limit
|
||||
if len(entity_set) >= v.limit: break
|
||||
|
||||
ents2 = []
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ class Processor(ConsumerProducer):
|
|||
|
||||
print(f"Handling input {id}...", flush=True)
|
||||
|
||||
entities = set()
|
||||
entity_set = set()
|
||||
entities = []
|
||||
|
||||
for vec in v.vectors:
|
||||
|
||||
|
|
@ -71,19 +72,28 @@ class Processor(ConsumerProducer):
|
|||
str(dim)
|
||||
)
|
||||
|
||||
# Heuristic hack, get (2*limit), so that we have more chance
|
||||
# of getting (limit) entities
|
||||
search_result = self.client.query_points(
|
||||
collection_name=collection,
|
||||
query=vec,
|
||||
limit=v.limit,
|
||||
limit=v.limit * 2,
|
||||
with_payload=True,
|
||||
).points
|
||||
|
||||
for r in search_result:
|
||||
ent = r.payload["entity"]
|
||||
entities.add(ent)
|
||||
|
||||
# Convert set to list
|
||||
entities = list(entities)
|
||||
# De-dupe entities
|
||||
if ent not in entity_set:
|
||||
entity_set.add(ent)
|
||||
entities.append(ent)
|
||||
|
||||
# Keep adding entities until limit
|
||||
if len(entity_set) >= v.limit: break
|
||||
|
||||
# Keep adding entities until limit
|
||||
if len(entity_set) >= v.limit: break
|
||||
|
||||
ents2 = []
|
||||
|
||||
|
|
|
|||
|
|
@ -76,8 +76,11 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Literal {value: $value}) "
|
||||
"RETURN $src as src",
|
||||
src=v.s.value, rel=v.p.value, value=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"rel": v.p.value,
|
||||
"value": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
|
|
@ -86,8 +89,11 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Node {uri: $uri}) "
|
||||
"RETURN $src as src",
|
||||
src=v.s.value, rel=v.p.value, uri=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"rel": v.p.value,
|
||||
"uri": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
|
|
@ -100,24 +106,26 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Literal) "
|
||||
"RETURN dest.value as dest",
|
||||
src=v.s.value, rel=v.p.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"rel": v.p.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, v.p.value, data["dest"]))
|
||||
triples.append((v.s.value, v.p.value, rec[0]))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel {uri: $rel}]->(dest:Node) "
|
||||
"RETURN dest.uri as dest",
|
||||
src=v.s.value, rel=v.p.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"rel": v.p.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, v.p.value, data["dest"]))
|
||||
triples.append((v.s.value, v.p.value, rec[0]))
|
||||
|
||||
else:
|
||||
|
||||
|
|
@ -128,50 +136,52 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel]->(dest:Literal {value: $value}) "
|
||||
"RETURN rel.uri as rel",
|
||||
src=v.s.value, value=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"value": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, data["rel"], v.o.value))
|
||||
triples.append((v.s.value, rec[0], v.o.value))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel]->(dest:Node {uri: $uri}) "
|
||||
"RETURN rel.uri as rel",
|
||||
src=v.s.value, uri=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
"uri": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, data["rel"], v.o.value))
|
||||
triples.append((v.s.value, rec[0], v.o.value))
|
||||
|
||||
else:
|
||||
|
||||
# S
|
||||
# s
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel]->(dest:Literal) "
|
||||
"RETURN rel.uri as rel, dest.value as dest",
|
||||
src=v.s.value,
|
||||
database_=self.db,
|
||||
"match (src:node {uri: $src})-[rel:rel]->(dest:literal) "
|
||||
"return rel.uri as rel, dest.value as dest",
|
||||
params={
|
||||
"src": v.s.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, data["rel"], data["dest"]))
|
||||
triples.append((v.s.value, rec[0], rec[1]))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node {uri: $src})-[rel:Rel]->(dest:Node) "
|
||||
"RETURN rel.uri as rel, dest.uri as dest",
|
||||
src=v.s.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": v.s.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((v.s.value, data["rel"], data["dest"]))
|
||||
triples.append((v.s.value, rec[0], rec[1]))
|
||||
|
||||
|
||||
else:
|
||||
|
|
@ -185,24 +195,26 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel {uri: $uri}]->(dest:Literal {value: $value}) "
|
||||
"RETURN src.uri as src",
|
||||
uri=v.p.value, value=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": v.p.value,
|
||||
"value": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], v.p.value, v.o.value))
|
||||
triples.append((rec[0], v.p.value, v.o.value))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel {uri: $uri}]->(dest:Node {uri: $uri}) "
|
||||
"RETURN src.uri as src",
|
||||
uri=v.p.value, dest=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": v.p.value,
|
||||
"dest": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], v.p.value, v.o.value))
|
||||
triples.append((rec[0], v.p.value, v.o.value))
|
||||
|
||||
else:
|
||||
|
||||
|
|
@ -211,24 +223,24 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel {uri: $uri}]->(dest:Literal) "
|
||||
"RETURN src.uri as src, dest.value as dest",
|
||||
uri=v.p.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": v.p.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], v.p.value, data["dest"]))
|
||||
triples.append((rec[0], v.p.value, rec[1]))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel {uri: $uri}]->(dest:Node) "
|
||||
"RETURN src.uri as src, dest.uri as dest",
|
||||
uri=v.p.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": v.p.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], v.p.value, data["dest"]))
|
||||
triples.append((rec[0], v.p.value, rec[1]))
|
||||
|
||||
else:
|
||||
|
||||
|
|
@ -239,24 +251,24 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel]->(dest:Literal {value: $value}) "
|
||||
"RETURN src.uri as src, rel.uri as rel",
|
||||
value=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"value": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], data["rel"], v.o.value))
|
||||
triples.append((rec[0], rec[1], v.o.value))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel]->(dest:Node {uri: $uri}) "
|
||||
"RETURN src.uri as src, rel.uri as rel",
|
||||
uri=v.o.value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": v.o.value,
|
||||
},
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], data["rel"], v.o.value))
|
||||
triples.append((rec[0], rec[1], v.o.value))
|
||||
|
||||
else:
|
||||
|
||||
|
|
@ -265,22 +277,18 @@ class Processor(ConsumerProducer):
|
|||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel]->(dest:Literal) "
|
||||
"RETURN src.uri as src, rel.uri as rel, dest.value as dest",
|
||||
database_=self.db,
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], data["rel"], data["dest"]))
|
||||
triples.append((rec[0], rec[1], rec[2]))
|
||||
|
||||
records = self.io.query(
|
||||
"MATCH (src:Node)-[rel:Rel]->(dest:Node) "
|
||||
"RETURN src.uri as src, rel.uri as rel, dest.uri as dest",
|
||||
database_=self.db,
|
||||
).result_set
|
||||
|
||||
for rec in records:
|
||||
data = rec.data()
|
||||
triples.append((data["src"], data["rel"], data["dest"]))
|
||||
triples.append((rec[0], rec[1], rec[2]))
|
||||
|
||||
triples = [
|
||||
Triple(
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class Processor(Consumer):
|
|||
self.client.create_collection(
|
||||
collection_name=collection,
|
||||
vectors_config=VectorParams(
|
||||
size=dim, distance=Distance.DOT
|
||||
size=dim, distance=Distance.COSINE
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@ class Processor(Consumer):
|
|||
|
||||
res = self.io.query(
|
||||
"MERGE (n:Node {uri: $uri})",
|
||||
uri=uri,
|
||||
database_=self.db,
|
||||
params={
|
||||
"uri": uri,
|
||||
},
|
||||
)
|
||||
|
||||
print("Created {nodes_created} nodes in {time} ms.".format(
|
||||
|
|
@ -67,8 +68,9 @@ class Processor(Consumer):
|
|||
|
||||
res = self.io.query(
|
||||
"MERGE (n:Literal {value: $value})",
|
||||
value=value,
|
||||
database_=self.db,
|
||||
params={
|
||||
"value": value,
|
||||
},
|
||||
)
|
||||
|
||||
print("Created {nodes_created} nodes in {time} ms.".format(
|
||||
|
|
@ -84,8 +86,11 @@ class Processor(Consumer):
|
|||
"MATCH (src:Node {uri: $src}) "
|
||||
"MATCH (dest:Node {uri: $dest}) "
|
||||
"MERGE (src)-[:Rel {uri: $uri}]->(dest)",
|
||||
src=src, dest=dest, uri=uri,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": src,
|
||||
"dest": dest,
|
||||
"uri": uri,
|
||||
},
|
||||
)
|
||||
|
||||
print("Created {nodes_created} nodes in {time} ms.".format(
|
||||
|
|
@ -101,8 +106,11 @@ class Processor(Consumer):
|
|||
"MATCH (src:Node {uri: $src}) "
|
||||
"MATCH (dest:Literal {value: $dest}) "
|
||||
"MERGE (src)-[:Rel {uri: $uri}]->(dest)",
|
||||
src=src, dest=dest, uri=uri,
|
||||
database_=self.db,
|
||||
params={
|
||||
"src": src,
|
||||
"dest": dest,
|
||||
"uri": uri,
|
||||
},
|
||||
)
|
||||
|
||||
print("Created {nodes_created} nodes in {time} ms.".format(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
"""
|
||||
Graph writer. Input is graph edge. Writes edges to Cassandra graph.
|
||||
Graph writer. Input is graph edge. Writes edges to Memgraph.
|
||||
"""
|
||||
|
||||
import pulsar
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"pulsar-client",
|
||||
"google-cloud-aiplatform",
|
||||
"prometheus-client",
|
||||
|
|
|
|||
|
|
@ -34,13 +34,12 @@ setuptools.setup(
|
|||
python_requires='>=3.8',
|
||||
download_url = "https://github.com/trustgraph-ai/trustgraph/archive/refs/tags/v" + version + ".tar.gz",
|
||||
install_requires=[
|
||||
"trustgraph-base>=0.17,<0.18",
|
||||
"trustgraph-bedrock>=0.17,<0.18",
|
||||
"trustgraph-cli>=0.17,<0.18",
|
||||
"trustgraph-embeddings-hf>=0.17,<0.18",
|
||||
"trustgraph-flow>=0.17,<0.18",
|
||||
"trustgraph-parquet>=0.17,<0.18",
|
||||
"trustgraph-vertexai>=0.17,<0.18",
|
||||
"trustgraph-base>=0.18,<0.19",
|
||||
"trustgraph-bedrock>=0.18,<0.19",
|
||||
"trustgraph-cli>=0.18,<0.19",
|
||||
"trustgraph-embeddings-hf>=0.18,<0.19",
|
||||
"trustgraph-flow>=0.18,<0.19",
|
||||
"trustgraph-vertexai>=0.18,<0.19",
|
||||
],
|
||||
scripts=[
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue