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:
parent
76c91de563
commit
5a6c556e36
6 changed files with 1222 additions and 1496 deletions
|
|
@ -115,6 +115,7 @@ dependencies = [
|
||||||
"langchain-ollama>=0.2.0",
|
"langchain-ollama>=0.2.0",
|
||||||
"sqlalchemy[aiosqlite,postgresql_psycopg2binary,postgresql_psycopgbinary]>=2.0.36",
|
"sqlalchemy[aiosqlite,postgresql_psycopg2binary,postgresql_psycopgbinary]>=2.0.36",
|
||||||
"atlassian-python-api>=3.41.16",
|
"atlassian-python-api>=3.41.16",
|
||||||
|
"mem0ai>=0.1.26",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
36
src/frontend/src/icons/Mem0/SvgMem.jsx
Normal file
36
src/frontend/src/icons/Mem0/SvgMem.jsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
src/frontend/src/icons/Mem0/index.tsx
Normal file
8
src/frontend/src/icons/Mem0/index.tsx
Normal 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} />;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
@ -238,6 +238,7 @@ import { IFixIcon } from "../icons/IFixIt";
|
||||||
import { LMStudioIcon } from "../icons/LMStudio";
|
import { LMStudioIcon } from "../icons/LMStudio";
|
||||||
import { LangChainIcon } from "../icons/LangChain";
|
import { LangChainIcon } from "../icons/LangChain";
|
||||||
import { MaritalkIcon } from "../icons/Maritalk";
|
import { MaritalkIcon } from "../icons/Maritalk";
|
||||||
|
import { Mem0 } from "../icons/Mem0";
|
||||||
import { MetaIcon } from "../icons/Meta";
|
import { MetaIcon } from "../icons/Meta";
|
||||||
import { MidjourneyIcon } from "../icons/Midjorney";
|
import { MidjourneyIcon } from "../icons/Midjorney";
|
||||||
import { MongoDBIcon } from "../icons/MongoDB";
|
import { MongoDBIcon } from "../icons/MongoDB";
|
||||||
|
|
@ -826,4 +827,5 @@ export const nodeIconsLucide: iconsType = {
|
||||||
CircleCheckBig,
|
CircleCheckBig,
|
||||||
ZoomIn,
|
ZoomIn,
|
||||||
ZoomOut,
|
ZoomOut,
|
||||||
|
Mem0,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue