Skip to content

Commit bfaabc3

Browse files
committed
continued work on ai chat
1 parent fc56c32 commit bfaabc3

1 file changed

Lines changed: 28 additions & 16 deletions

File tree

app/api/chat/route.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const STOP_WORDS = new Set([
1414
'i','you','he','she','it','we','they','what','which','who','how','when','where',
1515
'why','and','or','but','not','in','on','at','to','for','of','with','by','from',
1616
'this','that','these','those','my','your','his','her','its','our','their',
17+
'about','other','another','also','too','more','any','some','just','even',
18+
'still','like','else','same','different','similar','related','using','use',
1719
]);
1820

1921
function buildSearchQuery(text: string): string {
@@ -32,25 +34,32 @@ async function runSearch(query: string, maxPages = 8) {
3234
{
3335
indexName: process.env.NEXT_PUBLIC_ALGOLIA_INDEX!,
3436
query: searchQuery,
35-
hitsPerPage: 40,
37+
hitsPerPage: 60,
3638
},
3739
],
3840
});
3941

40-
const seen = new Set<string>();
41-
const hits: { url: string; title: string; section: string; content: string }[] = [];
42+
// Group all chunks by url+section, preserving rank order of first appearance
43+
const groups = new Map<string, { url: string; title: string; section: string; parts: string[] }>();
44+
const order: string[] = [];
4245

4346
for (const hit of (results[0] as any).hits ?? []) {
4447
const url = hit.url ?? hit.objectID;
48+
const section = (hit.section ?? '') as string;
4549
const content = (hit.content ?? '') as string;
46-
if (content.length < 40) continue; // skip table cell fragments
47-
if (seen.has(url)) continue; // one chunk per page
48-
seen.add(url);
49-
hits.push({ url, title: hit.title ?? '', section: hit.section ?? '', content });
50-
if (hits.length >= maxPages) break;
50+
if (!content.trim()) continue;
51+
const key = `${url}|${section}`;
52+
if (!groups.has(key)) {
53+
groups.set(key, { url, title: hit.title ?? '', section, parts: [] });
54+
order.push(key);
55+
}
56+
groups.get(key)!.parts.push(content);
5157
}
5258

53-
return hits;
59+
return order.slice(0, maxPages).map((key) => {
60+
const g = groups.get(key)!;
61+
return { url: g.url, title: g.title, section: g.section, content: g.parts.join(' | ') };
62+
});
5463
}
5564

5665
const openrouter = createOpenRouter({
@@ -71,13 +80,16 @@ export async function POST(req: Request) {
7180
const reqJson: { messages?: UIMessage[] } = await req.json();
7281
const messages = reqJson.messages ?? [];
7382

74-
const userMessages = messages.filter((m) => m.role === 'user');
75-
const recentUserText = userMessages
76-
.slice(-3)
77-
.flatMap((m) => m.parts?.filter((p: any) => p.type === 'text').map((p: any) => p.text as string) ?? [])
78-
.join(' ');
83+
const lastUserMessage = messages.filter((m) => m.role === 'user').at(-1);
84+
const lastUserText =
85+
lastUserMessage?.parts
86+
?.filter((p: any) => p.type === 'text')
87+
.map((p: any) => p.text as string)
88+
.join(' ') ?? '';
7989

80-
const docs = recentUserText ? await runSearch(recentUserText) : [];
90+
console.log('[chat] searching for:', lastUserText);
91+
const docs = lastUserText ? await runSearch(lastUserText) : [];
92+
console.log('[chat] got', docs.length, 'results:', docs.map(d => `${d.url} [${d.section}] "${d.content.slice(0, 80)}""`));
8193

8294
const contextBlock =
8395
docs.length > 0
@@ -91,7 +103,7 @@ export async function POST(req: Request) {
91103
model: openrouter.chat(process.env.OPENROUTER_MODEL ?? 'anthropic/claude-3.5-sonnet'),
92104
maxOutputTokens: 1024,
93105
messages: [
94-
{ role: 'system', content: `${systemPrompt}\n\n${contextBlock}` },
106+
{ role: 'system', content: `${systemPrompt}\n\n${contextBlock}\n\nCurrent question: ${lastUserText}` },
95107
...messages
96108
.filter((m) => m.role === 'user' || m.role === 'assistant')
97109
.map((m) => ({

0 commit comments

Comments
 (0)