mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-05 23:42:21 +00:00
Merge pull request #738 from elammertsma/dev
Updated README.md, reorganized and fixed sidebar
This commit is contained in:
commit
46dbd75440
2 changed files with 47 additions and 15 deletions
|
|
@ -52,8 +52,10 @@ https://github.com/user-attachments/assets/a0a16566-6967-4374-ac51-9b3e07fbecd7
|
|||
- Interact in Natural Language and get cited answers.
|
||||
### 📄 **Cited Answers**
|
||||
- Get Cited answers just like Perplexity.
|
||||
### 🧩 **Universal Compatibility**
|
||||
- Connect virtually any inference provider via the OpenAI spec and LiteLLM.
|
||||
### 🔔 **Privacy & Local LLM Support**
|
||||
- Works Flawlessly with Ollama local LLMs.
|
||||
- Works Flawlessly with local LLMs like vLLM and Ollama.
|
||||
### 🏠 **Self Hostable**
|
||||
- Open source and easy to deploy locally.
|
||||
### 👥 **Team Collaboration with RBAC**
|
||||
|
|
@ -61,6 +63,7 @@ https://github.com/user-attachments/assets/a0a16566-6967-4374-ac51-9b3e07fbecd7
|
|||
- Invite team members with customizable roles (Owner, Admin, Editor, Viewer)
|
||||
- Granular permissions for documents, chats, connectors, and settings
|
||||
- Share knowledge bases securely within your organization
|
||||
- Team chats update in real-time and "Chat about the chat" in comment threads
|
||||
### 🎙️ Podcasts
|
||||
- Blazingly fast podcast generation agent. (Creates a 3-minute podcast in under 20 seconds.)
|
||||
- Convert your chat conversations into engaging audio content
|
||||
|
|
@ -237,6 +240,8 @@ Before self-hosting installation, make sure to complete the [prerequisite setup
|
|||
|
||||
### **BackEnd**
|
||||
|
||||
- **LiteLLM**: Universal LLM integration supporting 100+ models (OpenAI, Anthropic, Ollama, etc.)
|
||||
|
||||
- **FastAPI**: Modern, fast web framework for building APIs with Python
|
||||
|
||||
- **PostgreSQL with pgvector**: Database with vector search capabilities for similarity searches
|
||||
|
|
@ -253,8 +258,6 @@ Before self-hosting installation, make sure to complete the [prerequisite setup
|
|||
|
||||
- **LangChain**: Framework for developing AI-powered applications.
|
||||
|
||||
- **LiteLLM**: Universal LLM integration supporting 100+ models (OpenAI, Anthropic, Ollama, etc.)
|
||||
|
||||
- **Rerankers**: Advanced result ranking for improved search relevance
|
||||
|
||||
- **Hybrid Search**: Combines vector similarity and full-text search for optimal results using Reciprocal Rank Fusion (RRF)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
"use client";
|
||||
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { Inbox, LogOut, SquareLibrary, Trash2 } from "lucide-react";
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { currentThreadAtom, resetCurrentThreadAtom } from "@/atoms/chat/current-thread.atom";
|
||||
import { deleteSearchSpaceMutationAtom } from "@/atoms/search-spaces/search-space-mutation.atoms";
|
||||
import { searchSpacesAtom } from "@/atoms/search-spaces/search-space-query.atoms";
|
||||
import { currentUserAtom } from "@/atoms/user/user-query.atoms";
|
||||
|
|
@ -66,11 +67,16 @@ export function LayoutDataProvider({
|
|||
const { data: user } = useAtomValue(currentUserAtom);
|
||||
const { data: searchSpacesData, refetch: refetchSearchSpaces } = useAtomValue(searchSpacesAtom);
|
||||
const { mutateAsync: deleteSearchSpace } = useAtomValue(deleteSearchSpaceMutationAtom);
|
||||
const currentThreadState = useAtomValue(currentThreadAtom);
|
||||
const resetCurrentThread = useSetAtom(resetCurrentThreadAtom);
|
||||
|
||||
// Current IDs from URL
|
||||
// State for handling new chat navigation when router is out of sync
|
||||
const [pendingNewChat, setPendingNewChat] = useState(false);
|
||||
|
||||
// Current IDs from URL, with fallback to atom for replaceState updates
|
||||
const currentChatId = params?.chat_id
|
||||
? Number(Array.isArray(params.chat_id) ? params.chat_id[0] : params.chat_id)
|
||||
: null;
|
||||
: currentThreadState.id;
|
||||
|
||||
// Fetch current search space (for caching purposes)
|
||||
useQuery({
|
||||
|
|
@ -122,6 +128,17 @@ export function LayoutDataProvider({
|
|||
const [isDeletingSearchSpace, setIsDeletingSearchSpace] = useState(false);
|
||||
const [isLeavingSearchSpace, setIsLeavingSearchSpace] = useState(false);
|
||||
|
||||
// Effect to complete new chat navigation after router syncs
|
||||
// This runs when handleNewChat detected an out-of-sync state and triggered a sync
|
||||
useEffect(() => {
|
||||
if (pendingNewChat && params?.chat_id) {
|
||||
// Router is now synced (chat_id is in params), complete navigation to new-chat
|
||||
resetCurrentThread();
|
||||
router.push(`/dashboard/${searchSpaceId}/new-chat`);
|
||||
setPendingNewChat(false);
|
||||
}
|
||||
}, [pendingNewChat, params?.chat_id, router, searchSpaceId, resetCurrentThread]);
|
||||
|
||||
const searchSpaces: SearchSpace[] = useMemo(() => {
|
||||
if (!searchSpacesData || !Array.isArray(searchSpacesData)) return [];
|
||||
return searchSpacesData.map((space) => ({
|
||||
|
|
@ -172,12 +189,6 @@ export function LayoutDataProvider({
|
|||
// Navigation items
|
||||
const navItems: NavItem[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: "Documents",
|
||||
url: `/dashboard/${searchSpaceId}/documents`,
|
||||
icon: SquareLibrary,
|
||||
isActive: pathname?.includes("/documents"),
|
||||
},
|
||||
{
|
||||
title: "Inbox",
|
||||
url: "#inbox", // Special URL to indicate this is handled differently
|
||||
|
|
@ -185,6 +196,12 @@ export function LayoutDataProvider({
|
|||
isActive: isInboxSidebarOpen,
|
||||
badge: unreadCount > 0 ? formatInboxCount(unreadCount) : undefined,
|
||||
},
|
||||
{
|
||||
title: "Documents",
|
||||
url: `/dashboard/${searchSpaceId}/documents`,
|
||||
icon: SquareLibrary,
|
||||
isActive: pathname?.includes("/documents"),
|
||||
},
|
||||
],
|
||||
[searchSpaceId, pathname, isInboxSidebarOpen, unreadCount]
|
||||
);
|
||||
|
|
@ -289,8 +306,20 @@ export function LayoutDataProvider({
|
|||
);
|
||||
|
||||
const handleNewChat = useCallback(() => {
|
||||
router.push(`/dashboard/${searchSpaceId}/new-chat`);
|
||||
}, [router, searchSpaceId]);
|
||||
// Check if router is out of sync (thread created via replaceState but params don't have chat_id)
|
||||
const isOutOfSync = currentThreadState.id !== null && !params?.chat_id;
|
||||
|
||||
if (isOutOfSync) {
|
||||
// First sync Next.js router by navigating to the current chat's actual URL
|
||||
// This updates the router's internal state to match the browser URL
|
||||
router.replace(`/dashboard/${searchSpaceId}/new-chat/${currentThreadState.id}`);
|
||||
// Set flag to trigger navigation to new-chat after params update
|
||||
setPendingNewChat(true);
|
||||
} else {
|
||||
// Normal navigation - router is in sync
|
||||
router.push(`/dashboard/${searchSpaceId}/new-chat`);
|
||||
}
|
||||
}, [router, searchSpaceId, currentThreadState.id, params?.chat_id]);
|
||||
|
||||
const handleChatSelect = useCallback(
|
||||
(chat: ChatItem) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue