diff --git a/level_2/api.py b/level_2/api.py index e79309de4..57942d582 100644 --- a/level_2/api.py +++ b/level_2/api.py @@ -168,12 +168,12 @@ def memory_factory(memory_type): # pages = loader.load_and_split() logging.info(" PDF split into pages") - Memory_ = Memory(user_id='555') + Memory_ = Memory(user_id=decoded_payload['user_id']) await Memory_.async_init() memory_class = getattr(Memory_, f"_add_{memory_type}_memory", None) - output= await memory_class(observation=str(loader)) + output= await memory_class(observation=str(loader), params =decoded_payload['params']) return JSONResponse(content={"response": output}, status_code=200) except Exception as e: @@ -181,7 +181,7 @@ def memory_factory(memory_type): return JSONResponse(content={"response": {"error": str(e)}}, status_code=503) @app.post("/{memory_type}/fetch-memory", response_model=dict) - async def add_memory( + async def fetch_memory( payload: Payload, # files: List[UploadFile] = File(...), ): @@ -189,7 +189,7 @@ def memory_factory(memory_type): decoded_payload = payload.payload - Memory_ = Memory(user_id='555') + Memory_ = Memory(user_id=decoded_payload['user_id']) await Memory_.async_init() @@ -202,7 +202,7 @@ def memory_factory(memory_type): return JSONResponse(content={"response": {"error": str(e)}}, status_code=503) @app.post("/{memory_type}/delete-memory", response_model=dict) - async def add_memory( + async def delete_memory( payload: Payload, # files: List[UploadFile] = File(...), ): @@ -210,7 +210,7 @@ def memory_factory(memory_type): decoded_payload = payload.payload - Memory_ = Memory(user_id='555') + Memory_ = Memory(user_id=decoded_payload['user_id']) await Memory_.async_init() @@ -227,6 +227,29 @@ for memory_type in memory_list: memory_factory(memory_type) + +@app.get("/available-buffer-actions", response_model=dict) +async def available_buffer_actions( + payload: Payload, + # files: List[UploadFile] = File(...), +): + try: + + decoded_payload = payload.payload + + Memory_ = Memory(user_id=decoded_payload['user_id']) + + await Memory_.async_init() + + # memory_class = getattr(Memory_, f"_delete_{memory_type}_memory", None) + output = Memory_._available_operations() + return JSONResponse(content={"response": output}, status_code=200) + + except Exception as e: + + return JSONResponse(content={"response": {"error": str(e)}}, status_code=503) + + # # # Process each uploaded PDF file # results = [] diff --git a/level_2/level_2_pdf_vectorstore__dlt_contracts.py b/level_2/level_2_pdf_vectorstore__dlt_contracts.py index e087cafcd..8212db028 100644 --- a/level_2/level_2_pdf_vectorstore__dlt_contracts.py +++ b/level_2/level_2_pdf_vectorstore__dlt_contracts.py @@ -55,7 +55,7 @@ from langchain.schema import Document, SystemMessage, HumanMessage from langchain.vectorstores import Weaviate import weaviate import uuid - +import humanize load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "") @@ -542,7 +542,7 @@ class EpisodicBuffer: vector_db = VectorDB(user_id=self.user_id, memory_id=self.memory_id, st_memory_id=self.st_memory_id, index_name=self.index_name, db_type=self.db_type, namespace=namespace) - query = await vector_db.fetch_memories(observation=observation) + query = await vector_db.fetch_memories(observation=observation, namespace=namespace) return query async def _add_memories(self, observation: str, namespace: str, params: dict = None): @@ -555,175 +555,380 @@ class EpisodicBuffer: async def _delete_memories(self, params: str = None) -> Coroutine[Any, Any, Any]: """Fetch related characteristics, preferences or dislikes for a user.""" # self.init_pinecone(index_name=self.index) + vector_db = VectorDB(user_id=self.user_id, memory_id=self.memory_id, st_memory_id=self.st_memory_id, + index_name=self.index_name, db_type=self.db_type, namespace=self.namespace) if self.db_type == "weaviate": - return await self.vector_db.delete_memories(params=params) + return await vector_db.delete_memories(params=params) elif self.db_type == "pinecone": pass - # async def freshness(self, observation: str,namespace:str) -> str: - # """Freshness - Score between 1 and 5 on how often was the information processed in episodic memory in the past""" - # - # memory = Memory(user_id=self.user_id) - # await memory.async_init() - # - # # gg = await memory._run_buffer(user_input= "bla", content = "blablabla ") - # # print(gg) - # - # - # - # ggur = await memory._fetch_episodic_memory(observation=observation) - # print(ggur) + async def freshness(self, observation: str,namespace:str=None) -> list[str]: + """Freshness - Score between 1 and 5 on how often was the information updated in episodic or semantic memory in the past""" + + memory = Memory(user_id=self.user_id) + await memory.async_init() + + lookup_value = await memory._fetch_episodic_memory(observation = observation) + unix_t = lookup_value["data"]["Get"]["EPISODICMEMORY"][0]["_additional"]["lastUpdateTimeUnix"] + + # Convert Unix timestamp to datetime + last_update_datetime = datetime.fromtimestamp(int(unix_t) / 1000) + time_difference = datetime.now() - last_update_datetime + time_difference_text = humanize.naturaltime(time_difference) + marvin.settings.openai.api_key = os.environ.get('OPENAI_API_KEY') + @ai_classifier + class MemoryRoute(Enum): + """Represents classifer for freshness of memories""" + + data_uploaded_now = "0" + data_uploaded_very_recently = "1" + data_uploaded_recently = "2" + data_uploaded_more_than_a_month_ago = "3" + data_uploaded_more_than_three_months_ago = "4" + data_uploaded_more_than_six_months_ago = "5" + + namespace = MemoryRoute(str(time_difference_text)) + return [namespace.value, lookup_value] + + + async def frequency(self, observation: str,namespace:str) -> list[str]: + """Frequency - Score between 1 and 5 on how often was the information processed in episodic memory in the past + Counts the number of times a memory was accessed in the past and divides it by the total number of memories in the episodic memory """ + client = self.init_weaviate_client(self.namespace) + + memory = Memory(user_id=self.user_id) + await memory.async_init() + + result_output = await memory._fetch_episodic_memory(observation=observation) + number_of_relevant_events = len(result_output["data"]["Get"]["EPISODICMEMORY"]) + number_of_total_events = client.query.aggregate( self.namespace).with_meta_count().do() + frequency = float(number_of_relevant_events) / float(number_of_total_events) + return [str(frequency), result_output["data"]["Get"]["EPISODICMEMORY"][0]] + + + + async def relevance(self, observation: str) -> list[str]: + """Relevance - Score between 1 and 5 on how often was the final information relevant to the user in the past. + Stored in the episodic memory, mainly to show how well a buffer did the job + Starts at 1, gets updated based on the user feedback """ + + return ["5", "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 ["5", "memory"] # @ai_classifier # class MemoryRoute(Enum): - # """Represents classifer for semantic fetching of memories""" + # """Represents classifer for freshness of memories""" # - # storage_of_documents_and_knowledge_to_memory = "SEMANTICMEMORY" - # raw_information_currently_processed_in_short_term_memory = "EPISODICBUFFER" - # raw_information_kept_in_short_term_memory = "SHORTTERMMEMORY" - # long_term_recollections_of_past_events_and_emotions = "EPISODICMEMORY" - # raw_information_to_store_as_events = "EVENTBUFFER" + # data_uploaded_now = "0" + # data_uploaded_very_recently = "1" + # data_uploaded_recently = "2" + # data_uploaded_more_than_a_month_ago = "3" + # data_uploaded_more_than_three_months_ago = "4" + # data_uploaded_more_than_six_months_ago = "5" # # namespace= MemoryRoute(observation) # return ggur - async def encoding(self, document: str, namespace: str = "EPISODICBUFFER") -> None: + 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""" vector_db = VectorDB(user_id=self.user_id, memory_id=self.memory_id, st_memory_id=self.st_memory_id, index_name=self.index_name, db_type=self.db_type, namespace=namespace) - query = await vector_db.add_memories(document) + query = await vector_db.add_memories(document, params=params) return query - async def main_buffer(self, user_input=None, content=None): - """AI buffer to convert unstructured data to structured data""" - # Here we define the user prompt and the structure of the output we desire - # prompt = output[0].page_content + async def available_operations(self) -> list[str]: + """Determines what operations are available for the user to process PDFs""" + return ["translate", "structure", "load to database", "load to semantic memory", "load to episodic memory", "load to buffer"] + + async def main_buffer(self, user_input=None, content=None, params=None): + + """AI buffer to understand user PDF query, prioritize memory info and process it based on available operations""" + + + list_of_operations = await self.available_operations() + + + #we just filter the data here + prompt_filter = ChatPromptTemplate.from_template( + "Filter and remove uneccessary information that is not relevant in the user query {query}") + chain_filter = prompt_filter | self.llm + output = await chain_filter.ainvoke({"query": user_input}) + + + if params: + context =[] + + if "freshness" in params: + params.get('freshness', None) # get the value of freshness + freshness = await self.freshness(observation=str(output)) + context.append(freshness) + + elif "frequency" in params: + params.get('freshness', None) + frequency = await self.freshness(observation=str(output)) + print("freshness", frequency) + context.append(frequency) + + #fix this so it actually filters + + + else: + #defaults to semantic search + memory = Memory(user_id=self.user_id) + await memory.async_init() + + lookup_value_episodic = await memory._fetch_episodic_memory(observation=str(output)) + lookup_value_semantic = await memory._fetch_episodic_memory(observation=str(output)) + lookup_value_buffer = await self._fetch_memories(observation=str(output), namespace=self.namespace) + + context = [lookup_value_episodic, lookup_value_semantic, lookup_value_buffer] + #copy the context over into the buffer + #do i need to do it for the episodic + raw data, might make sense + + + + print("HERE WE ARE") + + class Task(BaseModel): + """Schema for an individual task.""" + task_order: str = Field(..., description="The order at which the task needs to be performed") + task_name: str = Field(None, description="The task that needs to be performed") + operation: str = Field(None, description="The operation to be performed") + + class TaskList(BaseModel): + """Schema for the record containing a list of tasks.""" + tasks: List[Task] = Field(..., description="List of tasks") + + prompt_filter_chunk = f" Based on available operations {list_of_operations} determine only the relevant list of steps and operations sequentially based {output}" + # 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 = [ + SystemMessage( + 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:"), + HumanMessagePromptTemplate.from_template("{input}"), + HumanMessage(content="Tips: Make sure to answer in the correct format"), + HumanMessage(content="Tips: Only choose actions that are relevant to the user query and ignore others") + + ] + prompt_ = ChatPromptTemplate(messages=prompt_msgs) + chain = create_structured_output_chain(TaskList, self.llm, prompt_, verbose=True) + from langchain.callbacks import get_openai_callback + with get_openai_callback() as cb: + output = await chain.arun(input=prompt_filter_chunk, verbose=True) + print(cb) + # output = json.dumps(output) + my_object = parse_obj_as(TaskList, output) + print("HERE IS THE OUTPUT", my_object.json()) + + data = json.loads(my_object.json()) + + # Extract the list of tasks + tasks_list = data["tasks"] + + for task in tasks_list: + class TranslateText(BaseModel): + observation: str = Field( + description="observation we want to translate" + ) + + @tool("translate_to_en", args_schema=TranslateText, return_direct=True) + def translate_to_en(observation, args_schema=TranslateText): + """Translate to English""" + out = GoogleTranslator(source='auto', target='en').translate(text=observation) + return out + + agent = initialize_agent( + llm=self.llm, + tools=[translate_to_en], + agent=AgentType.OPENAI_FUNCTIONS, + + verbose=True, + ) + print("HERE IS THE TASK", task) + output = agent.run(input=task) + print(output) + await self.encoding(output) + + + + buffer_result = await self._fetch_memories(observation=str(output), namespace=self.namespace) + + #json here + + prompt_filter = ChatPromptTemplate.from_template( + "Format and collect all outputs from the tasks presented here {tasks} and their results {results}") + chain_filter_chunk = prompt_filter | self.llm.bind(function_call={"TaskList": "tasks"}, functions=TaskList) + output = await chain_filter_chunk.ainvoke({"query": buffer_result}) + print("HERE IS THE OUTPUT", output) + + + memory = Memory(user_id=self.user_id) + await memory.async_init() + + lookup_value = await memory._add_episodic_memory(observation=str(output), params={}) + + + #load to buffer once is done + + #fetch everything in the current session and load to episodic memory + + + + + + + + #for files where user input is provided and they are directly proccessed + + + # + # based on the semantic search , raw memory data will be fetched. also, episodic memory will be fetched + # they will be written down as a "context" for the user + + + # i get scores for the episodic memory and the semantic memory + # i get only the data with the highest score + # i use that data to form the context # file_upload # - if content is not None: - # operations -> translate, structure, load to db + #for files where user input is provided and they are directly proccessed - list_of_operations = ["translate", "structure", "load to db"] - prompt_filter = ChatPromptTemplate.from_template( - "Filter and remove uneccessary information that is not relevant in the user query {query}") - chain_filter = prompt_filter | self.llm - output = await chain_filter.ainvoke({"query": user_input}) - - class Task(BaseModel): - """Schema for an individual task.""" - task_order: str = Field(..., description="The order at which the task needs to be performed") - task_name: str = Field(None, description="The task that needs to be performed") - operation: str = Field(None, description="The operation to be performed") - - class TaskList(BaseModel): - """Schema for the record containing a list of tasks.""" - tasks: List[Task] = Field(..., description="List of tasks") - - prompt_filter_chunk = f" Based on available operations {list_of_operations} determine only the relevant list of steps and operations sequentially based {output}" - # 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 = [ - SystemMessage( - 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:"), - HumanMessagePromptTemplate.from_template("{input}"), - HumanMessage(content="Tips: Make sure to answer in the correct format"), - HumanMessage(content="Tips: Only choose actions that are relevant to the user query and ignore others") - - ] - prompt_ = ChatPromptTemplate(messages=prompt_msgs) - chain = create_structured_output_chain(TaskList, self.llm, prompt_, verbose=True) - from langchain.callbacks import get_openai_callback - with get_openai_callback() as cb: - output = await chain.arun(input=prompt_filter_chunk, verbose=True) - print(cb) - # output = json.dumps(output) - my_object = parse_obj_as(TaskList, output) - print("HERE IS THE OUTPUT", my_object.json()) - - data = json.loads(my_object.json()) - - # Extract the list of tasks - tasks_list = data["tasks"] - - for task in tasks_list: - class TranslateText(BaseModel): - observation: str = Field( - description="observation we want to translate" - ) - - @tool("translate_to_en", args_schema=TranslateText, return_direct=True) - def translate_to_en(observation, args_schema=TranslateText): - """Translate to English""" - out = GoogleTranslator(source='auto', target='en').translate(text=observation) - return out - - agent = initialize_agent( - llm=self.llm, - tools=[translate_to_en], - agent=AgentType.OPENAI_FUNCTIONS, - - verbose=True, - ) - - agent.run(task) - - # We need to encode the content. Note, this is not comp-sci encoding, but rather encoding in the sense of storing the content in the buffer - # output_translated = GoogleTranslator(source='auto', target='en').translate(text=content) - # await self.encoding(output_translated) - # freshness_score =await self.freshness(output_translated, namespace="EPISODICBUFFER") - # print(freshness_score) - # shows how much the data is relevant for the user, provided by the user in a separate step, starts at 0 - user_relevance_score = "0" - # similarity score between the user input and the content already available in the buffer - - # write this to episodic memory - - # prompt_filter = ChatPromptTemplate.from_template("Filter and remove uneccessary information that is not relevant in the user query {query}") - # chain_filter = prompt_filter | self.llm - # output = await chain_filter.ainvoke({"query": user_input}) - - # print(output) - - if content is None: - # Sensory and Linguistic Processing - prompt_filter = ChatPromptTemplate.from_template( - "Filter and remove uneccessary information that is not relevant in the user query {query}") - chain_filter = prompt_filter | self.llm - output = await chain_filter.ainvoke({"query": user_input}) - translation = GoogleTranslator(source='auto', target='en').translate(text=output.content) - - def top_down_processing(): - """Top-down processing""" - pass - - def bottom_up_processing(): - """Bottom-up processing""" - pass - - def interactive_processing(): - """interactive processing""" - pass - - working_memory_activation = "bla" - - prompt_chunk = ChatPromptTemplate.from_template( - "Can you break down the instruction 'Structure a PDF and load it into duckdb' into smaller tasks or actions? Return only tasks or actions. Be brief") - chain_chunk = prompt_chunk | self.llm - output_chunks = await chain_chunk.ainvoke({"query": output.content}) - - print(output_chunks.content) + # + # # + # + # if content is not None: + # + # # operations -> translate, structure, load to db + # + # list_of_operations = ["translate", "structure", "load to db"] + # + # prompt_filter = ChatPromptTemplate.from_template( + # "Filter and remove uneccessary information that is not relevant in the user query {query}") + # chain_filter = prompt_filter | self.llm + # output = await chain_filter.ainvoke({"query": user_input}) + # + # class Task(BaseModel): + # """Schema for an individual task.""" + # task_order: str = Field(..., description="The order at which the task needs to be performed") + # task_name: str = Field(None, description="The task that needs to be performed") + # operation: str = Field(None, description="The operation to be performed") + # + # class TaskList(BaseModel): + # """Schema for the record containing a list of tasks.""" + # tasks: List[Task] = Field(..., description="List of tasks") + # + # prompt_filter_chunk = f" Based on available operations {list_of_operations} determine only the relevant list of steps and operations sequentially based {output}" + # # 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 = [ + # SystemMessage( + # 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:"), + # HumanMessagePromptTemplate.from_template("{input}"), + # HumanMessage(content="Tips: Make sure to answer in the correct format"), + # HumanMessage(content="Tips: Only choose actions that are relevant to the user query and ignore others") + # + # ] + # prompt_ = ChatPromptTemplate(messages=prompt_msgs) + # chain = create_structured_output_chain(TaskList, self.llm, prompt_, verbose=True) + # from langchain.callbacks import get_openai_callback + # with get_openai_callback() as cb: + # output = await chain.arun(input=prompt_filter_chunk, verbose=True) + # print(cb) + # # output = json.dumps(output) + # my_object = parse_obj_as(TaskList, output) + # print("HERE IS THE OUTPUT", my_object.json()) + # + # data = json.loads(my_object.json()) + # + # # Extract the list of tasks + # tasks_list = data["tasks"] + # + # for task in tasks_list: + # class TranslateText(BaseModel): + # observation: str = Field( + # description="observation we want to translate" + # ) + # + # @tool("translate_to_en", args_schema=TranslateText, return_direct=True) + # def translate_to_en(observation, args_schema=TranslateText): + # """Translate to English""" + # out = GoogleTranslator(source='auto', target='en').translate(text=observation) + # return out + # + # agent = initialize_agent( + # llm=self.llm, + # tools=[translate_to_en], + # agent=AgentType.OPENAI_FUNCTIONS, + # + # verbose=True, + # ) + # + # agent.run(task) + # + # # We need to encode the content. Note, this is not comp-sci encoding, but rather encoding in the sense of storing the content in the buffer + # # output_translated = GoogleTranslator(source='auto', target='en').translate(text=content) + # # await self.encoding(output_translated) + # # freshness_score =await self.freshness(output_translated, namespace="EPISODICBUFFER") + # # print(freshness_score) + # # shows how much the data is relevant for the user, provided by the user in a separate step, starts at 0 + # user_relevance_score = "0" + # # similarity score between the user input and the content already available in the buffer + # + # # write this to episodic memory + # + # # prompt_filter = ChatPromptTemplate.from_template("Filter and remove uneccessary information that is not relevant in the user query {query}") + # # chain_filter = prompt_filter | self.llm + # # output = await chain_filter.ainvoke({"query": user_input}) + # + # # print(output) + # + # if content is None: + # # Sensory and Linguistic Processing + # prompt_filter = ChatPromptTemplate.from_template( + # "Filter and remove uneccessary information that is not relevant in the user query {query}") + # chain_filter = prompt_filter | self.llm + # output = await chain_filter.ainvoke({"query": user_input}) + # translation = GoogleTranslator(source='auto', target='en').translate(text=output.content) + # + # def top_down_processing(): + # """Top-down processing""" + # pass + # + # def bottom_up_processing(): + # """Bottom-up processing""" + # pass + # + # def interactive_processing(): + # """interactive processing""" + # pass + # + # working_memory_activation = "bla" + # + # prompt_chunk = ChatPromptTemplate.from_template( + # "Can you break down the instruction 'Structure a PDF and load it into duckdb' into smaller tasks or actions? Return only tasks or actions. Be brief") + # chain_chunk = prompt_chunk | self.llm + # output_chunks = await chain_chunk.ainvoke({"query": output.content}) + # + # print(output_chunks.content) # vectorstore = Weaviate.from_documents(documents, embeddings, client=client, by_text=False) # retriever = WeaviateHybridSearchRetriever( @@ -969,10 +1174,11 @@ class Memory: return await self.short_term_memory.episodic_buffer._fetch_memories(observation=user_input, namespace=namespace) async def _delete_buffer_memory(self, params: str = None): - return await self.long_term_memory.episodic_buffer._delete_memories( + return await self.short_term_memory.episodic_buffer._delete_memories( params=params ) - + async def _available_operations(self): + return await self.long_term_memory.episodic_buffer._available_operations() async def main(): memory = Memory(user_id="123") @@ -994,15 +1200,34 @@ async def main(): gg = await memory._run_buffer(user_input="i NEED TRANSLATION TO GERMAN ", content="i NEED TRANSLATION TO GERMAN ") print(gg) - # gg = await memory._delete_episodic_memory() + # gg = await memory._delete_buffer_memory() # print(gg) - # ggur = await memory._add_episodic_memory(observation = "bla bla bla", params=params) + 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." + } + ] + }""" + # + # ggur = await memory._add_episodic_memory(observation = episodic, params=params) # print(ggur) - # ggur = await memory._fetch_episodic_memory(observation = "bla bla bla") - # print(ggur) - # fff = await memory._fetch_memories_buffer(user_input = "bla bla bla", namespace="Test") - # print(fff) + + # fff = await memory._fetch_episodic_memory(observation = "healthy diet") + # print(len(fff["data"]["Get"]["EPISODICMEMORY"])) if __name__ == "__main__": diff --git a/level_2/poetry.lock b/level_2/poetry.lock index 7b95c721a..cdfb4ca4a 100644 --- a/level_2/poetry.lock +++ b/level_2/poetry.lock @@ -261,17 +261,17 @@ numpy = {version = ">=1.19.0", markers = "python_version >= \"3.9\""} [[package]] name = "boto3" -version = "1.28.30" +version = "1.28.32" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.7" files = [ - {file = "boto3-1.28.30-py3-none-any.whl", hash = "sha256:e095ede98d3680e65966ab71f273b7d86938f5d853773ef96f4cb646277c2a4b"}, - {file = "boto3-1.28.30.tar.gz", hash = "sha256:2b509a959966a572f15db5768a18066ce1f53022ac53fca9421c620219fa3998"}, + {file = "boto3-1.28.32-py3-none-any.whl", hash = "sha256:ed787f250ce2562c7744395bdf32b5a7bc9184126ef50a75e97bcb66043dccf3"}, + {file = "boto3-1.28.32.tar.gz", hash = "sha256:b505faa126db84e226f6f8d242a798fae30a725f0cac8a76c6aca9ace4e8eb28"}, ] [package.dependencies] -botocore = ">=1.31.30,<1.32.0" +botocore = ">=1.31.32,<1.32.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.6.0,<0.7.0" @@ -280,13 +280,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.31.30" +version = "1.31.32" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.7" files = [ - {file = "botocore-1.31.30-py3-none-any.whl", hash = "sha256:269f20dcadd8dfd0c26d0e6fbceb84814ff6638ff3aafcc5324b9fb9949a7051"}, - {file = "botocore-1.31.30.tar.gz", hash = "sha256:3cf6a9d7621b897c9ff23cd02113826141b3dd3d7e90273b661efc4dc05f84e2"}, + {file = "botocore-1.31.32-py3-none-any.whl", hash = "sha256:8992ac186988c4b4cc168e8e479e9472da1442b193c1bf7c9dcd1877ec62d23c"}, + {file = "botocore-1.31.32.tar.gz", hash = "sha256:7a07d8dc8cc47bf23af39409ada81f388eb78233e1bb2cde0c415756da753664"}, ] [package.dependencies] @@ -1053,13 +1053,13 @@ requests = ">=2.20.0,<3.0" [[package]] name = "gptcache" -version = "0.1.39.1" +version = "0.1.40" description = "GPTCache, a powerful caching library that can be used to speed up and lower the cost of chat applications that rely on the LLM service. GPTCache works as a memcache for AIGC applications, similar to how Redis works for traditional applications." optional = false python-versions = ">=3.8.1" files = [ - {file = "gptcache-0.1.39.1-py3-none-any.whl", hash = "sha256:81355f7878e12a820dccb017f8a45ea44b73178dac07108c56db664a476a4a07"}, - {file = "gptcache-0.1.39.1.tar.gz", hash = "sha256:a9c629fdeaa94b78a6cfe707a5f9a3a52b361655a3f01327709ca00c78a500eb"}, + {file = "gptcache-0.1.40-py3-none-any.whl", hash = "sha256:ba323e5e46b100fa7663b5f4d164cc2aee60f343184ed03ec2d2bb95e9f47c50"}, + {file = "gptcache-0.1.40.tar.gz", hash = "sha256:5fe4bcf3a45946177cb845b3e1ec01159f10622600e1384b9de0c7c6065d10d5"}, ] [package.dependencies] @@ -1415,13 +1415,13 @@ data = ["language-data (>=1.1,<2.0)"] [[package]] name = "langsmith" -version = "0.0.25" +version = "0.0.26" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = ">=3.8.1,<4.0" files = [ - {file = "langsmith-0.0.25-py3-none-any.whl", hash = "sha256:d595435ad21fa6077550d7c85472935d1e8241afa042c1e29287d2c95c3ed151"}, - {file = "langsmith-0.0.25.tar.gz", hash = "sha256:e728c398fc1adaa0ed8abeb21f6a92d7fb19fe3ab49d3911c22b03dfe25935d6"}, + {file = "langsmith-0.0.26-py3-none-any.whl", hash = "sha256:61c1d4582104d96edde04e1eea1dae347645b691c44489a5871341a2a1a2a1eb"}, + {file = "langsmith-0.0.26.tar.gz", hash = "sha256:80a4ef1b663a24a460d25b9986ab2010c5d06b6061c65be473abafc0647d191a"}, ] [package.dependencies] @@ -3561,13 +3561,13 @@ colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\" and python [[package]] name = "weaviate-client" -version = "3.22.1" +version = "3.23.0" description = "A python native Weaviate client" optional = false python-versions = ">=3.8" files = [ - {file = "weaviate-client-3.22.1.tar.gz", hash = "sha256:aff61bd3f5d74df20a62328443e3aa9c860d5330fdfb19c4d8ddc44cb604032f"}, - {file = "weaviate_client-3.22.1-py3-none-any.whl", hash = "sha256:01843a4899a227300e570409e77628e9d1b28476313f94943c37aee3f75112e1"}, + {file = "weaviate-client-3.23.0.tar.gz", hash = "sha256:3ffd7f1460c9e32755d84d4f5fc63dfc0bd990dbe2c3dc20d5c68119d467680e"}, + {file = "weaviate_client-3.23.0-py3-none-any.whl", hash = "sha256:3d3bb75c1d96b2b71e213c5eb885ae3e3f42e4304955383c467d100187d9ff8e"}, ] [package.dependencies] @@ -3581,13 +3581,13 @@ grpc = ["grpcio", "grpcio-tools"] [[package]] name = "wheel" -version = "0.41.1" +version = "0.41.2" description = "A built-package format for Python" optional = false python-versions = ">=3.7" files = [ - {file = "wheel-0.41.1-py3-none-any.whl", hash = "sha256:473219bd4cbedc62cea0cb309089b593e47c15c4a2531015f94e4e3b9a0f6981"}, - {file = "wheel-0.41.1.tar.gz", hash = "sha256:12b911f083e876e10c595779709f8a88a59f45aacc646492a67fe9ef796c1b47"}, + {file = "wheel-0.41.2-py3-none-any.whl", hash = "sha256:75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8"}, + {file = "wheel-0.41.2.tar.gz", hash = "sha256:0c5ac5ff2afb79ac23ab82bab027a0be7b5dbcf2e54dc50efe4bf507de1f7985"}, ] [package.extras] @@ -3795,4 +3795,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "13258c777467d93ab73021225322da670e42513cedec6252a40aacf74822ea68" +content-hash = "788ca51ba313eac5f1dbcadfd7f91109b8b7a7734a1f16e10c8fb2e3b435a606" diff --git a/level_2/pyproject.toml b/level_2/pyproject.toml index c8b2c95ee..461255af9 100644 --- a/level_2/pyproject.toml +++ b/level_2/pyproject.toml @@ -39,6 +39,7 @@ dlt = { version ="^0.3.8", extras = ["duckdb"]} weaviate-client = "^3.22.1" python-multipart = "^0.0.6" deep-translator = "^1.11.4" +humanize = "^4.8.0"