Skip to content

Commit

Permalink
feat: implement more fs APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
CNSeniorious000 committed Aug 23, 2024
1 parent 4e2c16c commit b4fdb9d
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 8 deletions.
40 changes: 37 additions & 3 deletions reasonify-headless/api/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

from bridge import with_toast
from js import window
from pyodide.ffi import create_once_callable, create_proxy
from utils.fs import NativeFS, mount
from pyodide.ffi import JsBuffer, create_once_callable, create_proxy
from utils.fs import NativeFS, mount, unmount
from utils.to_js import to_js


@cache
Expand All @@ -22,14 +23,15 @@ async def install_slugify():


mounted: dict[str, NativeFS] = {}
single_files = set[str]()


@create_proxy
async def mount_native_fs():
install_promise = _install_slugify()

handle = await window.showDirectoryPicker()
while await handle.requestPermission({"mode": "readwrite"}) != "granted":
while await handle.requestPermission(to_js({"mode": "readwrite"})) != "granted":
pass

await install_promise
Expand All @@ -45,6 +47,38 @@ async def mount_native_fs():
return name


async def add_single_files():
handles = await window.showOpenFilePicker(to_js({"multiple": True}))

names = []

for handle in handles:
path = root / handle.name
buffer: JsBuffer = await (await handle.getFile()).arrayBuffer()
with path.open("w") as f:
buffer.to_file(f)
single_files.add(str(path))
names.append(handle.name)

return to_js([handle.name for handle in handles])


async def sync_all():
for name, fs in mounted.items():
await with_toast(f"syncing {Path(name).name}")(fs.syncfs)()


def reset():
for path in single_files:
Path(path).unlink()
single_files.clear()

for path in mounted:
unmount(path)
Path(path).rmdir()
mounted.clear()


root = Path("/workspace/mnt")
root.mkdir(parents=True, exist_ok=True)
chdir(root)
Expand Down
10 changes: 10 additions & 0 deletions reasonify-headless/utils/to_js.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from typing import TYPE_CHECKING

if TYPE_CHECKING:

def to_js[T](x: T) -> T: ...

else:
from pyodide.ffi import to_js

__all__ = ["to_js"]
23 changes: 19 additions & 4 deletions src/lib/components/Chat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import type { PythonError } from "pyodide/ffi";
import { type Chain, initChain } from "../py";
import { clearApiCache } from "../py/api";
import { clearApiCache, getApi } from "../py/api";
import Highlight from "./Highlight.svelte";
import Markdown from "./Markdown.svelte";
import { dev } from "$app/environment";
import { mount } from "$lib/py/fs";
import { addFiles, mount } from "$lib/py/fs";
import { pyodideReady, reasonifyReady, startIconAnimation, stopIconAnimation } from "$lib/stores";
import { toast } from "svelte-sonner";
Expand Down Expand Up @@ -101,18 +101,33 @@
<div class="i-lucide-plane-takeoff" />
</button>
<button disabled={!$pyodideReady} on:click={async () => {
const name = await mount();
context.messages = [...messages, { role: "system", name: "info", content: `user mounted a directory: ./${name}` }];
const names = await addFiles();
context.messages = [...messages, { role: "system", name: "info", content: `user added ${names.length} files: ${(names.map(name => `./${name}`)).join(", ")}` }];
}}>
<div class="i-lucide-file-symlink" />
</button>
{#if "showDirectoryPicker" in window}
<button disabled={!$pyodideReady} on:click={async () => {
const name = await mount();
context.messages = [...messages, { role: "system", name: "info", content: `user mounted a directory: ./${name}` }];
}}>
<div class="i-lucide-folder-symlink" />
</button>
<button disabled={!$pyodideReady} on:click={async () => {
const syncAll = getApi("api.fs.sync_all");
await syncAll();
}}>
<div class="i-lucide-hard-drive-download" />
</button>
{/if}
{#if dev}
<button disabled={refreshing} on:click={refresh}>
<div class="i-lucide-refresh-cw" />
</button>
{/if}
<button disabled={!messages.length || running} on:click={() => {
context = { query: content };
getApi("api.fs.reset")();
}}>
<div class="i-lucide-circle-fading-plus" />
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/lib/py/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { py } from "./load";

const cache = new Map<string, any>();

export function getApi<T>(slug: string): T {
export function getApi<T = () => any>(slug: string): T {
if (cache.has(slug)) {
return cache.get(slug) as T;
} else {
Expand Down
5 changes: 5 additions & 0 deletions src/lib/py/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export async function mount(): Promise<string> {
const mount = getApi<() => Promise<string>>("api.fs.mount_native_fs");
return withToast("selecting a directory to mount", (name) => (`mounted ${name}`))(mount)();
}

export async function addFiles(): Promise<string[]> {
const mount = getApi<() => Promise<string[]>>("api.fs.add_single_files");
return withToast("selecting files to add to workspace", (names: string[]) => (names.length === 1 ? `added ${names[0]}` : `added ${names.length} files`))(mount)();
}

1 comment on commit b4fdb9d

@vercel
Copy link

@vercel vercel bot commented on b4fdb9d Aug 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

reasonify – ./

reasonify-git-main-promplate.vercel.app
reasonify.vercel.app
reasonify-promplate.vercel.app

Please sign in to comment.