diff --git a/.env b/.env index 2a6736ae0cd..cf597a33058 100644 --- a/.env +++ b/.env @@ -91,4 +91,7 @@ PUBLIC_APP_DISCLAIMER=#set to 1 to show a disclaimer on login page # PUBLIC_APP_ASSETS=huggingchat # PUBLIC_APP_COLOR=yellow # PUBLIC_APP_DATA_SHARING=1 -# PUBLIC_APP_DISCLAIMER=1 \ No newline at end of file +# PUBLIC_APP_DISCLAIMER=1 + +MATHPIX_APP_ID=#your mathpix app id here +MATHPIX_APP_KEY=#your mathpix app key here diff --git a/src/lib/components/FileDropzone.svelte b/src/lib/components/FileDropzone.svelte new file mode 100644 index 00000000000..fc7683194a7 --- /dev/null +++ b/src/lib/components/FileDropzone.svelte @@ -0,0 +1,104 @@ + + +
+
+
+ {#if fileList.length === 0} +
+ +
+

+ Drag and drop your PDF file here +

+ {:else if file_error === true} +

+ Error {file_error_message} +

+ {:else} + {#each fileList as file} +

+ + {file.name}: {file.size} bytes is being converted +

+ {/each} + {/if} +
+
diff --git a/src/lib/components/chat/ChatWindow.svelte b/src/lib/components/chat/ChatWindow.svelte index 476140bb52d..f9e7b29a64c 100644 --- a/src/lib/components/chat/ChatWindow.svelte +++ b/src/lib/components/chat/ChatWindow.svelte @@ -15,6 +15,7 @@ import WebSearchToggle from "../WebSearchToggle.svelte"; import type { WebSearchMessage } from "$lib/types/WebSearch"; import LoginModal from "../LoginModal.svelte"; + import FileDropzone from "../FileDropzone.svelte"; export let messages: Message[] = []; export let loading = false; @@ -44,6 +45,24 @@ dispatch("message", message); message = ""; }; + + let lastTarget: EventTarget | null = null; + let onDrag = false; + + const onDragEnter = (e: DragEvent) => { + lastTarget = e.target; + onDrag = true; + }; + + const onDragLeave = (e: DragEvent) => { + if (e.target === lastTarget) { + onDrag = false; + } + }; + + const onDragOver = (e: DragEvent) => { + e.preventDefault(); + };
@@ -69,78 +88,87 @@ />
-
- {#if settings?.searchEnabled} - - {/if} - {#if loading} - dispatch("stop")} - /> - {/if} -
-
-
- { - if (loginRequired) loginModalOpen = true; - }} - maxRows={4} - disabled={isReadOnly} - /> - + {#if onDrag} + + {:else} +
+ {#if settings?.searchEnabled} + + {/if} {#if loading} - - - {:else} + /> + {/if} +
+ +
+ { + if (loginRequired) loginModalOpen = true; + }} + maxRows={4} + disabled={isReadOnly} + /> + + {#if loading} + + + {:else} + + {/if} +
+ +
+

+ Model: {currentModel.displayName} ·
Generated content may be inaccurate + or false. +

+ {#if messages.length} {/if}
- -
-

- Model: {currentModel.displayName} ·
Generated content may be inaccurate - or false. -

- {#if messages.length} - - {/if} -
+ {/if}
diff --git a/src/lib/server/pdfconvert/requestPdfConversion.ts b/src/lib/server/pdfconvert/requestPdfConversion.ts new file mode 100644 index 00000000000..3bb1aa506dc --- /dev/null +++ b/src/lib/server/pdfconvert/requestPdfConversion.ts @@ -0,0 +1,72 @@ +import { MATHPIX_APP_ID, MATHPIX_APP_KEY } from "$env/static/private"; + +type MathpixOptions = { + conversion_formats: { + 'md': boolean; + 'docx': boolean; + 'tex.zip': boolean; + 'html': boolean; + }; + math_inline_delimiters: string[]; + rm_spaces: boolean; +}; + +const defaultOptions: MathpixOptions = { + conversion_formats: { + 'md': true, + 'docx': false, + 'tex.zip': false, + 'html': false, + }, + math_inline_delimiters: ['$', '$'], + rm_spaces: true, +}; + +// See https://docs.mathpix.com/#process-a-pdf +async function requestPdfConversion(file: Blob, option: MathpixOptions = defaultOptions): Promise { + const BASE_URL = 'https://api.mathpix.com/v3'; + const headers = { + 'app_id': MATHPIX_APP_ID, + 'app_key': MATHPIX_APP_KEY + }; + + // Start the conversion + const formData = new FormData(); + formData.append('file', file); + formData.append('options_json', JSON.stringify(option)); + + const initialResponse = await fetch(`${BASE_URL}/pdf`, { + method: 'POST', + headers: headers, + body: formData + }); + + const { pdf_id } = await initialResponse.json(); + + // Check conversion status + let conversionCompleted = false; + while (!conversionCompleted) { + const statusResponse = await fetch(`${BASE_URL}/converter/${pdf_id}`, { + method: 'GET', + headers: headers + }); + + const statusData = await statusResponse.json(); + if (statusData.status === "completed") { + conversionCompleted = true; + } else { + // Wait for a 1 second before polling again + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + + // Fetch the markdown data + const markdownResponse = await fetch(`${BASE_URL}/converter/${pdf_id}.md`, { + method: 'GET', + headers: headers + }); + + return await markdownResponse.text(); +} + +export { requestPdfConversion }; \ No newline at end of file diff --git a/src/routes/convertPdf/+server.ts b/src/routes/convertPdf/+server.ts new file mode 100644 index 00000000000..6e767e516e8 --- /dev/null +++ b/src/routes/convertPdf/+server.ts @@ -0,0 +1,8 @@ +import { requestPdfConversion } from '$lib/server/pdfconvert/requestPdfConversion'; +import { json } from '@sveltejs/kit'; + +export async function POST({ request }) { + const blob = await request.blob() + const result = await requestPdfConversion(blob); + return json({ result }, { status: 201 }); +}