diff --git a/src/lib/components/layout/Navbar/Menu.svelte b/src/lib/components/layout/Navbar/Menu.svelte
index 9d2ab76f66..29dfe754e2 100644
--- a/src/lib/components/layout/Navbar/Menu.svelte
+++ b/src/lib/components/layout/Navbar/Menu.svelte
@@ -51,8 +51,6 @@
export let chat;
export let onClose: Function = () => {};
- let showFullMessages = false;
-
const getChatAsText = async () => {
const history = chat.chat.history;
const messages = createMessagesList(history, history.currentId);
@@ -74,158 +72,22 @@
};
const downloadPdf = async () => {
- const [{ default: jsPDF }, { default: html2canvas }] = await Promise.all([
- import('jspdf'),
- import('html2canvas-pro')
- ]);
+ try {
+ // Call backend API for professional PDF generation
+ const messages = createMessagesList(chat.chat.history, chat.chat.history.currentId);
+ const blob = await downloadChatAsPDF(
+ localStorage.token,
+ chat.chat.title,
+ messages
+ );
- if ($settings?.stylizedPdfExport ?? true) {
- showFullMessages = true;
- await tick();
-
- const containerElement = document.getElementById('full-messages-container');
- if (containerElement) {
- try {
- const isDarkMode = document.documentElement.classList.contains('dark');
- const virtualWidth = 800; // px, fixed width for cloned element
-
- // Clone and style
- const clonedElement = containerElement.cloneNode(true);
- clonedElement.classList.add('text-black');
- clonedElement.classList.add('dark:text-white');
- clonedElement.style.width = `${virtualWidth}px`;
- clonedElement.style.position = 'absolute';
- clonedElement.style.left = '-9999px';
- clonedElement.style.height = 'auto';
- document.body.appendChild(clonedElement);
-
- // Wait for DOM update/layout
- await new Promise((r) => setTimeout(r, 100));
-
- // Render entire content once
- const canvas = await html2canvas(clonedElement, {
- backgroundColor: isDarkMode ? '#000' : '#fff',
- useCORS: true,
- scale: 2, // increase resolution
- width: virtualWidth
- });
-
- document.body.removeChild(clonedElement);
-
- const pdf = new jsPDF('p', 'mm', 'a4');
- const pageWidthMM = 210;
- const pageHeightMM = 297;
-
- // Convert page height in mm to px on canvas scale for cropping
- // Get canvas DPI scale:
- const pxPerMM = canvas.width / virtualWidth; // width in px / width in px?
- // Since 1 page width is 210 mm, but canvas width is 800 px at scale 2
- // Assume 1 mm = px / (pageWidthMM scaled)
- // Actually better: Calculate scale factor from px/mm:
- // virtualWidth px corresponds directly to 210mm in PDF, so pxPerMM:
- const pxPerPDFMM = canvas.width / pageWidthMM; // canvas px per PDF mm
-
- // Height in px for one page slice:
- const pagePixelHeight = Math.floor(pxPerPDFMM * pageHeightMM);
-
- let offsetY = 0;
- let page = 0;
-
- while (offsetY < canvas.height) {
- // Height of slice
- const sliceHeight = Math.min(pagePixelHeight, canvas.height - offsetY);
-
- // Create temp canvas for slice
- const pageCanvas = document.createElement('canvas');
- pageCanvas.width = canvas.width;
- pageCanvas.height = sliceHeight;
-
- const ctx = pageCanvas.getContext('2d');
-
- // Draw the slice of original canvas onto pageCanvas
- ctx.drawImage(
- canvas,
- 0,
- offsetY,
- canvas.width,
- sliceHeight,
- 0,
- 0,
- canvas.width,
- sliceHeight
- );
-
- const imgData = pageCanvas.toDataURL('image/jpeg', 0.7);
-
- // Calculate image height in PDF units keeping aspect ratio
- const imgHeightMM = (sliceHeight * pageWidthMM) / canvas.width;
-
- if (page > 0) pdf.addPage();
-
- if (isDarkMode) {
- pdf.setFillColor(0, 0, 0);
- pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg
- }
-
- pdf.addImage(imgData, 'JPEG', 0, 0, pageWidthMM, imgHeightMM);
-
- offsetY += sliceHeight;
- page++;
- }
-
- pdf.save(`chat-${chat.chat.title}.pdf`);
-
- showFullMessages = false;
- } catch (error) {
- console.error('Error generating PDF', error);
- }
+ if (blob) {
+ saveAs(blob, `chat-${chat.chat.title}.pdf`);
+ } else {
+ console.error('Failed to generate PDF');
}
- } else {
- console.log('Downloading PDF');
-
- const chatText = await getChatAsText();
-
- const doc = new jsPDF();
-
- // Margins
- const left = 15;
- const top = 20;
- const right = 15;
- const bottom = 20;
-
- const pageWidth = doc.internal.pageSize.getWidth();
- const pageHeight = doc.internal.pageSize.getHeight();
- const usableWidth = pageWidth - left - right;
- const usableHeight = pageHeight - top - bottom;
-
- // Font size and line height
- const fontSize = 8;
- doc.setFontSize(fontSize);
- const lineHeight = fontSize * 1; // adjust if needed
-
- // Split the markdown into lines (handles \n)
- const paragraphs = chatText.split('\n');
-
- let y = top;
-
- for (let paragraph of paragraphs) {
- // Wrap each paragraph to fit the width
- const lines = doc.splitTextToSize(paragraph, usableWidth);
-
- for (let line of lines) {
- // If the line would overflow the bottom, add a new page
- if (y + lineHeight > pageHeight - bottom) {
- doc.addPage();
- y = top;
- }
- doc.text(line, left, y);
- y += lineHeight * 0.5;
- }
- // Add empty line at paragraph breaks
- y += lineHeight * 0.1;
- }
-
- doc.save(`chat-${chat.chat.title}.pdf`);
+ } catch (error) {
+ console.error('Error generating PDF:', error);
}
};
@@ -247,27 +109,6 @@
};
-{#if showFullMessages}
-
-
- {}}
- continueResponse={() => {}}
- regenerateResponse={() => {}}
- messagesCount={null}
- editCodeBlock={false}
- />
-
-
-{/if}
-
{
if (e.detail === false) {
diff --git a/src/lib/components/layout/Sidebar/ChatMenu.svelte b/src/lib/components/layout/Sidebar/ChatMenu.svelte
index d6f3a3bfe0..f31a8d0487 100644
--- a/src/lib/components/layout/Sidebar/ChatMenu.svelte
+++ b/src/lib/components/layout/Sidebar/ChatMenu.svelte
@@ -47,7 +47,6 @@
let pinned = false;
let chat = null;
- let showFullMessages = false;
const pinHandler = async () => {
await toggleChatPinnedStatusById(localStorage.token, chatId);
@@ -88,158 +87,22 @@
return;
}
- const [{ default: jsPDF }, { default: html2canvas }] = await Promise.all([
- import('jspdf'),
- import('html2canvas-pro')
- ]);
+ try {
+ // Call backend API for professional PDF generation
+ const messages = createMessagesList(chat.chat.history, chat.chat.history.currentId);
+ const blob = await downloadChatAsPDF(
+ localStorage.token,
+ chat.chat.title,
+ messages
+ );
- if ($settings?.stylizedPdfExport ?? true) {
- showFullMessages = true;
- await tick();
-
- const containerElement = document.getElementById('full-messages-container');
- if (containerElement) {
- try {
- const isDarkMode = document.documentElement.classList.contains('dark');
- const virtualWidth = 800; // px, fixed width for cloned element
-
- // Clone and style
- const clonedElement = containerElement.cloneNode(true);
- clonedElement.classList.add('text-black');
- clonedElement.classList.add('dark:text-white');
- clonedElement.style.width = `${virtualWidth}px`;
- clonedElement.style.position = 'absolute';
- clonedElement.style.left = '-9999px';
- clonedElement.style.height = 'auto';
- document.body.appendChild(clonedElement);
-
- // Wait for DOM update/layout
- await new Promise((r) => setTimeout(r, 100));
-
- // Render entire content once
- const canvas = await html2canvas(clonedElement, {
- backgroundColor: isDarkMode ? '#000' : '#fff',
- useCORS: true,
- scale: 2, // increase resolution
- width: virtualWidth
- });
-
- document.body.removeChild(clonedElement);
-
- const pdf = new jsPDF('p', 'mm', 'a4');
- const pageWidthMM = 210;
- const pageHeightMM = 297;
-
- // Convert page height in mm to px on canvas scale for cropping
- // Get canvas DPI scale:
- const pxPerMM = canvas.width / virtualWidth; // width in px / width in px?
- // Since 1 page width is 210 mm, but canvas width is 800 px at scale 2
- // Assume 1 mm = px / (pageWidthMM scaled)
- // Actually better: Calculate scale factor from px/mm:
- // virtualWidth px corresponds directly to 210mm in PDF, so pxPerMM:
- const pxPerPDFMM = canvas.width / pageWidthMM; // canvas px per PDF mm
-
- // Height in px for one page slice:
- const pagePixelHeight = Math.floor(pxPerPDFMM * pageHeightMM);
-
- let offsetY = 0;
- let page = 0;
-
- while (offsetY < canvas.height) {
- // Height of slice
- const sliceHeight = Math.min(pagePixelHeight, canvas.height - offsetY);
-
- // Create temp canvas for slice
- const pageCanvas = document.createElement('canvas');
- pageCanvas.width = canvas.width;
- pageCanvas.height = sliceHeight;
-
- const ctx = pageCanvas.getContext('2d');
-
- // Draw the slice of original canvas onto pageCanvas
- ctx.drawImage(
- canvas,
- 0,
- offsetY,
- canvas.width,
- sliceHeight,
- 0,
- 0,
- canvas.width,
- sliceHeight
- );
-
- const imgData = pageCanvas.toDataURL('image/jpeg', 0.7);
-
- // Calculate image height in PDF units keeping aspect ratio
- const imgHeightMM = (sliceHeight * pageWidthMM) / canvas.width;
-
- if (page > 0) pdf.addPage();
-
- if (isDarkMode) {
- pdf.setFillColor(0, 0, 0);
- pdf.rect(0, 0, pageWidthMM, pageHeightMM, 'F'); // black bg
- }
-
- pdf.addImage(imgData, 'JPEG', 0, 0, pageWidthMM, imgHeightMM);
-
- offsetY += sliceHeight;
- page++;
- }
-
- pdf.save(`chat-${chat.chat.title}.pdf`);
-
- showFullMessages = false;
- } catch (error) {
- console.error('Error generating PDF', error);
- }
+ if (blob) {
+ saveAs(blob, `chat-${chat.chat.title}.pdf`);
+ } else {
+ console.error('Failed to generate PDF');
}
- } else {
- console.log('Downloading PDF');
-
- const chatText = await getChatAsText(chat);
-
- const doc = new jsPDF();
-
- // Margins
- const left = 15;
- const top = 20;
- const right = 15;
- const bottom = 20;
-
- const pageWidth = doc.internal.pageSize.getWidth();
- const pageHeight = doc.internal.pageSize.getHeight();
- const usableWidth = pageWidth - left - right;
- const usableHeight = pageHeight - top - bottom;
-
- // Font size and line height
- const fontSize = 8;
- doc.setFontSize(fontSize);
- const lineHeight = fontSize * 1; // adjust if needed
-
- // Split the markdown into lines (handles \n)
- const paragraphs = chatText.split('\n');
-
- let y = top;
-
- for (let paragraph of paragraphs) {
- // Wrap each paragraph to fit the width
- const lines = doc.splitTextToSize(paragraph, usableWidth);
-
- for (let line of lines) {
- // If the line would overflow the bottom, add a new page
- if (y + lineHeight > pageHeight - bottom) {
- doc.addPage();
- y = top;
- }
- doc.text(line, left, y);
- y += lineHeight * 0.5;
- }
- // Add empty line at paragraph breaks
- y += lineHeight * 0.1;
- }
-
- doc.save(`chat-${chat.chat.title}.pdf`);
+ } catch (error) {
+ console.error('Error generating PDF:', error);
}
};
@@ -259,27 +122,6 @@
}
-{#if chat && showFullMessages}
-
-
- {}}
- continueResponse={() => {}}
- regenerateResponse={() => {}}
- messagesCount={null}
- editCodeBlock={false}
- />
-
-
-{/if}
-
{
diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts
index 27ca354ec5..5b972b38e3 100644
--- a/src/lib/stores/index.ts
+++ b/src/lib/stores/index.ts
@@ -157,7 +157,7 @@ type Settings = {
expandDetails?: boolean;
notificationSound?: boolean;
notificationSoundAlways?: boolean;
- stylizedPdfExport?: boolean;
+ // stylizedPdfExport removed - always uses professional backend PDF now
notifications?: any;
imageCompression?: boolean;
imageCompressionSize?: any;