Skip to content

Commit 9ed55df

Browse files
committed
fixed so that neon connection doesn't randomly die
1 parent 0c70dc0 commit 9ed55df

File tree

3 files changed

+54
-18
lines changed

3 files changed

+54
-18
lines changed

api/llm/agent.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,35 @@
1414

1515
# Global agent instance
1616
_agent_executor = None
17+
_checkpointer = None
1718

1819

1920
@lru_cache
2021
def get_checkpointer():
21-
DATABASE_URL = os.environ.get("DATABASE_URL")
22-
if not DATABASE_URL:
23-
raise RuntimeError("DATABASE_URL is not set. Point it to your Neon connection string.")
24-
25-
cm = PostgresSaver.from_conn_string(DATABASE_URL)
26-
saver = cm.__enter__() # enter the context manager once
27-
atexit.register(lambda: cm.__exit__(None, None, None)) # clean shutdown
28-
saver.setup() # create tables on first run; no-op afterward
29-
return saver
22+
"""Open PostgresSaver once and reuse it (with keepalives)."""
23+
global _checkpointer
24+
25+
if _checkpointer is None:
26+
url = os.environ.get("DATABASE_URL")
27+
if not url:
28+
raise RuntimeError("DATABASE_URL is not set. Point it to your Neon connection string.")
29+
30+
# add keepalive params if missing
31+
if "keepalives=" not in url:
32+
sep = "&" if "?" in url else "?"
33+
url += (
34+
sep
35+
+ "sslmode=require&keepalives=1&keepalives_idle=30&keepalives_interval=10\
36+
&keepalives_count=3"
37+
)
38+
39+
cm = PostgresSaver.from_conn_string(url)
40+
saver = cm.__enter__() # enter the context manager once
41+
atexit.register(lambda: cm.__exit__(None, None, None)) # clean shutdown
42+
saver.setup() # create tables on first run; no-op afterward
43+
_checkpointer = saver
44+
45+
return _checkpointer
3046

3147

3248
def get_agent():

src/app/page.tsx

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const SAMPLE_IMAGES: ImageItem[] = [
2222
description:
2323
"A beautiful landscape with mountains and a serene lake reflecting the sky.",
2424
timestamp: new Date(Date.now() - 86400000), // 1 day ago
25+
type: "sample",
2526
},
2627
{
2728
id: "img_002",
@@ -30,6 +31,7 @@ const SAMPLE_IMAGES: ImageItem[] = [
3031
description:
3132
"Urban cityscape with modern architecture and vibrant street life.",
3233
timestamp: new Date(Date.now() - 43200000), // 12 hours ago
34+
type: "sample",
3335
},
3436
{
3537
id: "img_003",
@@ -38,26 +40,27 @@ const SAMPLE_IMAGES: ImageItem[] = [
3840
description:
3941
"Portrait photography with dramatic lighting and artistic composition.",
4042
timestamp: new Date(),
43+
type: "sample",
4144
},
4245
];
4346

4447
export default function Home() {
4548
const [messages, setMessages] = useState<Message[]>([INITIAL_MESSAGE]);
4649
const [selectedImages, setSelectedImages] = useState<Set<string>>(new Set());
47-
const [images] = useState<ImageItem[]>(SAMPLE_IMAGES);
50+
const [images, setImages] = useState<ImageItem[]>(SAMPLE_IMAGES);
4851
const [isLoading, setIsLoading] = useState(false);
4952
const [userId] = useState(() => crypto.randomUUID());
5053

51-
// Scroll to the right end (newest images) on mount and window resize
52-
useEffect(() => {
54+
// Reusable scroll function
55+
const scrollToRight = () => {
5356
const scrollContainer = document.getElementById("image-scroll-container");
57+
if (scrollContainer) {
58+
scrollContainer.scrollLeft = scrollContainer.scrollWidth;
59+
}
60+
};
5461

55-
const scrollToRight = () => {
56-
if (scrollContainer) {
57-
scrollContainer.scrollLeft = scrollContainer.scrollWidth;
58-
}
59-
};
60-
62+
// Scroll to the right end (newest images) on mount and window resize
63+
useEffect(() => {
6164
// Initial scroll
6265
setTimeout(scrollToRight, 1);
6366

@@ -133,6 +136,22 @@ export default function Home() {
133136
};
134137

135138
const handleChatImageUpload = async (file: File) => {
139+
// Create uploaded image item with UUID
140+
const uploadedImage: ImageItem = {
141+
id: crypto.randomUUID(),
142+
url: URL.createObjectURL(file),
143+
title: "",
144+
description: "",
145+
timestamp: new Date(),
146+
type: "uploaded",
147+
};
148+
149+
// Add to images list
150+
setImages((prev) => [...prev, uploadedImage]);
151+
152+
// Scroll to show the new image
153+
setTimeout(scrollToRight, 100);
154+
136155
const uploadMessage = `📷 Uploaded image: ${file.name}`;
137156

138157
// Add user message

src/lib/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export interface ImageItem {
1111
title: string;
1212
description: string;
1313
timestamp: Date;
14+
type: "uploaded" | "generated" | "sample";
1415
}

0 commit comments

Comments
 (0)