Skip to content

Commit c39827a

Browse files
committed
added managed database for persistent memory
1 parent 4cdb797 commit c39827a

File tree

4 files changed

+27
-17
lines changed

4 files changed

+27
-17
lines changed

api/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
REPLICATE_API_TOKEN=YOUR_REPLICATE_API_TOKEN
22
GOOGLE_API_KEY=YOUR_GOOGLE_API_KEY
3+
DATABASE_URL=YOUR_DATABASE_URL

api/llm/agent.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,48 @@
1-
import sqlite3
1+
import atexit
2+
import os
3+
from functools import lru_cache
24
from typing import List, Optional
35

46
from dotenv import load_dotenv
57
from langchain_google_genai import ChatGoogleGenerativeAI
6-
from langgraph.checkpoint.sqlite import SqliteSaver
8+
from langgraph.checkpoint.postgres import PostgresSaver
79
from langgraph.prebuilt import create_react_agent
810

911
load_dotenv()
1012

1113
# Global agent instance
1214
_agent_executor = None
13-
_memory = None
15+
16+
17+
@lru_cache
18+
def get_checkpointer():
19+
DATABASE_URL = os.environ.get("DATABASE_URL")
20+
if not DATABASE_URL:
21+
raise RuntimeError("DATABASE_URL is not set. Point it to your Neon connection string.")
22+
23+
cm = PostgresSaver.from_conn_string(DATABASE_URL)
24+
saver = cm.__enter__() # enter the context manager once
25+
atexit.register(lambda: cm.__exit__(None, None, None)) # clean shutdown
26+
saver.setup() # create tables on first run; no-op afterward
27+
return saver
1428

1529

1630
def get_agent():
1731
"""Get or create the agent instance."""
18-
global _agent_executor, _memory
32+
global _agent_executor
1933

2034
if _agent_executor is None:
35+
# Build LLM
2136
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")
2237

23-
# Build persistent checkpointer
24-
con = sqlite3.connect("db.sqlite3", check_same_thread=False)
25-
_memory = SqliteSaver(con)
26-
2738
# Create agent
2839
_agent_executor = create_react_agent(
2940
llm,
30-
[],
41+
tools=[],
3142
prompt="You are a helpful AI image editing assistant. \
32-
You help users with image editing tasks and provide guidance \
43+
You help users with image editing tasks and provide guidance \
3344
on how to modify their images.",
34-
checkpointer=_memory,
45+
checkpointer=get_checkpointer(),
3546
)
3647

3748
return _agent_executor

api/pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ dependencies = [
1919
"langchain-core",
2020
"langgraph>0.2.27",
2121
"langchain[google-genai]",
22-
"langgraph-checkpoint-sqlite",
22+
"langgraph-checkpoint-postgres",
2323
]
2424

2525
[project.optional-dependencies]
@@ -36,11 +36,11 @@ where = ["."]
3636
include = ["llm*", "server*"]
3737

3838
[tool.black]
39-
line-length = 88
39+
line-length = 100
4040
target-version = ["py310"]
4141

4242
[tool.ruff]
43-
line-length = 88
43+
line-length = 100
4444
target-version = "py310"
4545
fix = true
4646
unsafe-fixes = true

api/server/main.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ async def chat_endpoint(request: ChatRequest):
5656
return ChatResponse(response=response, status="success")
5757

5858
except Exception as e:
59-
raise HTTPException(
60-
status_code=500, detail=f"Error processing request: {str(e)}"
61-
)
59+
raise HTTPException(status_code=500, detail=f"Error processing request: {str(e)}")
6260

6361

6462
if __name__ == "__main__":

0 commit comments

Comments
 (0)