Feat: Adding Mem0 Integration (#4339)

* feat(frontend): adding Mem0 Icon

* feat(dependencies): adding and setting Mem0 dependency

* feat(frontend): adding Mem0 Icon

* feat: adding Mem0 components

* feat(dependencies): adding and setting Mem0 dependency

* Update uv.lock

update uv for memo

* update and delete mem0 removed

update and delete mem0 removed as per suggestion

* update requirement

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
João 2024-11-11 12:15:09 -03:00 committed by GitHub
commit 5a6c556e36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1222 additions and 1496 deletions

View file

@ -115,6 +115,7 @@ dependencies = [
"langchain-ollama>=0.2.0",
"sqlalchemy[aiosqlite,postgresql_psycopg2binary,postgresql_psycopgbinary]>=2.0.36",
"atlassian-python-api>=3.41.16",
"mem0ai>=0.1.26",
]
[project.urls]

View file

@ -0,0 +1,144 @@
import logging
import os
from mem0 import Memory, MemoryClient
from langflow.base.memory.model import LCChatMemoryComponent
from langflow.inputs import (
DictInput,
HandleInput,
MessageTextInput,
NestedDictInput,
SecretStrInput,
)
from langflow.io import Output
from langflow.schema import Data
logger = logging.getLogger(__name__)
class Mem0MemoryComponent(LCChatMemoryComponent):
display_name = "Mem0 Chat Memory"
description = "Retrieves and stores chat messages using Mem0 memory storage."
name = "mem0_chat_memory"
icon: str = "Mem0"
inputs = [
NestedDictInput(
name="mem0_config",
display_name="Mem0 Configuration",
info="""Configuration dictionary for initializing Mem0 memory instance.
Example:
{
"graph_store": {
"provider": "neo4j",
"config": {
"url": "neo4j+s://your-neo4j-url",
"username": "neo4j",
"password": "your-password"
}
},
"version": "v1.1"
}""",
input_types=["Data"],
),
MessageTextInput(
name="ingest_message",
display_name="Message to Ingest",
info="The message content to be ingested into Mem0 memory.",
),
HandleInput(
name="existing_memory",
display_name="Existing Memory Instance",
input_types=["Memory"],
info="Optional existing Mem0 memory instance. If not provided, a new instance will be created.",
),
MessageTextInput(
name="user_id", display_name="User ID", info="Identifier for the user associated with the messages."
),
MessageTextInput(
name="search_query", display_name="Search Query", info="Input text for searching related memories in Mem0."
),
SecretStrInput(
name="mem0_api_key",
display_name="Mem0 API Key",
info="API key for Mem0 platform. Leave empty to use the local version.",
),
DictInput(
name="metadata",
display_name="Metadata",
info="Additional metadata to associate with the ingested message.",
advanced=True,
),
SecretStrInput(
name="openai_api_key",
display_name="OpenAI API Key",
required=False,
info="API key for OpenAI. Required if using OpenAI Embeddings without a provided configuration.",
),
]
outputs = [
Output(name="memory", display_name="Mem0 Memory", method="ingest_data"),
Output(
name="search_results",
display_name="Search Results",
method="build_search_results",
),
]
def build_mem0(self) -> Memory:
"""Initializes a Mem0 memory instance based on provided configuration and API keys."""
if self.openai_api_key:
os.environ["OPENAI_API_KEY"] = self.openai_api_key
try:
if not self.mem0_api_key:
return Memory.from_config(config_dict=dict(self.mem0_config)) if self.mem0_config else Memory()
if self.mem0_config:
return MemoryClient.from_config(api_key=self.mem0_api_key, config_dict=dict(self.mem0_config))
return MemoryClient(api_key=self.mem0_api_key)
except ImportError as e:
msg = "Mem0 is not properly installed. Please install it with 'pip install -U mem0ai'."
raise ImportError(msg) from e
def ingest_data(self) -> Memory:
"""Ingests a new message into Mem0 memory and returns the updated memory instance."""
mem0_memory = self.existing_memory if self.existing_memory else self.build_mem0()
if not self.ingest_message or not self.user_id:
logger.warning("Missing 'ingest_message' or 'user_id'; cannot ingest data.")
return mem0_memory
metadata = self.metadata if self.metadata else {}
logger.info("Ingesting message for user_id: %s", self.user_id)
try:
mem0_memory.add(self.ingest_message, user_id=self.user_id, metadata=metadata)
except Exception:
logger.exception("Failed to add message to Mem0 memory.")
raise
return mem0_memory
def build_search_results(self) -> Data:
"""Searches the Mem0 memory for related messages based on the search query and returns the results."""
mem0_memory = self.ingest_data()
search_query = self.search_query
user_id = self.user_id
logger.info("Search query: %s", search_query)
try:
if search_query:
logger.info("Performing search with query.")
related_memories = mem0_memory.search(query=search_query, user_id=user_id)
else:
logger.info("Retrieving all memories for user_id: %s", user_id)
related_memories = mem0_memory.get_all(user_id=user_id)
except Exception:
logger.exception("Failed to retrieve related memories from Mem0.")
raise
logger.info("Related memories retrieved: %s", related_memories)
return related_memories

View file

@ -0,0 +1,36 @@
export default function SvgMem0(props) {
return (
<svg
width="126pt"
height="127pt"
viewBox="0 0 126 127"
preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<g
transform="translate(0.000000,127.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none"
>
<path d="M648 1248 c-26 -22 -29 -47 -8 -68 25 -25 42 -25 63 -2 22 24 21 45 -1 65 -22 20 -33 21 -54 5z" />
<path d="M440 1201 c-16 -4 -32 -21 -44 -45 -19 -38 -19 -39 3 -82 30 -64 27 -79 -23 -113 -66 -46 -75 -93 -27 -142 35 -34 68 -37 105 -8 45 35 50 63 21 120 -30 57 -25 75 29 108 45 28 60 71 42 116 -8 18 -18 35 -22 37 -19 11 -60 15 -84 9z" />
<path d="M807 1160 c-15 -12 -29 -36 -33 -55 -10 -57 -48 -74 -106 -50 -9 4 -33 1 -53 -5 -89 -29 -64 -164 30 -164 29 0 43 7 61 28 13 15 24 35 24 44 0 10 7 28 16 41 15 21 21 23 79 16 57 -6 65 -4 91 18 82 71 -24 194 -109 127z" />
<path d="M231 1104 c-38 -27 -22 -84 25 -84 29 0 46 23 42 56 -4 34 -37 48 -67 28z" />
<path d="M1032 1048 c-28 -28 -7 -78 33 -78 12 0 26 5 33 12 7 7 12 21 12 33 0 12 -5 26 -12 33 -7 7 -21 12 -33 12 -12 0 -26 -5 -33 -12z" />
<path d="M841 946 c-55 -31 -65 -93 -22 -137 35 -35 73 -38 116 -9 42 28 59 25 89 -12 50 -64 55 -68 94 -68 78 0 113 93 56 145 -32 30 -55 31 -113 5 -55 -25 -75 -19 -107 31 -13 22 -36 44 -50 49 -32 12 -34 12 -63 -4z" />
<path d="M119 921 c-51 -52 -33 -119 39 -141 65 -21 73 -35 66 -106 -6 -58 -5 -64 19 -88 36 -36 80 -35 118 3 32 33 36 58 14 100 -10 21 -26 31 -59 40 -57 14 -68 33 -60 108 6 54 4 60 -21 86 -37 36 -78 36 -116 -2z" />
<path d="M592 783 c-36 -7 -89 -65 -101 -109 -17 -64 8 -132 62 -164 43 -26 121 -26 164 0 86 52 88 189 3 251 -26 19 -89 30 -128 22z" />
<path d="M26 699 c-20 -30 -6 -63 28 -67 49 -6 74 38 40 72 -22 22 -50 20 -68 -5z" />
<path d="M928 704 c-31 -16 -51 -62 -42 -98 7 -29 48 -66 73 -66 9 0 27 -7 39 -16 22 -15 23 -21 17 -78 -6 -53 -4 -64 15 -89 46 -58 150 -21 150 53 0 36 -46 90 -77 90 -10 0 -29 7 -41 16 -20 14 -22 21 -16 82 4 49 2 72 -8 85 -20 26 -79 37 -110 21z" />
<path d="M1177 632 c-22 -24 -21 -45 1 -65 25 -23 48 -21 66 5 20 29 20 34 -4 58 -25 25 -42 25 -63 2z" />
<path d="M113 550 c-47 -19 -59 -102 -21 -137 36 -32 57 -35 105 -13 60 26 78 25 100 -6 37 -55 62 -74 93 -74 37 0 90 47 90 80 0 35 -27 76 -58 89 -26 11 -36 9 -81 -14 -60 -30 -77 -25 -110 30 -28 48 -70 64 -118 45z" />
<path d="M806 454 c-32 -33 -34 -74 -5 -120 26 -43 18 -68 -31 -99 -47 -29 -52 -37 -53 -80 -2 -70 77 -109 138 -69 35 23 41 65 15 117 -28 56 -24 75 25 108 48 33 67 71 53 111 -22 61 -96 78 -142 32z" />
<path d="M572 370 c-12 -11 -26 -38 -32 -60 -13 -47 -43 -67 -87 -55 -93 26 -160 -53 -110 -129 39 -59 131 -38 152 36 18 62 30 70 101 63 58 -7 64 -5 88 18 42 42 34 107 -15 132 -39 21 -71 19 -97 -5z" />
<path d="M190 297 c-45 -22 -34 -87 14 -87 45 0 62 52 28 83 -15 13 -22 14 -42 4z" />
<path d="M987 242 c-32 -35 -15 -82 28 -82 44 0 61 52 27 83 -24 22 -35 21 -55 -1z" />
<path d="M566 94 c-33 -32 -13 -74 36 -74 38 0 55 33 33 66 -18 28 -46 31 -69 8z" />
</g>
</svg>
);
}

View file

@ -0,0 +1,8 @@
import React, { forwardRef } from "react";
import SvgMem from "./SvgMem";
export const Mem0 = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>(
(props, ref) => {
return <SvgMem className="icon" ref={ref} {...props} />;
},
);

View file

@ -238,6 +238,7 @@ import { IFixIcon } from "../icons/IFixIt";
import { LMStudioIcon } from "../icons/LMStudio";
import { LangChainIcon } from "../icons/LangChain";
import { MaritalkIcon } from "../icons/Maritalk";
import { Mem0 } from "../icons/Mem0";
import { MetaIcon } from "../icons/Meta";
import { MidjourneyIcon } from "../icons/Midjorney";
import { MongoDBIcon } from "../icons/MongoDB";
@ -826,4 +827,5 @@ export const nodeIconsLucide: iconsType = {
CircleCheckBig,
ZoomIn,
ZoomOut,
Mem0,
};

2527
uv.lock generated

File diff suppressed because it is too large Load diff