Skip to content

Commit

Permalink
Capture screen like similar to Claude (#1604)
Browse files Browse the repository at this point in the history
* feat: capture screen

* feat: make it work with latest tool UI

* fix: add screenshot icon

* Update src/lib/components/icons/iconScreenshot.svelte

Co-authored-by: Victor Muštar <[email protected]>

* fix: capitalization

* fix: stop tracks in finally block

* fix: revert chatwindow changes that shouldnt be there

* fix: tooltip classes

---------

Co-authored-by: Nathan Sarrazin <[email protected]>
Co-authored-by: Victor Muštar <[email protected]>
  • Loading branch information
3 people authored Jan 8, 2025
1 parent f48d079 commit 79c26f2
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/lib/components/chat/ChatInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import { goto } from "$app/navigation";
import { base } from "$app/paths";
import IconAdd from "~icons/carbon/add";
import { captureScreen } from "$lib/utils/screenshot";
import IconScreenshot from "../icons/IconScreenshot.svelte";
export let files: File[] = [];
export let mimeTypes: string[] = [];
Expand Down Expand Up @@ -250,6 +252,31 @@
</label>
</HoverTooltip>
</form>
{#if mimeTypes.includes("image/*")}
<HoverTooltip
label="Capture screenshot"
position="top"
TooltipClassNames="text-xs !text-left !w-auto whitespace-nowrap !py-1 !mb-0 max-sm:hidden"
>
<button
class="base-tool"
on:click|preventDefault={async () => {
const screenshot = await captureScreen();

// Convert base64 to blob
const base64Response = await fetch(screenshot);
const blob = await base64Response.blob();

// Create a File object from the blob
const file = new File([blob], "screenshot.png", { type: "image/png" });

files = [...files, file];
}}
>
<IconScreenshot classNames="text-xl" />
</button>
</HoverTooltip>
{/if}
{/if}
{#if modelHasTools}
{#each extraTools as tool}
Expand Down
20 changes: 20 additions & 0 deletions src/lib/components/icons/IconScreenshot.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
export let classNames = "";
</script>

<svg
class={classNames}
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
focusable="false"
role="img"
width="1em"
height="1em"
fill="currentColor"
viewBox="0 0 32 32"
><path
fill-rule="evenodd"
clip-rule="evenodd"
d="M5.98 6.01h20.04v16.1H5.98V6.02Zm-2.1 0c0-1.16.94-2.1 2.1-2.1h20.04c1.16 0 2.1.94 2.1 2.1v16.1a2.1 2.1 0 0 1-2.1 2.11H5.98a2.1 2.1 0 0 1-2.1-2.1V6.02Zm5.7 1.65a2.1 2.1 0 0 0-2.1 2.1v2.61a1.05 1.05 0 0 0 2.1 0v-2.6h2.96a1.05 1.05 0 1 0 0-2.11H9.58ZM24.41 18.4a2.1 2.1 0 0 1-2.1 2.1h-2.95a1.05 1.05 0 1 1 0-2.1h2.95v-2.61a1.05 1.05 0 0 1 2.1 0v2.6ZM10.1 25.9a1.05 1.05 0 1 0 0 2.1H22.3a1.05 1.05 0 1 0 0-2.1H10.1Z"
/>
</svg>
43 changes: 43 additions & 0 deletions src/lib/utils/screenshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export async function captureScreen(): Promise<string> {
let stream: MediaStream | undefined;
try {
// This will show the native browser dialog for screen capture
stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false,
});

// Create a canvas element to capture the screenshot
const canvas = document.createElement("canvas");
const video = document.createElement("video");

// Wait for the video to load metadata
await new Promise((resolve) => {
video.onloadedmetadata = () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
video.play();
resolve(null);
};
if (stream) {
video.srcObject = stream;
} else {
throw Error("No stream available");
}
});

// Draw the video frame to canvas
const context = canvas.getContext("2d");
context?.drawImage(video, 0, 0, canvas.width, canvas.height);
// Convert to base64
return canvas.toDataURL("image/png");
} catch (error) {
console.error("Error capturing screenshot:", error);
throw error;
} finally {
// Stop all tracks
if (stream) {
stream.getTracks().forEach((track) => track.stop());
}
}
}

0 comments on commit 79c26f2

Please sign in to comment.