Tested and ran the script to make sure the outputs make sense and actions get completed
This commit is contained in:
parent
40b93f11ca
commit
e7698af597
3 changed files with 187 additions and 263 deletions
|
|
@ -9,7 +9,8 @@ Initial code lets you do three operations:
|
||||||
|
|
||||||
1. Add to memory
|
1. Add to memory
|
||||||
2. Retrieve from memory
|
2. Retrieve from memory
|
||||||
3. Structure the data to schema and load to duckdb
|
3. Structure the data to schema
|
||||||
|
4. Load to a database
|
||||||
|
|
||||||
#How to use
|
#How to use
|
||||||
|
|
||||||
|
|
@ -38,13 +39,17 @@ The Memory API provides the following endpoints:
|
||||||
- /run-buffer (POST)
|
- /run-buffer (POST)
|
||||||
- /buffer/create-context (POST)
|
- /buffer/create-context (POST)
|
||||||
|
|
||||||
Here is a payload example:
|
|
||||||
|
|
||||||
|
|
||||||
|
## How To Get Started
|
||||||
|
|
||||||
|
1. We do a post request to add-memory endpoint with the following payload:
|
||||||
|
It will upload Jack London "Call of the Wild" to SEMANTIC memory
|
||||||
```
|
```
|
||||||
{
|
curl -X POST http://localhost:8000/semantic/add-memory -H "Content-Type: application/json" -d '{
|
||||||
"payload": {
|
"payload": {
|
||||||
"user_id": "681",
|
"user_id": "681",
|
||||||
"prompt": "I want ",
|
"prompt": "I am adding docs",
|
||||||
"params": {
|
"params": {
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"agreement_id": "AG123456",
|
"agreement_id": "AG123456",
|
||||||
|
|
@ -59,13 +64,45 @@ Here is a payload example:
|
||||||
"validity_end": "2024-07-31"
|
"validity_end": "2024-07-31"
|
||||||
},
|
},
|
||||||
"loader_settings": {
|
"loader_settings": {
|
||||||
"format": "PDF", // or "HTML" // or 'DOCX' // or 'TXT'
|
"format": "PDF",
|
||||||
"source": "url", // or "file"
|
"source": "url",
|
||||||
"path": "https://www.ibiblio.org/ebooks/London/Call%20of%20Wild.pdf"
|
"path": "https://www.ibiblio.org/ebooks/London/Call%20of%20Wild.pdf"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
2. We run the buffer with the prompt "I want to know how does Buck adapt to life in the wild and then have that info translated to German "
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -X POST http://localhost:8000/run-buffer -H "Content-Type: application/json" -d '{
|
||||||
|
"payload": {
|
||||||
|
"user_id": "681",
|
||||||
|
"prompt": "I want to know how does Buck adapt to life in the wild and then have that info translated to German ",
|
||||||
|
"params": {
|
||||||
|
"version": "1.0",
|
||||||
|
"agreement_id": "AG123456",
|
||||||
|
"privacy_policy": "https://example.com/privacy",
|
||||||
|
"terms_of_service": "https://example.com/terms",
|
||||||
|
"format": "json",
|
||||||
|
"schema_version": "1.1",
|
||||||
|
"checksum": "a1b2c3d4e5f6",
|
||||||
|
"owner": "John Doe",
|
||||||
|
"license": "MIT",
|
||||||
|
"validity_start": "2023-08-01",
|
||||||
|
"validity_end": "2024-07-31"
|
||||||
},
|
},
|
||||||
"attention_modulators": {
|
"attention_modulators": {
|
||||||
"relevance": 0.5,
|
"relevance": 0.0,
|
||||||
"saliency": 0.5,
|
"saliency": 0.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Other attention modulators that could be implemented:
|
||||||
|
|
||||||
"frequency": 0.5,
|
"frequency": 0.5,
|
||||||
"repetition": 0.5,
|
"repetition": 0.5,
|
||||||
"length": 0.5,
|
"length": 0.5,
|
||||||
|
|
@ -96,8 +133,4 @@ Here is a payload example:
|
||||||
"vividness": 0.5,
|
"vividness": 0.5,
|
||||||
"originality": 0.5,
|
"originality": 0.5,
|
||||||
"creativity": 0.5,
|
"creativity": 0.5,
|
||||||
"humor": 0.5,
|
"humor": 0.5,
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
146
level_2/api.py
146
level_2/api.py
|
|
@ -1,24 +1,14 @@
|
||||||
from io import BytesIO
|
import logging
|
||||||
|
import os
|
||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
from langchain.document_loaders import PyPDFLoader
|
import uvicorn
|
||||||
|
|
||||||
from level_2_pdf_vectorstore__dlt_contracts import Memory
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Dict, Any
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import uvicorn
|
|
||||||
from fastapi import Request
|
|
||||||
import yaml
|
|
||||||
from fastapi import HTTPException
|
|
||||||
from fastapi import FastAPI, UploadFile, File
|
|
||||||
from typing import List
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
from level_2_pdf_vectorstore__dlt_contracts import Memory
|
||||||
|
from dotenv import load_dotenv
|
||||||
# Set up logging
|
# Set up logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO, # Set the logging level (e.g., DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
level=logging.INFO, # Set the logging level (e.g., DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||||
|
|
@ -26,23 +16,18 @@ logging.basicConfig(
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
||||||
|
|
||||||
app = FastAPI(debug=True)
|
app = FastAPI(debug=True)
|
||||||
|
|
||||||
|
|
||||||
from fastapi import Depends
|
|
||||||
|
|
||||||
|
|
||||||
class ImageResponse(BaseModel):
|
class ImageResponse(BaseModel):
|
||||||
success: bool
|
success: bool
|
||||||
message: str
|
message: str
|
||||||
|
|
||||||
|
|
||||||
@app.get(
|
@app.get(
|
||||||
"/",
|
"/",
|
||||||
)
|
)
|
||||||
|
|
@ -52,83 +37,15 @@ async def root():
|
||||||
"""
|
"""
|
||||||
return {"message": "Hello, World, I am alive!"}
|
return {"message": "Hello, World, I am alive!"}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
def health_check():
|
def health_check():
|
||||||
"""
|
"""
|
||||||
Health check endpoint that returns the server status.
|
Health check endpoint that returns the server status.
|
||||||
"""
|
"""
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
|
|
||||||
# curl -X POST -H "Content-Type: application/json" -d '{"data": "YourPayload"}' -F "files=@/path/to/your/pdf/file.pdf" http://127.0.0.1:8000/upload/
|
|
||||||
|
|
||||||
|
|
||||||
class Payload(BaseModel):
|
class Payload(BaseModel):
|
||||||
payload: Dict[str, Any]
|
payload: Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
# @app.post("/upload/", response_model=dict)
|
|
||||||
# async def upload_pdf_and_payload(
|
|
||||||
# payload: Payload,
|
|
||||||
# # files: List[UploadFile] = File(...),
|
|
||||||
# ):
|
|
||||||
# try:
|
|
||||||
# # Process the payload
|
|
||||||
# decoded_payload = payload.payload
|
|
||||||
# # except:
|
|
||||||
# # pass
|
|
||||||
# #
|
|
||||||
# # return JSONResponse(content={"response": decoded_payload}, status_code=200)
|
|
||||||
#
|
|
||||||
# # Download the remote PDF if URL is provided
|
|
||||||
# if 'pdf_url' in decoded_payload:
|
|
||||||
# pdf_response = requests.get(decoded_payload['pdf_url'])
|
|
||||||
# pdf_content = pdf_response.content
|
|
||||||
#
|
|
||||||
# logging.info("Downloaded PDF from URL")
|
|
||||||
#
|
|
||||||
# # Create an in-memory file-like object for the PDF content
|
|
||||||
# pdf_stream = BytesIO(pdf_content)
|
|
||||||
#
|
|
||||||
# contents = pdf_stream.read()
|
|
||||||
#
|
|
||||||
# tmp_location = os.path.join('/tmp', "tmp.pdf")
|
|
||||||
# with open(tmp_location, 'wb') as tmp_file:
|
|
||||||
# tmp_file.write(contents)
|
|
||||||
#
|
|
||||||
# logging.info("Wrote PDF from URL")
|
|
||||||
#
|
|
||||||
# # Process the PDF using PyPDFLoader
|
|
||||||
# loader = PyPDFLoader(tmp_location)
|
|
||||||
# pages = loader.load_and_split()
|
|
||||||
# logging.info(" PDF split into pages")
|
|
||||||
# Memory_ = Memory(index_name="my-agent", user_id='555' )
|
|
||||||
# await Memory_.async_init()
|
|
||||||
# Memory_._add_episodic_memory(user_input="I want to get a schema for my data", content =pages)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# # Run the buffer
|
|
||||||
# response = Memory_._run_buffer(user_input="I want to get a schema for my data")
|
|
||||||
# return JSONResponse(content={"response": response}, status_code=200)
|
|
||||||
#
|
|
||||||
# #to do: add the user id to the payload
|
|
||||||
# #to do add the raw pdf to payload
|
|
||||||
# # bb = await Memory_._run_buffer(user_input=decoded_payload['prompt'])
|
|
||||||
# # print(bb)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# except Exception as e:
|
|
||||||
#
|
|
||||||
# return {"error": str(e)}
|
|
||||||
# # Here you can perform your processing on the PDF contents
|
|
||||||
# # results.append({"filename": file.filename, "size": len(contents)})
|
|
||||||
#
|
|
||||||
# # Append the in-memory file to the files list
|
|
||||||
# # files.append(UploadFile(pdf_stream, filename="downloaded.pdf"))
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
def memory_factory(memory_type):
|
def memory_factory(memory_type):
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
|
@ -231,7 +148,7 @@ async def available_buffer_actions(
|
||||||
|
|
||||||
|
|
||||||
@app.post("/run-buffer", response_model=dict)
|
@app.post("/run-buffer", response_model=dict)
|
||||||
async def available_buffer_actions(
|
async def run_buffer(
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
# files: List[UploadFile] = File(...),
|
# files: List[UploadFile] = File(...),
|
||||||
):
|
):
|
||||||
|
|
@ -243,8 +160,8 @@ async def available_buffer_actions(
|
||||||
await Memory_.async_init()
|
await Memory_.async_init()
|
||||||
|
|
||||||
# memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None)
|
# memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None)
|
||||||
output = await Memory_._run_buffer(
|
output = await Memory_._run_main_buffer(
|
||||||
user_input=decoded_payload["prompt"], params=decoded_payload["params"]
|
user_input=decoded_payload["prompt"], params=decoded_payload["params"], attention_modulators=decoded_payload["attention_modulators"]
|
||||||
)
|
)
|
||||||
return JSONResponse(content={"response": output}, status_code=200)
|
return JSONResponse(content={"response": output}, status_code=200)
|
||||||
|
|
||||||
|
|
@ -253,7 +170,7 @@ async def available_buffer_actions(
|
||||||
|
|
||||||
|
|
||||||
@app.post("/buffer/create-context", response_model=dict)
|
@app.post("/buffer/create-context", response_model=dict)
|
||||||
async def available_buffer_actions(
|
async def create_context(
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
# files: List[UploadFile] = File(...),
|
# files: List[UploadFile] = File(...),
|
||||||
):
|
):
|
||||||
|
|
@ -266,7 +183,7 @@ async def available_buffer_actions(
|
||||||
|
|
||||||
# memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None)
|
# memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None)
|
||||||
output = await Memory_._create_buffer_context(
|
output = await Memory_._create_buffer_context(
|
||||||
user_input=decoded_payload["prompt"], params=decoded_payload["params"]
|
user_input=decoded_payload["prompt"], params=decoded_payload["params"], attention_modulators=decoded_payload["attention_modulators"]
|
||||||
)
|
)
|
||||||
return JSONResponse(content={"response": output}, status_code=200)
|
return JSONResponse(content={"response": output}, status_code=200)
|
||||||
|
|
||||||
|
|
@ -274,29 +191,26 @@ async def available_buffer_actions(
|
||||||
return JSONResponse(content={"response": {"error": str(e)}}, status_code=503)
|
return JSONResponse(content={"response": {"error": str(e)}}, status_code=503)
|
||||||
|
|
||||||
|
|
||||||
#
|
@app.post("/buffer/get-tasks", response_model=dict)
|
||||||
# # Process each uploaded PDF file
|
async def create_context(
|
||||||
# results = []
|
payload: Payload,
|
||||||
# for file in files:
|
# files: List[UploadFile] = File(...),
|
||||||
# contents = await file.read()
|
):
|
||||||
# tmp_location = os.path.join('/tmp', "tmp.pdf")
|
try:
|
||||||
# with open(tmp_location, 'wb') as tmp_file:
|
decoded_payload = payload.payload
|
||||||
# tmp_file.write(contents)
|
|
||||||
# loader = PyPDFLoader(tmp_location)
|
|
||||||
# pages = loader.load_and_split()
|
|
||||||
#
|
|
||||||
# stm = ShortTermMemory(user_id=decoded_payload['user_id'])
|
|
||||||
# stm.episodic_buffer.main_buffer(prompt=decoded_payload['prompt'], pages=pages)
|
|
||||||
# # Here you can perform your processing on the PDF contents
|
|
||||||
# results.append({"filename": file.filename, "size": len(contents)})
|
|
||||||
#
|
|
||||||
# return {"message": "Upload successful", "results": results}
|
|
||||||
#
|
|
||||||
# except Exception as e:
|
|
||||||
# return {"error": str(e)}
|
|
||||||
|
|
||||||
|
Memory_ = Memory(user_id=decoded_payload["user_id"])
|
||||||
|
|
||||||
#
|
await Memory_.async_init()
|
||||||
|
|
||||||
|
# memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None)
|
||||||
|
output = await Memory_._get_task_list(
|
||||||
|
user_input=decoded_payload["prompt"], params=decoded_payload["params"], attention_modulators=decoded_payload["attention_modulators"]
|
||||||
|
)
|
||||||
|
return JSONResponse(content={"response": output}, status_code=200)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return JSONResponse(content={"response": {"error": str(e)}}, status_code=503)
|
||||||
|
|
||||||
def start_api_server(host: str = "0.0.0.0", port: int = 8000):
|
def start_api_server(host: str = "0.0.0.0", port: int = 8000):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -208,11 +208,13 @@ class WeaviateVectorDB(VectorDB):
|
||||||
|
|
||||||
|
|
||||||
async def add_memories(
|
async def add_memories(
|
||||||
self, observation: str, loader_settings: dict = None, params: dict = None
|
self, observation: str, loader_settings: dict = None, params: dict = None ,namespace:str=None
|
||||||
):
|
):
|
||||||
# Update Weaviate memories here
|
# Update Weaviate memories here
|
||||||
print(self.namespace)
|
print(self.namespace)
|
||||||
retriever = self.init_weaviate(self.namespace)
|
if namespace is None:
|
||||||
|
namespace = self.namespace
|
||||||
|
retriever = self.init_weaviate(namespace)
|
||||||
|
|
||||||
def _stuct(observation, params):
|
def _stuct(observation, params):
|
||||||
"""Utility function to not repeat metadata structure"""
|
"""Utility function to not repeat metadata structure"""
|
||||||
|
|
@ -348,7 +350,9 @@ class WeaviateVectorDB(VectorDB):
|
||||||
.with_additional(
|
.with_additional(
|
||||||
["id", "creationTimeUnix", "lastUpdateTimeUnix", "score", 'distance']
|
["id", "creationTimeUnix", "lastUpdateTimeUnix", "score", 'distance']
|
||||||
)
|
)
|
||||||
.with_near_text({"concepts": [observation]})
|
.with_hybrid(
|
||||||
|
query=observation,
|
||||||
|
)
|
||||||
.with_autocut(1)
|
.with_autocut(1)
|
||||||
.with_where(params_user_id)
|
.with_where(params_user_id)
|
||||||
.do()
|
.do()
|
||||||
|
|
@ -444,10 +448,11 @@ class BaseMemory:
|
||||||
observation: Optional[str] = None,
|
observation: Optional[str] = None,
|
||||||
loader_settings: dict = None,
|
loader_settings: dict = None,
|
||||||
params: Optional[dict] = None,
|
params: Optional[dict] = None,
|
||||||
|
namespace: Optional[str] = None,
|
||||||
):
|
):
|
||||||
if self.db_type == "weaviate":
|
if self.db_type == "weaviate":
|
||||||
return await self.vector_db.add_memories(
|
return await self.vector_db.add_memories(
|
||||||
observation=observation, loader_settings=loader_settings, params=params
|
observation=observation, loader_settings=loader_settings, params=params, namespace=namespace
|
||||||
)
|
)
|
||||||
# Add other db_type conditions if necessary
|
# Add other db_type conditions if necessary
|
||||||
|
|
||||||
|
|
@ -552,7 +557,6 @@ class EpisodicBuffer(BaseMemory):
|
||||||
last_update_datetime = datetime.fromtimestamp(int(unix_t) / 1000)
|
last_update_datetime = datetime.fromtimestamp(int(unix_t) / 1000)
|
||||||
time_difference = datetime.now() - last_update_datetime
|
time_difference = datetime.now() - last_update_datetime
|
||||||
time_difference_text = humanize.naturaltime(time_difference)
|
time_difference_text = humanize.naturaltime(time_difference)
|
||||||
print("WE GOT THIS FAR")
|
|
||||||
namespace = await self.memory_route(str(time_difference_text))
|
namespace = await self.memory_route(str(time_difference_text))
|
||||||
return [namespace.value, lookup_value]
|
return [namespace.value, lookup_value]
|
||||||
|
|
||||||
|
|
@ -569,12 +573,6 @@ class EpisodicBuffer(BaseMemory):
|
||||||
number_of_total_events = (
|
number_of_total_events = (
|
||||||
weaviate_client.query.aggregate(namespace).with_meta_count().do()
|
weaviate_client.query.aggregate(namespace).with_meta_count().do()
|
||||||
)
|
)
|
||||||
print(number_of_total_events)
|
|
||||||
print(
|
|
||||||
number_of_total_events["data"]["Aggregate"]["EPISODICMEMORY"][0]["meta"][
|
|
||||||
"count"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
frequency = float(number_of_relevant_events) / float(
|
frequency = float(number_of_relevant_events) / float(
|
||||||
number_of_total_events["data"]["Aggregate"]["EPISODICMEMORY"][0]["meta"][
|
number_of_total_events["data"]["Aggregate"]["EPISODICMEMORY"][0]["meta"][
|
||||||
"count"
|
"count"
|
||||||
|
|
@ -587,33 +585,37 @@ class EpisodicBuffer(BaseMemory):
|
||||||
Stored in the episodic memory, mainly to show how well a buffer did the job
|
Stored in the episodic memory, mainly to show how well a buffer did the job
|
||||||
Starts at 0, gets updated based on the user feedback"""
|
Starts at 0, gets updated based on the user feedback"""
|
||||||
|
|
||||||
print("WE START WITH RELEVANCE")
|
return ["0", "memory"]
|
||||||
|
|
||||||
weaviate_client = self.init_client(namespace=namespace)
|
async def saliency(self, observation: str, namespace=None) -> list[str]:
|
||||||
|
"""Determines saliency by scoring the set of retrieved documents against each other and trying to determine saliency
|
||||||
|
"""
|
||||||
|
class SaliencyRawList(BaseModel):
|
||||||
|
"""Schema for documentGroups"""
|
||||||
|
original_document: str = Field(
|
||||||
|
...,
|
||||||
|
description="The original document retrieved from the database")
|
||||||
|
saliency_score: str = Field(
|
||||||
|
None, description="The score between 0 and 1")
|
||||||
|
class SailencyContextList(BaseModel):
|
||||||
|
"""Buffer raw context processed by the buffer"""
|
||||||
|
|
||||||
result_output = await self.fetch_memories(
|
docs: List[SaliencyRawList] = Field(..., description="List of docs")
|
||||||
observation=observation, params=None, namespace=namespace
|
observation: str = Field(..., description="The original user query")
|
||||||
|
|
||||||
|
parser = PydanticOutputParser(pydantic_object=SailencyContextList)
|
||||||
|
prompt = PromptTemplate(
|
||||||
|
template="Determine saliency of documents compared to the other documents retrieved \n{format_instructions}\nOriginal observation is: {query}\n",
|
||||||
|
input_variables=["query"],
|
||||||
|
partial_variables={"format_instructions": parser.get_format_instructions()},
|
||||||
)
|
)
|
||||||
|
|
||||||
print("HERE IS THE RESULT OUTPUT TO DETERMINE RELEVANCE: ", result_output)
|
_input = prompt.format_prompt(query=observation)
|
||||||
|
document_context_result = self.llm_base(_input.to_string())
|
||||||
|
document_context_result_parsed = parser.parse(document_context_result)
|
||||||
|
return document_context_result_parsed.json()
|
||||||
|
|
||||||
return ["0", "memory"]
|
|
||||||
|
|
||||||
async def saliency(self, observation: str) -> list[str]:
|
|
||||||
"""Determines saliency by finding relevance between user input and document schema values.
|
|
||||||
After finding document schena value relevant for the user, it forms a new query based on the schema value and the user input
|
|
||||||
"""
|
|
||||||
|
|
||||||
return ["0", "memory"]
|
|
||||||
|
|
||||||
async def encoding(
|
|
||||||
self, document: str, namespace: str = "EPISODICBUFFER", params: dict = None
|
|
||||||
) -> list[str]:
|
|
||||||
"""Encoding for the buffer, stores raw data in the buffer
|
|
||||||
Note, this is not comp-sci encoding, but rather encoding in the sense of storing the content in the buffer
|
|
||||||
"""
|
|
||||||
query = await self.add_memories(document, params=params)
|
|
||||||
return query
|
|
||||||
|
|
||||||
async def handle_modulator(
|
async def handle_modulator(
|
||||||
self,
|
self,
|
||||||
|
|
@ -639,6 +641,7 @@ class EpisodicBuffer(BaseMemory):
|
||||||
"freshness": lambda obs, ns: self.freshness(observation=obs, namespace=ns),
|
"freshness": lambda obs, ns: self.freshness(observation=obs, namespace=ns),
|
||||||
"frequency": lambda obs, ns: self.frequency(observation=obs, namespace=ns),
|
"frequency": lambda obs, ns: self.frequency(observation=obs, namespace=ns),
|
||||||
"relevance": lambda obs, ns: self.relevance(observation=obs, namespace=ns),
|
"relevance": lambda obs, ns: self.relevance(observation=obs, namespace=ns),
|
||||||
|
"saliency": lambda obs, ns: self.saliency(observation=obs, namespace=ns),
|
||||||
}
|
}
|
||||||
|
|
||||||
result_func = modulator_functions.get(modulator_name)
|
result_func = modulator_functions.get(modulator_name)
|
||||||
|
|
@ -663,16 +666,15 @@ class EpisodicBuffer(BaseMemory):
|
||||||
return [
|
return [
|
||||||
"translate",
|
"translate",
|
||||||
"structure",
|
"structure",
|
||||||
"load to database",
|
"fetch from vector store"
|
||||||
"load to semantic memory",
|
# "load to semantic memory",
|
||||||
"load to episodic memory",
|
# "load to episodic memory",
|
||||||
"load to buffer",
|
# "load to buffer",
|
||||||
]
|
]
|
||||||
|
|
||||||
async def buffer_context(
|
async def buffer_context(
|
||||||
self,
|
self,
|
||||||
user_input=None,
|
user_input=None,
|
||||||
content=None,
|
|
||||||
params=None,
|
params=None,
|
||||||
attention_modulators: dict = None,
|
attention_modulators: dict = None,
|
||||||
):
|
):
|
||||||
|
|
@ -685,7 +687,7 @@ class EpisodicBuffer(BaseMemory):
|
||||||
pass
|
pass
|
||||||
# we just filter the data here to make sure input is clean
|
# we just filter the data here to make sure input is clean
|
||||||
prompt_filter = ChatPromptTemplate.from_template(
|
prompt_filter = ChatPromptTemplate.from_template(
|
||||||
"Filter and remove uneccessary information that is not relevant in the user query, keep it as original as possbile: {query}"
|
"Filter and remove uneccessary information that is not relevant in the query to the vector store to get more information, keep it as original as possbile: {query}"
|
||||||
)
|
)
|
||||||
chain_filter = prompt_filter | self.llm
|
chain_filter = prompt_filter | self.llm
|
||||||
output = await chain_filter.ainvoke({"query": user_input})
|
output = await chain_filter.ainvoke({"query": user_input})
|
||||||
|
|
@ -739,8 +741,8 @@ class EpisodicBuffer(BaseMemory):
|
||||||
...,
|
...,
|
||||||
description="The search term to use to get relevant input based on user query",
|
description="The search term to use to get relevant input based on user query",
|
||||||
)
|
)
|
||||||
document_description: str = Field(
|
document_content: str = Field(
|
||||||
None, description="The short summary of what the document is about"
|
None, description="Shortened original content of the document"
|
||||||
)
|
)
|
||||||
document_relevance: str = Field(
|
document_relevance: str = Field(
|
||||||
None,
|
None,
|
||||||
|
|
@ -767,21 +769,15 @@ class EpisodicBuffer(BaseMemory):
|
||||||
_input = prompt.format_prompt(query=user_input, context=context)
|
_input = prompt.format_prompt(query=user_input, context=context)
|
||||||
document_context_result = self.llm_base(_input.to_string())
|
document_context_result = self.llm_base(_input.to_string())
|
||||||
document_context_result_parsed = parser.parse(document_context_result)
|
document_context_result_parsed = parser.parse(document_context_result)
|
||||||
print("HERE ARE THE DOCS PARSED AND STRUCTURED", document_context_result_parsed)
|
print("HERE ARE THE DOCS PARSED AND STRUCTURED", document_context_result_parsed.json())
|
||||||
|
|
||||||
return document_context_result_parsed
|
return document_context_result_parsed
|
||||||
|
|
||||||
async def get_task_list(
|
async def get_task_list(
|
||||||
self, user_input=None, content=None, params=None, attention_modulators=None
|
self, user_input=None, params=None, attention_modulators=None,
|
||||||
):
|
):
|
||||||
"""Gets the task list from the document context result to enchance it and be able to pass to the agent"""
|
"""Gets the task list from the document context result to enchance it and be able to pass to the agent"""
|
||||||
list_of_operations = await self.available_operations()
|
list_of_operations = await self.available_operations()
|
||||||
document_context_result_parsed = await self.buffer_context(
|
|
||||||
user_input=user_input,
|
|
||||||
content=content,
|
|
||||||
params=params,
|
|
||||||
attention_modulators=attention_modulators,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Task(BaseModel):
|
class Task(BaseModel):
|
||||||
"""Schema for an individual task."""
|
"""Schema for an individual task."""
|
||||||
|
|
@ -802,19 +798,17 @@ class EpisodicBuffer(BaseMemory):
|
||||||
|
|
||||||
tasks: List[Task] = Field(..., description="List of tasks")
|
tasks: List[Task] = Field(..., description="List of tasks")
|
||||||
|
|
||||||
prompt_filter_chunk = f"The raw context data is {str(document_context_result_parsed)} Based on available operations {list_of_operations} determine only the relevant list of steps and operations sequentially based {user_input}"
|
prompt_filter_chunk = f" Based on available operations {list_of_operations} determine only the relevant list of steps and operations sequentially based {user_input}"
|
||||||
# chain_filter_chunk = prompt_filter_chunk | self.llm.bind(function_call={"TaskList": "tasks"}, functions=TaskList)
|
|
||||||
# output_chunk = await chain_filter_chunk.ainvoke({"query": output, "list_of_operations": list_of_operations})
|
|
||||||
prompt_msgs = [
|
prompt_msgs = [
|
||||||
SystemMessage(
|
SystemMessage(
|
||||||
content="You are a world class algorithm for decomposing prompts into steps and operations and choosing relevant ones"
|
content="You are a world class algorithm for decomposing prompts into steps and operations and choosing relevant ones"
|
||||||
),
|
),
|
||||||
HumanMessage(content="Decompose based on the following prompt:"),
|
HumanMessage(content="Decompose based on the following prompt and provide relevant document context reponse:"),
|
||||||
HumanMessagePromptTemplate.from_template("{input}"),
|
HumanMessagePromptTemplate.from_template("{input}"),
|
||||||
HumanMessage(content="Tips: Make sure to answer in the correct format"),
|
HumanMessage(content="Tips: Make sure to answer in the correct format"),
|
||||||
HumanMessage(
|
HumanMessage(
|
||||||
content="Tips: Only choose actions that are relevant to the user query and ignore others"
|
content="Tips: Only choose actions that are relevant to the user query and ignore others"
|
||||||
),
|
)
|
||||||
]
|
]
|
||||||
prompt_ = ChatPromptTemplate(messages=prompt_msgs)
|
prompt_ = ChatPromptTemplate(messages=prompt_msgs)
|
||||||
chain = create_structured_output_chain(
|
chain = create_structured_output_chain(
|
||||||
|
|
@ -828,29 +822,36 @@ class EpisodicBuffer(BaseMemory):
|
||||||
# output = json.dumps(output)
|
# output = json.dumps(output)
|
||||||
my_object = parse_obj_as(TaskList, output)
|
my_object = parse_obj_as(TaskList, output)
|
||||||
print("HERE IS THE OUTPUT", my_object.json())
|
print("HERE IS THE OUTPUT", my_object.json())
|
||||||
|
|
||||||
data = json.loads(my_object.json())
|
data = json.loads(my_object.json())
|
||||||
# Extract the list of tasks
|
# Extract the list of tasks
|
||||||
tasks_list = data["tasks"]
|
tasks_list = data["tasks"]
|
||||||
return tasks_list
|
return tasks_list
|
||||||
|
|
||||||
async def main_buffer(
|
async def main_buffer(
|
||||||
self, user_input=None, content=None, params=None, attention_modulators=None
|
self, user_input=None, params=None, attention_modulators=None
|
||||||
):
|
):
|
||||||
"""AI buffer to understand user PDF query, prioritize memory info and process it based on available operations"""
|
"""AI buffer to run the AI agent to execute the set of tasks"""
|
||||||
|
|
||||||
memory = Memory(user_id=self.user_id)
|
document_context_result_parsed = await self.buffer_context(
|
||||||
await memory.async_init()
|
|
||||||
tasks_list = await self.get_task_list(
|
|
||||||
user_input=user_input,
|
user_input=user_input,
|
||||||
content=content,
|
|
||||||
params=params,
|
params=params,
|
||||||
attention_modulators=attention_modulators,
|
attention_modulators=attention_modulators,
|
||||||
)
|
)
|
||||||
|
tasks_list = await self.get_task_list(
|
||||||
|
user_input=user_input,
|
||||||
|
params=params,
|
||||||
|
attention_modulators=attention_modulators
|
||||||
|
)
|
||||||
result_tasks = []
|
result_tasks = []
|
||||||
|
document_context_result_parsed = document_context_result_parsed.dict()
|
||||||
|
document_from_vectorstore = [doc["document_content"] for doc in document_context_result_parsed["docs"]]
|
||||||
|
|
||||||
for task in tasks_list:
|
for task in tasks_list:
|
||||||
|
print("HERE IS THE TASK", task)
|
||||||
|
|
||||||
|
complete_agent_prompt= f" Document context is: {document_from_vectorstore} \n Task is : {task['task_order']} {task['task_name']} {task['operation']} "
|
||||||
|
|
||||||
|
# task['vector_store_context_results']=document_context_result_parsed.dict()
|
||||||
class PromptWrapper(BaseModel):
|
class PromptWrapper(BaseModel):
|
||||||
observation: str = Field(
|
observation: str = Field(
|
||||||
description="observation we want to fetch from vectordb"
|
description="observation we want to fetch from vectordb"
|
||||||
|
|
@ -901,6 +902,17 @@ class EpisodicBuffer(BaseMemory):
|
||||||
result = run_open_ai_mapper(observation, json_schema)
|
result = run_open_ai_mapper(observation, json_schema)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
class FetchText(BaseModel):
|
||||||
|
observation: str = Field(description="observation we want to translate")
|
||||||
|
@tool("fetch_from_vector_store", args_schema=FetchText, return_direct=True)
|
||||||
|
def fetch_from_vector_store(observation, args_schema=FetchText):
|
||||||
|
"""Fetch from vectorstore if data doesn't exist in the context"""
|
||||||
|
if document_context_result_parsed:
|
||||||
|
return document_context_result_parsed
|
||||||
|
else:
|
||||||
|
out = self.fetch_memories(observation['original_query'], namespace="SEMANTICMEMORY")
|
||||||
|
return out
|
||||||
|
|
||||||
class TranslateText(BaseModel):
|
class TranslateText(BaseModel):
|
||||||
observation: str = Field(description="observation we want to translate")
|
observation: str = Field(description="observation we want to translate")
|
||||||
|
|
||||||
|
|
@ -914,23 +926,21 @@ class EpisodicBuffer(BaseMemory):
|
||||||
|
|
||||||
agent = initialize_agent(
|
agent = initialize_agent(
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
tools=[translate_to_de, convert_to_structured],
|
tools=[fetch_from_vector_store,translate_to_de, convert_to_structured],
|
||||||
agent=AgentType.OPENAI_FUNCTIONS,
|
agent=AgentType.OPENAI_FUNCTIONS,
|
||||||
verbose=True,
|
verbose=True,
|
||||||
)
|
)
|
||||||
print("HERE IS THE TASK", task)
|
|
||||||
output = agent.run(input=task)
|
output = agent.run(input=complete_agent_prompt )
|
||||||
print(output)
|
|
||||||
result_tasks.append(task)
|
result_tasks.append(task)
|
||||||
result_tasks.append(output)
|
result_tasks.append(output)
|
||||||
|
|
||||||
print("HERE IS THE RESULT TASKS", str(result_tasks))
|
# print("HERE IS THE RESULT TASKS", str(result_tasks))
|
||||||
|
#
|
||||||
await self.encoding(str(result_tasks), self.namespace, params=params)
|
# buffer_result = await self.fetch_memories(observation=str(user_input))
|
||||||
|
#
|
||||||
buffer_result = await self.fetch_memories(observation=str(user_input))
|
# print("HERE IS THE RESULT TASKS", str(buffer_result))
|
||||||
|
|
||||||
print("HERE IS THE RESULT TASKS", str(buffer_result))
|
|
||||||
|
|
||||||
class EpisodicTask(BaseModel):
|
class EpisodicTask(BaseModel):
|
||||||
"""Schema for an individual task."""
|
"""Schema for an individual task."""
|
||||||
|
|
@ -969,19 +979,19 @@ class EpisodicBuffer(BaseMemory):
|
||||||
)
|
)
|
||||||
|
|
||||||
_input = prompt.format_prompt(
|
_input = prompt.format_prompt(
|
||||||
query=user_input, steps=str(tasks_list), buffer=buffer_result
|
query=user_input, steps=str(tasks_list)
|
||||||
|
, buffer=str(result_tasks)
|
||||||
)
|
)
|
||||||
|
|
||||||
# return "a few things to do like load episodic memory in a structured format"
|
# return "a few things to do like load episodic memory in a structured format"
|
||||||
|
|
||||||
output = self.llm_base(_input.to_string())
|
output = self.llm_base(_input.to_string())
|
||||||
result_parsing = parser.parse(output)
|
result_parsing = parser.parse(output)
|
||||||
print("here is the parsing result", result_parsing)
|
lookup_value = await self.add_memories(
|
||||||
lookup_value = await memory._add_episodic_memory(
|
observation=str(result_parsing.json()), params=params, namespace='EPISODICMEMORY'
|
||||||
observation=str(output), params=params
|
|
||||||
)
|
)
|
||||||
|
# print("THE RESULT OF THIS QUERY IS ", result_parsing.json())
|
||||||
await self.delete_memories()
|
await self.delete_memories()
|
||||||
return lookup_value
|
return result_parsing.json()
|
||||||
|
|
||||||
|
|
||||||
class LongTermMemory:
|
class LongTermMemory:
|
||||||
|
|
@ -1116,12 +1126,6 @@ class Memory:
|
||||||
params=params
|
params=params
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _run_buffer(
|
|
||||||
self, user_input: str, content: str = None, params: str = None
|
|
||||||
):
|
|
||||||
return await self.short_term_memory.episodic_buffer.main_buffer(
|
|
||||||
user_input=user_input, content=content, params=params
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _add_buffer_memory(
|
async def _add_buffer_memory(
|
||||||
self,
|
self,
|
||||||
|
|
@ -1147,27 +1151,33 @@ class Memory:
|
||||||
async def _create_buffer_context(
|
async def _create_buffer_context(
|
||||||
self,
|
self,
|
||||||
user_input: str,
|
user_input: str,
|
||||||
content: str = None,
|
params: dict = None,
|
||||||
params: str = None,
|
|
||||||
attention_modulators: dict = None,
|
attention_modulators: dict = None,
|
||||||
):
|
):
|
||||||
return await self.short_term_memory.episodic_buffer.buffer_context(
|
return await self.short_term_memory.episodic_buffer.buffer_context(
|
||||||
user_input=user_input,
|
user_input=user_input,
|
||||||
content=content,
|
|
||||||
params=params,
|
params=params,
|
||||||
attention_modulators=attention_modulators,
|
attention_modulators=attention_modulators,
|
||||||
)
|
)
|
||||||
|
async def _get_task_list(
|
||||||
|
self,
|
||||||
|
user_input: str,
|
||||||
|
params: str = None,
|
||||||
|
attention_modulators: dict = None,
|
||||||
|
):
|
||||||
|
return await self.short_term_memory.episodic_buffer.get_task_list(
|
||||||
|
user_input=user_input,
|
||||||
|
params=params,
|
||||||
|
attention_modulators=attention_modulators,
|
||||||
|
)
|
||||||
async def _run_main_buffer(
|
async def _run_main_buffer(
|
||||||
self,
|
self,
|
||||||
user_input: str,
|
user_input: str,
|
||||||
content: str = None,
|
params: dict = None,
|
||||||
params: str = None,
|
attention_modulators: dict = None,
|
||||||
attention_modulators: str = None,
|
|
||||||
):
|
):
|
||||||
return await self.short_term_memory.episodic_buffer.main_buffer(
|
return await self.short_term_memory.episodic_buffer.main_buffer(
|
||||||
user_input=user_input,
|
user_input=user_input,
|
||||||
content=content,
|
|
||||||
params=params,
|
params=params,
|
||||||
attention_modulators=attention_modulators,
|
attention_modulators=attention_modulators,
|
||||||
)
|
)
|
||||||
|
|
@ -1199,35 +1209,15 @@ async def main():
|
||||||
# gg = await memory._fetch_buffer_memory(user_input="i TO GERMAN ")
|
# gg = await memory._fetch_buffer_memory(user_input="i TO GERMAN ")
|
||||||
# print(gg)
|
# print(gg)
|
||||||
|
|
||||||
episodic = """{
|
|
||||||
"start_date": "2023-08-23",
|
|
||||||
"end_date": "2023-08-30",
|
|
||||||
"user_query": "How can I plan a healthy diet?",
|
|
||||||
"action_steps": [
|
|
||||||
{
|
|
||||||
"step_number": 1,
|
|
||||||
"description": "Research and gather information about basic principles of a healthy diet."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"step_number": 2,
|
|
||||||
"description": "Create a weekly meal plan that includes a variety of nutritious foods."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"step_number": 3,
|
|
||||||
"description": "Prepare and cook meals according to your meal plan. Include fruits, vegetables, lean proteins, and whole grains."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}"""
|
|
||||||
|
|
||||||
# modulator = {"relevance": 0.2, "saliency": 0.0, "frequency": 0.7}
|
modulator = {"relevance": 0.0, "saliency": 0.0, "frequency": 0.0}
|
||||||
# #
|
# #
|
||||||
# ggur = await memory._create_buffer_context(
|
ggur = await memory._run_main_buffer(
|
||||||
# user_input="i NEED TRANSLATION TO GERMAN ",
|
user_input="I want to know how does Buck adapt to life in the wild and then have that info translated to german ",
|
||||||
# content="i NEED TRANSLATION TO GERMAN ",
|
params=params,
|
||||||
# params=str(params),
|
attention_modulators=modulator,
|
||||||
# attention_modulators=modulator,
|
)
|
||||||
# )
|
print(ggur)
|
||||||
# print(ggur)
|
|
||||||
|
|
||||||
ll = {
|
ll = {
|
||||||
"format": "PDF",
|
"format": "PDF",
|
||||||
|
|
@ -1239,8 +1229,8 @@ async def main():
|
||||||
# fff = await memory._delete_semantic_memory()
|
# fff = await memory._delete_semantic_memory()
|
||||||
# print(fff)
|
# print(fff)
|
||||||
|
|
||||||
fff = await memory._fetch_semantic_memory(observation = "dog pulling sleds ", params=None)
|
# fff = await memory._fetch_semantic_memory(observation = "dog pulling sleds ", params=None)
|
||||||
print(fff)
|
# print(fff)
|
||||||
# print(len(fff["data"]["Get"]["EPISODICMEMORY"]))
|
# print(len(fff["data"]["Get"]["EPISODICMEMORY"]))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1249,16 +1239,3 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
|
|
||||||
# bb = agent._update_semantic_memory(semantic_memory="Users core summary")
|
|
||||||
# bb = agent._fetch_semantic_memory(observation= "Users core summary", params = {
|
|
||||||
# "path": ["inserted_at"],
|
|
||||||
# "operator": "Equal",
|
|
||||||
# "valueText": "*2023*"
|
|
||||||
# })
|
|
||||||
# buffer = agent._run_buffer(user_input="I want to get a schema for my data")
|
|
||||||
# print(bb)
|
|
||||||
# rrr = {
|
|
||||||
# "path": ["year"],
|
|
||||||
# "operator": "Equal",
|
|
||||||
# "valueText": "2017*"
|
|
||||||
# }
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue