From 1f85354856f92f3b7f97a974833817ad0c49004b Mon Sep 17 00:00:00 2001 From: "Timothy J. Baek" Date: Wed, 3 Apr 2024 20:35:32 -0700 Subject: [PATCH] feat: stylised pdf --- backend/apps/web/routers/utils.py | 13 ++++++ src/lib/apis/utils/index.ts | 25 +++++++++++ src/lib/components/layout/Navbar/Menu.svelte | 44 ++++++++++++++++++-- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/backend/apps/web/routers/utils.py b/backend/apps/web/routers/utils.py index 4b5ac8cfa..ef5717f10 100644 --- a/backend/apps/web/routers/utils.py +++ b/backend/apps/web/routers/utils.py @@ -5,6 +5,8 @@ from starlette.responses import StreamingResponse, FileResponse from pydantic import BaseModel + +import markdown import requests import os import aiohttp @@ -28,6 +30,17 @@ async def get_gravatar( return get_gravatar_url(email) +class MarkdownForm(BaseModel): + md: str + + +@router.post("/markdown") +async def get_html_from_markdown( + form_data: MarkdownForm, +): + return {"html": markdown.markdown(form_data.md)} + + @router.get("/db/download") async def download_db(user=Depends(get_admin_user)): diff --git a/src/lib/apis/utils/index.ts b/src/lib/apis/utils/index.ts index bcb554077..53e93688a 100644 --- a/src/lib/apis/utils/index.ts +++ b/src/lib/apis/utils/index.ts @@ -22,6 +22,31 @@ export const getGravatarUrl = async (email: string) => { return res; }; +export const getHTMLFromMarkdown = async (md: string) => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/utils/markdown`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + md: md + }) + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.log(err); + error = err; + return null; + }); + + return res.html; +}; + export const downloadDatabase = async (token: string) => { let error = null; diff --git a/src/lib/components/layout/Navbar/Menu.svelte b/src/lib/components/layout/Navbar/Menu.svelte index 048adbeb9..ae505ec6f 100644 --- a/src/lib/components/layout/Navbar/Menu.svelte +++ b/src/lib/components/layout/Navbar/Menu.svelte @@ -46,11 +46,47 @@ const doc = new jsPDF(); - const chatText = _chat.messages.reduce((a, message, i, arr) => { - return `${a}### ${message.role.toUpperCase()}\n${message.content}\n\n`; - }, ''); + // Initialize y-coordinate for text placement + let yPos = 10; + const pageHeight = doc.internal.pageSize.height; + + // Function to check if new text exceeds the current page height + function checkAndAddNewPage() { + if (yPos > pageHeight - 10) { + doc.addPage(); + yPos = 10; // Reset yPos for the new page + } + } + + // Function to add text with specific style + function addStyledText(text, isTitle = false) { + // Set font style and size based on the parameters + doc.setFont('helvetica', isTitle ? 'bold' : 'normal'); + doc.setFontSize(isTitle ? 12 : 10); + + const textMargin = 7; + + // Split text into lines to ensure it fits within the page width + const lines = doc.splitTextToSize(text, 180); // Adjust the width as needed + + lines.forEach((line) => { + checkAndAddNewPage(); // Check if we need a new page before adding more text + doc.text(line, 10, yPos); + yPos += textMargin; // Increment yPos for the next line + }); + + // Add extra space after a block of text + yPos += 2; + } + + _chat.messages.forEach((message, i) => { + // Add user text in bold + doc.setFont('helvetica', 'normal', 'bold'); + + addStyledText(message.role.toUpperCase(), { isTitle: true }); + addStyledText(message.content); + }); - doc.text(chatText, 10, 10); doc.save(`chat-${_chat.title}.pdf`); };