memorizz 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.3
2
+ Name: memorizz
3
+ Version: 0.0.1
4
+ Summary: A memory management library for Python
5
+ Project-URL: Homepage, https://github.com/RichmondAlake/memorizz
6
+ Project-URL: Bug Tracker, https://github.com/yourusername/memorizz/issues
7
+ Author-email: Richmond Alake <richmond.alake@gmail.com>
8
+ License-File: LICENCE.txt
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+
15
+ MemoRizz is a comprehensive library for AI-assisted tools and functionalities. It currently includes MongoDB tools for storing function definitions and performing customizable vector searches.
16
+
17
+ ## Installation
18
+
19
+ ```
20
+ pip install memorizz
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ MemoRizz can be used with either a custom configuration or the default settings. Here are examples of both approaches:
26
+
27
+ ### Using Custom Configuration
28
+
29
+ ```python
30
+ from memorizz.databases.mongodb import MongoDBTools, MongoDBToolsConfig, mongodb_toolbox
31
+
32
+ # Create a custom configuration
33
+ custom_config = MongoDBToolsConfig(
34
+ mongo_uri="mongodb://custom-uri:27017",
35
+ db_name="my_custom_db",
36
+ collection_name="my_custom_tools",
37
+ embedding_model="text-embedding-ada-002",
38
+ vector_search_candidates=200,
39
+ vector_index_name="my_custom_index"
40
+ )
41
+
42
+ # Initialize MongoDBTools with custom configuration
43
+ custom_mongo_tools = MongoDBTools(custom_config)
44
+
45
+ # Use the custom mongodb_toolbox decorator
46
+ @custom_mongo_tools.mongodb_toolbox()
47
+ def custom_function(param1: str, param2: int) -> str:
48
+ """
49
+ This is a custom function using a custom configuration.
50
+ """
51
+ return f"Custom processed {param1} with {param2}"
52
+
53
+ # Use the custom tools
54
+ user_query = "How do I process something custom?"
55
+ custom_tools = custom_mongo_tools.populate_tools(user_query, num_tools=3)
56
+
57
+ print("Custom tools:", custom_tools)
58
+ ```
59
+
60
+ ### Using Default Configuration
61
+
62
+ ```python
63
+ from memorizz.databases.mongodb import mongodb_toolbox, MongoDBTools
64
+
65
+ # Use the default mongodb_toolbox decorator
66
+ @mongodb_toolbox()
67
+ def default_function(param1: str, param2: int) -> str:
68
+ """
69
+ This is a default function using the default configuration.
70
+ """
71
+ return f"Default processed {param1} with {param2}"
72
+
73
+ # Use the default tools
74
+ default_mongo_tools = MongoDBTools() # This uses the default configuration
75
+ user_query = "How do I process something with default settings?"
76
+ default_tools = default_mongo_tools.populate_tools(user_query, num_tools=2)
77
+
78
+ print("Default tools:", default_tools)
79
+ ```
80
+
81
+ In both cases, the `mongodb_toolbox` decorator is used to register functions, and the `populate_tools` method is used to retrieve relevant tools based on a user query. The main difference is in the setup and configuration.
82
+
83
+ The custom configuration approach allows you to specify your own MongoDB URI, database name, collection name, and other settings. This is useful when you need to connect to a specific MongoDB instance or customize the behavior of the tools.
84
+
85
+ The default configuration approach is simpler and requires less setup. It's suitable for quick starts or when the default settings meet your needs.
86
+
87
+ Choose the approach that best fits your project requirements and structure.
88
+
89
+ ## Features
90
+
91
+ - MongoDB Tools:
92
+ - Automatic tool registration with MongoDB
93
+ - Vector search based on user queries
94
+ - Customizable number of tools returned
95
+ - Configurable embedding model and search parameters
96
+ - Error handling and logging
97
+ - Extensible structure for future database support
98
+
99
+
100
+ ## Feature Roadmap
101
+
102
+ - [x] Implement basic MongoDB tools functionality
103
+ - [x] Add customizable vector search
104
+ - [x] Implement error handling and logging
105
+ - [x] Create PyPI package
106
+ - [x] Restructure package for extensibility to other databases
107
+ - [ ] Add support for multiple embedding models to make MongoDBToolsConfig embedding model agnostic
108
+ - [ ] Implement MemScore logic for improved tool ranking and memory component retrival
109
+ - [ ] Add async support for improved performance
110
+ - [ ] Implement caching mechanism for embeddings and search results
111
+ - [ ] Create comprehensive API documentation
112
+ - [ ] Implement automated testing suite with high coverage
113
+ - [ ] Create example projects and use cases
114
+ - [ ] Add support for additional databases (e.g., PostgreSQL, Redis)
115
+
116
+ ## License
117
+
118
+ This project is licensed under the MIT License.
@@ -0,0 +1,104 @@
1
+ MemoRizz is a comprehensive library for AI-assisted tools and functionalities. It currently includes MongoDB tools for storing function definitions and performing customizable vector searches.
2
+
3
+ ## Installation
4
+
5
+ ```
6
+ pip install memorizz
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ MemoRizz can be used with either a custom configuration or the default settings. Here are examples of both approaches:
12
+
13
+ ### Using Custom Configuration
14
+
15
+ ```python
16
+ from memorizz.databases.mongodb import MongoDBTools, MongoDBToolsConfig, mongodb_toolbox
17
+
18
+ # Create a custom configuration
19
+ custom_config = MongoDBToolsConfig(
20
+ mongo_uri="mongodb://custom-uri:27017",
21
+ db_name="my_custom_db",
22
+ collection_name="my_custom_tools",
23
+ embedding_model="text-embedding-ada-002",
24
+ vector_search_candidates=200,
25
+ vector_index_name="my_custom_index"
26
+ )
27
+
28
+ # Initialize MongoDBTools with custom configuration
29
+ custom_mongo_tools = MongoDBTools(custom_config)
30
+
31
+ # Use the custom mongodb_toolbox decorator
32
+ @custom_mongo_tools.mongodb_toolbox()
33
+ def custom_function(param1: str, param2: int) -> str:
34
+ """
35
+ This is a custom function using a custom configuration.
36
+ """
37
+ return f"Custom processed {param1} with {param2}"
38
+
39
+ # Use the custom tools
40
+ user_query = "How do I process something custom?"
41
+ custom_tools = custom_mongo_tools.populate_tools(user_query, num_tools=3)
42
+
43
+ print("Custom tools:", custom_tools)
44
+ ```
45
+
46
+ ### Using Default Configuration
47
+
48
+ ```python
49
+ from memorizz.databases.mongodb import mongodb_toolbox, MongoDBTools
50
+
51
+ # Use the default mongodb_toolbox decorator
52
+ @mongodb_toolbox()
53
+ def default_function(param1: str, param2: int) -> str:
54
+ """
55
+ This is a default function using the default configuration.
56
+ """
57
+ return f"Default processed {param1} with {param2}"
58
+
59
+ # Use the default tools
60
+ default_mongo_tools = MongoDBTools() # This uses the default configuration
61
+ user_query = "How do I process something with default settings?"
62
+ default_tools = default_mongo_tools.populate_tools(user_query, num_tools=2)
63
+
64
+ print("Default tools:", default_tools)
65
+ ```
66
+
67
+ In both cases, the `mongodb_toolbox` decorator is used to register functions, and the `populate_tools` method is used to retrieve relevant tools based on a user query. The main difference is in the setup and configuration.
68
+
69
+ The custom configuration approach allows you to specify your own MongoDB URI, database name, collection name, and other settings. This is useful when you need to connect to a specific MongoDB instance or customize the behavior of the tools.
70
+
71
+ The default configuration approach is simpler and requires less setup. It's suitable for quick starts or when the default settings meet your needs.
72
+
73
+ Choose the approach that best fits your project requirements and structure.
74
+
75
+ ## Features
76
+
77
+ - MongoDB Tools:
78
+ - Automatic tool registration with MongoDB
79
+ - Vector search based on user queries
80
+ - Customizable number of tools returned
81
+ - Configurable embedding model and search parameters
82
+ - Error handling and logging
83
+ - Extensible structure for future database support
84
+
85
+
86
+ ## Feature Roadmap
87
+
88
+ - [x] Implement basic MongoDB tools functionality
89
+ - [x] Add customizable vector search
90
+ - [x] Implement error handling and logging
91
+ - [x] Create PyPI package
92
+ - [x] Restructure package for extensibility to other databases
93
+ - [ ] Add support for multiple embedding models to make MongoDBToolsConfig embedding model agnostic
94
+ - [ ] Implement MemScore logic for improved tool ranking and memory component retrival
95
+ - [ ] Add async support for improved performance
96
+ - [ ] Implement caching mechanism for embeddings and search results
97
+ - [ ] Create comprehensive API documentation
98
+ - [ ] Implement automated testing suite with high coverage
99
+ - [ ] Create example projects and use cases
100
+ - [ ] Add support for additional databases (e.g., PostgreSQL, Redis)
101
+
102
+ ## License
103
+
104
+ This project is licensed under the MIT License.
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "memorizz"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Richmond Alake", email="richmond.alake@gmail.com" },
10
+ ]
11
+ description = "A memory management library for Python"
12
+ readme = "README.md"
13
+ requires-python = ">=3.7"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+
20
+ [tool.setuptools]
21
+ package-dir = {"" = "src"}
22
+
23
+ [project.urls]
24
+ "Homepage" = "https://github.com/RichmondAlake/memorizz"
25
+ "Bug Tracker" = "https://github.com/yourusername/memorizz/issues"
@@ -0,0 +1,6 @@
1
+ print("Starting memorizz __init__.py")
2
+ from .database.mongodb import MongoDBTools, MongoDBToolsConfig, get_embedding, get_mongodb_toolbox
3
+ print("Finished importing from mongodb in memorizz __init__.py")
4
+
5
+ __all__ = ['MongoDBTools', 'MongoDBToolsConfig', 'get_embedding', 'get_mongodb_toolbox']
6
+ print("Exiting memorizz __init__.py")
@@ -0,0 +1,5 @@
1
+ print("Entering database __init__.py")
2
+ from .mongodb import MongoDBTools, MongoDBToolsConfig, get_embedding, get_mongodb_toolbox
3
+
4
+ __all__ = ['MongoDBTools', 'MongoDBToolsConfig', 'get_embedding', 'get_mongodb_toolbox']
5
+ print("Exiting database __init__.py")
@@ -0,0 +1,5 @@
1
+ print("Entering mongodb __init__.py")
2
+ from .mongodb_tools import MongoDBTools, MongoDBToolsConfig, get_embedding, get_mongodb_toolbox
3
+
4
+ __all__ = ['MongoDBTools', 'MongoDBToolsConfig', 'get_embedding', 'get_mongodb_toolbox']
5
+ print("Exiting mongodb __init__.py")
@@ -0,0 +1,166 @@
1
+ import os
2
+ import json
3
+ import getpass
4
+ import inspect
5
+ from functools import wraps
6
+ from typing import get_type_hints, List, Dict, Any, Optional
7
+ import openai
8
+ import pymongo
9
+ import logging
10
+ from dataclasses import dataclass
11
+
12
+ logging.basicConfig(level=logging.INFO)
13
+ logger = logging.getLogger(__name__)
14
+
15
+ @dataclass
16
+ class MongoDBToolsConfig:
17
+ mongo_uri: Optional[str] = None
18
+ db_name: str = 'function_calling_db'
19
+ collection_name: str = 'tools'
20
+ embedding_model: str = "text-embedding-3-small"
21
+ vector_search_candidates: int = 150
22
+ vector_index_name: str = "vector_index"
23
+
24
+ def get_embedding(text: str, model: str = "text-embedding-3-small") -> List[float]:
25
+ text = text.replace("\n", " ")
26
+ try:
27
+ return openai.OpenAI().embeddings.create(input=[text], model=model).data[0].embedding
28
+ except Exception as e:
29
+ logger.error(f"Error generating embedding: {str(e)}")
30
+ raise
31
+
32
+ class MongoDBTools:
33
+ def __init__(self, config: MongoDBToolsConfig = MongoDBToolsConfig()):
34
+ self.config = config
35
+ if self.config.mongo_uri is None:
36
+ self.config.mongo_uri = os.getenv('MONGO_URI') or getpass.getpass("Enter MongoDB URI: ")
37
+ try:
38
+ self.mongo_client = pymongo.MongoClient(self.config.mongo_uri)
39
+ self.db = self.mongo_client[self.config.db_name]
40
+ self.tools_collection = self.db[self.config.collection_name]
41
+ except Exception as e:
42
+ logger.error(f"Error connecting to MongoDB: {str(e)}")
43
+ raise
44
+
45
+ def mongodb_toolbox(self, collection: Optional[pymongo.collection.Collection] = None):
46
+ if collection is None:
47
+ collection = self.tools_collection
48
+
49
+ def decorator(func):
50
+ @wraps(func)
51
+ def wrapper(*args, **kwargs):
52
+ return func(*args, **kwargs)
53
+
54
+ signature = inspect.signature(func)
55
+ docstring = inspect.getdoc(func) or ""
56
+
57
+ if not docstring:
58
+ raise ValueError(f"Error registering tool {func.__name__}: Docstring is missing. Please provide a docstring for the function.")
59
+
60
+ type_hints = get_type_hints(func)
61
+
62
+ tool_def = {
63
+ "name": func.__name__,
64
+ "description": docstring.strip(),
65
+ "parameters": {
66
+ "type": "object",
67
+ "properties": {},
68
+ "required": []
69
+ }
70
+ }
71
+
72
+ for param_name, param in signature.parameters.items():
73
+ if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD):
74
+ continue
75
+
76
+ param_type = type_hints.get(param_name, type(None))
77
+ json_type = "string"
78
+ if param_type in (int, float):
79
+ json_type = "number"
80
+ elif param_type == bool:
81
+ json_type = "boolean"
82
+
83
+ tool_def["parameters"]["properties"][param_name] = {
84
+ "type": json_type,
85
+ "description": f"Parameter {param_name}"
86
+ }
87
+
88
+ if param.default == inspect.Parameter.empty:
89
+ tool_def["parameters"]["required"].append(param_name)
90
+
91
+ tool_def["parameters"]["additionalProperties"] = False
92
+
93
+ try:
94
+ vector = get_embedding(tool_def["description"], self.config.embedding_model)
95
+ tool_doc = {
96
+ **tool_def,
97
+ "embedding": vector
98
+ }
99
+ collection.update_one({"name": func.__name__}, {"$set": tool_doc}, upsert=True)
100
+ logger.info(f"Successfully registered tool: {func.__name__}")
101
+ except Exception as e:
102
+ logger.error(f"Error registering tool {func.__name__}: {str(e)}")
103
+ raise
104
+
105
+ return wrapper
106
+ return decorator
107
+
108
+ def _vector_search(self, user_query: str, collection: Optional[pymongo.collection.Collection] = None, limit: int = 2) -> List[Dict[str, Any]]:
109
+ if collection is None:
110
+ collection = self.tools_collection
111
+
112
+ try:
113
+ query_embedding = get_embedding(user_query, self.config.embedding_model)
114
+ except Exception as e:
115
+ logger.error(f"Error generating embedding for query: {str(e)}")
116
+ raise
117
+
118
+ vector_search_stage = {
119
+ "$vectorSearch": {
120
+ "index": self.config.vector_index_name,
121
+ "queryVector": query_embedding,
122
+ "path": "embedding",
123
+ "numCandidates": self.config.vector_search_candidates,
124
+ "limit": limit
125
+ }
126
+ }
127
+
128
+ unset_stage = {
129
+ "$unset": "embedding"
130
+ }
131
+
132
+ pipeline = [vector_search_stage, unset_stage]
133
+
134
+ try:
135
+ results = collection.aggregate(pipeline)
136
+ return list(results)
137
+ except Exception as e:
138
+ logger.error(f"Error performing vector search: {str(e)}")
139
+ raise
140
+
141
+ def populate_tools(self, user_query: str, num_tools: int = 2) -> List[Dict[str, Any]]:
142
+ try:
143
+ search_results = self._vector_search(user_query, limit=num_tools)
144
+ tools = []
145
+ for result in search_results:
146
+ print(result)
147
+ tool = {
148
+ "type": "function",
149
+ "function": {
150
+ "name": result["name"],
151
+ "description": result["description"],
152
+ "parameters": result["parameters"]
153
+ }
154
+ }
155
+ tools.append(tool)
156
+ logger.info(f"Successfully populated {len(tools)} tools")
157
+ return tools
158
+ except Exception as e:
159
+ logger.error(f"Error populating tools: {str(e)}")
160
+ raise
161
+
162
+ __all__ = ['MongoDBTools', 'MongoDBToolsConfig', 'get_embedding']
163
+
164
+ # You can create a function to get the mongodb_toolbox decorator:
165
+ def get_mongodb_toolbox(config: MongoDBToolsConfig = MongoDBToolsConfig()):
166
+ return MongoDBTools(config).mongodb_toolbox
@@ -0,0 +1,265 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 17,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "from memorizz.database.mongodb import mongodb_tools, MongoDBToolsConfig, MongoDBTools, get_mongodb_toolbox"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": 25,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import os\n",
19
+ "import getpass\n",
20
+ "\n",
21
+ "OPENAI_API_KEY = getpass.getpass(\"OpenAI API Key: \")\n",
22
+ "os.environ[\"OPENAI_API_KEY\"] = OPENAI_API_KEY\n",
23
+ "\n",
24
+ "MONGO_URI = getpass.getpass(\"Enter MongoDB URI: \")\n",
25
+ "os.environ[\"MONGO_URI\"] = MONGO_URI\n",
26
+ "\n",
27
+ "GPT_MODEL = \"gpt-4o\""
28
+ ]
29
+ },
30
+ {
31
+ "cell_type": "code",
32
+ "execution_count": 26,
33
+ "metadata": {},
34
+ "outputs": [],
35
+ "source": [
36
+ "# Option 1: Create MongoDBTools instance and get the decorator\n",
37
+ "config = MongoDBToolsConfig(mongo_uri=MONGO_URI)\n",
38
+ "mongodb_tools = MongoDBTools(config)\n",
39
+ "# mongodb_toolbox = mongodb_tools.mongodb_toolbox"
40
+ ]
41
+ },
42
+ {
43
+ "cell_type": "code",
44
+ "execution_count": 27,
45
+ "metadata": {},
46
+ "outputs": [],
47
+ "source": [
48
+ "# Option 2: Use the get_mongodb_toolbox function\n",
49
+ "mongodb_toolbox = get_mongodb_toolbox(config)"
50
+ ]
51
+ },
52
+ {
53
+ "cell_type": "code",
54
+ "execution_count": 40,
55
+ "metadata": {},
56
+ "outputs": [
57
+ {
58
+ "name": "stderr",
59
+ "output_type": "stream",
60
+ "text": [
61
+ "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 400 Bad Request\"\n",
62
+ "ERROR:memorizz.database.mongodb.mongodb_tools:Error generating embedding: Error code: 400 - {'error': {'message': \"'$.input' is invalid. Please check the API reference: https://platform.openai.com/docs/api-reference.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}\n",
63
+ "ERROR:memorizz.database.mongodb.mongodb_tools:Error registering tool shout: Error code: 400 - {'error': {'message': \"'$.input' is invalid. Please check the API reference: https://platform.openai.com/docs/api-reference.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}\n"
64
+ ]
65
+ },
66
+ {
67
+ "ename": "BadRequestError",
68
+ "evalue": "Error code: 400 - {'error': {'message': \"'$.input' is invalid. Please check the API reference: https://platform.openai.com/docs/api-reference.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}",
69
+ "output_type": "error",
70
+ "traceback": [
71
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
72
+ "\u001b[0;31mBadRequestError\u001b[0m Traceback (most recent call last)",
73
+ "Cell \u001b[0;32mIn[40], line 5\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mrandom\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mdatetime\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m datetime\n\u001b[1;32m 4\u001b[0m \u001b[38;5;129;43m@mongodb_toolbox\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m----> 5\u001b[0m \u001b[38;5;28;43;01mdef\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;21;43mshout\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m>\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m:\u001b[49m\n\u001b[1;32m 6\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mreturn\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mstatement\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mupper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;129m@mongodb_toolbox\u001b[39m()\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_weather\u001b[39m(location: \u001b[38;5;28mstr\u001b[39m, unit: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcelsius\u001b[39m\u001b[38;5;124m\"\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n",
74
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/memorizz/database/mongodb/mongodb_tools.py:90\u001b[0m, in \u001b[0;36mMongoDBTools.mongodb_toolbox.<locals>.decorator\u001b[0;34m(func)\u001b[0m\n\u001b[1;32m 87\u001b[0m tool_def[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparameters\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124madditionalProperties\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 90\u001b[0m vector \u001b[38;5;241m=\u001b[39m \u001b[43mget_embedding\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtool_def\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mdescription\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43membedding_model\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 91\u001b[0m tool_doc \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 92\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mtool_def,\n\u001b[1;32m 93\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124membedding\u001b[39m\u001b[38;5;124m\"\u001b[39m: vector\n\u001b[1;32m 94\u001b[0m }\n\u001b[1;32m 95\u001b[0m collection\u001b[38;5;241m.\u001b[39mupdate_one({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m: func\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m}, {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m$set\u001b[39m\u001b[38;5;124m\"\u001b[39m: tool_doc}, upsert\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m)\n",
75
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/memorizz/database/mongodb/mongodb_tools.py:27\u001b[0m, in \u001b[0;36mget_embedding\u001b[0;34m(text, model)\u001b[0m\n\u001b[1;32m 25\u001b[0m text \u001b[38;5;241m=\u001b[39m text\u001b[38;5;241m.\u001b[39mreplace(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 27\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mopenai\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mOpenAI\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43membeddings\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcreate\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mtext\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmodel\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mdata[\u001b[38;5;241m0\u001b[39m]\u001b[38;5;241m.\u001b[39membedding\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 29\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mError generating embedding: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mstr\u001b[39m(e)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n",
76
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/openai/resources/embeddings.py:114\u001b[0m, in \u001b[0;36mEmbeddings.create\u001b[0;34m(self, input, model, dimensions, encoding_format, user, extra_headers, extra_query, extra_body, timeout)\u001b[0m\n\u001b[1;32m 108\u001b[0m embedding\u001b[38;5;241m.\u001b[39membedding \u001b[38;5;241m=\u001b[39m np\u001b[38;5;241m.\u001b[39mfrombuffer( \u001b[38;5;66;03m# type: ignore[no-untyped-call]\u001b[39;00m\n\u001b[1;32m 109\u001b[0m base64\u001b[38;5;241m.\u001b[39mb64decode(data), dtype\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfloat32\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 110\u001b[0m )\u001b[38;5;241m.\u001b[39mtolist()\n\u001b[1;32m 112\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m obj\n\u001b[0;32m--> 114\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_post\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 115\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m/embeddings\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 116\u001b[0m \u001b[43m \u001b[49m\u001b[43mbody\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmaybe_transform\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43membedding_create_params\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mEmbeddingCreateParams\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 117\u001b[0m \u001b[43m \u001b[49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_request_options\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 118\u001b[0m \u001b[43m \u001b[49m\u001b[43mextra_headers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mextra_headers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 119\u001b[0m \u001b[43m \u001b[49m\u001b[43mextra_query\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mextra_query\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 120\u001b[0m \u001b[43m \u001b[49m\u001b[43mextra_body\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mextra_body\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 121\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 122\u001b[0m \u001b[43m \u001b[49m\u001b[43mpost_parser\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparser\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 123\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 124\u001b[0m \u001b[43m \u001b[49m\u001b[43mcast_to\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mCreateEmbeddingResponse\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 125\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n",
77
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/openai/_base_client.py:1260\u001b[0m, in \u001b[0;36mSyncAPIClient.post\u001b[0;34m(self, path, cast_to, body, options, files, stream, stream_cls)\u001b[0m\n\u001b[1;32m 1246\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpost\u001b[39m(\n\u001b[1;32m 1247\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 1248\u001b[0m path: \u001b[38;5;28mstr\u001b[39m,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1255\u001b[0m stream_cls: \u001b[38;5;28mtype\u001b[39m[_StreamT] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 1256\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseT \u001b[38;5;241m|\u001b[39m _StreamT:\n\u001b[1;32m 1257\u001b[0m opts \u001b[38;5;241m=\u001b[39m FinalRequestOptions\u001b[38;5;241m.\u001b[39mconstruct(\n\u001b[1;32m 1258\u001b[0m method\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mpost\u001b[39m\u001b[38;5;124m\"\u001b[39m, url\u001b[38;5;241m=\u001b[39mpath, json_data\u001b[38;5;241m=\u001b[39mbody, files\u001b[38;5;241m=\u001b[39mto_httpx_files(files), \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39moptions\n\u001b[1;32m 1259\u001b[0m )\n\u001b[0;32m-> 1260\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m cast(ResponseT, \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcast_to\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mopts\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstream_cls\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream_cls\u001b[49m\u001b[43m)\u001b[49m)\n",
78
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/openai/_base_client.py:937\u001b[0m, in \u001b[0;36mSyncAPIClient.request\u001b[0;34m(self, cast_to, options, remaining_retries, stream, stream_cls)\u001b[0m\n\u001b[1;32m 928\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mrequest\u001b[39m(\n\u001b[1;32m 929\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[1;32m 930\u001b[0m cast_to: Type[ResponseT],\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 935\u001b[0m stream_cls: \u001b[38;5;28mtype\u001b[39m[_StreamT] \u001b[38;5;241m|\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[1;32m 936\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m ResponseT \u001b[38;5;241m|\u001b[39m _StreamT:\n\u001b[0;32m--> 937\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 938\u001b[0m \u001b[43m \u001b[49m\u001b[43mcast_to\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcast_to\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 939\u001b[0m \u001b[43m \u001b[49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 940\u001b[0m \u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 941\u001b[0m \u001b[43m \u001b[49m\u001b[43mstream_cls\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream_cls\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 942\u001b[0m \u001b[43m \u001b[49m\u001b[43mremaining_retries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mremaining_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 943\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
79
+ "File \u001b[0;32m~/miniconda3/envs/memorizz/lib/python3.9/site-packages/openai/_base_client.py:1041\u001b[0m, in \u001b[0;36mSyncAPIClient._request\u001b[0;34m(self, cast_to, options, remaining_retries, stream, stream_cls)\u001b[0m\n\u001b[1;32m 1038\u001b[0m err\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mread()\n\u001b[1;32m 1040\u001b[0m log\u001b[38;5;241m.\u001b[39mdebug(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mRe-raising status error\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m-> 1041\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_make_status_error_from_response(err\u001b[38;5;241m.\u001b[39mresponse) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 1043\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_process_response(\n\u001b[1;32m 1044\u001b[0m cast_to\u001b[38;5;241m=\u001b[39mcast_to,\n\u001b[1;32m 1045\u001b[0m options\u001b[38;5;241m=\u001b[39moptions,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1049\u001b[0m retries_taken\u001b[38;5;241m=\u001b[39moptions\u001b[38;5;241m.\u001b[39mget_max_retries(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmax_retries) \u001b[38;5;241m-\u001b[39m retries,\n\u001b[1;32m 1050\u001b[0m )\n",
80
+ "\u001b[0;31mBadRequestError\u001b[0m: Error code: 400 - {'error': {'message': \"'$.input' is invalid. Please check the API reference: https://platform.openai.com/docs/api-reference.\", 'type': 'invalid_request_error', 'param': None, 'code': None}}"
81
+ ]
82
+ }
83
+ ],
84
+ "source": [
85
+ "import random\n",
86
+ "from datetime import datetime\n",
87
+ "\n",
88
+ "@mongodb_toolbox()\n",
89
+ "def shout(statement: str) -> str:\n",
90
+ " \"\"\"\n",
91
+ " Convert a statement to uppercase letters to emulate shouting. Use this when a user wants to emphasize something strongly or when they explicitly ask to 'shout' something..\n",
92
+ "\n",
93
+ " \"\"\"\n",
94
+ " return statement.upper()\n",
95
+ "\n",
96
+ "@mongodb_toolbox()\n",
97
+ "def get_weather(location: str, unit: str = \"celsius\") -> str:\n",
98
+ " \"\"\"\n",
99
+ " Get the current weather for a specified location.\n",
100
+ " Use this when a user asks about the weather in a specific place.\n",
101
+ "\n",
102
+ " :param location: The name of the city or location to get weather for.\n",
103
+ " :param unit: The temperature unit, either 'celsius' or 'fahrenheit'. Defaults to 'celsius'.\n",
104
+ " :return: A string describing the current weather.\n",
105
+ " \"\"\"\n",
106
+ " conditions = [\"sunny\", \"cloudy\", \"rainy\", \"snowy\"]\n",
107
+ " temperature = random.randint(-10, 35)\n",
108
+ "\n",
109
+ " if unit.lower() == \"fahrenheit\":\n",
110
+ " temperature = (temperature * 9/5) + 32\n",
111
+ "\n",
112
+ " condition = random.choice(conditions)\n",
113
+ " return f\"The weather in {location} is currently {condition} with a temperature of {temperature}°{'C' if unit.lower() == 'celsius' else 'F'}.\"\n",
114
+ "\n",
115
+ "@mongodb_toolbox()\n",
116
+ "def get_stock_price(symbol: str) -> str:\n",
117
+ " \"\"\"\n",
118
+ " Get the current stock price for a given stock symbol.\n",
119
+ " Use this when a user asks about the current price of a specific stock.\n",
120
+ "\n",
121
+ " :param symbol: The stock symbol to look up (e.g., 'AAPL' for Apple Inc.).\n",
122
+ " :return: A string with the current stock price.\n",
123
+ " \"\"\"\n",
124
+ " price = round(random.uniform(10, 1000), 2)\n",
125
+ " return f\"The current stock price of {symbol} is ${price}.\"\n",
126
+ "\n",
127
+ "@mongodb_toolbox()\n",
128
+ "def get_current_time(timezone: str = \"UTC\") -> str:\n",
129
+ " \"\"\"\n",
130
+ " Get the current time for a specified timezone.\n",
131
+ " Use this when a user asks about the current time in a specific timezone.\n",
132
+ "\n",
133
+ " :param timezone: The timezone to get the current time for. Defaults to 'UTC'.\n",
134
+ " :return: A string with the current time in the specified timezone.\n",
135
+ " \"\"\"\n",
136
+ " current_time = datetime.utcnow().strftime(\"%H:%M:%S\")\n",
137
+ " return f\"The current time in {timezone} is {current_time}.\"\n"
138
+ ]
139
+ },
140
+ {
141
+ "cell_type": "code",
142
+ "execution_count": 29,
143
+ "metadata": {},
144
+ "outputs": [],
145
+ "source": [
146
+ "def populate_tools(search_results):\n",
147
+ " \"\"\"\n",
148
+ " Populate the tools array based on the results from the vector search.\n",
149
+ "\n",
150
+ " Args:\n",
151
+ " search_results (list): The list of documents returned from the vector search.\n",
152
+ "\n",
153
+ " Returns:\n",
154
+ " list: A list of tool definitions in the format required by the OpenAI API.\n",
155
+ " \"\"\"\n",
156
+ " tools = []\n",
157
+ " for result in search_results:\n",
158
+ " tool = {\n",
159
+ " \"type\": \"function\",\n",
160
+ " \"function\": {\n",
161
+ " \"name\": result[\"name\"],\n",
162
+ " \"description\": result[\"description\"],\n",
163
+ " \"parameters\": result[\"parameters\"]\n",
164
+ " }\n",
165
+ " }\n",
166
+ " tools.append(tool)\n",
167
+ " return tools"
168
+ ]
169
+ },
170
+ {
171
+ "cell_type": "code",
172
+ "execution_count": 31,
173
+ "metadata": {},
174
+ "outputs": [],
175
+ "source": [
176
+ "user_query = \"Hi, can you shout the statement: We are there\""
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": 37,
182
+ "metadata": {},
183
+ "outputs": [
184
+ {
185
+ "name": "stderr",
186
+ "output_type": "stream",
187
+ "text": [
188
+ "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/embeddings \"HTTP/1.1 200 OK\"\n",
189
+ "INFO:memorizz.database.mongodb.mongodb_tools:Successfully populated 2 tools\n"
190
+ ]
191
+ }
192
+ ],
193
+ "source": [
194
+ "tools = mongodb_tools.populate_tools(user_query)"
195
+ ]
196
+ },
197
+ {
198
+ "cell_type": "code",
199
+ "execution_count": 38,
200
+ "metadata": {},
201
+ "outputs": [
202
+ {
203
+ "name": "stdout",
204
+ "output_type": "stream",
205
+ "text": [
206
+ "[{'function': {'description': 'Convert a statement to uppercase letters to '\n",
207
+ " 'emulate shouting. Use this when a user wants to '\n",
208
+ " 'emphasize something strongly or when they '\n",
209
+ " \"explicitly ask to 'shout' something..\",\n",
210
+ " 'name': 'shout',\n",
211
+ " 'parameters': {'additionalProperties': False,\n",
212
+ " 'properties': {'statement': {'description': 'Parameter '\n",
213
+ " 'statement',\n",
214
+ " 'type': 'string'}},\n",
215
+ " 'required': ['statement'],\n",
216
+ " 'type': 'object'}},\n",
217
+ " 'type': 'function'},\n",
218
+ " {'function': {'description': 'Get the current stock price for a given stock '\n",
219
+ " 'symbol.\\n'\n",
220
+ " 'Use this when a user asks about the current '\n",
221
+ " 'price of a specific stock.\\n'\n",
222
+ " '\\n'\n",
223
+ " ':param symbol: The stock symbol to look up '\n",
224
+ " \"(e.g., 'AAPL' for Apple Inc.).\\n\"\n",
225
+ " ':return: A string with the current stock price.',\n",
226
+ " 'name': 'get_stock_price',\n",
227
+ " 'parameters': {'additionalProperties': False,\n",
228
+ " 'properties': {'symbol': {'description': 'Parameter '\n",
229
+ " 'symbol',\n",
230
+ " 'type': 'string'}},\n",
231
+ " 'required': ['symbol'],\n",
232
+ " 'type': 'object'}},\n",
233
+ " 'type': 'function'}]\n"
234
+ ]
235
+ }
236
+ ],
237
+ "source": [
238
+ "import pprint\n",
239
+ "\n",
240
+ "pprint.pprint(tools)"
241
+ ]
242
+ }
243
+ ],
244
+ "metadata": {
245
+ "kernelspec": {
246
+ "display_name": "memorizz",
247
+ "language": "python",
248
+ "name": "python3"
249
+ },
250
+ "language_info": {
251
+ "codemirror_mode": {
252
+ "name": "ipython",
253
+ "version": 3
254
+ },
255
+ "file_extension": ".py",
256
+ "mimetype": "text/x-python",
257
+ "name": "python",
258
+ "nbconvert_exporter": "python",
259
+ "pygments_lexer": "ipython3",
260
+ "version": "3.9.19"
261
+ }
262
+ },
263
+ "nbformat": 4,
264
+ "nbformat_minor": 2
265
+ }