Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add memory upsert and redis functionality to local api #320

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions .well-known/ai-plugin.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"schema_version": "v1",
"name_for_model": "retrieval",
"name_for_human": "Retrieval Plugin",
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "user_http",
"authorization_type": "bearer"
},
"api": {
"type": "openapi",
"url": "https://your-app-url.com/.well-known/openapi.yaml",
"has_user_authentication": false
},
"logo_url": "https://your-app-url.com/.well-known/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "http://example.com/legal-info"
"schema_version": "v1",
"name_for_model": "retrieval",
"name_for_human": "Retrieval Plugin",
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information, or asks you to save information for later.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "user_http",
"authorization_type": "bearer"
},
"api": {
"type": "openapi",
"url": "https://localhost:3333/.well-known/openapi.yaml",
"has_user_authentication": false
},
"logo_url": "https://localhost:3333/.well-known/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "hello@legal.com"
}
Binary file added .well-known/logo-local.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 82 additions & 2 deletions .well-known/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,35 @@ info:
title: Retrieval Plugin API
description: A retrieval API for querying and filtering documents based on natural language queries and metadata
version: 1.0.0
servers:
- url: https://your-app-url.com
servers:
- url: https://localhost:3333
paths:
/upsert:
post:
summary: Upsert
description: Save chat information. Accepts an array of documents with text (potential questions + conversation text), metadata (source 'chat' and timestamp, no ID as this will be generated). Confirm with the user before saving, ask for more details/context.
operationId: upsert_upsert_post
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UpsertRequest"
required: true
responses:
"200":
description: Successful Response
content:
application/json:
schema:
$ref: "#/components/schemas/UpsertResponse"
"422":
description: Validation Error
content:
application/json:
schema:
$ref: "#/components/schemas/HTTPValidationError"
security:
- HTTPBearer: []
/query:
post:
summary: Query
Expand Down Expand Up @@ -34,6 +60,20 @@ paths:
- HTTPBearer: []
components:
schemas:
Document:
title: Document
required:
- text
type: object
properties:
id:
title: Id
type: string
text:
title: Text
type: string
metadata:
$ref: "#/components/schemas/DocumentMetadata"
DocumentChunkMetadata:
title: DocumentChunkMetadata
type: object
Expand Down Expand Up @@ -79,6 +119,24 @@ components:
score:
title: Score
type: number
DocumentMetadata:
title: DocumentMetadata
type: object
properties:
source:
$ref: "#/components/schemas/Source"
source_id:
title: Source Id
type: string
url:
title: Url
type: string
created_at:
title: Created At
type: string
author:
title: Author
type: string
DocumentMetadataFilter:
title: DocumentMetadataFilter
type: object
Expand Down Expand Up @@ -169,6 +227,28 @@ components:
- chat
type: string
description: An enumeration.
UpsertRequest:
title: UpsertRequest
required:
- documents
type: object
properties:
documents:
title: Documents
type: array
items:
$ref: "#/components/schemas/Document"
UpsertResponse:
title: UpsertResponse
required:
- ids
type: object
properties:
ids:
title: Ids
type: array
items:
type: string
ValidationError:
title: ValidationError
required:
Expand Down
19 changes: 19 additions & 0 deletions PROMPTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Prompts

Use the following prompt in ChatGPT at chat.openai.com to test the plugin:

```text
As an AI language model, you have access to a variety of plugins that enhance your capabilities. I want you to utilize these plugins effectively to provide the most accurate and comprehensive responses. Here's how you should proceed:

1. **Data Retrieval Plugin**: Whenever a question is asked or a task is given, your first step should be to use the data retrieval plugin to check your memory storage. This plugin allows you to search through stored documents, files, emails, and more to find answers to questions and retrieve relevant information. See if a similar question has been asked before, or if the data from a previous information gathering task is stored.

2. **WebPilot Plugin**: If no relevant information is found in memory, use the web browsing plugins like WebPilot to search the internet. The WebPilot plugin allows you to visit web pages, retrieve content from them, and interact with the content if necessary. Use this tool to download the relevant information.

3. **Data Storage**: Any new information gathered from the internet or other sources should be saved into the retrieval system for future reference. Use the 'Retrieval Plugin (local)' `/upsert` endpoint to upload this information into the plugin's vector datastore. This will allow you to access this information in the future without needing to search the internet again.

4. **Clarification**: If there's any uncertainty about the provided information or the task at hand, don't hesitate to ask follow-up questions for clarification. It's better to ask and be sure than to assume and make mistakes.

5. **Prompt Understanding**: Read each prompt carefully and ask if there are any questions about the instructions. This will ensure that you fully understand the task at hand and can provide the most accurate response.

Remember, these plugins are tools to enhance your capabilities. Use them effectively to provide the best possible service.
```
5 changes: 3 additions & 2 deletions examples/docker/redis/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ version: "3.9"
services:
redis:
image: redis/redis-stack-server:latest
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis_data:/data
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-h", "localhost", "-p", "6379", "ping"]
interval: 2s
Expand All @@ -15,4 +16,4 @@ services:
start_period: 5s

volumes:
redis_data:
redis_data:
14 changes: 7 additions & 7 deletions examples/memory/ai-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information, or asks you to save information for later.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "user_http",
"authorization_type": "bearer"
"type": "user_http",
"authorization_type": "bearer"
},
"api": {
"type": "openapi",
"url": "https://your-app-url.com/.well-known/openapi.yaml",
"has_user_authentication": false
"type": "openapi",
"url": "https://your-app-url.com/.well-known/openapi.yaml",
"has_user_authentication": false
},
"logo_url": "https://your-app-url.com/.well-known/logo.png",
"contact_email": "[email protected]",
"contact_email": "[email protected]",
"legal_info_url": "[email protected]"
}
}
2 changes: 1 addition & 1 deletion examples/providers/redis/semantic-search-and-filter.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.1"
"version": "3.10.6"
},
"vscode": {
"interpreter": {
Expand Down
17 changes: 17 additions & 0 deletions local_server/ai-plugin-local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"schema_version": "v1",
"name_for_model": "retrieval",
"name_for_human": "Retrieval Plugin (localhost)",
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "http://localhost:3333/.well-known/openapi.yaml"
},
"logo_url": "http://localhost:3333/.well-known/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "[email protected]"
}
31 changes: 15 additions & 16 deletions local_server/ai-plugin.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
{
"schema_version": "v1",
"name_for_model": "retrieval",
"name_for_human": "Retrieval Plugin",
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "http://localhost:3333/.well-known/openapi.yaml"
},
"logo_url": "http://localhost:3333/.well-known/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "[email protected]"
"schema_version": "v1",
"name_for_model": "retrieval",
"name_for_human": "Retrieval Plugin (local)",
"description_for_model": "Plugin for searching through the user's documents (such as files, emails, and more) to find answers to questions and retrieve relevant information. Use it whenever a user asks something that might be found in their personal information, or asks you to save information for later.",
"description_for_human": "Search through your documents.",
"auth": {
"type": "none"
},
"api": {
"type": "openapi",
"url": "http://localhost:3333/.well-known/openapi.yaml"
},
"logo_url": "http://localhost:3333/.well-known/logo.png",
"contact_email": "[email protected]",
"legal_info_url": "[email protected]"
}

Binary file added local_server/logo-local.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 52 additions & 3 deletions local_server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async def get_manifest(request):

@app.route("/.well-known/logo.png")
async def get_logo(request):
file_path = "./local_server/logo.png"
file_path = "./local_server/logo-local.png"
return FileResponse(file_path, media_type="text/json")


Expand All @@ -59,6 +59,14 @@ async def get_openapi(request):
file_path = "./local_server/openapi.yaml"
return FileResponse(file_path, media_type="text/json")

# Create a sub-application, in order to access just the upsert and query endpoints in the OpenAPI schema, found at http://0.0.0.0:3333/sub/openapi.json when the app is running locally
sub_app = FastAPI(
title="Retrieval Plugin API",
description="A retrieval API for querying and filtering documents based on natural language queries and metadata",
version="1.0.0",
servers=[{"url": "http://localhost:{PORT}"}],
)
app.mount("/sub", sub_app)

@app.post(
"/upsert-file",
Expand Down Expand Up @@ -91,6 +99,23 @@ async def upsert_file(
"/upsert",
response_model=UpsertResponse,
)
async def upsert_main(
request: UpsertRequest = Body(...),
):
try:
ids = await datastore.upsert(request.documents)
return UpsertResponse(ids=ids)
except Exception as e:
logger.error(e)
raise HTTPException(status_code=500, detail="Internal Service Error")


@sub_app.post(
"/upsert",
response_model=UpsertResponse,
# NOTE: We are describing the shape of the API endpoint input due to a current limitation in parsing arrays of objects from OpenAPI schemas. This will not be necessary in the future.
description="Save chat information. Accepts an array of documents with text (potential questions + conversation text), metadata (source 'chat' and timestamp, no ID as this will be generated). Confirm with the user before saving, ask for more details/context.",
)
async def upsert(
request: UpsertRequest = Body(...),
):
Expand All @@ -102,8 +127,32 @@ async def upsert(
raise HTTPException(status_code=500, detail="Internal Service Error")


@app.post("/query", response_model=QueryResponse)
async def query_main(request: QueryRequest = Body(...)):
@app.post(
"/query",
response_model=QueryResponse,
)
async def query_main(
request: QueryRequest = Body(...),
):
try:
results = await datastore.query(
request.queries,
)
return QueryResponse(results=results)
except Exception as e:
logger.error(e)
raise HTTPException(status_code=500, detail="Internal Service Error")


@sub_app.post(
"/query",
response_model=QueryResponse,
# NOTE: We are describing the shape of the API endpoint input due to a current limitation in parsing arrays of objects from OpenAPI schemas. This will not be necessary in the future.
description="Accepts search query objects array each with query and optional filter. Break down complex questions into sub-questions. Refine results by criteria, e.g. time / source, don't do this often. Split queries if ResponseTooLargeError occurs.",
)
async def query(
request: QueryRequest = Body(...),
):
try:
results = await datastore.query(
request.queries,
Expand Down
Loading