Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c49e1aa0b |
@@ -42,6 +42,9 @@ clean:
|
||||
test:
|
||||
hatch run test
|
||||
|
||||
test-py-3.9:
|
||||
hatch run dev_py_3_9:test
|
||||
|
||||
test-py-3.10:
|
||||
hatch run dev_py_3_10:test
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mem0/cli",
|
||||
"version": "0.2.4",
|
||||
"version": "0.2.3",
|
||||
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface AddOptions {
|
||||
infer?: boolean;
|
||||
expires?: string;
|
||||
categories?: string[];
|
||||
enableGraph?: boolean;
|
||||
}
|
||||
|
||||
export interface SearchOptions {
|
||||
@@ -28,6 +29,7 @@ export interface SearchOptions {
|
||||
keyword?: boolean;
|
||||
filters?: Record<string, unknown>;
|
||||
fields?: string[];
|
||||
enableGraph?: boolean;
|
||||
}
|
||||
|
||||
export interface ListOptions {
|
||||
@@ -40,6 +42,7 @@ export interface ListOptions {
|
||||
category?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
enableGraph?: boolean;
|
||||
}
|
||||
|
||||
export interface DeleteOptions {
|
||||
|
||||
@@ -115,9 +115,10 @@ export class PlatformBackend implements Backend {
|
||||
if (opts.infer === false) payload.infer = false;
|
||||
if (opts.expires) payload.expiration_date = opts.expires;
|
||||
if (opts.categories) payload.categories = opts.categories;
|
||||
if (opts.enableGraph) payload.enable_graph = true;
|
||||
payload.source = "CLI";
|
||||
|
||||
return (await this._request("POST", "/v3/memories/add/", {
|
||||
return (await this._request("POST", "/v1/memories/", {
|
||||
json: payload,
|
||||
})) as Record<string, unknown>;
|
||||
}
|
||||
@@ -175,9 +176,10 @@ export class PlatformBackend implements Backend {
|
||||
if (opts.rerank) payload.rerank = true;
|
||||
if (opts.keyword) payload.keyword_search = true;
|
||||
if (opts.fields) payload.fields = opts.fields;
|
||||
if (opts.enableGraph) payload.enable_graph = true;
|
||||
payload.source = "CLI";
|
||||
|
||||
const result = (await this._request("POST", "/v3/memories/search/", {
|
||||
const result = (await this._request("POST", "/v2/memories/search/", {
|
||||
json: payload,
|
||||
})) as unknown;
|
||||
if (Array.isArray(result)) return result;
|
||||
@@ -225,9 +227,10 @@ export class PlatformBackend implements Backend {
|
||||
extraFilters: Object.keys(extra).length > 0 ? extra : undefined,
|
||||
});
|
||||
if (apiFilters) payload.filters = apiFilters;
|
||||
if (opts.enableGraph) payload.enable_graph = true;
|
||||
payload.source = "CLI";
|
||||
|
||||
const result = (await this._request("POST", "/v3/memories/", {
|
||||
const result = (await this._request("POST", "/v2/memories/", {
|
||||
json: payload,
|
||||
params,
|
||||
})) as unknown;
|
||||
|
||||
@@ -29,6 +29,7 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
|
||||
agent_id: config.defaults.agentId || null,
|
||||
app_id: config.defaults.appId || null,
|
||||
run_id: config.defaults.runId || null,
|
||||
enable_graph: config.defaults.enableGraph,
|
||||
},
|
||||
platform: {
|
||||
api_key: redactKey(config.platform.apiKey),
|
||||
@@ -55,6 +56,7 @@ export function cmdConfigShow(opts: { output?: string } = {}): void {
|
||||
]);
|
||||
table.push(["defaults.app_id", config.defaults.appId || dim("(not set)")]);
|
||||
table.push(["defaults.run_id", config.defaults.runId || dim("(not set)")]);
|
||||
table.push(["defaults.enable_graph", String(config.defaults.enableGraph)]);
|
||||
table.push(["", ""]);
|
||||
|
||||
// Platform
|
||||
|
||||
@@ -49,6 +49,7 @@ export async function cmdAdd(
|
||||
noInfer: boolean;
|
||||
expires?: string;
|
||||
categories?: string;
|
||||
enableGraph: boolean;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
@@ -139,6 +140,7 @@ export async function cmdAdd(
|
||||
infer: !opts.noInfer,
|
||||
expires: opts.expires,
|
||||
categories: cats,
|
||||
enableGraph: opts.enableGraph,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -223,6 +225,7 @@ export async function cmdSearch(
|
||||
keyword: boolean;
|
||||
filterJson?: string;
|
||||
fields?: string;
|
||||
enableGraph: boolean;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
@@ -271,6 +274,7 @@ export async function cmdSearch(
|
||||
keyword: opts.keyword,
|
||||
filters,
|
||||
fields: fieldList,
|
||||
enableGraph: opts.enableGraph,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -364,6 +368,7 @@ export async function cmdList(
|
||||
category?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
enableGraph: boolean;
|
||||
output: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
@@ -391,6 +396,7 @@ export async function cmdList(
|
||||
category: opts.category,
|
||||
after: opts.after,
|
||||
before: opts.before,
|
||||
enableGraph: opts.enableGraph,
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface DefaultsConfig {
|
||||
agentId: string;
|
||||
appId: string;
|
||||
runId: string;
|
||||
enableGraph: boolean;
|
||||
}
|
||||
|
||||
export interface TelemetryConfig {
|
||||
@@ -49,6 +50,7 @@ export function createDefaultConfig(): Mem0Config {
|
||||
agentId: "",
|
||||
appId: "",
|
||||
runId: "",
|
||||
enableGraph: false,
|
||||
},
|
||||
platform: {
|
||||
apiKey: "",
|
||||
@@ -85,6 +87,8 @@ export function loadConfig(): Mem0Config {
|
||||
config.defaults.agentId = defaults.agent_id ?? "";
|
||||
config.defaults.appId = defaults.app_id ?? "";
|
||||
config.defaults.runId = defaults.run_id ?? "";
|
||||
config.defaults.enableGraph = defaults.enable_graph ?? false;
|
||||
|
||||
const telemetry = data.telemetry ?? {};
|
||||
config.telemetry.anonymousId = telemetry.anonymous_id ?? "";
|
||||
}
|
||||
@@ -100,6 +104,12 @@ export function loadConfig(): Mem0Config {
|
||||
config.defaults.agentId = process.env.MEM0_AGENT_ID;
|
||||
if (process.env.MEM0_APP_ID) config.defaults.appId = process.env.MEM0_APP_ID;
|
||||
if (process.env.MEM0_RUN_ID) config.defaults.runId = process.env.MEM0_RUN_ID;
|
||||
if (process.env.MEM0_ENABLE_GRAPH) {
|
||||
config.defaults.enableGraph = ["true", "1", "yes"].includes(
|
||||
process.env.MEM0_ENABLE_GRAPH.toLowerCase(),
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -113,6 +123,7 @@ export function saveConfig(config: Mem0Config): void {
|
||||
agent_id: config.defaults.agentId,
|
||||
app_id: config.defaults.appId,
|
||||
run_id: config.defaults.runId,
|
||||
enable_graph: config.defaults.enableGraph,
|
||||
},
|
||||
platform: {
|
||||
api_key: config.platform.apiKey,
|
||||
@@ -143,6 +154,7 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
||||
"defaults.agent_id": ["defaults", "agentId"],
|
||||
"defaults.app_id": ["defaults", "appId"],
|
||||
"defaults.run_id": ["defaults", "runId"],
|
||||
"defaults.enable_graph": ["defaults", "enableGraph"],
|
||||
// Short-form aliases
|
||||
api_key: ["platform", "apiKey"],
|
||||
base_url: ["platform", "baseUrl"],
|
||||
@@ -151,6 +163,7 @@ const KEY_MAP: Record<string, [keyof Mem0Config, string]> = {
|
||||
agent_id: ["defaults", "agentId"],
|
||||
app_id: ["defaults", "appId"],
|
||||
run_id: ["defaults", "runId"],
|
||||
enable_graph: ["defaults", "enableGraph"],
|
||||
};
|
||||
|
||||
export function getNestedValue(config: Mem0Config, dottedKey: string): unknown {
|
||||
|
||||
@@ -134,6 +134,18 @@ function resolveIds(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve graph tri-state: --no-graph > --graph > config default.
|
||||
*/
|
||||
function resolveGraph(
|
||||
config: Mem0Config,
|
||||
opts: { graph?: boolean; noGraph?: boolean },
|
||||
): boolean {
|
||||
if (opts.noGraph) return false;
|
||||
if (opts.graph) return true;
|
||||
return config.defaults.enableGraph;
|
||||
}
|
||||
|
||||
// ── Main program ──────────────────────────────────────────────────────────
|
||||
|
||||
program
|
||||
@@ -224,6 +236,8 @@ program
|
||||
.option("--no-infer", "Skip inference, store raw.")
|
||||
.option("--expires <date>", "Expiration date (YYYY-MM-DD).")
|
||||
.option("--categories <value>", "Categories (JSON array or comma-separated).")
|
||||
.option("--graph", "Enable graph memory extraction.", false)
|
||||
.option("--no-graph", "Disable graph memory extraction.")
|
||||
.option("-o, --output <format>", "Output format: text, json, quiet.", "text")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -239,8 +253,9 @@ program
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdAdd(backend, text, { ...ids, ...opts, output });
|
||||
await cmdAdd(backend, text, { ...ids, ...opts, enableGraph, output });
|
||||
});
|
||||
|
||||
// ── Memory: search ────────────────────────────────────────────────────────
|
||||
@@ -270,6 +285,8 @@ program
|
||||
.option("--keyword", "Use keyword search.", false)
|
||||
.option("--filter <json>", "Advanced filter expression (JSON).")
|
||||
.option("--fields <list>", "Specific fields to return (comma-separated).")
|
||||
.option("--graph", "Enable graph in search.", false)
|
||||
.option("--no-graph", "Disable graph in search.")
|
||||
.option("-o, --output <format>", "Output: text, json, table.", "text")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -293,6 +310,7 @@ program
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdSearch(backend, resolvedQuery, {
|
||||
...ids,
|
||||
@@ -302,6 +320,7 @@ program
|
||||
keyword: opts.keyword,
|
||||
filterJson: opts.filter,
|
||||
fields: opts.fields,
|
||||
enableGraph,
|
||||
output,
|
||||
});
|
||||
});
|
||||
@@ -345,6 +364,8 @@ program
|
||||
.option("--category <name>", "Filter by category.")
|
||||
.option("--after <date>", "Created after (YYYY-MM-DD).")
|
||||
.option("--before <date>", "Created before (YYYY-MM-DD).")
|
||||
.option("--graph", "Enable graph in listing.", false)
|
||||
.option("--no-graph", "Disable graph in listing.")
|
||||
.option("-o, --output <format>", "Output: text, json, table.", "table")
|
||||
.option("--api-key <key>", "Override API key.")
|
||||
.option("--base-url <url>", "Override API base URL.")
|
||||
@@ -360,6 +381,7 @@ program
|
||||
opts.baseUrl,
|
||||
);
|
||||
const ids = resolveIds(config, opts);
|
||||
const enableGraph = resolveGraph(config, opts);
|
||||
const output = isAgent ? "agent" : opts.output;
|
||||
await cmdList(backend, {
|
||||
...ids,
|
||||
@@ -368,6 +390,7 @@ program
|
||||
category: opts.category,
|
||||
after: opts.after,
|
||||
before: opts.before,
|
||||
enableGraph,
|
||||
output,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -107,22 +107,22 @@ describe("CLI Integration — help and version", () => {
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
it("add help has --output flag", () => {
|
||||
it("add help has --graph flag", () => {
|
||||
const result = run(["add", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stdout).toContain("--output");
|
||||
expect(result.stdout).toContain("--graph");
|
||||
});
|
||||
|
||||
it("search help has --rerank flag", () => {
|
||||
it("search help has --graph flag", () => {
|
||||
const result = run(["search", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stdout).toContain("--rerank");
|
||||
expect(result.stdout).toContain("--graph");
|
||||
});
|
||||
|
||||
it("list help has --category flag", () => {
|
||||
it("list help has --graph flag", () => {
|
||||
const result = run(["list", "--help"]);
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stdout).toContain("--category");
|
||||
expect(result.stdout).toContain("--graph");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("cmdAdd", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||
@@ -55,7 +55,7 @@ describe("cmdAdd", () => {
|
||||
messages: JSON.stringify([{ role: "user", content: "I love Python" }]),
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(mockBackend.add).toHaveBeenCalledOnce();
|
||||
@@ -67,7 +67,7 @@ describe("cmdAdd", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "json",
|
||||
});
|
||||
expect(output).toContain("results");
|
||||
@@ -79,7 +79,7 @@ describe("cmdAdd", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "quiet",
|
||||
});
|
||||
expect(output).not.toContain("dark mode");
|
||||
@@ -101,7 +101,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(output.match(/Queued/g)?.length).toBe(1);
|
||||
@@ -114,7 +114,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "json",
|
||||
});
|
||||
const data = JSON.parse(output);
|
||||
@@ -130,7 +130,7 @@ describe("cmdAdd deduplicates PENDING", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "agent",
|
||||
});
|
||||
const data = JSON.parse(output);
|
||||
@@ -148,7 +148,7 @@ describe("cmdSearch", () => {
|
||||
threshold: 0.3,
|
||||
rerank: false,
|
||||
keyword: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(output).toContain("Found 2");
|
||||
@@ -162,7 +162,7 @@ describe("cmdSearch", () => {
|
||||
threshold: 0.3,
|
||||
rerank: false,
|
||||
keyword: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "json",
|
||||
});
|
||||
expect(output).toContain("memory");
|
||||
@@ -177,7 +177,7 @@ describe("cmdSearch", () => {
|
||||
threshold: 0.3,
|
||||
rerank: false,
|
||||
keyword: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(errOutput).toContain("No memories found");
|
||||
@@ -205,7 +205,7 @@ describe("cmdList", () => {
|
||||
userId: "alice",
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
|
||||
enableGraph: false,
|
||||
output: "table",
|
||||
});
|
||||
expect(output).toContain("dark mode");
|
||||
@@ -218,7 +218,7 @@ describe("cmdList", () => {
|
||||
userId: "alice",
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
|
||||
enableGraph: false,
|
||||
output: "text",
|
||||
});
|
||||
expect(errOutput).toContain("No memories found");
|
||||
@@ -316,7 +316,7 @@ describe("agent mode", () => {
|
||||
userId: "alice",
|
||||
immutable: false,
|
||||
noInfer: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "agent",
|
||||
});
|
||||
const parsed = JSON.parse(output.trim());
|
||||
@@ -336,7 +336,7 @@ describe("agent mode", () => {
|
||||
threshold: 0.3,
|
||||
rerank: false,
|
||||
keyword: false,
|
||||
|
||||
enableGraph: false,
|
||||
output: "agent",
|
||||
});
|
||||
const parsed = JSON.parse(output.trim());
|
||||
@@ -361,7 +361,7 @@ describe("agent mode", () => {
|
||||
userId: "alice",
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
|
||||
enableGraph: false,
|
||||
output: "agent",
|
||||
});
|
||||
const parsed = JSON.parse(output.trim());
|
||||
|
||||
@@ -64,6 +64,7 @@ describe("createDefaultConfig", () => {
|
||||
expect(config.platform.baseUrl).toBe("https://api.mem0.ai");
|
||||
expect(config.platform.apiKey).toBe("");
|
||||
expect(config.defaults.userId).toBe("");
|
||||
expect(config.defaults.enableGraph).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,4 +105,9 @@ describe("setNestedValue", () => {
|
||||
expect(config.defaults.userId).toBe("bob");
|
||||
});
|
||||
|
||||
it("coerces boolean for enable_graph", () => {
|
||||
const config = createDefaultConfig();
|
||||
expect(setNestedValue(config, "defaults.enable_graph", "true")).toBe(true);
|
||||
expect(config.defaults.enableGraph).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "mem0-cli"
|
||||
version = "0.2.4"
|
||||
version = "0.2.3"
|
||||
description = "The official CLI for mem0 — the memory layer for AI agents"
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"""mem0 CLI — the command-line interface for the mem0 memory layer."""
|
||||
|
||||
__version__ = "0.2.4"
|
||||
__version__ = "0.2.3"
|
||||
|
||||
@@ -267,6 +267,8 @@ def add(
|
||||
categories: str | None = typer.Option(
|
||||
None, "--categories", help="Categories (JSON array or comma-separated)."
|
||||
),
|
||||
graph: bool = typer.Option(False, "--graph", help="Enable graph memory extraction."),
|
||||
no_graph: bool = typer.Option(False, "--no-graph", help="Disable graph memory extraction."),
|
||||
output: str = typer.Option(
|
||||
"text", "--output", "-o", help="Output format: text, json, quiet.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -293,6 +295,13 @@ def add(
|
||||
backend, config = _get_backend_and_config(api_key, base_url)
|
||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||
|
||||
if no_graph:
|
||||
graph_enabled = False
|
||||
elif graph:
|
||||
graph_enabled = True
|
||||
else:
|
||||
graph_enabled = config.defaults.enable_graph
|
||||
|
||||
cmd_add(
|
||||
backend,
|
||||
text,
|
||||
@@ -304,6 +313,7 @@ def add(
|
||||
no_infer=no_infer,
|
||||
expires=expires,
|
||||
categories=categories,
|
||||
enable_graph=graph_enabled,
|
||||
output=output,
|
||||
)
|
||||
|
||||
@@ -347,6 +357,12 @@ def search(
|
||||
help="Specific fields to return (comma-separated).",
|
||||
rich_help_panel="Search",
|
||||
),
|
||||
graph: bool = typer.Option(
|
||||
False, "--graph", help="Enable graph in search.", rich_help_panel="Search"
|
||||
),
|
||||
no_graph: bool = typer.Option(
|
||||
False, "--no-graph", help="Disable graph in search.", rich_help_panel="Search"
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"text", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -380,6 +396,13 @@ def search(
|
||||
backend, config = _get_backend_and_config(api_key, base_url)
|
||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||
|
||||
if no_graph:
|
||||
graph_enabled = False
|
||||
elif graph:
|
||||
graph_enabled = True
|
||||
else:
|
||||
graph_enabled = config.defaults.enable_graph
|
||||
|
||||
cmd_search(
|
||||
backend,
|
||||
query,
|
||||
@@ -390,6 +413,7 @@ def search(
|
||||
keyword=keyword,
|
||||
filter_json=filter_json,
|
||||
fields=fields,
|
||||
enable_graph=graph_enabled,
|
||||
output=output,
|
||||
)
|
||||
|
||||
@@ -456,6 +480,12 @@ def list_cmd(
|
||||
before: str | None = typer.Option(
|
||||
None, "--before", help="Created before (YYYY-MM-DD).", rich_help_panel="Filters"
|
||||
),
|
||||
graph: bool = typer.Option(
|
||||
False, "--graph", help="Enable graph in listing.", rich_help_panel="Filters"
|
||||
),
|
||||
no_graph: bool = typer.Option(
|
||||
False, "--no-graph", help="Disable graph in listing.", rich_help_panel="Filters"
|
||||
),
|
||||
output: str = typer.Option(
|
||||
"table", "--output", "-o", help="Output: text, json, table.", rich_help_panel="Output"
|
||||
),
|
||||
@@ -481,6 +511,13 @@ def list_cmd(
|
||||
backend, config = _get_backend_and_config(api_key, base_url)
|
||||
ids = _resolve_ids(config, user_id=user_id, agent_id=agent_id, app_id=app_id, run_id=run_id)
|
||||
|
||||
if no_graph:
|
||||
graph_enabled = False
|
||||
elif graph:
|
||||
graph_enabled = True
|
||||
else:
|
||||
graph_enabled = config.defaults.enable_graph
|
||||
|
||||
cmd_list(
|
||||
backend,
|
||||
**ids,
|
||||
@@ -489,6 +526,7 @@ def list_cmd(
|
||||
category=category,
|
||||
after=after,
|
||||
before=before,
|
||||
enable_graph=graph_enabled,
|
||||
output=output,
|
||||
)
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class Backend(ABC):
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
categories: list[str] | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> dict: ...
|
||||
|
||||
@abstractmethod
|
||||
@@ -43,6 +44,7 @@ class Backend(ABC):
|
||||
keyword: bool = False,
|
||||
filters: dict | None = None,
|
||||
fields: list[str] | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> list[dict]: ...
|
||||
|
||||
@abstractmethod
|
||||
@@ -61,6 +63,7 @@ class Backend(ABC):
|
||||
category: str | None = None,
|
||||
after: str | None = None,
|
||||
before: str | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> list[dict]: ...
|
||||
|
||||
@abstractmethod
|
||||
|
||||
@@ -64,6 +64,7 @@ class PlatformBackend(Backend):
|
||||
infer: bool = True,
|
||||
expires: str | None = None,
|
||||
categories: list[str] | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> dict:
|
||||
payload: dict[str, Any] = {}
|
||||
|
||||
@@ -90,9 +91,11 @@ class PlatformBackend(Backend):
|
||||
payload["expiration_date"] = expires
|
||||
if categories:
|
||||
payload["categories"] = categories
|
||||
if enable_graph:
|
||||
payload["enable_graph"] = True
|
||||
payload["source"] = "CLI"
|
||||
|
||||
return self._request("POST", "/v3/memories/add/", json=payload)
|
||||
return self._request("POST", "/v1/memories/", json=payload)
|
||||
|
||||
def _build_filters(
|
||||
self,
|
||||
@@ -103,7 +106,7 @@ class PlatformBackend(Backend):
|
||||
run_id: str | None = None,
|
||||
extra_filters: dict | None = None,
|
||||
) -> dict | None:
|
||||
"""Build a filters dict for v3 API endpoints.
|
||||
"""Build a filters dict for v2 API endpoints.
|
||||
|
||||
Entity IDs are ANDed (all provided IDs must match).
|
||||
Extra filters (date ranges, categories) are also ANDed.
|
||||
@@ -149,6 +152,7 @@ class PlatformBackend(Backend):
|
||||
keyword: bool = False,
|
||||
filters: dict | None = None,
|
||||
fields: list[str] | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> list[dict]:
|
||||
payload: dict[str, Any] = {"query": query, "top_k": top_k, "threshold": threshold}
|
||||
|
||||
@@ -167,9 +171,11 @@ class PlatformBackend(Backend):
|
||||
payload["keyword_search"] = True
|
||||
if fields:
|
||||
payload["fields"] = fields
|
||||
if enable_graph:
|
||||
payload["enable_graph"] = True
|
||||
payload["source"] = "CLI"
|
||||
|
||||
result = self._request("POST", "/v3/memories/search/", json=payload)
|
||||
result = self._request("POST", "/v2/memories/search/", json=payload)
|
||||
return (
|
||||
result
|
||||
if isinstance(result, list)
|
||||
@@ -191,11 +197,12 @@ class PlatformBackend(Backend):
|
||||
category: str | None = None,
|
||||
after: str | None = None,
|
||||
before: str | None = None,
|
||||
enable_graph: bool = False,
|
||||
) -> list[dict]:
|
||||
payload: dict[str, Any] = {}
|
||||
params = {"page": str(page), "page_size": str(page_size)}
|
||||
|
||||
# Build filters — entity IDs and date filters go inside "filters"
|
||||
# Build filters for v2 API — entity IDs and date filters go inside "filters"
|
||||
extra: dict[str, Any] = {}
|
||||
if category:
|
||||
extra["categories"] = {"contains": category}
|
||||
@@ -213,9 +220,11 @@ class PlatformBackend(Backend):
|
||||
)
|
||||
if api_filters:
|
||||
payload["filters"] = api_filters
|
||||
if enable_graph:
|
||||
payload["enable_graph"] = True
|
||||
payload["source"] = "CLI"
|
||||
|
||||
result = self._request("POST", "/v3/memories/", json=payload, params=params)
|
||||
result = self._request("POST", "/v2/memories/", json=payload, params=params)
|
||||
return (
|
||||
result
|
||||
if isinstance(result, list)
|
||||
|
||||
@@ -39,6 +39,7 @@ def cmd_config_show(*, output: str = "text") -> None:
|
||||
"agent_id": config.defaults.agent_id or None,
|
||||
"app_id": config.defaults.app_id or None,
|
||||
"run_id": config.defaults.run_id or None,
|
||||
"enable_graph": config.defaults.enable_graph,
|
||||
},
|
||||
"platform": {
|
||||
"api_key": redact_key(config.platform.api_key),
|
||||
@@ -72,6 +73,10 @@ def cmd_config_show(*, output: str = "text") -> None:
|
||||
"defaults.run_id",
|
||||
config.defaults.run_id or f"[{DIM_COLOR}](not set)[/]",
|
||||
)
|
||||
table.add_row(
|
||||
"defaults.enable_graph",
|
||||
str(config.defaults.enable_graph).lower(),
|
||||
)
|
||||
table.add_row("", "")
|
||||
|
||||
# Platform
|
||||
|
||||
@@ -62,6 +62,7 @@ def cmd_add(
|
||||
no_infer: bool,
|
||||
expires: str | None,
|
||||
categories: str | None,
|
||||
enable_graph: bool = False,
|
||||
output: str = "text",
|
||||
) -> None:
|
||||
"""Add a memory."""
|
||||
@@ -144,6 +145,7 @@ def cmd_add(
|
||||
infer=not no_infer,
|
||||
expires=expires,
|
||||
categories=cats,
|
||||
enable_graph=enable_graph,
|
||||
)
|
||||
except Exception as e:
|
||||
ts.error_msg = str(e)
|
||||
@@ -224,6 +226,7 @@ def cmd_search(
|
||||
keyword: bool,
|
||||
filter_json: str | None,
|
||||
fields: str | None,
|
||||
enable_graph: bool = False,
|
||||
output: str = "text",
|
||||
) -> None:
|
||||
"""Search memories."""
|
||||
@@ -266,6 +269,7 @@ def cmd_search(
|
||||
keyword=keyword,
|
||||
filters=filters,
|
||||
fields=field_list,
|
||||
enable_graph=enable_graph,
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
@@ -352,6 +356,7 @@ def cmd_list(
|
||||
category: str | None,
|
||||
after: str | None,
|
||||
before: str | None,
|
||||
enable_graph: bool = False,
|
||||
output: str = "table",
|
||||
) -> None:
|
||||
"""List memories."""
|
||||
@@ -380,6 +385,7 @@ def cmd_list(
|
||||
category=category,
|
||||
after=after,
|
||||
before=before,
|
||||
enable_graph=enable_graph,
|
||||
)
|
||||
except Exception as e:
|
||||
print_error(err_console, str(e))
|
||||
|
||||
@@ -36,6 +36,7 @@ class DefaultsConfig:
|
||||
agent_id: str = ""
|
||||
app_id: str = ""
|
||||
run_id: str = ""
|
||||
enable_graph: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -59,6 +60,7 @@ SHORT_KEY_ALIASES: dict[str, str] = {
|
||||
"agent_id": "defaults.agent_id",
|
||||
"app_id": "defaults.app_id",
|
||||
"run_id": "defaults.run_id",
|
||||
"enable_graph": "defaults.enable_graph",
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +91,8 @@ def load_config() -> Mem0Config:
|
||||
config.defaults.agent_id = defaults.get("agent_id", "")
|
||||
config.defaults.app_id = defaults.get("app_id", "")
|
||||
config.defaults.run_id = defaults.get("run_id", "")
|
||||
config.defaults.enable_graph = defaults.get("enable_graph", False)
|
||||
|
||||
telemetry = data.get("telemetry", {})
|
||||
config.telemetry.anonymous_id = telemetry.get("anonymous_id", "")
|
||||
|
||||
@@ -117,6 +121,10 @@ def load_config() -> Mem0Config:
|
||||
if env_run_id:
|
||||
config.defaults.run_id = env_run_id
|
||||
|
||||
env_graph = os.environ.get("MEM0_ENABLE_GRAPH")
|
||||
if env_graph:
|
||||
config.defaults.enable_graph = env_graph.lower() in ("true", "1", "yes")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@@ -131,6 +139,7 @@ def save_config(config: Mem0Config) -> None:
|
||||
"agent_id": config.defaults.agent_id,
|
||||
"app_id": config.defaults.app_id,
|
||||
"run_id": config.defaults.run_id,
|
||||
"enable_graph": config.defaults.enable_graph,
|
||||
},
|
||||
"platform": {
|
||||
"api_key": config.platform.api_key,
|
||||
|
||||
@@ -224,13 +224,24 @@ class TestCLIIsolated:
|
||||
|
||||
|
||||
class TestCLINewFeatures:
|
||||
"""Tests for MCP parity features: --limit, entities delete."""
|
||||
"""Tests for MCP parity features: --graph, --limit, entities delete."""
|
||||
|
||||
def test_search_help_has_limit(self):
|
||||
def test_add_help_has_graph(self):
|
||||
result = _run(["add", "--help"])
|
||||
assert result.returncode == 0
|
||||
assert "--graph" in result.stdout
|
||||
|
||||
def test_search_help_has_graph_and_limit(self):
|
||||
result = _run(["search", "--help"])
|
||||
assert result.returncode == 0
|
||||
assert "--graph" in result.stdout
|
||||
assert "--limit" in result.stdout
|
||||
|
||||
def test_list_help_has_graph(self):
|
||||
result = _run(["list", "--help"])
|
||||
assert result.returncode == 0
|
||||
assert "--graph" in result.stdout
|
||||
|
||||
def test_delete_entity_via_delete_flag(self):
|
||||
"""delete --entity should appear in help output."""
|
||||
result = _run(["delete", "--help"])
|
||||
|
||||
@@ -997,6 +997,85 @@ class TestEntitiesDeleteCommand:
|
||||
mock_backend.delete_entities.assert_not_called()
|
||||
|
||||
|
||||
class TestEnableGraph:
|
||||
def test_add_with_graph(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_add(
|
||||
mock_backend,
|
||||
"test",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
messages=None,
|
||||
file=None,
|
||||
metadata=None,
|
||||
immutable=False,
|
||||
no_infer=False,
|
||||
expires=None,
|
||||
categories=None,
|
||||
enable_graph=True,
|
||||
output="text",
|
||||
)
|
||||
call_kwargs = mock_backend.add.call_args
|
||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
||||
|
||||
def test_search_with_graph(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_search(
|
||||
mock_backend,
|
||||
"test",
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
top_k=10,
|
||||
threshold=0.3,
|
||||
rerank=False,
|
||||
keyword=False,
|
||||
filter_json=None,
|
||||
fields=None,
|
||||
enable_graph=True,
|
||||
output="text",
|
||||
)
|
||||
call_kwargs = mock_backend.search.call_args
|
||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
||||
|
||||
def test_list_with_graph(self, mock_backend):
|
||||
console, _buf = _make_console()
|
||||
err_console, _err_buf = _make_err_console()
|
||||
with (
|
||||
patch("mem0_cli.commands.memory.console", console),
|
||||
patch("mem0_cli.commands.memory.err_console", err_console),
|
||||
):
|
||||
cmd_list(
|
||||
mock_backend,
|
||||
user_id="alice",
|
||||
agent_id=None,
|
||||
app_id=None,
|
||||
run_id=None,
|
||||
page=1,
|
||||
page_size=100,
|
||||
category=None,
|
||||
after=None,
|
||||
before=None,
|
||||
enable_graph=True,
|
||||
output="table",
|
||||
)
|
||||
call_kwargs = mock_backend.list_memories.call_args
|
||||
assert call_kwargs.kwargs.get("enable_graph") is True
|
||||
|
||||
|
||||
class TestEventCommands:
|
||||
def test_event_list_table(self, mock_backend):
|
||||
console, buf = _make_console()
|
||||
|
||||
@@ -121,6 +121,46 @@ class TestConfig:
|
||||
assert config.defaults.agent_id == ""
|
||||
assert config.defaults.app_id == ""
|
||||
assert config.defaults.run_id == ""
|
||||
assert config.defaults.enable_graph is False
|
||||
|
||||
def test_enable_graph_save_and_load(self, isolate_config):
|
||||
config = Mem0Config()
|
||||
config.defaults.enable_graph = True
|
||||
save_config(config)
|
||||
loaded = load_config()
|
||||
assert loaded.defaults.enable_graph is True
|
||||
|
||||
def test_enable_graph_env_var_true(self, isolate_config, monkeypatch):
|
||||
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "true")
|
||||
loaded = load_config()
|
||||
assert loaded.defaults.enable_graph is True
|
||||
|
||||
def test_enable_graph_env_var_false(self, isolate_config, monkeypatch):
|
||||
config = Mem0Config()
|
||||
config.defaults.enable_graph = True
|
||||
save_config(config)
|
||||
monkeypatch.setenv("MEM0_ENABLE_GRAPH", "false")
|
||||
loaded = load_config()
|
||||
assert loaded.defaults.enable_graph is False
|
||||
|
||||
def test_backward_compat_no_enable_graph_key(self, isolate_config):
|
||||
"""Old config files without 'enable_graph' key should default to False."""
|
||||
import json
|
||||
|
||||
from mem0_cli.config import CONFIG_FILE, ensure_config_dir
|
||||
|
||||
ensure_config_dir()
|
||||
data = {
|
||||
"version": 1,
|
||||
"defaults": {"user_id": "alice"},
|
||||
"platform": {"api_key": "m0-test", "base_url": "https://api.mem0.ai"},
|
||||
}
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
json.dump(data, f)
|
||||
|
||||
loaded = load_config()
|
||||
assert loaded.defaults.enable_graph is False
|
||||
assert loaded.defaults.user_id == "alice"
|
||||
|
||||
|
||||
class TestNestedAccess:
|
||||
@@ -152,6 +192,11 @@ class TestNestedAccess:
|
||||
assert set_nested_value(config, "defaults.user_id", "bob")
|
||||
assert config.defaults.user_id == "bob"
|
||||
|
||||
def test_set_defaults_enable_graph(self):
|
||||
config = Mem0Config()
|
||||
assert set_nested_value(config, "defaults.enable_graph", "true")
|
||||
assert config.defaults.enable_graph is True
|
||||
|
||||
|
||||
class TestResolveIds:
|
||||
def test_cli_flag_overrides_default(self):
|
||||
|
||||
@@ -1269,16 +1269,6 @@ See the [TypeScript SDK migration guide](https://docs.mem0.ai/migration/ts-v2-to
|
||||
|
||||
<Tab title="CLI">
|
||||
|
||||
<Update label="2026-04-22" description="Python v0.2.4 / Node v0.2.4">
|
||||
|
||||
**New Features:**
|
||||
- **V3 API Routes:** Migrated `add`, `search`, and `list` commands from v1/v2 to v3 API endpoints — `POST /v3/memories/add/`, `POST /v3/memories/search/`, `POST /v3/memories/`. Aligns both CLIs with the Python and TypeScript SDKs which already use v3 ([#4916](https://github.com/mem0ai/mem0/pull/4916))
|
||||
|
||||
**Breaking Changes:**
|
||||
- **`--graph` / `--no-graph` removed:** The `enable_graph` config option, `--graph` and `--no-graph` CLI flags, and `MEM0_ENABLE_GRAPH` environment variable have been removed from both CLIs. Graph memory is now a project-level setting on the Platform ([#4916](https://github.com/mem0ai/mem0/pull/4916))
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026-04-11" description="Python v0.2.3 / Node v0.2.3">
|
||||
|
||||
**Bug Fixes:**
|
||||
|
||||
@@ -216,7 +216,7 @@ memory.delete_all(user_id="alice")
|
||||
## Put it into practice
|
||||
|
||||
- Review the <Link href="/api-reference/memory/delete-memory">Delete Memory API reference</Link>, plus <Link href="/api-reference/memory/batch-delete">Batch Delete</Link> and <Link href="/api-reference/memory/delete-memories">Filtered Delete</Link>.
|
||||
- Pair deletes with <Link href="/platform/features/platform-overview">Expiration Policies</Link> to automate retention.
|
||||
- Pair deletes with <Link href="/platform/features/expiration-date">Expiration Policies</Link> to automate retention.
|
||||
|
||||
## See it live
|
||||
|
||||
@@ -236,6 +236,6 @@ memory.delete_all(user_id="alice")
|
||||
title="Enable Expiration Policies"
|
||||
description="Automate retention with the platform’s expiration feature."
|
||||
icon="clock"
|
||||
href="/platform/features/platform-overview"
|
||||
href="/platform/features/expiration-date"
|
||||
/>
|
||||
</CardGroup>
|
||||
|
||||
@@ -399,8 +399,6 @@
|
||||
"integrations/langgraph",
|
||||
"integrations/llama-index",
|
||||
"integrations/crewai",
|
||||
"integrations/autogen",
|
||||
"integrations/agno",
|
||||
"integrations/camel-ai",
|
||||
"integrations/openai-agents-sdk",
|
||||
"integrations/google-ai-adk",
|
||||
@@ -429,12 +427,7 @@
|
||||
"group": "Developer Tools",
|
||||
"icon": "wrench",
|
||||
"pages": [
|
||||
"integrations/dify",
|
||||
"integrations/flowise",
|
||||
"integrations/langchain-tools",
|
||||
"integrations/agentops",
|
||||
"integrations/keywords",
|
||||
"integrations/raycast"
|
||||
"integrations/langchain-tools"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1101,6 +1094,34 @@
|
||||
"source": "/v0x/faqs",
|
||||
"destination": "/platform/faqs"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/raycast",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/autogen",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/keywords",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/agentops",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/flowise",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/agno",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/dify",
|
||||
"destination": "/integrations"
|
||||
},
|
||||
{
|
||||
"source": "/integrations/multion",
|
||||
"destination": "/integrations"
|
||||
|
||||
@@ -20,23 +20,6 @@ Here are the available integrations for Mem0:
|
||||
## Integrations
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="AgentOps"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="25"
|
||||
height="26"
|
||||
viewBox="0 0 30 36"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M10.4659 6.47277C10.45 6.37428 10.4381 6.27986 10.4303 6.18101L10.4285 6.16388C10.4212 6.09482 10.414 6.02566 10.4106 5.95626L1.18538 21.8752C0.505422 23.0493 0.323356 24.4208 0.675227 25.7289C0.849119 26.3869 1.14971 26.9859 1.55323 27.5098C1.95675 28.0338 2.46282 28.4751 3.05175 28.8143C3.83464 29.2675 4.70856 29.5 5.59028 29.5C6.03318 29.5 6.4798 29.4408 6.91899 29.3226C8.23581 28.972 9.3349 28.1326 10.0152 26.9545L15.9268 16.749V16.7449L16.5001 15.7637L17.6431 13.7936L16.5001 11.8234L15.9309 10.8381L15.9268 10.8341L13.7836 7.13406C13.6651 6.933 13.5741 6.72418 13.5109 6.51165C13.2817 5.80223 13.3292 5.04172 13.6097 4.37599L13.8115 4.02535C14.3532 3.09155 15.31 2.53987 16.3184 2.47692C16.3738 2.46915 16.4251 2.46915 16.4804 2.46915C16.5421 2.46915 16.6038 2.47257 16.6654 2.47599L16.6822 2.47692C17.6906 2.53987 18.6474 3.09155 19.1892 4.02535L21.2216 7.52838L21.8146 8.55289L21.8421 8.60399L30.1024 22.8601C30.5174 23.5814 30.6281 24.4167 30.4148 25.2205C30.1975 26.0244 29.6832 26.6942 28.9598 27.1081C28.2364 27.5258 27.3977 27.6361 26.5911 27.4195C25.7844 27.2066 25.1123 26.6905 24.6968 25.9696L18.2119 14.7788L17.069 16.7449L22.9847 26.9545C23.6646 28.1326 24.7641 28.972 26.0809 29.3226C26.5197 29.4408 26.9626 29.5 27.4096 29.5C28.2914 29.5 29.1612 29.2675 29.9482 28.8143C31.1264 28.1367 31.9728 27.0411 32.3247 25.7289C32.6766 24.4208 32.4949 23.0493 31.8145 21.8752L21.1261 3.43034C20.7029 2.51617 20.0033 1.72011 19.0621 1.18027C18.5281 0.877027 17.9708 0.675975 17.3975 0.581189C17.3027 0.565268 17.2076 0.549717 17.1129 0.537868C17.0099 0.52602 16.9074 0.518244 16.8045 0.510469C16.6027 0.498621 16.3972 0.494548 16.1914 0.510469C16.0885 0.518244 15.9859 0.52639 15.883 0.537868C15.795 0.54887 15.7067 0.563384 15.6187 0.577852L15.5984 0.581189C15.0291 0.675605 14.4673 0.876657 13.9375 1.18027C12.9885 1.72789 12.2766 2.53579 11.8537 3.46181C11.7742 3.63473 11.707 3.81282 11.6471 3.99314C11.6361 4.02668 11.6269 4.06051 11.6177 4.09435C11.612 4.11503 11.6064 4.13579 11.6003 4.15642C11.5624 4.28601 11.5275 4.41634 11.4996 4.54853C11.4885 4.60231 11.4794 4.65668 11.4703 4.71111L11.4666 4.73329C11.4443 4.86399 11.4264 4.99543 11.4145 5.12762C11.4093 5.18686 11.4045 5.24573 11.4012 5.30534C11.3934 5.44567 11.3923 5.58637 11.3963 5.72744C11.3969 5.74403 11.3962 5.76062 11.3956 5.7772C11.3949 5.79616 11.3942 5.81512 11.3952 5.83407C11.3952 5.86184 11.3952 5.88924 11.3993 5.92071C11.3998 5.9291 11.4006 5.93736 11.4014 5.94564C11.402 5.95125 11.4026 5.95687 11.403 5.96255C11.4045 5.98181 11.4064 6.00106 11.4082 6.02031C11.4097 6.03577 11.4109 6.05122 11.4122 6.06674C11.4142 6.09134 11.4163 6.11621 11.419 6.14139L11.4428 6.32282C11.4506 6.38983 11.4625 6.46092 11.4744 6.52757C11.5063 6.68863 11.5468 6.84896 11.5936 7.0078C11.5944 7.0102 11.5949 7.0127 11.5955 7.0152C11.5958 7.01662 11.5961 7.01804 11.5965 7.01944C11.5967 7.02051 11.597 7.02157 11.5974 7.02261C11.6483 7.19293 11.7081 7.36177 11.7787 7.52838C11.8619 7.72943 11.9607 7.92641 12.0715 8.11932L12.3245 8.5566V8.56067L12.4984 8.85614L12.7199 9.24232H12.7239L12.728 9.25417L14.7802 12.7927V12.7968L14.7883 12.805V12.809L15.3576 13.7943L14.7883 14.7796L8.30344 25.9703C7.88431 26.6912 7.21216 27.2077 6.40921 27.4202C6.14019 27.4913 5.86338 27.5306 5.59474 27.5306C5.053 27.5306 4.51906 27.3888 4.04085 27.1089C3.31705 26.6953 2.79909 26.0251 2.58581 25.2213C2.36845 24.4174 2.47917 23.5821 2.89829 22.8609L11.1585 8.60473L11.186 8.56141V8.55734C11.1266 8.45478 11.0753 8.35629 11.024 8.25409C11.0105 8.22496 10.9969 8.19611 10.9834 8.16739C10.9458 8.08735 10.9086 8.00836 10.8739 7.92715C10.8718 7.92504 10.8708 7.92194 10.8698 7.91887C10.8688 7.91602 10.8679 7.91319 10.8661 7.91123V7.90346C10.8423 7.8483 10.8186 7.79311 10.7989 7.73795C10.7476 7.60799 10.7041 7.47803 10.6644 7.3477C10.6012 7.15479 10.5536 6.96152 10.518 6.76861C10.4942 6.67012 10.4786 6.5757 10.4667 6.47684C10.4667 6.47684 10.47 6.47684 10.4659 6.47277Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/agentops"
|
||||
>
|
||||
Monitor and analyze Mem0 operations with comprehensive AI agent analytics and LLM observability.
|
||||
</Card>
|
||||
<Card
|
||||
title="Camel AI"
|
||||
href="/integrations/camel-ai"
|
||||
@@ -103,27 +86,6 @@ Here are the available integrations for Mem0:
|
||||
>
|
||||
Build RAG applications with LlamaIndex and Mem0.
|
||||
</Card>
|
||||
<Card
|
||||
title="AutoGen"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 96 85"
|
||||
fill="none"
|
||||
>
|
||||
<rect width="96" height="85" rx="6" fill="#2D2D2F" />
|
||||
<path
|
||||
d="M32.6484 28.7109L23.3672 57H15.8906L28.5703 22.875H33.3281L32.6484 28.7109ZM40.3594 57L31.0547 28.7109L30.3047 22.875H35.1094L47.8594 57H40.3594ZM39.9375 44.2969V49.8047H21.9141V44.2969H39.9375ZM77.6484 39.1641V52.6875C77.1172 53.3281 76.2969 54.0234 75.1875 54.7734C74.0781 55.5078 72.6484 56.1406 70.8984 56.6719C69.1484 57.2031 67.0312 57.4688 64.5469 57.4688C62.3438 57.4688 60.3359 57.1094 58.5234 56.3906C56.7109 55.6562 55.1484 54.5859 53.8359 53.1797C52.5391 51.7734 51.5391 50.0547 50.8359 48.0234C50.1328 45.9766 49.7812 43.6406 49.7812 41.0156V38.8828C49.7812 36.2578 50.1172 33.9219 50.7891 31.875C51.4766 29.8281 52.4531 28.1016 53.7188 26.6953C54.9844 25.2891 56.4922 24.2188 58.2422 23.4844C59.9922 22.75 61.9375 22.3828 64.0781 22.3828C67.0469 22.3828 69.4844 22.8672 71.3906 23.8359C73.2969 24.7891 74.75 26.1172 75.75 27.8203C76.7656 29.5078 77.3906 31.4453 77.625 33.6328H70.8047C70.6328 32.4766 70.3047 31.4688 69.8203 30.6094C69.3359 29.75 68.6406 29.0781 67.7344 28.5938C66.8438 28.1094 65.6875 27.8672 64.2656 27.8672C63.0938 27.8672 62.0469 28.1094 61.125 28.5938C60.2188 29.0625 59.4531 29.7578 58.8281 30.6797C58.2031 31.6016 57.7266 32.7422 57.3984 34.1016C57.0703 35.4609 56.9062 37.0391 56.9062 38.8359V41.0156C56.9062 42.7969 57.0781 44.375 57.4219 45.75C57.7656 47.1094 58.2734 48.2578 58.9453 49.1953C59.6328 50.1172 60.4766 50.8125 61.4766 51.2812C62.4766 51.75 63.6406 51.9844 64.9688 51.9844C66.0781 51.9844 67 51.8906 67.7344 51.7031C68.4844 51.5156 69.0859 51.2891 69.5391 51.0234C70.0078 50.7422 70.3672 50.4766 70.6172 50.2266V44.1797H64.1953V39.1641H77.6484Z"
|
||||
fill="white"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/autogen"
|
||||
>
|
||||
Build multi-agent systems with persistent memory capabilities.
|
||||
</Card>
|
||||
<Card
|
||||
title="CrewAI"
|
||||
icon={
|
||||
@@ -205,26 +167,6 @@ Here are the available integrations for Mem0:
|
||||
>
|
||||
Use Mem0 with LangChain Tools for enhanced agent capabilities.
|
||||
</Card>
|
||||
<Card
|
||||
title="Dify"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 200 200"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M40 20 H120 C160 20, 160 180, 120 180 H40 V20"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/dify"
|
||||
>
|
||||
Build AI applications with persistent memory using Dify and Mem0.
|
||||
</Card>
|
||||
<Card
|
||||
title="Livekit"
|
||||
icon={
|
||||
@@ -290,63 +232,6 @@ Here are the available integrations for Mem0:
|
||||
>
|
||||
Build conversational AI agents with memory using Pipecat.
|
||||
</Card>
|
||||
<Card
|
||||
title="Agno"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path d="M8 4h8v12h8" stroke="currentColor" strokeWidth="2" fill="none" transform="rotate(15, 12, 12)"/>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/agno"
|
||||
>
|
||||
Build autonomous agents with memory using Agno framework.
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title="Keywords AI"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.07513 1.1863C9.21663 1.07722 9.39144 1.01009 9.56624 1.01009C9.83261 1.01009 10.0823 1.12756 10.2405 1.33734L15.0101 7.4964V12.4136L16.4335 13.8401C16.7582 14.1673 16.7582 14.7043 16.4335 15.0316C16.1089 15.3588 15.5762 15.3588 15.2515 15.0316L13.3453 13.1016V8.07538L8.92529 2.36944V2.36105C8.64228 2.00024 8.70887 1.4716 9.07513 1.1863ZM18.976 14.4133C18.8344 14.3778 18.7003 14.3042 18.5894 14.1925L16.9163 12.5059C16.7249 12.3129 16.6416 12.0528 16.6749 11.8094V6.88385H16.6499L11.8553 0.691225C11.7282 0.529117 11.6716 0.333133 11.6803 0.140562C11.134 0.0481292 10.5726 0 10 0C4.47715 0 0 4.47715 0 10C0 15.5228 4.47715 20 10 20C13.9387 20 17.3456 17.7229 18.976 14.4133Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/keywords"
|
||||
>
|
||||
Build AI applications with persistent memory and comprehensive LLM observability.
|
||||
</Card>
|
||||
<Card
|
||||
title="Raycast"
|
||||
icon={
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M3 12L21 12M12 3L12 21M7.5 7.5L16.5 16.5M16.5 7.5L7.5 16.5"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
href="/integrations/raycast"
|
||||
>
|
||||
Mem0 Raycast extension for intelligent memory management and retrieval.
|
||||
</Card>
|
||||
<Card
|
||||
title="Mastra"
|
||||
icon={
|
||||
@@ -395,13 +280,6 @@ Here are the available integrations for Mem0:
|
||||
>
|
||||
Integrate Mem0 with Google Agent Development Kit for persistent memory across multi-agent workflows.
|
||||
</Card>
|
||||
<Card
|
||||
title="Flowise"
|
||||
icon="diagram-project"
|
||||
href="/integrations/flowise"
|
||||
>
|
||||
Add persistent Mem0 memory to Flowise chatflows for context-aware conversations in the low-code builder.
|
||||
</Card>
|
||||
<Card
|
||||
title="AWS Bedrock"
|
||||
icon="cloud"
|
||||
|
||||
@@ -1,175 +0,0 @@
|
||||
---
|
||||
title: AgentOps
|
||||
description: "Integrate Mem0 with AgentOps for automatic monitoring, analytics, and real-time tracking of memory operations."
|
||||
---
|
||||
|
||||
Integrate [**Mem0**](https://github.com/mem0ai/mem0) with [AgentOps](https://agentops.ai), a comprehensive monitoring and analytics platform for AI agents. This integration enables automatic tracking and analysis of memory operations, providing insights into agent performance and memory usage patterns.
|
||||
|
||||
## Overview
|
||||
|
||||
1. Automatic monitoring of Mem0 operations and performance metrics
|
||||
2. Real-time tracking of memory add, search, and retrieval operations
|
||||
3. Analytics dashboard with memory usage patterns and insights
|
||||
4. Error tracking and debugging capabilities for memory operations
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with AgentOps, ensure you have:
|
||||
|
||||
1. Installed the required packages:
|
||||
```bash
|
||||
pip install mem0ai agentops python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- [AgentOps API Key](https://app.agentops.ai/dashboard/api-keys)
|
||||
- OpenAI API Key (for LLM operations)
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a> (optional, for cloud operations)
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
The following example demonstrates how to integrate Mem0 with AgentOps monitoring for comprehensive memory operation tracking:
|
||||
|
||||
```python
|
||||
#Import the required libraries for local memory management with Mem0
|
||||
from mem0 import Memory, AsyncMemory
|
||||
import os
|
||||
import asyncio
|
||||
import logging
|
||||
from dotenv import load_dotenv
|
||||
import agentops
|
||||
import openai
|
||||
|
||||
load_dotenv()
|
||||
#Set up environment variables for API keys
|
||||
os.environ["AGENTOPS_API_KEY"] = os.getenv("AGENTOPS_API_KEY")
|
||||
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
|
||||
|
||||
#Set up the configuration for local memory storage and define sample user data.
|
||||
local_config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-5-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
},
|
||||
}
|
||||
}
|
||||
user_id = "alice_demo"
|
||||
agent_id = "assistant_demo"
|
||||
run_id = "session_001"
|
||||
|
||||
sample_messages = [
|
||||
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
|
||||
{"role": "assistant", "content": "How about a thriller? They can be quite engaging."},
|
||||
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future.",
|
||||
},
|
||||
]
|
||||
|
||||
sample_preferences = [
|
||||
"I prefer dark roast coffee over light roast",
|
||||
"I exercise every morning at 6 AM",
|
||||
"I'm vegetarian and avoid all meat products",
|
||||
"I love reading science fiction novels",
|
||||
"I work in software engineering",
|
||||
]
|
||||
|
||||
#This function demonstrates sequential memory operations using the synchronous Memory class
|
||||
def demonstrate_sync_memory(local_config, sample_messages, sample_preferences, user_id):
|
||||
"""
|
||||
Demonstrate synchronous Memory class operations.
|
||||
"""
|
||||
|
||||
agentops.start_trace("mem0_memory_example", tags=["mem0_memory_example"])
|
||||
try:
|
||||
|
||||
memory = Memory.from_config(local_config)
|
||||
|
||||
result = memory.add(
|
||||
sample_messages, user_id=user_id, metadata={"category": "movie_preferences", "session": "demo"}
|
||||
)
|
||||
|
||||
for i, preference in enumerate(sample_preferences):
|
||||
result = memory.add(preference, user_id=user_id, metadata={"type": "preference", "index": i})
|
||||
|
||||
search_queries = [
|
||||
"What movies does the user like?",
|
||||
"What are the user's food preferences?",
|
||||
"When does the user exercise?",
|
||||
]
|
||||
|
||||
for query in search_queries:
|
||||
results = memory.search(query, filters={"user_id": user_id})
|
||||
|
||||
if results and "results" in results:
|
||||
for j, result in enumerate(results['results']):
|
||||
print(f"Result {j+1}: {result.get('memory', 'N/A')}")
|
||||
else:
|
||||
print("No results found")
|
||||
|
||||
all_memories = memory.get_all(filters={"user_id": user_id})
|
||||
if all_memories and "results" in all_memories:
|
||||
print(f"Total memories: {len(all_memories['results'])}")
|
||||
|
||||
delete_all_result = memory.delete_all(user_id=user_id)
|
||||
print(f"Delete all result: {delete_all_result}")
|
||||
|
||||
agentops.end_trace(end_state="success")
|
||||
except Exception as e:
|
||||
agentops.end_trace(end_state="error")
|
||||
|
||||
# Execute sync demonstrations
|
||||
demonstrate_sync_memory(local_config, sample_messages, sample_preferences, user_id)
|
||||
|
||||
```
|
||||
|
||||
For detailed information on this integration, refer to the official [Agentops Mem0 integration documentation](https://docs.agentops.ai/v2/integrations/mem0).
|
||||
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Automatic Operation Tracking
|
||||
|
||||
AgentOps automatically monitors all Mem0 operations:
|
||||
|
||||
- **Memory Operations**: Track add, search, get_all, delete operations and much more
|
||||
- **Performance Metrics**: Monitor response times and success rates
|
||||
- **Error Tracking**: Capture and analyze operation failures
|
||||
|
||||
### 2. Real-time Analytics Dashboard
|
||||
|
||||
Access comprehensive analytics through the AgentOps dashboard:
|
||||
|
||||
- **Usage Patterns**: Visualize memory usage trends over time
|
||||
- **User Behavior**: Analyze how different users interact with memory
|
||||
- **Performance Insights**: Identify bottlenecks and optimization opportunities
|
||||
|
||||
### 3. Session Management
|
||||
|
||||
Organize your monitoring with structured sessions:
|
||||
|
||||
- **Session Tracking**: Group related operations into logical sessions
|
||||
- **Success/Failure Rates**: Track session outcomes for reliability monitoring
|
||||
- **Custom Metadata**: Add context to sessions for better analysis
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Initialize Early**: Always initialize AgentOps before importing Mem0 classes
|
||||
2. **Session Management**: Use meaningful session names and end sessions appropriately
|
||||
3. **Error Handling**: Wrap operations in try-catch blocks and report failures
|
||||
4. **Tagging**: Use tags to organize different types of memory operations
|
||||
5. **Environment Separation**: Use different projects or tags for dev/staging/prod
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
|
||||
Monitor multi-agent CrewAI systems
|
||||
</Card>
|
||||
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
|
||||
Track LangChain agent performance
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
---
|
||||
title: Agno
|
||||
description: "Add persistent multimodal memory to Agno-based agents using Mem0 for text and image interactions."
|
||||
---
|
||||
|
||||
This integration of [**Mem0**](https://github.com/mem0ai/mem0) with [Agno](https://github.com/agno-agi/agno) enables persistent, multimodal memory for Agno-based agents - improving personalization, context awareness, and continuity across conversations.
|
||||
|
||||
## Overview
|
||||
|
||||
1. Store and retrieve memories from Mem0 within Agno agents
|
||||
2. Support for multimodal interactions (text and images)
|
||||
3. Semantic search for relevant past conversations
|
||||
4. Personalized responses based on user history
|
||||
5. One-line memory integration via `Mem0Tools`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with Agno, ensure you have:
|
||||
|
||||
1. Installed the required packages:
|
||||
```bash
|
||||
pip install agno mem0ai python-dotenv
|
||||
```
|
||||
|
||||
2. Valid API keys:
|
||||
- <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key</a>
|
||||
- OpenAI API Key (for the agent model)
|
||||
|
||||
## Quick Integration (Using `Mem0Tools`)
|
||||
|
||||
The simplest way to integrate Mem0 with Agno Agents is to use Mem0 as a tool using built-in `Mem0Tools`:
|
||||
|
||||
```python
|
||||
from agno.agent import Agent
|
||||
from agno.models.openai import OpenAIChat
|
||||
from agno.tools.mem0 import Mem0Tools
|
||||
|
||||
agent = Agent(
|
||||
name="Memory Agent",
|
||||
model=OpenAIChat(id="gpt-5-mini"),
|
||||
tools=[Mem0Tools()],
|
||||
description="An assistant that remembers and personalizes using Mem0 memory."
|
||||
)
|
||||
```
|
||||
|
||||
This enables memory functionality out of the box:
|
||||
|
||||
- **Persistent memory writing**: `Mem0Tools` uses `MemoryClient.add(...)` to store messages from user-agent interactions, including optional metadata such as user ID or session.
|
||||
- **Contextual memory search**: Compatible queries use `MemoryClient.search(...)` to retrieve relevant past messages, improving contextual understanding.
|
||||
- **Multimodal support**: Both text and image inputs are supported, allowing richer memory records.
|
||||
|
||||
> `Mem0Tools` uses the `MemoryClient` under the hood and requires no additional setup. You can customize its behavior by modifying your tools list or extending it in code.
|
||||
|
||||
## Full Manual Example
|
||||
|
||||
> Note: Mem0 can also be used with Agno Agents as a separate memory layer.
|
||||
|
||||
The following example demonstrates how to create an Agno agent with Mem0 memory integration, including support for image processing:
|
||||
|
||||
```python
|
||||
import base64
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
from agno.agent import Agent
|
||||
from agno.media import Image
|
||||
from agno.models.openai import OpenAIChat
|
||||
from mem0 import MemoryClient
|
||||
|
||||
# Initialize the Mem0 client
|
||||
client = MemoryClient()
|
||||
|
||||
# Define the agent
|
||||
agent = Agent(
|
||||
name="Personal Agent",
|
||||
model=OpenAIChat(id="gpt-4"),
|
||||
description="You are a helpful personal agent that helps me with day to day activities."
|
||||
"You can process both text and images.",
|
||||
markdown=True
|
||||
)
|
||||
|
||||
|
||||
def chat_user(
|
||||
user_input: Optional[str] = None,
|
||||
user_id: str = "alex",
|
||||
image_path: Optional[str] = None
|
||||
) -> str:
|
||||
"""
|
||||
Handle user input with memory integration, supporting both text and images.
|
||||
|
||||
Args:
|
||||
user_input: The user's text input
|
||||
user_id: Unique identifier for the user
|
||||
image_path: Path to an image file if provided
|
||||
|
||||
Returns:
|
||||
The agent's response as a string
|
||||
"""
|
||||
if image_path:
|
||||
# Convert image to base64
|
||||
with open(image_path, "rb") as image_file:
|
||||
base64_image = base64.b64encode(image_file.read()).decode("utf-8")
|
||||
|
||||
# Create message objects for text and image
|
||||
messages = []
|
||||
|
||||
if user_input:
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": user_input
|
||||
})
|
||||
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": {
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/jpeg;base64,{base64_image}"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
# Store messages in memory
|
||||
client.add(messages, user_id=user_id)
|
||||
print("✅ Image and text stored in memory.")
|
||||
|
||||
if user_input:
|
||||
# Search for relevant memories
|
||||
memories = client.search(user_input, filters={"user_id": user_id})
|
||||
memory_context = "\n".join(f"- {m['memory']}" for m in memories['results'])
|
||||
|
||||
# Construct the prompt
|
||||
prompt = f"""
|
||||
You are a helpful personal assistant who helps users with their day-to-day activities and keeps track of everything.
|
||||
|
||||
Your task is to:
|
||||
1. Analyze the given image (if present) and extract meaningful details to answer the user's question.
|
||||
2. Use your past memory of the user to personalize your answer.
|
||||
3. Combine the image content and memory to generate a helpful, context-aware response.
|
||||
|
||||
Here is what I remember about the user:
|
||||
{memory_context}
|
||||
|
||||
User question:
|
||||
{user_input}
|
||||
"""
|
||||
# Get response from agent
|
||||
if image_path:
|
||||
response = agent.run(prompt, images=[Image(filepath=Path(image_path))])
|
||||
else:
|
||||
response = agent.run(prompt)
|
||||
|
||||
# Store the interaction in memory
|
||||
interaction_message = [{"role": "user", "content": f"User: {user_input}\nAssistant: {response.content}"}]
|
||||
client.add(interaction_message, user_id=user_id)
|
||||
return response.content
|
||||
|
||||
return "No user input or image provided."
|
||||
|
||||
|
||||
# Example Usage
|
||||
if __name__ == "__main__":
|
||||
response = chat_user(
|
||||
"I like to travel and my favorite destination is London",
|
||||
image_path="travel_items.jpeg",
|
||||
user_id="alex"
|
||||
)
|
||||
print(response)
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Multimodal Memory Storage
|
||||
|
||||
The integration supports storing both text and image data:
|
||||
|
||||
- **Text Storage**: Conversation history is saved in a structured format
|
||||
- **Image Analysis**: Agents can analyze images and store visual information
|
||||
- **Combined Context**: Memory retrieval combines both text and visual data
|
||||
|
||||
### 2. Personalized Agent Responses
|
||||
|
||||
Improve your agent's context awareness:
|
||||
|
||||
- **Memory Retrieval**: Semantic search finds relevant past interactions
|
||||
- **User Preferences**: Personalize responses based on stored user information
|
||||
- **Continuity**: Maintain conversation threads across multiple sessions
|
||||
|
||||
### 3. Flexible Configuration
|
||||
|
||||
Customize the integration to your needs:
|
||||
|
||||
- **Use `Mem0Tools()`** for drop-in memory support
|
||||
- **Use `MemoryClient` directly** for advanced control
|
||||
- **User Identification**: Organize memories by user ID
|
||||
- **Memory Search**: Configure search relevance and result count
|
||||
- **Memory Formatting**: Support for various OpenAI message formats
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
|
||||
Build agents with OpenAI SDK and Mem0
|
||||
</Card>
|
||||
<Card title="Mastra Integration" icon="star" href="/integrations/mastra">
|
||||
Create intelligent agents with Mastra framework
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
---
|
||||
title: AutoGen
|
||||
description: "Build conversational AI agents with AutoGen and Mem0 for context-aware, personalized interactions."
|
||||
---
|
||||
|
||||
Build conversational AI agents with memory capabilities. This integration combines AutoGen for creating AI agents with Mem0 for memory management, enabling context-aware and personalized interactions.
|
||||
|
||||
## Overview
|
||||
|
||||
This guide demonstrates creating a conversational AI system with memory. We'll build a customer service bot that can recall previous interactions and provide personalized responses.
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Install necessary libraries:
|
||||
|
||||
```bash
|
||||
pip install autogen mem0ai openai python-dotenv
|
||||
```
|
||||
|
||||
First, we'll import the necessary libraries and set up our configurations.
|
||||
|
||||
<Note>Remember to get the Mem0 API key from <a href="https://app.mem0.ai" rel="nofollow">Mem0 Platform</a>.</Note>
|
||||
|
||||
```python
|
||||
import os
|
||||
from autogen import ConversableAgent
|
||||
from mem0 import MemoryClient
|
||||
from openai import OpenAI
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# Configuration
|
||||
# OPENAI_API_KEY = 'sk-xxx' # Replace with your actual OpenAI API key
|
||||
# MEM0_API_KEY = 'your-mem0-key' # Replace with your actual Mem0 API key from https://app.mem0.ai
|
||||
USER_ID = "alice"
|
||||
|
||||
# Set up OpenAI API key
|
||||
OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY')
|
||||
# os.environ['MEM0_API_KEY'] = MEM0_API_KEY
|
||||
|
||||
# Initialize Mem0 and AutoGen agents
|
||||
memory_client = MemoryClient()
|
||||
agent = ConversableAgent(
|
||||
"chatbot",
|
||||
llm_config={"config_list": [{"model": "gpt-4", "api_key": OPENAI_API_KEY}]},
|
||||
code_execution_config=False,
|
||||
human_input_mode="NEVER",
|
||||
)
|
||||
```
|
||||
|
||||
## Storing Conversations in Memory
|
||||
|
||||
Add conversation history to Mem0 for future reference:
|
||||
|
||||
```python
|
||||
conversation = [
|
||||
{"role": "assistant", "content": "Hi, I'm Best Buy's chatbot! How can I help you?"},
|
||||
{"role": "user", "content": "I'm seeing horizontal lines on my TV."},
|
||||
{"role": "assistant", "content": "I'm sorry to hear that. Can you provide your TV model?"},
|
||||
{"role": "user", "content": "It's a Sony - 77\" Class BRAVIA XR A80K OLED 4K UHD Smart Google TV"},
|
||||
{"role": "assistant", "content": "Thank you for the information. Let's troubleshoot this issue..."}
|
||||
]
|
||||
|
||||
memory_client.add(messages=conversation, user_id=USER_ID)
|
||||
print("Conversation added to memory.")
|
||||
```
|
||||
|
||||
## Retrieving and Using Memory
|
||||
|
||||
Create a function to get context-aware responses based on user's question and previous interactions:
|
||||
|
||||
```python
|
||||
def get_context_aware_response(question):
|
||||
relevant_memories = memory_client.search(question, filters={"user_id": USER_ID})
|
||||
context = "\n".join([m["memory"] for m in relevant_memories.get('results', [])])
|
||||
|
||||
prompt = f"""Answer the user question considering the previous interactions:
|
||||
Previous interactions:
|
||||
{context}
|
||||
|
||||
Question: {question}
|
||||
"""
|
||||
|
||||
reply = agent.generate_reply(messages=[{"content": prompt, "role": "user"}])
|
||||
return reply
|
||||
|
||||
# Example usage
|
||||
question = "What was the issue with my TV?"
|
||||
answer = get_context_aware_response(question)
|
||||
print("Context-aware answer:", answer)
|
||||
```
|
||||
|
||||
## Multi-Agent Conversation
|
||||
|
||||
For more complex scenarios, you can create multiple agents:
|
||||
|
||||
```python
|
||||
manager = ConversableAgent(
|
||||
"manager",
|
||||
system_message="You are a manager who helps in resolving complex customer issues.",
|
||||
llm_config={"config_list": [{"model": "gpt-4", "api_key": OPENAI_API_KEY}]},
|
||||
human_input_mode="NEVER"
|
||||
)
|
||||
|
||||
def escalate_to_manager(question):
|
||||
relevant_memories = memory_client.search(question, filters={"user_id": USER_ID})
|
||||
context = "\n".join([m["memory"] for m in relevant_memories.get('results', [])])
|
||||
|
||||
prompt = f"""
|
||||
Context from previous interactions:
|
||||
{context}
|
||||
|
||||
Customer question: {question}
|
||||
|
||||
As a manager, how would you address this issue?
|
||||
"""
|
||||
|
||||
manager_response = manager.generate_reply(messages=[{"content": prompt, "role": "user"}])
|
||||
return manager_response
|
||||
|
||||
# Example usage
|
||||
complex_question = "I'm not satisfied with the troubleshooting steps. What else can be done?"
|
||||
manager_answer = escalate_to_manager(complex_question)
|
||||
print("Manager's response:", manager_answer)
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
By integrating AutoGen with Mem0, you've created a conversational AI system with memory capabilities. This example demonstrates a customer service bot that can recall previous interactions and provide context-aware responses, with the ability to escalate complex issues to a manager agent.
|
||||
|
||||
This integration enables the creation of more intelligent and personalized AI agents for various applications, such as customer support, virtual assistants, and interactive chatbots.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
|
||||
Build multi-agent systems with CrewAI and Mem0
|
||||
</Card>
|
||||
<Card title="LangGraph Integration" icon="diagram-project" href="/integrations/langgraph">
|
||||
Create stateful workflows with LangGraph
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -237,7 +237,7 @@ By adding Mem0 as a memory store in ChatDev, your multi-agent workflows gain per
|
||||
<Card title="CrewAI Integration" icon="users" href="/integrations/crewai">
|
||||
Build multi-agent systems with CrewAI and Mem0
|
||||
</Card>
|
||||
<Card title="AutoGen Integration" icon="robot" href="/integrations/autogen">
|
||||
Build conversational agents with AutoGen and Mem0
|
||||
<Card title="OpenAI Agents SDK" icon="robot" href="/integrations/openai-agents-sdk">
|
||||
Build conversational agents with OpenAI Agents SDK and Mem0
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -32,19 +32,12 @@ export MEM0_API_KEY="m0-your-api-key"
|
||||
|
||||
### Option A — Plugin Marketplace (Recommended)
|
||||
|
||||
Install the full plugin including MCP server, lifecycle hooks, and SDK skill.
|
||||
Install the full plugin including MCP server, lifecycle hooks, and SDK skill:
|
||||
|
||||
1. Add the Mem0 marketplace:
|
||||
|
||||
```
|
||||
/plugin marketplace add mem0ai/mem0
|
||||
```
|
||||
|
||||
2. Install the plugin:
|
||||
|
||||
```
|
||||
/plugin install mem0@mem0-plugins
|
||||
```
|
||||
```
|
||||
/plugin marketplace add mem0ai/mem0
|
||||
/plugin install mem0@mem0-plugins
|
||||
```
|
||||
|
||||
**Claude Cowork desktop app:** Open the Cowork tab, click **Customize** in the sidebar, click **Browse plugins**, and install Mem0.
|
||||
|
||||
|
||||
@@ -162,8 +162,8 @@ if __name__ == "__main__":
|
||||
By combining CrewAI with Mem0, you can create sophisticated AI systems that maintain context and provide personalized experiences while leveraging the power of autonomous agents.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="AutoGen Integration" icon="users" href="/integrations/autogen">
|
||||
Build multi-agent systems with AutoGen and Mem0
|
||||
<Card title="OpenAI Agents SDK" icon="users" href="/integrations/openai-agents-sdk">
|
||||
Build multi-agent systems with OpenAI Agents SDK and Mem0
|
||||
</Card>
|
||||
<Card title="LangGraph Integration" icon="diagram-project" href="/integrations/langgraph">
|
||||
Create stateful agent workflows with memory
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
---
|
||||
title: Dify
|
||||
description: "Integrate Mem0 as a plugin in Dify AI workflows for persistent conversation storage and retrieval."
|
||||
---
|
||||
|
||||
# Integrating Mem0 with Dify AI
|
||||
|
||||
Mem0 brings a robust memory layer to Dify AI, empowering your AI agents with persistent conversation storage and retrieval capabilities. With Mem0, your Dify applications gain the ability to recall past interactions and maintain context, ensuring more natural and insightful conversations.
|
||||
|
||||
---
|
||||
|
||||
## How to Integrate Mem0 in Your Dify Workflow
|
||||
|
||||
1. **Install the Mem0 Plugin:**
|
||||
Head to the [Dify Marketplace](https://marketplace.dify.ai/plugins/yevanchen/mem0) and install the Mem0 plugin. This is your first step toward adding intelligent memory to your AI applications.
|
||||
|
||||
2. **Create or Open Your Dify Project:**
|
||||
Whether you're starting fresh or updating an existing project, simply create or open your Dify workspace.
|
||||
|
||||
3. **Add the Mem0 Plugin to Your Project:**
|
||||
Within your project, add the Mem0 plugin. This integration connects Mem0’s memory management capabilities directly to your Dify application.
|
||||
|
||||
4. **Configure Your Mem0 Settings:**
|
||||
Customize Mem0 to suit your needs—set preferences for how conversation history is stored, the search parameters, and any other context-aware features.
|
||||
|
||||
5. **Leverage Mem0 in Your Workflow:**
|
||||
Use Mem0 to store every conversation turn and retrieve past interactions seamlessly. This integration ensures that your AI agents can refer back to important context, making multi-turn dialogues more effective and user-centric.
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
Enhance your Dify-powered AI with Mem0 and transform your conversational experiences. Start integrating intelligent memory management today and give your agents the context they need to excel!
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Flowise Integration" icon="share-nodes" href="/integrations/flowise">
|
||||
Build visual AI workflows with Flowise
|
||||
</Card>
|
||||
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
|
||||
Create LangChain-powered applications
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
title: Flowise
|
||||
description: "Add persistent Mem0 memory to Flowise chatflows for context-aware conversations in the low-code builder."
|
||||
---
|
||||
|
||||
The [**Mem0 Memory**](https://github.com/mem0ai/mem0) integration with [Flowise](https://github.com/FlowiseAI/Flowise) enables persistent memory capabilities for your AI chatflows. [Flowise](https://flowiseai.com/) is an open-source low-code tool for developers to build customized LLM orchestration flows & AI agents using a drag & drop interface.
|
||||
|
||||
## Overview
|
||||
|
||||
1. Provides persistent memory storage for Flowise chatflows
|
||||
2. Seamless integration with existing Flowise templates
|
||||
3. Compatible with various LLM nodes in Flowise
|
||||
4. Supports custom memory configurations
|
||||
5. Easy to set up and manage
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before setting up Mem0 with Flowise, ensure you have:
|
||||
|
||||
1. [Flowise installed](https://github.com/FlowiseAI/Flowise#⚡quick-start) (NodeJS >= 18.15.0 required):
|
||||
```bash
|
||||
npm install -g flowise
|
||||
npx flowise start
|
||||
```
|
||||
|
||||
2. Access to the Flowise UI at http://localhost:3000
|
||||
3. Basic familiarity with [Flowise's LLM orchestration](https://flowiseai.com/#features) concepts
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
### 1. Set Up Flowise
|
||||
|
||||
1. Open the Flowise application and create a new canvas, or select a template from the Flowise marketplace.
|
||||
2. In this example, we use the **Conversation Chain** template.
|
||||
3. Replace the default **Buffer Memory** with **Mem0 Memory**.
|
||||
|
||||

|
||||
|
||||
### 2. Obtain Your Mem0 API Key
|
||||
|
||||
1. Navigate to the <a href="https://app.mem0.ai/dashboard/api-keys" rel="nofollow">Mem0 API Key dashboard</a>.
|
||||
2. Generate or copy your existing Mem0 API Key.
|
||||
|
||||

|
||||
|
||||
### 3. Configure Mem0 Credentials
|
||||
|
||||
1. Enter the **Mem0 API Key** in the Mem0 Credentials section.
|
||||
2. Configure additional settings as needed:
|
||||
|
||||
```typescript
|
||||
{
|
||||
"apiKey": "m0-xxx",
|
||||
"userId": "user-123", // Optional: Specify user ID
|
||||
"projectId": "proj-xxx", // Optional: Specify project ID
|
||||
"orgId": "org-xxx" // Optional: Specify organization ID
|
||||
}
|
||||
```
|
||||
|
||||
<figure>
|
||||
<img src="https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/creds.png" alt="Mem0 Credentials" />
|
||||
<figcaption>Configure API Credentials</figcaption>
|
||||
</figure>
|
||||
|
||||
## Memory Features
|
||||
|
||||
### 1. Basic Memory Storage
|
||||
|
||||
Test your memory configuration:
|
||||
|
||||
1. Save your Flowise configuration
|
||||
2. Run a test chat and store some information
|
||||
3. Verify the stored memories in the <a href="https://app.mem0.ai/dashboard/requests" rel="nofollow">Mem0 Dashboard</a>
|
||||
|
||||

|
||||
|
||||
### 2. Memory Retention
|
||||
|
||||
Validate memory persistence:
|
||||
|
||||
1. Clear the chat history in Flowise
|
||||
2. Ask a question about previously stored information
|
||||
3. Confirm that the AI remembers the context
|
||||
|
||||

|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Memory Settings
|
||||
|
||||

|
||||
|
||||
Available settings include:
|
||||
|
||||
1. **Search Only Mode**: Enable memory retrieval without creating new memories
|
||||
2. **Mem0 Entities**: Configure identifiers:
|
||||
- `user_id`: Unique identifier for each user
|
||||
- `run_id`: Specific conversation session ID
|
||||
- `app_id`: Application identifier
|
||||
- `agent_id`: AI agent identifier
|
||||
3. **Project ID**: Assign memories to specific projects
|
||||
4. **Organization ID**: Organize memories by organization
|
||||
|
||||
### Platform Configuration
|
||||
|
||||
Additional settings available in <a href="https://app.mem0.ai/dashboard/project-settings" rel="nofollow">Mem0 Project Settings</a>:
|
||||
|
||||
1. **Custom Instructions**: Define memory extraction rules
|
||||
2. **Expiration Date**: Set automatic memory cleanup periods
|
||||
|
||||

|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **User Identification**: Use consistent `user_id` values for reliable memory retrieval
|
||||
2. **Memory Organization**: Utilize projects and organizations for better memory management
|
||||
3. **Regular Maintenance**: Monitor and clean up unused memories periodically
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="LangChain Integration" icon="link" href="/integrations/langchain">
|
||||
Build LangChain-powered flows with memory
|
||||
</Card>
|
||||
<Card title="Dify Integration" icon="blocks" href="/integrations/dify">
|
||||
Create AI workflows with Dify platform
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
---
|
||||
title: Keywords AI
|
||||
description: "Combine Mem0 persistent memory with Keywords AI observability for tracked, cost-optimized AI applications."
|
||||
---
|
||||
|
||||
Build AI applications with persistent memory and comprehensive LLM observability by integrating Mem0 with Keywords AI.
|
||||
|
||||
## Overview
|
||||
|
||||
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. Keywords AI provides complete LLM observability.
|
||||
|
||||
Combining Mem0 with Keywords AI allows you to:
|
||||
1. Add persistent memory to your AI applications
|
||||
2. Track interactions across sessions
|
||||
3. Monitor memory usage and retrieval with Keywords AI observability
|
||||
4. Optimize token usage and reduce costs
|
||||
|
||||
<Note>
|
||||
You can get your Mem0 API key from the <a href="https://app.mem0.ai/" rel="nofollow">Mem0 dashboard</a>.
|
||||
</Note>
|
||||
|
||||
## Setup and Configuration
|
||||
|
||||
Install the necessary libraries:
|
||||
|
||||
```bash
|
||||
pip install mem0ai keywordsai-sdk
|
||||
```
|
||||
|
||||
Set up your environment variables:
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
# Set your API keys
|
||||
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
|
||||
os.environ["KEYWORDSAI_API_KEY"] = "your-keywords-api-key"
|
||||
os.environ["KEYWORDSAI_BASE_URL"] = "https://api.keywordsai.co/api/"
|
||||
```
|
||||
|
||||
## Basic Integration Example
|
||||
|
||||
Here's a simple example of using Mem0 with Keywords AI:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
import os
|
||||
|
||||
# Configuration
|
||||
api_key = os.getenv("MEM0_API_KEY")
|
||||
keywordsai_api_key = os.getenv("KEYWORDSAI_API_KEY")
|
||||
base_url = os.getenv("KEYWORDSAI_BASE_URL") # "https://api.keywordsai.co/api/"
|
||||
|
||||
# Set up Mem0 with Keywords AI as the LLM provider
|
||||
config = {
|
||||
"llm": {
|
||||
"provider": "openai",
|
||||
"config": {
|
||||
"model": "gpt-5-mini",
|
||||
"temperature": 0.0,
|
||||
"api_key": keywordsai_api_key,
|
||||
"openai_base_url": base_url,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# Initialize Memory
|
||||
memory = Memory.from_config(config)
|
||||
|
||||
# Add a memory
|
||||
result = memory.add(
|
||||
"I like to take long walks on weekends.",
|
||||
user_id="alice",
|
||||
metadata={"category": "hobbies"},
|
||||
)
|
||||
|
||||
print(result)
|
||||
```
|
||||
|
||||
## Advanced Integration with OpenAI SDK
|
||||
|
||||
For more advanced use cases, you can integrate Keywords AI with Mem0 through the OpenAI SDK:
|
||||
|
||||
```python
|
||||
from openai import OpenAI
|
||||
import os
|
||||
import json
|
||||
|
||||
# Initialize client
|
||||
client = OpenAI(
|
||||
api_key=os.environ.get("KEYWORDSAI_API_KEY"),
|
||||
base_url=os.environ.get("KEYWORDSAI_BASE_URL"),
|
||||
)
|
||||
|
||||
# Sample conversation messages
|
||||
messages = [
|
||||
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
|
||||
{"role": "assistant", "content": "How about thriller movies? They can be quite engaging."},
|
||||
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
|
||||
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
|
||||
]
|
||||
|
||||
# Add memory and generate a response
|
||||
response = client.chat.completions.create(
|
||||
model="openai/gpt-4.1-nano",
|
||||
messages=messages,
|
||||
extra_body={
|
||||
"mem0_params": {
|
||||
"user_id": "test_user",
|
||||
"api_key": os.environ.get("MEM0_API_KEY"),
|
||||
"add_memories": {
|
||||
"messages": messages,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
print(json.dumps(response.model_dump(), indent=4))
|
||||
```
|
||||
|
||||
For detailed information on this integration, refer to the official [Keywords AI Mem0 integration documentation](https://docs.keywordsai.co/integration/development-frameworks/mem0).
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Memory Integration**: Store and retrieve relevant information from past interactions
|
||||
2. **LLM Observability**: Track memory usage and retrieval patterns with Keywords AI
|
||||
3. **Session Persistence**: Maintain context across multiple user sessions
|
||||
4. **Cost Optimization**: Reduce token usage through efficient memory retrieval
|
||||
|
||||
## Conclusion
|
||||
|
||||
Integrating Mem0 with Keywords AI provides a powerful combination for building AI applications with persistent memory and comprehensive observability. This integration enables more personalized user experiences while providing insights into your application's memory usage.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
|
||||
Build monitored agents with OpenAI SDK
|
||||
</Card>
|
||||
<Card title="AgentOps Integration" icon="chart-line" href="/integrations/agentops">
|
||||
Monitor agent performance with AgentOps
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
title: "Raycast Extension"
|
||||
description: "Mem0 Raycast extension for intelligent memory management"
|
||||
---
|
||||
|
||||
Mem0 is a self-improving memory layer for LLM applications, enabling personalized AI experiences that save costs and delight users. This extension lets you store and retrieve text snippets using Mem0's intelligent memory system. Find Mem0 in [Raycast Store](https://www.raycast.com/dev_khant/mem0) for using it.
|
||||
|
||||
## Getting Started
|
||||
|
||||
**Get your API Key**: You'll need a Mem0 API key to use this extension:
|
||||
|
||||
a. Sign up at <a href="https://app.mem0.ai" rel="nofollow">app.mem0.ai</a>
|
||||
|
||||
b. Navigate to your API Keys page
|
||||
|
||||
c. Copy your API key
|
||||
|
||||
d. Enter this key in the extension preferences
|
||||
|
||||
**Basic Usage**:
|
||||
|
||||
- Store memories and text snippets
|
||||
- Retrieve context-aware information
|
||||
- Manage persistent user preferences
|
||||
- Search through stored memories
|
||||
|
||||
## Features
|
||||
|
||||
**Remember Everything**: Never lose important information. Store notes, preferences, and conversations that your AI can recall later.
|
||||
|
||||
**Smart Connections**: Automatically links related topics, helping you discover useful connections.
|
||||
|
||||
**Cost Saver**: Spend less on AI usage by efficiently retrieving relevant information instead of regenerating responses.
|
||||
|
||||
## How This Helps You
|
||||
|
||||
**More Personal Experience**: Your AI remembers your preferences and past conversations, making interactions feel more natural.
|
||||
|
||||
**Learn Your Style**: Adapts to how you work and what you like, becoming more helpful over time.
|
||||
|
||||
**No More Repetition**: Stop explaining the same things repeatedly. Your AI remembers your context and preferences.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="OpenAI Agents SDK" icon="cube" href="/integrations/openai-agents-sdk">
|
||||
Build desktop AI agents with OpenAI SDK
|
||||
</Card>
|
||||
<Card title="Mastra Integration" icon="star" href="/integrations/mastra">
|
||||
Create intelligent desktop workflows
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -231,8 +231,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
- [LangChain Tools](https://docs.mem0.ai/integrations/langchain-tools) [Both]: Use when Mem0 should be exposed as a LangChain tool.
|
||||
- [LlamaIndex](https://docs.mem0.ai/integrations/llama-index) [Both]: Use when layering memory on a LlamaIndex RAG app.
|
||||
- [CrewAI](https://docs.mem0.ai/integrations/crewai) [Both]: Use when building CrewAI multi-agent systems.
|
||||
- [AutoGen](https://docs.mem0.ai/integrations/autogen) [Both]: Use when the user is on Microsoft AutoGen.
|
||||
- [Agno](https://docs.mem0.ai/integrations/agno) [Both]: Use when the user is on Agno.
|
||||
- [Camel AI](https://docs.mem0.ai/integrations/camel-ai) [Both]: Use when the user is on Camel AI.
|
||||
- [ChatDev](https://docs.mem0.ai/integrations/chatdev) [Both]: Use when the user is on ChatDev.
|
||||
- [Hermes](https://docs.mem0.ai/integrations/hermes) [Both]: Use when the user is on Hermes.
|
||||
@@ -255,12 +253,6 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f
|
||||
### Cloud & Infrastructure
|
||||
- [AWS Bedrock](https://docs.mem0.ai/integrations/aws-bedrock) [Both]: Use when the user is on AWS Bedrock managed AI services.
|
||||
|
||||
### Developer Tools
|
||||
- [Dify](https://docs.mem0.ai/integrations/dify) [Both]: Use when the user is on Dify LLMOps.
|
||||
- [Flowise](https://docs.mem0.ai/integrations/flowise) [Both]: Use when the user is on Flowise no-code.
|
||||
- [AgentOps](https://docs.mem0.ai/integrations/agentops) [Both]: Use when tracking agent observability with memory metadata.
|
||||
- [Keywords AI](https://docs.mem0.ai/integrations/keywords) [Both]: Use when monitoring with Keywords AI.
|
||||
- [Raycast](https://docs.mem0.ai/integrations/raycast) [Both]: Use when the user wants quick memory access via Raycast.
|
||||
|
||||
## Cookbooks
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: 'Full Stack'
|
||||
---
|
||||
|
||||
The Full Stack app example can be found [here](https://github.com/mem0ai/mem0/tree/main/embedchain/examples/full_stack).
|
||||
|
||||
This guide will help you setup the full stack app on your local machine.
|
||||
|
||||
### 🐳 Docker Setup
|
||||
|
||||
- Create a `docker-compose.yml` file and paste the following code in it.
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
backend:
|
||||
container_name: embedchain-backend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: backend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
frontend:
|
||||
container_name: embedchain-frontend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: frontend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- "backend"
|
||||
```
|
||||
|
||||
- Run the following command,
|
||||
|
||||
```bash
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
📝 Note: The build command might take a while to install all the packages depending on your system resources.
|
||||
|
||||

|
||||
|
||||
### 🚀 Usage Instructions
|
||||
|
||||
- Go to [http://localhost:3000/](http://localhost:3000/) in your browser to view the dashboard.
|
||||
- Add your `OpenAI API key` 🔑 in the Settings.
|
||||
- Create a new bot and you'll be navigated to its page.
|
||||
- Here you can add your data sources and then chat with the bot.
|
||||
|
||||
🎉 Happy Chatting! 🎉
|
||||
@@ -182,6 +182,7 @@
|
||||
"examples/rest-api/check-status"
|
||||
]
|
||||
},
|
||||
"examples/full_stack",
|
||||
"examples/openai-assistant",
|
||||
"examples/opensource-assistant",
|
||||
"examples/nextjs-assistant",
|
||||
|
||||
@@ -17,6 +17,9 @@ Chatbots, especially those powered by Large Language Models (LLMs), have a wide
|
||||
Embedchain provides the right set of tools to create chatbots for the above use cases. Refer to the following examples of chatbots on and you can built on top of these examples:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Full Stack Chatbot" href="/examples/full_stack" icon="link">
|
||||
Learn to integrate a chatbot within a full-stack application.
|
||||
</Card>
|
||||
<Card title="Custom GPT Creation" href="https://app.embedchain.ai/create-your-gpt/" target="_blank" icon="link">
|
||||
Build a tailored GPT chatbot suited for your specific needs.
|
||||
</Card>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
gradio>=4.14.0
|
||||
gradio==4.11.0
|
||||
embedchain
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
chainlit==0.7.700
|
||||
embedchain==0.1.57
|
||||
embedchain==0.1.31
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
discord==2.3.1
|
||||
embedchain==0.1.57
|
||||
embedchain==0.0.58
|
||||
python-dotenv==1.0.0
|
||||
@@ -0,0 +1 @@
|
||||
.git
|
||||
@@ -0,0 +1,18 @@
|
||||
## 🐳 Docker Setup
|
||||
|
||||
- To setup full stack app using docker, run the following command inside this folder using your terminal.
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
📝 Note: The build command might take a while to install all the packages depending on your system resources.
|
||||
|
||||
## 🚀 Usage Instructions
|
||||
|
||||
- Go to [http://localhost:3000/](http://localhost:3000/) in your browser to view the dashboard.
|
||||
- Add your `OpenAI API key` 🔑 in the Settings.
|
||||
- Create a new bot and you'll be navigated to its page.
|
||||
- Here you can add your data sources and then chat with the bot.
|
||||
|
||||
🎉 Happy Chatting! 🎉
|
||||
@@ -0,0 +1,7 @@
|
||||
__pycache__/
|
||||
database
|
||||
pyenv
|
||||
venv
|
||||
.env
|
||||
.git
|
||||
trash_files/
|
||||
@@ -0,0 +1,6 @@
|
||||
__pycache__
|
||||
database
|
||||
pyenv
|
||||
venv
|
||||
.env
|
||||
trash_files/
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM python:3.11-slim AS backend
|
||||
|
||||
WORKDIR /usr/src/app/backend
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "server.py"]
|
||||
@@ -0,0 +1,14 @@
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
db = SQLAlchemy()
|
||||
|
||||
|
||||
class APIKey(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
key = db.Column(db.String(255), nullable=False)
|
||||
|
||||
|
||||
class BotList(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255), nullable=False)
|
||||
slug = db.Column(db.String(255), nullable=False, unique=True)
|
||||
@@ -0,0 +1,5 @@
|
||||
import os
|
||||
|
||||
ROOT_DIRECTORY = os.getcwd()
|
||||
DB_DIRECTORY_OPEN_AI = os.path.join(os.getcwd(), "database", "open_ai")
|
||||
DB_DIRECTORY_OPEN_SOURCE = os.path.join(os.getcwd(), "database", "open_source")
|
||||
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
from flask import Blueprint, jsonify, make_response, request
|
||||
from models import APIKey
|
||||
from paths import DB_DIRECTORY_OPEN_AI
|
||||
|
||||
from embedchain import App
|
||||
|
||||
chat_response_bp = Blueprint("chat_response", __name__)
|
||||
|
||||
|
||||
# Chat Response for user query
|
||||
@chat_response_bp.route("/api/get_answer", methods=["POST"])
|
||||
def get_answer():
|
||||
try:
|
||||
data = request.get_json()
|
||||
query = data.get("query")
|
||||
embedding_model = data.get("embedding_model")
|
||||
app_type = data.get("app_type")
|
||||
|
||||
if embedding_model == "open_ai":
|
||||
os.chdir(DB_DIRECTORY_OPEN_AI)
|
||||
api_key = APIKey.query.first().key
|
||||
os.environ["OPENAI_API_KEY"] = api_key
|
||||
if app_type == "app":
|
||||
chat_bot = App()
|
||||
|
||||
response = chat_bot.chat(query)
|
||||
return make_response(jsonify({"response": response}), 200)
|
||||
|
||||
except Exception as e:
|
||||
return make_response(jsonify({"error": str(e)}), 400)
|
||||
@@ -0,0 +1,72 @@
|
||||
from flask import Blueprint, jsonify, make_response, request
|
||||
from models import APIKey, BotList, db
|
||||
|
||||
dashboard_bp = Blueprint("dashboard", __name__)
|
||||
|
||||
|
||||
# Set Open AI Key
|
||||
@dashboard_bp.route("/api/set_key", methods=["POST"])
|
||||
def set_key():
|
||||
data = request.get_json()
|
||||
api_key = data["openAIKey"]
|
||||
existing_key = APIKey.query.first()
|
||||
if existing_key:
|
||||
existing_key.key = api_key
|
||||
else:
|
||||
new_key = APIKey(key=api_key)
|
||||
db.session.add(new_key)
|
||||
db.session.commit()
|
||||
return make_response(jsonify(message="API key saved successfully"), 200)
|
||||
|
||||
|
||||
# Check OpenAI Key
|
||||
@dashboard_bp.route("/api/check_key", methods=["GET"])
|
||||
def check_key():
|
||||
existing_key = APIKey.query.first()
|
||||
if existing_key:
|
||||
return make_response(jsonify(status="ok", message="OpenAI Key exists"), 200)
|
||||
else:
|
||||
return make_response(jsonify(status="fail", message="No OpenAI Key present"), 200)
|
||||
|
||||
|
||||
# Create a bot
|
||||
@dashboard_bp.route("/api/create_bot", methods=["POST"])
|
||||
def create_bot():
|
||||
data = request.get_json()
|
||||
name = data["name"]
|
||||
slug = name.lower().replace(" ", "_")
|
||||
existing_bot = BotList.query.filter_by(slug=slug).first()
|
||||
if existing_bot:
|
||||
return (make_response(jsonify(message="Bot already exists"), 400),)
|
||||
new_bot = BotList(name=name, slug=slug)
|
||||
db.session.add(new_bot)
|
||||
db.session.commit()
|
||||
return make_response(jsonify(message="Bot created successfully"), 200)
|
||||
|
||||
|
||||
# Delete a bot
|
||||
@dashboard_bp.route("/api/delete_bot", methods=["POST"])
|
||||
def delete_bot():
|
||||
data = request.get_json()
|
||||
slug = data.get("slug")
|
||||
bot = BotList.query.filter_by(slug=slug).first()
|
||||
if bot:
|
||||
db.session.delete(bot)
|
||||
db.session.commit()
|
||||
return make_response(jsonify(message="Bot deleted successfully"), 200)
|
||||
return make_response(jsonify(message="Bot not found"), 400)
|
||||
|
||||
|
||||
# Get the list of bots
|
||||
@dashboard_bp.route("/api/get_bots", methods=["GET"])
|
||||
def get_bots():
|
||||
bots = BotList.query.all()
|
||||
bot_list = []
|
||||
for bot in bots:
|
||||
bot_list.append(
|
||||
{
|
||||
"name": bot.name,
|
||||
"slug": bot.slug,
|
||||
}
|
||||
)
|
||||
return jsonify(bot_list)
|
||||
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
from flask import Blueprint, jsonify, make_response, request
|
||||
from models import APIKey
|
||||
from paths import DB_DIRECTORY_OPEN_AI
|
||||
|
||||
from embedchain import App
|
||||
|
||||
sources_bp = Blueprint("sources", __name__)
|
||||
|
||||
|
||||
# API route to add data sources
|
||||
@sources_bp.route("/api/add_sources", methods=["POST"])
|
||||
def add_sources():
|
||||
try:
|
||||
embedding_model = request.json.get("embedding_model")
|
||||
name = request.json.get("name")
|
||||
value = request.json.get("value")
|
||||
if embedding_model == "open_ai":
|
||||
os.chdir(DB_DIRECTORY_OPEN_AI)
|
||||
api_key = APIKey.query.first().key
|
||||
os.environ["OPENAI_API_KEY"] = api_key
|
||||
chat_bot = App()
|
||||
chat_bot.add(name, value)
|
||||
return make_response(jsonify(message="Sources added successfully"), 200)
|
||||
except Exception as e:
|
||||
return make_response(jsonify(message=f"Error adding sources: {str(e)}"), 400)
|
||||
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
|
||||
from flask import Flask
|
||||
from models import db
|
||||
from paths import DB_DIRECTORY_OPEN_AI, ROOT_DIRECTORY
|
||||
from routes.chat_response import chat_response_bp
|
||||
from routes.dashboard import dashboard_bp
|
||||
from routes.sources import sources_bp
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(ROOT_DIRECTORY, "database", "user_data.db")
|
||||
app.register_blueprint(dashboard_bp)
|
||||
app.register_blueprint(sources_bp)
|
||||
app.register_blueprint(chat_response_bp)
|
||||
|
||||
|
||||
# Initialize the app on startup
|
||||
def load_app():
|
||||
os.makedirs(DB_DIRECTORY_OPEN_AI, exist_ok=True)
|
||||
db.init_app(app)
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
load_app()
|
||||
app.run(host="0.0.0.0", debug=True, port=8000)
|
||||
@@ -0,0 +1,24 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
backend:
|
||||
container_name: embedchain-backend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: backend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
frontend:
|
||||
container_name: embedchain-frontend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: frontend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- "backend"
|
||||
@@ -0,0 +1,7 @@
|
||||
node_modules/
|
||||
build
|
||||
dist
|
||||
.env
|
||||
.git
|
||||
.next/
|
||||
trash_files/
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["next/babel", "next/core-web-vitals"]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
vscode/
|
||||
trash_files/
|
||||
@@ -0,0 +1,14 @@
|
||||
FROM node:18-slim AS frontend
|
||||
|
||||
WORKDIR /usr/src/app/frontend
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["npm", "start"]
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: "/api/:path*",
|
||||
destination: "http://backend:8000/api/:path*",
|
||||
},
|
||||
];
|
||||
},
|
||||
reactStrictMode: true,
|
||||
experimental: {
|
||||
proxyTimeout: 6000000,
|
||||
},
|
||||
webpack(config) {
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/i,
|
||||
issuer: /\.[jt]sx?$/,
|
||||
use: ["@svgr/webpack"],
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "8.44.0",
|
||||
"eslint-config-next": "13.4.9",
|
||||
"flowbite": "^1.7.0",
|
||||
"next": "13.4.9",
|
||||
"postcss": "8.4.25",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"tailwindcss": "3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^8.0.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M14 2C14 2.74028 13.5978 3.38663 13 3.73244V4H20C21.6569 4 23 5.34315 23 7V19C23 20.6569 21.6569 22 20 22H4C2.34315 22 1 20.6569 1 19V7C1 5.34315 2.34315 4 4 4H11V3.73244C10.4022 3.38663 10 2.74028 10 2C10 0.895431 10.8954 0 12 0C13.1046 0 14 0.895431 14 2ZM4 6H11H13H20C20.5523 6 21 6.44772 21 7V19C21 19.5523 20.5523 20 20 20H4C3.44772 20 3 19.5523 3 19V7C3 6.44772 3.44772 6 4 6ZM15 11.5C15 10.6716 15.6716 10 16.5 10C17.3284 10 18 10.6716 18 11.5C18 12.3284 17.3284 13 16.5 13C15.6716 13 15 12.3284 15 11.5ZM16.5 8C14.567 8 13 9.567 13 11.5C13 13.433 14.567 15 16.5 15C18.433 15 20 13.433 20 11.5C20 9.567 18.433 8 16.5 8ZM7.5 10C6.67157 10 6 10.6716 6 11.5C6 12.3284 6.67157 13 7.5 13C8.32843 13 9 12.3284 9 11.5C9 10.6716 8.32843 10 7.5 10ZM4 11.5C4 9.567 5.567 8 7.5 8C9.433 8 11 9.567 11 11.5C11 13.433 9.433 15 7.5 15C5.567 15 4 13.433 4 11.5ZM10.8944 16.5528C10.6474 16.0588 10.0468 15.8586 9.55279 16.1056C9.05881 16.3526 8.85858 16.9532 9.10557 17.4472C9.68052 18.5971 10.9822 19 12 19C13.0178 19 14.3195 18.5971 14.8944 17.4472C15.1414 16.9532 14.9412 16.3526 14.4472 16.1056C13.9532 15.8586 13.3526 16.0588 13.1056 16.5528C13.0139 16.7362 12.6488 17 12 17C11.3512 17 10.9861 16.7362 10.8944 16.5528Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 14 14"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 252 B |
@@ -0,0 +1,15 @@
|
||||
<svg
|
||||
fill="currentColor"
|
||||
viewBox="0 0 32 32"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M18.8,16l5.5-5.5c0.8-0.8,0.8-2,0-2.8l0,0C24,7.3,23.5,7,23,7c-0.5,0-1,0.2-1.4,0.6L16,13.2l-5.5-5.5 c-0.8-0.8-2.1-0.8-2.8,0C7.3,8,7,8.5,7,9.1s0.2,1,0.6,1.4l5.5,5.5l-5.5,5.5C7.3,21.9,7,22.4,7,23c0,0.5,0.2,1,0.6,1.4 C8,24.8,8.5,25,9,25c0.5,0,1-0.2,1.4-0.6l5.5-5.5l5.5,5.5c0.8,0.8,2.1,0.8,2.8,0c0.8-0.8,0.8-2.1,0-2.8L18.8,16z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
@@ -0,0 +1,9 @@
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 22 21"
|
||||
>
|
||||
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z" />
|
||||
<path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 369 B |
@@ -0,0 +1,15 @@
|
||||
<svg
|
||||
fill="currentColor"
|
||||
viewBox="0 0 56 56"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M 15.5547 53.125 L 40.4453 53.125 C 45.2969 53.125 47.7109 50.6640 47.7109 45.7890 L 47.7109 24.5078 L 30.7422 24.5078 C 27.7422 24.5078 26.3359 23.0781 26.3359 20.0781 L 26.3359 2.8750 L 15.5547 2.8750 C 10.7266 2.8750 8.2891 5.3594 8.2891 10.2344 L 8.2891 45.7890 C 8.2891 50.6875 10.7266 53.125 15.5547 53.125 Z M 30.8125 21.2969 L 47.4531 21.2969 C 47.2891 20.3359 46.6094 19.3984 45.5078 18.2500 L 32.5703 5.1015 C 31.4922 3.9766 30.5078 3.2969 29.5234 3.1328 L 29.5234 20.0313 C 29.5234 20.875 29.9687 21.2969 30.8125 21.2969 Z M 18.9766 34.6562 C 18.0156 34.6562 17.3359 33.9766 17.3359 33.0625 C 17.3359 32.1484 18.0156 31.4687 18.9766 31.4687 L 37.0469 31.4687 C 37.9844 31.4687 38.7109 32.1484 38.7109 33.0625 C 38.7109 33.9766 37.9844 34.6562 37.0469 34.6562 Z M 18.9766 43.5859 C 18.0156 43.5859 17.3359 42.9062 17.3359 41.9922 C 17.3359 41.0781 18.0156 40.3984 18.9766 40.3984 L 37.0469 40.3984 C 37.9844 40.3984 38.7109 41.0781 38.7109 41.9922 C 38.7109 42.9062 37.9844 43.5859 37.0469 43.5859 Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
fill-rule="evenodd"
|
||||
d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"
|
||||
></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 415 B |
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 10 6"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="m1 1 4 4 4-4"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 230 B |
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 10 6"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 5 5 1 1 5"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 254 B |
@@ -0,0 +1,39 @@
|
||||
<svg
|
||||
viewBox="0 0 20 20"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
fill="currentColor"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<title>github [#142]</title> <desc>Created with Sketch.</desc>
|
||||
<defs> </defs>
|
||||
<g
|
||||
id="Page-1"
|
||||
stroke="none"
|
||||
stroke-width="1"
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
>
|
||||
<g
|
||||
id="Dribbble-Light-Preview"
|
||||
transform="translate(-140.000000, -7559.000000)"
|
||||
fill="currentColor"
|
||||
>
|
||||
<g id="icons" transform="translate(56.000000, 160.000000)">
|
||||
<path
|
||||
d="M94,7399 C99.523,7399 104,7403.59 104,7409.253 C104,7413.782 101.138,7417.624 97.167,7418.981 C96.66,7419.082 96.48,7418.762 96.48,7418.489 C96.48,7418.151 96.492,7417.047 96.492,7415.675 C96.492,7414.719 96.172,7414.095 95.813,7413.777 C98.04,7413.523 100.38,7412.656 100.38,7408.718 C100.38,7407.598 99.992,7406.684 99.35,7405.966 C99.454,7405.707 99.797,7404.664 99.252,7403.252 C99.252,7403.252 98.414,7402.977 96.505,7404.303 C95.706,7404.076 94.85,7403.962 94,7403.958 C93.15,7403.962 92.295,7404.076 91.497,7404.303 C89.586,7402.977 88.746,7403.252 88.746,7403.252 C88.203,7404.664 88.546,7405.707 88.649,7405.966 C88.01,7406.684 87.619,7407.598 87.619,7408.718 C87.619,7412.646 89.954,7413.526 92.175,7413.785 C91.889,7414.041 91.63,7414.493 91.54,7415.156 C90.97,7415.418 89.522,7415.871 88.63,7414.304 C88.63,7414.304 88.101,7413.319 87.097,7413.247 C87.097,7413.247 86.122,7413.234 87.029,7413.87 C87.029,7413.87 87.684,7414.185 88.139,7415.37 C88.139,7415.37 88.726,7417.2 91.508,7416.58 C91.513,7417.437 91.522,7418.245 91.522,7418.489 C91.522,7418.76 91.338,7419.077 90.839,7418.982 C86.865,7417.627 84,7413.783 84,7409.253 C84,7403.59 88.478,7399 94,7399"
|
||||
id="github-[#142]"
|
||||
>
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1,17 @@
|
||||
<svg
|
||||
fill="currentColor"
|
||||
viewBox="0 0 32 32"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<title>linkedin</title>
|
||||
<path d="M28.778 1.004h-25.56c-0.008-0-0.017-0-0.027-0-1.199 0-2.172 0.964-2.186 2.159v25.672c0.014 1.196 0.987 2.161 2.186 2.161 0.010 0 0.019-0 0.029-0h25.555c0.008 0 0.018 0 0.028 0 1.2 0 2.175-0.963 2.194-2.159l0-0.002v-25.67c-0.019-1.197-0.994-2.161-2.195-2.161-0.010 0-0.019 0-0.029 0h0.001zM9.9 26.562h-4.454v-14.311h4.454zM7.674 10.293c-1.425 0-2.579-1.155-2.579-2.579s1.155-2.579 2.579-2.579c1.424 0 2.579 1.154 2.579 2.578v0c0 0.001 0 0.002 0 0.004 0 1.423-1.154 2.577-2.577 2.577-0.001 0-0.002 0-0.003 0h0zM26.556 26.562h-4.441v-6.959c0-1.66-0.034-3.795-2.314-3.795-2.316 0-2.669 1.806-2.669 3.673v7.082h-4.441v-14.311h4.266v1.951h0.058c0.828-1.395 2.326-2.315 4.039-2.315 0.061 0 0.121 0.001 0.181 0.003l-0.009-0c4.5 0 5.332 2.962 5.332 6.817v7.855z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,28 @@
|
||||
<svg
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
d="M3.5 8H3V7H3.5C3.77614 7 4 7.22386 4 7.5C4 7.77614 3.77614 8 3.5 8Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M7 10V7H7.5C7.77614 7 8 7.22386 8 7.5V9.5C8 9.77614 7.77614 10 7.5 10H7Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M1 1.5C1 0.671573 1.67157 0 2.5 0H10.7071L14 3.29289V13.5C14 14.3284 13.3284 15 12.5 15H2.5C1.67157 15 1 14.3284 1 13.5V1.5ZM3.5 6H2V11H3V9H3.5C4.32843 9 5 8.32843 5 7.5C5 6.67157 4.32843 6 3.5 6ZM7.5 6H6V11H7.5C8.32843 11 9 10.3284 9 9.5V7.5C9 6.67157 8.32843 6 7.5 6ZM10 11V6H13V7H11V8H12V9H11V11H10Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 947 B |
@@ -0,0 +1,13 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 227 B |
@@ -0,0 +1,57 @@
|
||||
<svg
|
||||
viewBox="-0.5 0 25 25"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
{" "}
|
||||
<path
|
||||
d="M12 7.82001H22"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
<path
|
||||
d="M2 7.82001H4"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
<path
|
||||
d="M20 16.82H22"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
<path
|
||||
d="M2 16.82H12"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
<path
|
||||
d="M8 11.82C10.2091 11.82 12 10.0291 12 7.82001C12 5.61087 10.2091 3.82001 8 3.82001C5.79086 3.82001 4 5.61087 4 7.82001C4 10.0291 5.79086 11.82 8 11.82Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
<path
|
||||
d="M16 20.82C18.2091 20.82 20 19.0291 20 16.82C20 14.6109 18.2091 12.82 16 12.82C13.7909 12.82 12 14.6109 12 16.82C12 19.0291 13.7909 20.82 16 20.82Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>{" "}
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,61 @@
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<rect
|
||||
height="4"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
width="4"
|
||||
x="10"
|
||||
y="4"
|
||||
></rect>
|
||||
<rect
|
||||
height="4"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
width="4"
|
||||
x="10"
|
||||
y="16"
|
||||
></rect>
|
||||
<rect
|
||||
height="4"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
width="4"
|
||||
x="3"
|
||||
y="16"
|
||||
></rect>
|
||||
<rect
|
||||
height="4"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
width="4"
|
||||
x="17"
|
||||
y="16"
|
||||
></rect>
|
||||
<path
|
||||
d="M12 8V12M12 16V12M12 12H17C18.1046 12 19 12.8954 19 14V16M12 12H7C5.89543 12 5 12.8954 5 14V16"
|
||||
stroke="currentColor"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,21 @@
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path
|
||||
d="M12 3V21M9 21H15M19 6V3H5V6"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 445 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="svg5" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1668.56 1221.19"
|
||||
style="enable-background:new 0 0 1668.56 1221.19;" xml:space="preserve">
|
||||
<g id="layer1" transform="translate(52.390088,-25.058597)">
|
||||
<path id="path1009" d="M283.94,167.31l386.39,516.64L281.5,1104h87.51l340.42-367.76L984.48,1104h297.8L874.15,558.3l361.92-390.99
|
||||
h-87.51l-313.51,338.7l-253.31-338.7H283.94z M412.63,231.77h136.81l604.13,807.76h-136.81L412.63,231.77z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 722 B |
@@ -0,0 +1,20 @@
|
||||
<svg
|
||||
fill="currentColor"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 24 24"
|
||||
enable-background="new 0 0 24 24"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<path d="M18.41,0.01H4V9h2V2.01h10v6h6v14H4v2h20V5.6L18.41,0.01z M18,2.43l3.59,3.59H18V2.43z M21,18v2h-1h-1h-1v-8h2v6H21z M7,12 H6v2h1v6h2v-6h1v-2H9H7z M15,12l-1,1.61L13,12v0h-2v8h2v-4.21l1,1.61l1-1.61V20h2v-8L15,12L15,12z M3,15H2v-3H0v8h2v-3h1v3h2v-8H3 V15z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 689 B |
@@ -0,0 +1,39 @@
|
||||
<svg
|
||||
viewBox="0 -3 20 20"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
fill="currentColor"
|
||||
>
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||
<g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g>
|
||||
<g id="SVGRepo_iconCarrier">
|
||||
<title>youtube [#168]</title> <desc>Created with Sketch.</desc>
|
||||
<defs> </defs>
|
||||
<g
|
||||
id="Page-1"
|
||||
stroke="none"
|
||||
stroke-width="1"
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
>
|
||||
<g
|
||||
id="Dribbble-Light-Preview"
|
||||
transform="translate(-300.000000, -7442.000000)"
|
||||
fill="currentColor"
|
||||
>
|
||||
<g id="icons" transform="translate(56.000000, 160.000000)">
|
||||
<path
|
||||
d="M251.988432,7291.58588 L251.988432,7285.97425 C253.980638,7286.91168 255.523602,7287.8172 257.348463,7288.79353 C255.843351,7289.62824 253.980638,7290.56468 251.988432,7291.58588 M263.090998,7283.18289 C262.747343,7282.73013 262.161634,7282.37809 261.538073,7282.26141 C259.705243,7281.91336 248.270974,7281.91237 246.439141,7282.26141 C245.939097,7282.35515 245.493839,7282.58153 245.111335,7282.93357 C243.49964,7284.42947 244.004664,7292.45151 244.393145,7293.75096 C244.556505,7294.31342 244.767679,7294.71931 245.033639,7294.98558 C245.376298,7295.33761 245.845463,7295.57995 246.384355,7295.68865 C247.893451,7296.0008 255.668037,7296.17532 261.506198,7295.73552 C262.044094,7295.64178 262.520231,7295.39147 262.895762,7295.02447 C264.385932,7293.53455 264.28433,7285.06174 263.090998,7283.18289"
|
||||
id="youtube-[#168]"
|
||||
>
|
||||
</path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,9 @@
|
||||
export default function PageWrapper({ children }) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex pt-4 px-4 sm:ml-64 min-h-screen">
|
||||
<div className="flex-grow pt-4 px-4 rounded-lg">{children}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export default function BotWrapper({ children }) {
|
||||
return (
|
||||
<>
|
||||
<div className="rounded-lg">
|
||||
<div className="flex flex-row items-center">
|
||||
<div className="flex items-center justify-center h-10 w-10 rounded-full bg-black text-white flex-shrink-0">
|
||||
B
|
||||
</div>
|
||||
<div className="ml-3 text-sm bg-white py-2 px-4 shadow-lg rounded-xl">
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
export default function HumanWrapper({ children }) {
|
||||
return (
|
||||
<>
|
||||
<div className="rounded-lg">
|
||||
<div className="flex items-center justify-start flex-row-reverse">
|
||||
<div className="flex items-center justify-center h-10 w-10 rounded-full bg-blue-800 text-white flex-shrink-0">
|
||||
H
|
||||
</div>
|
||||
<div className="mr-3 text-sm bg-blue-200 py-2 px-4 shadow-lg rounded-xl">
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function CreateBot() {
|
||||
const [botName, setBotName] = useState("");
|
||||
const [status, setStatus] = useState("");
|
||||
const router = useRouter();
|
||||
|
||||
const handleCreateBot = async (e) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
name: botName,
|
||||
};
|
||||
|
||||
const response = await fetch("/api/create_bot", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const botSlug = botName.toLowerCase().replace(/\s+/g, "_");
|
||||
router.push(`/${botSlug}/app`);
|
||||
} else {
|
||||
setBotName("");
|
||||
setStatus("fail");
|
||||
setTimeout(() => {
|
||||
setStatus("");
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full">
|
||||
{/* Create Bot */}
|
||||
<h2 className="text-xl font-bold text-gray-800">CREATE BOT</h2>
|
||||
<form className="py-2" onSubmit={handleCreateBot}>
|
||||
<label
|
||||
htmlFor="bot_name"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
Name of Bot
|
||||
</label>
|
||||
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
|
||||
<input
|
||||
type="text"
|
||||
id="bot_name"
|
||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
placeholder="Eg. Naval Ravikant"
|
||||
required
|
||||
value={botName}
|
||||
onChange={(e) => setBotName(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="h-fit text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
{status === "fail" && (
|
||||
<div className="text-red-600 text-sm font-bold py-1">
|
||||
An error occurred while creating your bot!
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
export default function DeleteBot() {
|
||||
const [bots, setBots] = useState([]);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBots = async () => {
|
||||
const response = await fetch("/api/get_bots");
|
||||
const data = await response.json();
|
||||
setBots(data);
|
||||
};
|
||||
fetchBots();
|
||||
}, []);
|
||||
|
||||
const handleDeleteBot = async (event) => {
|
||||
event.preventDefault();
|
||||
const selectedBotSlug = event.target.bot_name.value;
|
||||
if (selectedBotSlug === "none") {
|
||||
return;
|
||||
}
|
||||
const response = await fetch("/api/delete_bot", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ slug: selectedBotSlug }),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
router.reload();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{bots.length !== 0 && (
|
||||
<div className="w-full">
|
||||
{/* Delete Bot */}
|
||||
<h2 className="text-xl font-bold text-gray-800">DELETE BOTS</h2>
|
||||
<form className="py-2" onSubmit={handleDeleteBot}>
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900">
|
||||
List of Bots
|
||||
</label>
|
||||
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
|
||||
<select
|
||||
name="bot_name"
|
||||
defaultValue="none"
|
||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
>
|
||||
<option value="none">Select a Bot</option>
|
||||
{bots.map((bot) => (
|
||||
<option key={bot.slug} value={bot.slug}>
|
||||
{bot.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
type="submit"
|
||||
className="h-fit text-white bg-red-600 hover:bg-red-600/90 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { useState } from "react";
|
||||
|
||||
export default function PurgeChats() {
|
||||
const [status, setStatus] = useState("");
|
||||
const handleChatsPurge = (event) => {
|
||||
event.preventDefault();
|
||||
localStorage.clear();
|
||||
setStatus("success");
|
||||
setTimeout(() => {
|
||||
setStatus(false);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full">
|
||||
{/* Purge Chats */}
|
||||
<h2 className="text-xl font-bold text-gray-800">PURGE CHATS</h2>
|
||||
<form className="py-2" onSubmit={handleChatsPurge}>
|
||||
<label className="block mb-2 text-sm font-medium text-red-600">
|
||||
Warning
|
||||
</label>
|
||||
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
|
||||
<div
|
||||
type="text"
|
||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
>
|
||||
The following action will clear all your chat logs. Proceed with
|
||||
caution!
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="h-fit text-white bg-red-600 hover:bg-red-600/80 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
|
||||
>
|
||||
Purge
|
||||
</button>
|
||||
</div>
|
||||
{status === "success" && (
|
||||
<div className="text-green-600 text-sm font-bold py-1">
|
||||
Your chats have been purged!
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useState } from "react";
|
||||
|
||||
export default function SetOpenAIKey({ setIsKeyPresent }) {
|
||||
const [openAIKey, setOpenAIKey] = useState("");
|
||||
const [status, setStatus] = useState("");
|
||||
|
||||
const handleOpenAIKey = async (e) => {
|
||||
e.preventDefault();
|
||||
const response = await fetch("/api/set_key", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ openAIKey }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setOpenAIKey("");
|
||||
setStatus("success");
|
||||
setIsKeyPresent(true);
|
||||
} else {
|
||||
setStatus("fail");
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
setStatus("");
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-full">
|
||||
{/* Set Open AI Key */}
|
||||
<h2 className="text-xl font-bold text-gray-800">SET OPENAI KEY</h2>
|
||||
<form className="py-2" onSubmit={handleOpenAIKey}>
|
||||
<label
|
||||
htmlFor="openai_key"
|
||||
className="block mb-2 text-sm font-medium text-gray-900"
|
||||
>
|
||||
OpenAI Key
|
||||
</label>
|
||||
<div className="flex flex-col sm:flex-row gap-x-4 gap-y-4">
|
||||
<input
|
||||
type="password"
|
||||
id="openai_key"
|
||||
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
placeholder="Enter Open AI Key here"
|
||||
required
|
||||
value={openAIKey}
|
||||
onChange={(e) => setOpenAIKey(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="h-fit text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
{status === "success" && (
|
||||
<div className="text-green-600 text-sm font-bold py-1">
|
||||
Your Open AI key has been saved successfully!
|
||||
</div>
|
||||
)}
|
||||
{status === "fail" && (
|
||||
<div className="text-red-600 text-sm font-bold py-1">
|
||||
An error occurred while saving your OpenAI Key!
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import BotWrapper from "@/components/chat/BotWrapper";
|
||||
import HumanWrapper from "@/components/chat/HumanWrapper";
|
||||
import SetSources from "@/containers/SetSources";
|
||||
|
||||
export default function ChatWindow({ embedding_model, app_type, setBotTitle }) {
|
||||
const [bot, setBot] = useState(null);
|
||||
const [chats, setChats] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [selectChat, setSelectChat] = useState(true);
|
||||
|
||||
const router = useRouter();
|
||||
const { bot_slug } = router.query;
|
||||
|
||||
useEffect(() => {
|
||||
if (bot_slug) {
|
||||
const fetchBots = async () => {
|
||||
const response = await fetch("/api/get_bots");
|
||||
const data = await response.json();
|
||||
const matchingBot = data.find((item) => item.slug === bot_slug);
|
||||
setBot(matchingBot);
|
||||
setBotTitle(matchingBot.name);
|
||||
};
|
||||
fetchBots();
|
||||
}
|
||||
}, [bot_slug]);
|
||||
|
||||
useEffect(() => {
|
||||
const storedChats = localStorage.getItem(`chat_${bot_slug}_${app_type}`);
|
||||
if (storedChats) {
|
||||
const parsedChats = JSON.parse(storedChats);
|
||||
setChats(parsedChats.chats);
|
||||
}
|
||||
}, [app_type, bot_slug]);
|
||||
|
||||
const handleChatResponse = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
const queryInput = e.target.query.value;
|
||||
e.target.query.value = "";
|
||||
const chatEntry = {
|
||||
sender: "H",
|
||||
message: queryInput,
|
||||
};
|
||||
setChats((prevChats) => [...prevChats, chatEntry]);
|
||||
|
||||
const response = await fetch("/api/get_answer", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
query: queryInput,
|
||||
embedding_model,
|
||||
app_type,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (response.ok) {
|
||||
const botResponse = data.response;
|
||||
const botEntry = {
|
||||
sender: "B",
|
||||
message: botResponse,
|
||||
};
|
||||
setIsLoading(false);
|
||||
setChats((prevChats) => [...prevChats, botEntry]);
|
||||
const savedChats = {
|
||||
chats: [...chats, chatEntry, botEntry],
|
||||
};
|
||||
localStorage.setItem(
|
||||
`chat_${bot_slug}_${app_type}`,
|
||||
JSON.stringify(savedChats)
|
||||
);
|
||||
} else {
|
||||
router.reload();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col justify-between h-full">
|
||||
<div className="space-y-4 overflow-x-auto h-full pb-8">
|
||||
{/* Greeting Message */}
|
||||
<BotWrapper>
|
||||
Hi, I am {bot?.name}. How can I help you today?
|
||||
</BotWrapper>
|
||||
|
||||
{/* Chat Messages */}
|
||||
{chats.map((chat, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{chat.sender === "B" ? (
|
||||
<BotWrapper>{chat.message}</BotWrapper>
|
||||
) : (
|
||||
<HumanWrapper>{chat.message}</HumanWrapper>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
{/* Loader */}
|
||||
{isLoading && (
|
||||
<BotWrapper>
|
||||
<div className="flex items-center justify-center space-x-2 animate-pulse">
|
||||
<div className="w-2 h-2 bg-black rounded-full"></div>
|
||||
<div className="w-2 h-2 bg-black rounded-full"></div>
|
||||
<div className="w-2 h-2 bg-black rounded-full"></div>
|
||||
</div>
|
||||
</BotWrapper>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bg-white fixed bottom-0 left-0 right-0 h-28 sm:h-16"></div>
|
||||
|
||||
{/* Query Form */}
|
||||
<div className="flex flex-row gap-x-2 sticky bottom-3">
|
||||
<SetSources
|
||||
setChats={setChats}
|
||||
embedding_model={embedding_model}
|
||||
setSelectChat={setSelectChat}
|
||||
/>
|
||||
{selectChat && (
|
||||
<form
|
||||
onSubmit={handleChatResponse}
|
||||
className="w-full flex flex-col sm:flex-row gap-y-2 gap-x-2"
|
||||
>
|
||||
<div className="w-full">
|
||||
<input
|
||||
id="query"
|
||||
name="query"
|
||||
type="text"
|
||||
placeholder="Enter your query..."
|
||||
className="text-sm w-full border-2 border-black rounded-xl focus:outline-none focus:border-blue-800 sm:pl-4 h-11"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="w-full sm:w-fit">
|
||||
<button
|
||||
type="submit"
|
||||
id="sender"
|
||||
disabled={isLoading}
|
||||
className={`${
|
||||
isLoading ? "opacity-60" : ""
|
||||
} w-full bg-black hover:bg-blue-800 rounded-xl text-lg text-white px-6 h-11`}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import { useState } from "react";
|
||||
import PlusIcon from "../../public/icons/plus.svg";
|
||||
import CrossIcon from "../../public/icons/cross.svg";
|
||||
import YoutubeIcon from "../../public/icons/youtube.svg";
|
||||
import PDFIcon from "../../public/icons/pdf.svg";
|
||||
import WebIcon from "../../public/icons/web.svg";
|
||||
import DocIcon from "../../public/icons/doc.svg";
|
||||
import SitemapIcon from "../../public/icons/sitemap.svg";
|
||||
import TextIcon from "../../public/icons/text.svg";
|
||||
|
||||
export default function SetSources({
|
||||
setChats,
|
||||
embedding_model,
|
||||
setSelectChat,
|
||||
}) {
|
||||
const [sourceName, setSourceName] = useState("");
|
||||
const [sourceValue, setSourceValue] = useState("");
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const dataTypes = {
|
||||
youtube_video: "YouTube Video",
|
||||
pdf_file: "PDF File",
|
||||
web_page: "Web Page",
|
||||
doc_file: "Doc File",
|
||||
sitemap: "Sitemap",
|
||||
text: "Text",
|
||||
};
|
||||
|
||||
const dataIcons = {
|
||||
youtube_video: <YoutubeIcon className="w-5 h-5 mr-3" />,
|
||||
pdf_file: <PDFIcon className="w-5 h-5 mr-3" />,
|
||||
web_page: <WebIcon className="w-5 h-5 mr-3" />,
|
||||
doc_file: <DocIcon className="w-5 h-5 mr-3" />,
|
||||
sitemap: <SitemapIcon className="w-5 h-5 mr-3" />,
|
||||
text: <TextIcon className="w-5 h-5 mr-3" />,
|
||||
};
|
||||
|
||||
const handleDropdownClose = () => {
|
||||
setIsDropdownOpen(false);
|
||||
setSourceName("");
|
||||
setSelectChat(true);
|
||||
};
|
||||
const handleDropdownSelect = (dataType) => {
|
||||
setSourceName(dataType);
|
||||
setSourceValue("");
|
||||
setIsDropdownOpen(false);
|
||||
setSelectChat(false);
|
||||
};
|
||||
|
||||
const handleAddDataSource = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
|
||||
const addDataSourceEntry = {
|
||||
sender: "B",
|
||||
message: `Adding the following ${dataTypes[sourceName]}: ${sourceValue}`,
|
||||
};
|
||||
setChats((prevChats) => [...prevChats, addDataSourceEntry]);
|
||||
let name = sourceName;
|
||||
let value = sourceValue;
|
||||
setSourceValue("");
|
||||
const response = await fetch("/api/add_sources", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
embedding_model,
|
||||
name,
|
||||
value,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
if (response.ok) {
|
||||
const successEntry = {
|
||||
sender: "B",
|
||||
message: `Successfully added ${dataTypes[sourceName]}!`,
|
||||
};
|
||||
setChats((prevChats) => [...prevChats, successEntry]);
|
||||
} else {
|
||||
const errorEntry = {
|
||||
sender: "B",
|
||||
message: `Failed to add ${dataTypes[sourceName]}. Please try again.`,
|
||||
};
|
||||
setChats((prevChats) => [...prevChats, errorEntry]);
|
||||
}
|
||||
setSourceName("");
|
||||
setIsLoading(false);
|
||||
setSelectChat(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="w-fit">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
|
||||
className="w-fit p-2.5 rounded-xl text-white bg-black hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300"
|
||||
>
|
||||
<PlusIcon className="w-6 h-6" />
|
||||
</button>
|
||||
{isDropdownOpen && (
|
||||
<div className="absolute left-0 bottom-full bg-white border border-gray-300 rounded-lg shadow-lg mb-2">
|
||||
<ul className="py-1">
|
||||
<li
|
||||
className="block px-4 py-2 text-sm text-black cursor-pointer hover:bg-gray-200"
|
||||
onClick={handleDropdownClose}
|
||||
>
|
||||
<span className="flex items-center text-red-600">
|
||||
<CrossIcon className="w-5 h-5 mr-3" />
|
||||
Close
|
||||
</span>
|
||||
</li>
|
||||
{Object.entries(dataTypes).map(([key, value]) => (
|
||||
<li
|
||||
key={key}
|
||||
className="block px-4 py-2 text-sm text-black cursor-pointer hover:bg-gray-200"
|
||||
onClick={() => handleDropdownSelect(key)}
|
||||
>
|
||||
<span className="flex items-center">
|
||||
{dataIcons[key]}
|
||||
{value}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{sourceName && (
|
||||
<form
|
||||
onSubmit={handleAddDataSource}
|
||||
className="w-full flex flex-col sm:flex-row gap-y-2 gap-x-2 items-center"
|
||||
>
|
||||
<div className="w-full">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter URL, Data or File path here..."
|
||||
className="text-sm w-full border-2 border-black rounded-xl focus:outline-none focus:border-blue-800 sm:pl-4 h-11"
|
||||
required
|
||||
value={sourceValue}
|
||||
onChange={(e) => setSourceValue(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full sm:w-fit">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className={`${
|
||||
isLoading ? "opacity-60" : ""
|
||||
} w-full bg-black hover:bg-blue-800 rounded-xl text-lg text-white px-6 h-11`}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import DrawerIcon from "../../public/icons/drawer.svg";
|
||||
import SettingsIcon from "../../public/icons/settings.svg";
|
||||
import BotIcon from "../../public/icons/bot.svg";
|
||||
import DropdownIcon from "../../public/icons/dropdown.svg";
|
||||
import TwitterIcon from "../../public/icons/twitter.svg";
|
||||
import GithubIcon from "../../public/icons/github.svg";
|
||||
import LinkedinIcon from "../../public/icons/linkedin.svg";
|
||||
|
||||
export default function Sidebar() {
|
||||
const [bots, setBots] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBots = async () => {
|
||||
const response = await fetch("/api/get_bots");
|
||||
const data = await response.json();
|
||||
setBots(data);
|
||||
};
|
||||
|
||||
fetchBots();
|
||||
}, []);
|
||||
|
||||
const toggleDropdown = () => {
|
||||
const dropdown = document.getElementById("dropdown-toggle");
|
||||
dropdown.classList.toggle("hidden");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Mobile Toggle */}
|
||||
<button
|
||||
data-drawer-target="logo-sidebar"
|
||||
data-drawer-toggle="logo-sidebar"
|
||||
aria-controls="logo-sidebar"
|
||||
type="button"
|
||||
className="inline-flex items-center p-2 mt-2 ml-3 text-sm text-gray-500 rounded-lg sm:hidden hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-200"
|
||||
>
|
||||
<DrawerIcon className="w-6 h-6" />
|
||||
</button>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div
|
||||
id="logo-sidebar"
|
||||
className="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0"
|
||||
>
|
||||
<div className="flex flex-col h-full px-3 py-4 overflow-y-auto bg-gray-100">
|
||||
<div className="pb-10">
|
||||
<Link href="/" className="flex items-center justify-evenly mb-5">
|
||||
<Image
|
||||
src="/images/embedchain.png"
|
||||
alt="Embedchain Logo"
|
||||
width={45}
|
||||
height={0}
|
||||
className="block h-auto w-auto"
|
||||
/>
|
||||
<span className="self-center text-2xl font-bold whitespace-nowrap">
|
||||
Embedchain
|
||||
</span>
|
||||
</Link>
|
||||
<ul className="space-y-2 font-medium text-lg">
|
||||
{/* Settings */}
|
||||
<li>
|
||||
<Link
|
||||
href="/"
|
||||
className="flex items-center p-2 text-gray-900 rounded-lg hover:bg-gray-200 group"
|
||||
>
|
||||
<SettingsIcon className="w-6 h-6 text-gray-600 transition duration-75 group-hover:text-gray-900" />
|
||||
<span className="ml-3">Settings</span>
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
{/* Bots */}
|
||||
{bots.length !== 0 && (
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-200"
|
||||
onClick={toggleDropdown}
|
||||
>
|
||||
<BotIcon className="w-6 h-6 text-gray-600 transition duration-75 group-hover:text-gray-900" />
|
||||
<span className="flex-1 ml-3 text-left whitespace-nowrap">
|
||||
Bots
|
||||
</span>
|
||||
<DropdownIcon className="w-3 h-3" />
|
||||
</button>
|
||||
<ul
|
||||
id="dropdown-toggle"
|
||||
className="hidden text-sm py-2 space-y-2"
|
||||
>
|
||||
{bots.map((bot, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<li>
|
||||
<Link
|
||||
href={`/${bot.slug}/app`}
|
||||
className="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-200"
|
||||
>
|
||||
{bot.name}
|
||||
</Link>
|
||||
</li>
|
||||
</React.Fragment>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="bg-gray-200 absolute bottom-0 left-0 right-0 h-20"></div>
|
||||
|
||||
{/* Social Icons */}
|
||||
<div className="mt-auto mb-3 flex flex-row justify-evenly sticky bottom-3">
|
||||
<a href="https://twitter.com/embedchain" target="blank">
|
||||
<TwitterIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
|
||||
</a>
|
||||
<a href="https://github.com/embedchain/embedchain" target="blank">
|
||||
<GithubIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
|
||||
</a>
|
||||
<a
|
||||
href="https://www.linkedin.com/company/embedchain"
|
||||
target="blank"
|
||||
>
|
||||
<LinkedinIcon className="w-6 h-6 text-gray-600 transition duration-75 hover:text-gray-900" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import Wrapper from "@/components/PageWrapper";
|
||||
import Sidebar from "@/containers/Sidebar";
|
||||
import ChatWindow from "@/containers/ChatWindow";
|
||||
import { useState } from "react";
|
||||
import Head from "next/head";
|
||||
|
||||
export default function App() {
|
||||
const [botTitle, setBotTitle] = useState("");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{botTitle}</title>
|
||||
</Head>
|
||||
<Sidebar />
|
||||
<Wrapper>
|
||||
<ChatWindow
|
||||
embedding_model="open_ai"
|
||||
app_type="app"
|
||||
setBotTitle={setBotTitle}
|
||||
/>
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import "@/styles/globals.css";
|
||||
import Script from "next/script";
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.7.0/flowbite.min.js"
|
||||
strategy="beforeInteractive"
|
||||
/>
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<Head>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/flowbite/1.7.0/flowbite.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import Wrapper from "@/components/PageWrapper";
|
||||
import Sidebar from "@/containers/Sidebar";
|
||||
import CreateBot from "@/components/dashboard/CreateBot";
|
||||
import SetOpenAIKey from "@/components/dashboard/SetOpenAIKey";
|
||||
import PurgeChats from "@/components/dashboard/PurgeChats";
|
||||
import DeleteBot from "@/components/dashboard/DeleteBot";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function Home() {
|
||||
const [isKeyPresent, setIsKeyPresent] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/api/check_key")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (data.status === "ok") {
|
||||
setIsKeyPresent(true);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Sidebar />
|
||||
<Wrapper>
|
||||
<div className="text-center">
|
||||
<h1 className="mb-4 text-4xl font-extrabold leading-none tracking-tight text-gray-900 md:text-5xl">
|
||||
Welcome to Embedchain Playground
|
||||
</h1>
|
||||
<p className="mb-6 text-lg font-normal text-gray-500 lg:text-xl">
|
||||
Embedchain is a Data Platform for LLMs - Load, index, retrieve, and sync any unstructured data
|
||||
dataset
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
className={`pt-6 gap-y-4 gap-x-8 ${
|
||||
isKeyPresent ? "grid lg:grid-cols-2" : "w-[50%] mx-auto"
|
||||
}`}
|
||||
>
|
||||
<SetOpenAIKey setIsKeyPresent={setIsKeyPresent} />
|
||||
{isKeyPresent && (
|
||||
<>
|
||||
<CreateBot />
|
||||
<DeleteBot />
|
||||
<PurgeChats />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Wrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||