Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
add a document table to persist all the uploaded document names and sizes#9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
eba8ee7e1fefe2261b1ee8892ef6267abffFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -94,12 +94,26 @@ export async function POST(request: NextRequest) { | ||
| ); | ||
| } | ||
| // 5. Increment document count in Prisma | ||
| await prisma.chat.update({ | ||
| where: { id: chatId }, | ||
| // 5. Create a Document record in Prisma | ||
| // Use storage_key as the Document ID for direct lookup during deletion | ||
| const filename = result?.filename || "unknown"; | ||
| const storageKey = result?.storage_key; | ||
| const fileSize = result?.file_size || 0; | ||
| if (!storageKey) { | ||
| console.error("Backend did not return a storage_key"); | ||
| return NextResponse.json( | ||
| { error: "Backend returned an invalid response (missing storage_key)" }, | ||
| { status: 502 }, | ||
| ); | ||
| } | ||
| await prisma.document.create({ | ||
| data: { | ||
| documentCount: { increment: 1 }, | ||
| updatedAt: new Date(), | ||
| id: storageKey, | ||
| name: filename, | ||
| size: BigInt(fileSize), | ||
| chatId, | ||
Comment on lines
+97
to
+116
CopilotAI | ||
| }, | ||
| }); | ||
Comment on lines
+111
to
118
CopilotAI | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -14,6 +14,8 @@ class IngestResponse(BaseModel): | ||
| """Successful response for document ingestion.""" | ||
| chat_id: str = Field(..., description="Chat ID the documents were ingested into") | ||
| filename: str = Field(..., description="Original filename of the uploaded document") | ||
| storage_key: str = Field(..., description="Unique backend storage key for this document upload") | ||
| file_size: int = Field(..., description="File size in bytes") | ||
| chunks_created: int = Field(..., description="Number of text chunks created from the document") | ||
| document_ids: List[str] = Field(..., description="List of document IDs for the created chunks") | ||
| pages_processed: int = Field(default=1, description="Number of pages processed (for PDFs)") | ||
Comment on lines
14
to
21
CopilotAI | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -233,33 +233,37 @@ def delete_collection(self, chat_id: str) -> DeleteCollectionResponse: | ||
| message=f"Failed to delete collection: {str(e)}" | ||
| ) | ||
| def delete_documents_by_filename(self, chat_id: str, filename: str) -> Dict[str, Any]: | ||
| def delete_documents_by_storage_key(self, chat_id: str, storage_key: str) -> Dict[str, Any]: | ||
| """ | ||
| Delete all chunks belonging to a specific file from a chat collection. | ||
| Delete all chunks belonging to a specific document upload from a chat collection. | ||
| Args: | ||
| chat_id: UUID of the chat session. | ||
| filename: The original file name used during ingestion (stored in metadata as file_name). | ||
| storage_key: The unique storage key assigned during ingestion (stored in metadata as source_id). | ||
| Returns: | ||
| Dictionary with success status and deleted count. | ||
| """ | ||
| if not self.collection_exists(chat_id): | ||
| logger.info(f"No collection exists for chat {chat_id}, nothing to delete") | ||
| return {"success": True, "deleted_chunks": 0} | ||
| collection = self.get_collection(chat_id) | ||
| try: | ||
| # ChromaDB supports metadata filtering via the 'where' clause | ||
| # First get the IDs so we can report the count | ||
| results = collection.get( | ||
| where={"file_name": {"$eq": filename}}, | ||
| where={"source_id": {"$eq": storage_key}}, | ||
| include=[] | ||
| ) | ||
coderabbitai[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| chunk_ids = results.get("ids", []) | ||
| if chunk_ids: | ||
| collection.delete(ids=chunk_ids) | ||
| logger.info(f"Deleted {len(chunk_ids)} chunks for file '{filename}' from chat {chat_id}") | ||
| logger.info(f"Deleted {len(chunk_ids)} chunks for storage_key '{storage_key}' from chat {chat_id}") | ||
| else: | ||
| logger.info(f"No chunks found for file '{filename}' in chat {chat_id}") | ||
| logger.info(f"No chunks found for storage_key '{storage_key}' in chat {chat_id}") | ||
| return {"success": True, "deleted_chunks": len(chunk_ids)} | ||
| except Exception as e: | ||
| logger.error(f"Error deleting documents for file '{filename}' in chat {chat_id}: {e}") | ||
| logger.error(f"Error deleting documents for storage_key '{storage_key}' in chat {chat_id}: {e}") | ||
| return {"success": False, "deleted_chunks": 0, "error": str(e)} | ||
| def collection_exists(self, chat_id: str) -> bool: | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -36,10 +36,15 @@ interface UploadedDocument { | ||||||
| id: string; | ||||||
| name: string; | ||||||
| size: string; | ||||||
| filename: string; | ||||||
| uploading?: boolean; | ||||||
| } | ||||||
| function formatFileSize(bytes: number): string { | ||||||
| if (bytes < 1024) return `${bytes} B`; | ||||||
| if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`; | ||||||
| return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; | ||||||
| } | ||||||
| export function ChatArea({ | ||||||
| currentChat, | ||||||
| messages, | ||||||
| @@ -48,14 +53,29 @@ export function ChatArea({ | ||||||
| const [input, setInput] = useState(""); | ||||||
| const [localMessages, setLocalMessages] = useState<Message[]>(messages); | ||||||
| const [isGenerating, setIsGenerating] = useState(false); | ||||||
| const [documents, setDocuments] = useState<UploadedDocument[]>([]); | ||||||
| const [documents, setDocuments] = useState<UploadedDocument[]>( | ||||||
| (currentChat?.documents ?? []).map((d) => ({ | ||||||
| id: d.id, | ||||||
| name: d.name, | ||||||
| size: formatFileSize(d.size), | ||||||
| uploading: false, | ||||||
| })), | ||||||
| ); | ||||||
coderabbitai[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page.
Comment on lines
+56
to
+63
CopilotAI | ||||||
| const fileInputRef = useRef<HTMLInputElement>(null); | ||||||
| const messagesContainerRef = useRef<HTMLDivElement>(null); | ||||||
| const router = useRouter(); | ||||||
| // Reset internal state when navigating between chats | ||||||
| useEffect(() => { | ||||||
| setLocalMessages(messages); | ||||||
| setDocuments( | ||||||
| (currentChat?.documents ?? []).map((d) => ({ | ||||||
| id: d.id, | ||||||
| name: d.name, | ||||||
| size: formatFileSize(d.size), | ||||||
| uploading: false, | ||||||
| })), | ||||||
| ); | ||||||
| }, [messages, currentChat?.id]); | ||||||
CopilotAI | ||||||
| },[messages,currentChat?.id]); | |
| },[messages,currentChat?.id,currentChat?.documents]); |
CopilotAIApr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The optimistic document id is generated client-side, but deletes now use doc.id as the backend storage_key/Prisma Document.id. After upload succeeds you need to replace this optimistic id with the server-provided storage_key (or fully re-sync documents from refreshed currentChat.documents), otherwise delete will call the backend/DB with an ID that doesn’t exist.
Uh oh!
There was an error while loading. Please reload this page.
CopilotAIApr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The schema comment says Document.name is the original display name and Document.filename is the backend storage name, but this code sets both to result.filename (which the backend describes as the original filename). Either persist the original name separately from a stable storage key returned by the backend, or rename/adjust the schema fields/comments so they reflect what’s actually stored. Also, silently defaulting to "unknown" / 0 risks writing bad rows if the backend response changes—prefer validating required fields and returning an error instead.