Skip to content

Commit 0ef57b1

Browse files
Cloud UserCloud User
authored andcommitted
feat(opennext): optimize ram; caching
1 parent ebc7c7b commit 0ef57b1

5 files changed

Lines changed: 56 additions & 126 deletions

File tree

src/app/api/chat/route.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
smoothStream,
66
stepCountIs,
77
streamText,
8-
Tool,
98
UIMessage,
109
} from "ai";
10+
import type { Tool } from "ai";
1111

1212
import { customModelProvider, isToolCallUnsupportedModel } from "lib/ai/models";
1313

@@ -45,10 +45,7 @@ import {
4545
import { getSession } from "auth/server";
4646
import { colorize } from "consola/utils";
4747
import { generateUUID } from "lib/utils";
48-
import { nanoBananaTool, openaiImageTool } from "lib/ai/tools/image";
4948
import { ImageToolName } from "lib/ai/tools";
50-
import { buildCsvIngestionPreviewParts } from "@/lib/ai/ingest/csv-ingest";
51-
import { serverFileStorage } from "lib/file-storage";
5249

5350
const logger = globalLogger.withDefaults({
5451
message: colorize("blackBright", `Chat API: `),
@@ -105,10 +102,16 @@ export async function POST(request: Request) {
105102
if (messages.at(-1)?.id == message.id) {
106103
messages.pop();
107104
}
108-
const ingestionPreviewParts = await buildCsvIngestionPreviewParts(
109-
attachments,
110-
(key) => serverFileStorage.download(key),
111-
);
105+
const ingestionPreviewParts = attachments.length
106+
? await Promise.all([
107+
import("@/lib/ai/ingest/csv-ingest"),
108+
import("lib/file-storage"),
109+
]).then(([{ buildCsvIngestionPreviewParts }, { serverFileStorage }]) =>
110+
buildCsvIngestionPreviewParts(attachments, (key) =>
111+
serverFileStorage.download(key),
112+
),
113+
)
114+
: [];
112115
if (ingestionPreviewParts.length) {
113116
const baseParts = [...message.parts];
114117
let insertionIndex = -1;
@@ -268,14 +271,14 @@ export async function POST(request: Request) {
268271
!supportToolCall && buildToolCallUnsupportedModelSystemPrompt,
269272
);
270273

271-
const IMAGE_TOOL: Record<string, Tool> = useImageTool
272-
? {
273-
[ImageToolName]:
274-
imageTool?.model === "google"
275-
? nanoBananaTool
276-
: openaiImageTool,
277-
}
278-
: {};
274+
const IMAGE_TOOL: Record<string, Tool> = {};
275+
if (useImageTool) {
276+
const { nanoBananaTool, openaiImageTool } = await import(
277+
"lib/ai/tools/image"
278+
);
279+
IMAGE_TOOL[ImageToolName] =
280+
imageTool?.model === "google" ? nanoBananaTool : openaiImageTool;
281+
}
279282
const vercelAITooles = safe({
280283
...MCP_TOOLS,
281284
...WORKFLOW_TOOLS,

src/components/pre-block.tsx

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
"use client";
22

33
import type { JSX } from "react";
4-
import {
5-
bundledLanguages,
6-
codeToHast,
7-
type BundledLanguage,
8-
} from "shiki/bundle/web";
9-
import { Fragment, useLayoutEffect, useState } from "react";
10-
import { jsx, jsxs } from "react/jsx-runtime";
11-
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
12-
import { safe } from "ts-safe";
134
import { cn } from "lib/utils";
14-
import { useTheme } from "next-themes";
155
import { Button } from "ui/button";
166
import { CheckIcon, CopyIcon } from "lucide-react";
177
import JsonView from "ui/json-view";
@@ -76,15 +66,7 @@ const PurePre = ({
7666
);
7767
};
7868

79-
export async function Highlight(
80-
code: string,
81-
lang: BundledLanguage | (string & {}),
82-
theme: string,
83-
) {
84-
const parsed: BundledLanguage = (
85-
bundledLanguages[lang] ? lang : "md"
86-
) as BundledLanguage;
87-
69+
export function Highlight(code: string, lang: string): JSX.Element {
8870
if (lang === "json") {
8971
return (
9072
<PurePre code={code} lang={lang}>
@@ -101,50 +83,22 @@ export async function Highlight(
10183
);
10284
}
10385

104-
const out = await codeToHast(code, {
105-
lang: parsed,
106-
theme,
107-
});
108-
109-
return toJsxRuntime(out, {
110-
Fragment,
111-
jsx,
112-
jsxs,
113-
components: {
114-
pre: (props) => <PurePre {...props} code={code} lang={lang} />,
115-
},
116-
}) as JSX.Element;
86+
return (
87+
<PurePre code={code} lang={lang}>
88+
<code className={`language-${lang}`}>{code}</code>
89+
</PurePre>
90+
);
11791
}
11892

11993
export function PreBlock({ children }: { children: any }) {
12094
const code = children.props.children;
121-
const { theme } = useTheme();
12295
const language = children.props.className?.split("-")?.[1] || "bash";
123-
const [loading, setLoading] = useState(true);
124-
const [component, setComponent] = useState<JSX.Element | null>(
125-
<PurePre className="animate-pulse" code={code} lang={language}>
126-
{children}
127-
</PurePre>,
128-
);
129-
130-
useLayoutEffect(() => {
131-
safe()
132-
.map(() =>
133-
Highlight(
134-
code,
135-
language,
136-
theme == "dark" ? "dark-plus" : "github-light",
137-
),
138-
)
139-
.ifOk(setComponent)
140-
.watch(() => setLoading(false));
141-
}, [theme, language, code]);
96+
const component = Highlight(code, language);
14297

14398
// For other code blocks, render as before
14499
return (
145100
<div
146101
className={cn(
147-
loading && "animate-pulse",
148102
"text-sm flex bg-secondary/40 shadow border flex-col rounded relative my-4 overflow-hidden",
149103
)}
150104
>

src/components/ui/CodeBlock.tsx

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
"use client";
2-
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
3-
import { useTheme } from "next-themes";
4-
import { Fragment, useLayoutEffect, useState } from "react";
5-
import type { JSX, ReactNode } from "react";
6-
import { codeToHast } from "shiki/bundle/web";
7-
import { safe } from "ts-safe";
8-
import { jsx, jsxs } from "react/jsx-runtime";
2+
import type { ReactNode } from "react";
93
import { cn } from "lib/utils";
104

115
export function CodeBlock({
@@ -21,48 +15,20 @@ export function CodeBlock({
2115
className?: string;
2216
showLineNumbers?: boolean;
2317
}) {
24-
const { theme } = useTheme();
25-
26-
const [component, setComponent] = useState<JSX.Element | null>(null);
27-
28-
useLayoutEffect(() => {
29-
safe()
30-
.map(async () => {
31-
const out = await codeToHast(code || "", {
32-
lang: lang,
33-
theme: theme == "dark" ? "github-dark" : "github-light",
34-
});
35-
return toJsxRuntime(out, {
36-
Fragment,
37-
jsx,
38-
jsxs,
39-
components: {
40-
pre: (props) => (
41-
<pre
42-
{...props}
43-
lang={lang}
44-
style={undefined}
45-
className={cn(props.className, className)}
46-
>
47-
<div className={cn(showLineNumbers && "pl-12 relative")}>
48-
{showLineNumbers && (
49-
<div className="absolute left-0 top-0 w-6 flex flex-col select-none text-right text-muted-foreground">
50-
{code?.split("\n").map((_, index) => (
51-
<span key={index}>{index + 1}</span>
52-
))}
53-
</div>
54-
)}
55-
{props.children}
56-
</div>
57-
</pre>
58-
),
59-
},
60-
}) as JSX.Element;
61-
})
62-
.ifOk(setComponent);
63-
}, [theme, lang, code]);
64-
6518
if (!code) return fallback;
6619

67-
return component ?? fallback;
20+
return (
21+
<pre lang={lang} className={cn("overflow-x-auto", className)}>
22+
<div className={cn(showLineNumbers && "pl-12 relative")}>
23+
{showLineNumbers && (
24+
<div className="absolute left-0 top-0 w-6 flex flex-col select-none text-right text-muted-foreground">
25+
{code.split("\n").map((_, index) => (
26+
<span key={index}>{index + 1}</span>
27+
))}
28+
</div>
29+
)}
30+
<code>{code}</code>
31+
</div>
32+
</pre>
33+
);
6834
}

src/lib/db/pg/db.pg.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ const getCloudflareContext: GetCloudflareContext | undefined =
1616
: undefined;
1717

1818
const createPgDb = (connectionString: string) => {
19+
const isCloudflareWorker = process.env.APP_RUNTIME === "cloudflare-workers";
1920
const pool = new Pool({
2021
connectionString,
22+
max: isCloudflareWorker ? 1 : undefined,
2123
maxUses: 1,
2224
});
2325

wrangler.jsonc

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,22 @@
22
"$schema": "node_modules/wrangler/config-schema.json",
33
"main": ".open-next/worker.js",
44
"name": "semantyka-app-better-chatbot",
5-
"compatibility_date": "2026-07-05",
5+
"compatibility_date": "2026-07-06",
66
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
7+
"observability": {
8+
"enabled": true,
9+
},
10+
"cache": {
11+
"enabled": true,
12+
},
713
"assets": {
814
"directory": ".open-next/assets",
9-
"binding": "ASSETS"
15+
"binding": "ASSETS",
1016
},
1117
"services": [
1218
{
1319
"binding": "WORKER_SELF_REFERENCE",
14-
"service": "semantyka-app-better-chatbot"
15-
}
20+
},
1621
],
1722
"vars": {
1823
"APP_RUNTIME": "cloudflare-workers",
@@ -22,13 +27,13 @@
2227
"FILE_STORAGE_PREFIX": "uploads",
2328
"MCP_REMOTE_ONLY": "1",
2429
"FILE_BASED_MCP_CONFIG": "false",
25-
"NEXTJS_ENV": "production"
30+
"NEXTJS_ENV": "production",
2631
},
2732
"hyperdrive": [
2833
{
2934
"binding": "HYPERDRIVE",
3035
"id": "replace-with-hyperdrive-id",
31-
"localConnectionString": "postgres://your_username:your_password@localhost:5432/your_database_name"
32-
}
33-
]
36+
"localConnectionString": "postgres://your_username:your_password@localhost:5432/your_database_name",
37+
},
38+
],
3439
}

0 commit comments

Comments
 (0)