Files
app/app/api/calculate-graph/route.ts
Albert 0ed2d6c0b3 feat: Improve UI layout and navigation
- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility
- Add logo as favicon
- Add logo to mobile header
- Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile)
- Fix desktop chat layout - container structure prevents voice controls cutoff
- Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons
- Hide Create Node/New Conversation buttons on mobile to save header space
- Make fixed header and voice controls work properly with containers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:43:11 +00:00

90 lines
2.9 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { cookies } from 'next/headers';
import { UMAP } from 'umap-js';
import { connectToDB } from '@/lib/db';
import { verifySurrealJwt } from '@/lib/auth/jwt';
/**
* POST /api/calculate-graph
*
* Calculates 3D coordinates for all nodes using UMAP dimensionality reduction.
* This route:
* 1. Fetches all nodes with embeddings but no 3D coordinates
* 2. Runs UMAP to reduce embeddings from 768-D to 3-D
* 3. Updates each node with its calculated 3D coordinates
*/
export async function POST(request: NextRequest) {
const cookieStore = await cookies();
const surrealJwt = cookieStore.get('ponderants-auth')?.value;
if (!surrealJwt) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
}
// Verify JWT to get user's DID
const userSession = verifySurrealJwt(surrealJwt);
if (!userSession) {
return NextResponse.json({ error: 'Invalid auth token' }, { status: 401 });
}
const { did: userDid } = userSession;
try {
const db = await connectToDB();
// 1. Fetch all nodes that have an embedding but no coords_3d (filtered by user_did)
const query = `SELECT id, embedding FROM node WHERE user_did = $userDid AND embedding != NONE AND coords_3d = NONE`;
const results = await db.query<[Array<{ id: string; embedding: number[] }>]>(query, { userDid });
const nodes = results[0] || [];
if (nodes.length < 3) {
// UMAP needs at least 3 points to work well
return NextResponse.json(
{ message: 'Not enough nodes to map. Create at least 3 nodes with content.' },
{ status: 200 }
);
}
console.log(`[Calculate Graph] Processing ${nodes.length} nodes for UMAP projection`);
// 2. Prepare data for UMAP
const embeddings = nodes.map((n) => n.embedding);
// 3. Run UMAP to reduce 768-D (or 1536-D) to 3-D
const umap = new UMAP({
nComponents: 3,
nNeighbors: Math.min(15, nodes.length - 1), // nNeighbors must be < sample size
minDist: 0.1,
spread: 1.0,
});
console.log('[Calculate Graph] Running UMAP dimensionality reduction...');
const coords_3d_array = await umap.fitAsync(embeddings);
console.log('[Calculate Graph] ✓ UMAP projection complete');
// 4. Update nodes in SurrealDB with their new 3D coords
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
const coords = coords_3d_array[i];
await db.merge(node.id, {
coords_3d: [coords[0], coords[1], coords[2]],
});
}
console.log(`[Calculate Graph] ✓ Updated ${nodes.length} nodes with 3D coordinates`);
return NextResponse.json({
success: true,
nodes_mapped: nodes.length,
});
} catch (error) {
console.error('[Calculate Graph] Error:', error);
return NextResponse.json(
{ error: 'Failed to calculate graph' },
{ status: 500 }
);
}
}