we do a bit of solidifying :trolley:
parent
7bdcce22a8
commit
add896662f
@ -1 +0,0 @@
|
|||||||
/target
|
|
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"rust-analyzer.linkedProjects": [
|
||||||
|
".\\backend\\Cargo.toml"
|
||||||
|
],
|
||||||
|
"[scss]": {
|
||||||
|
"editor.tabSize": 2
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
[workspace]
|
|
||||||
resolver = "2"
|
|
||||||
members = ["crates/*"]
|
|
@ -1,6 +1,3 @@
|
|||||||
# ai-gui-web
|
# ai-gui-web
|
||||||
|
|
||||||
Janky port of ai-gui to the web.
|
A version of AI Gui made for the web.
|
||||||
Made to test out leptos.
|
|
||||||
|
|
||||||
Probably won't be getting updated much considering it was made as a test.
|
|
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
/history
|
||||||
|
config.ron
|
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
|||||||
config.ron
|
|
@ -1 +0,0 @@
|
|||||||
dist/
|
|
@ -1,14 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "frontend"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
ai_core = { git = "https://git.ruthenic.com/xTymon/ai-gui", rev = "a847557914" }
|
|
||||||
leptos = "0.2.5"
|
|
||||||
tracing = "0.1.37"
|
|
||||||
tracing-wasm = "0.2.1"
|
|
||||||
gloo-net = "0.2.6"
|
|
||||||
serde_json = "1.0.96"
|
|
@ -1,3 +0,0 @@
|
|||||||
[[proxy]]
|
|
||||||
rewrite = "/api/"
|
|
||||||
backend = "http://localhost:3000/"
|
|
@ -1,9 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<link data-trunk rel="scss" href="./index.scss"/>
|
|
||||||
</head>
|
|
||||||
<body></body>
|
|
||||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||||||
mod ui;
|
|
||||||
|
|
||||||
use leptos::*;
|
|
||||||
use ui::*;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
tracing_wasm::set_as_global_default();
|
|
||||||
|
|
||||||
mount_to_body(|cx| view! { cx, <GenerationUI /> })
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
use ai_core::ai::Params;
|
|
||||||
use gloo_net::http::Request;
|
|
||||||
use leptos::{
|
|
||||||
html::{Input, Option_, Select, Textarea},
|
|
||||||
*,
|
|
||||||
};
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn GenerationUI(cx: Scope) -> impl IntoView {
|
|
||||||
let input: NodeRef<Textarea> = create_node_ref(cx);
|
|
||||||
let output: NodeRef<Textarea> = create_node_ref(cx);
|
|
||||||
|
|
||||||
let ai_selector: NodeRef<Select> = create_node_ref(cx);
|
|
||||||
let temp: NodeRef<Input> = create_node_ref(cx);
|
|
||||||
let max_tokens: NodeRef<Input> = create_node_ref(cx);
|
|
||||||
|
|
||||||
let generate_action = create_action(cx, move |_: &()| async move {
|
|
||||||
// these unwraps should never fail as the elements will always exist at this point
|
|
||||||
let prompt = input.get().unwrap().value();
|
|
||||||
let output = output.get().unwrap();
|
|
||||||
|
|
||||||
let temperature = temp.get().unwrap().value_as_number();
|
|
||||||
let max_tokens = max_tokens.get().unwrap().value_as_number();
|
|
||||||
|
|
||||||
let ai_selector = ai_selector.get().unwrap().value();
|
|
||||||
|
|
||||||
output.set_value("Generating...");
|
|
||||||
|
|
||||||
let res = Request::post("/api/generate")
|
|
||||||
.json(&json!({
|
|
||||||
"ai": ai_selector,
|
|
||||||
"params": Params {
|
|
||||||
prompt,
|
|
||||||
max_tokens: max_tokens as _,
|
|
||||||
temperature: temperature as _
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.unwrap()
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Ok(res) => {
|
|
||||||
if res.status() != 200 {
|
|
||||||
output.set_value("Failed to generate!");
|
|
||||||
tracing::error!("Status code not 200");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = res.text().await.unwrap(); // should be safe to unwrap here?
|
|
||||||
|
|
||||||
output.set_value(&res);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
output.set_value("Failed to generate!");
|
|
||||||
tracing::error!("{}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
_ = create_resource(cx, || (), move |_| async move {
|
|
||||||
let res = Request::get("/api/ais").send().await;
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Ok(res) => {
|
|
||||||
if res.status() != 200 {
|
|
||||||
tracing::error!("Status code not 200 for AI selector fetch");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// these should never fail in theory
|
|
||||||
let res: Value = res.json().await.unwrap();
|
|
||||||
let res = res.as_array().unwrap().to_vec();
|
|
||||||
|
|
||||||
for ai in res {
|
|
||||||
let ai = ai.as_str().unwrap(); // should never fail
|
|
||||||
let option = &Option_::default();
|
|
||||||
|
|
||||||
option.set_value(ai);
|
|
||||||
option.set_label(ai);
|
|
||||||
|
|
||||||
ai_selector.get().unwrap().append_child(&option).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
tracing::error!("Failed to get AIs for selector! {}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
view! { cx,
|
|
||||||
<main>
|
|
||||||
<div class="bar">
|
|
||||||
<button on:click=move |_| {
|
|
||||||
generate_action.dispatch(());
|
|
||||||
}>
|
|
||||||
"Generate"
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<h5>"AI"</h5>
|
|
||||||
<select node_ref=ai_selector />
|
|
||||||
|
|
||||||
<h5>"Temperature"</h5>
|
|
||||||
<input type="number" min="0" max="2" step="0.1" value="1" node_ref=temp />
|
|
||||||
|
|
||||||
<h5>"Max Tokens"</h5>
|
|
||||||
<input type="number" min="0" max="2000" step="10" value="1000" node_ref=max_tokens />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="io">
|
|
||||||
<textarea node_ref=input />
|
|
||||||
<textarea readonly="true" node_ref=output />
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>AI Gui</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
<script src="/src/index.tsx" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "",
|
||||||
|
"scripts": {
|
||||||
|
"start": "vite",
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"serve": "vite preview"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"sass": "^1.62.0",
|
||||||
|
"typescript": "^5.0.4",
|
||||||
|
"vite": "^4.3.1",
|
||||||
|
"vite-plugin-solid": "^2.7.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"solid-js": "^1.7.3"
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,89 @@
|
|||||||
|
import {
|
||||||
|
createSignal,
|
||||||
|
type Component,
|
||||||
|
createMemo,
|
||||||
|
For,
|
||||||
|
createResource,
|
||||||
|
} from "solid-js";
|
||||||
|
|
||||||
|
const App: Component = () => {
|
||||||
|
const [input, setInput] = createSignal("");
|
||||||
|
const [output, setOutput] = createSignal("");
|
||||||
|
|
||||||
|
const [selectedAI, setSelectedAI] = createSignal("");
|
||||||
|
const [temperature, setTemperature] = createSignal(1.0);
|
||||||
|
const [maxTokens, setMaxTokens] = createSignal(1000);
|
||||||
|
|
||||||
|
const [ais] = createResource(async () => {
|
||||||
|
const res: string[] = await (await fetch("/api/ais")).json();
|
||||||
|
|
||||||
|
setSelectedAI(res[0]);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function generate() {
|
||||||
|
setOutput("Generating...");
|
||||||
|
|
||||||
|
const res = await (
|
||||||
|
await fetch("/api/generate", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
ai: selectedAI(),
|
||||||
|
params: {
|
||||||
|
prompt: input(),
|
||||||
|
temperature: temperature(),
|
||||||
|
max_tokens: maxTokens(),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
).text();
|
||||||
|
|
||||||
|
setOutput(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div class="root">
|
||||||
|
{/* TODO: Make this part of the ui better */}
|
||||||
|
<div class="bar">
|
||||||
|
<button onClick={generate}>Generate</button>
|
||||||
|
|
||||||
|
<label for="ais">AI</label>
|
||||||
|
<select id="ais" onChange={(e) => setSelectedAI(e.target.value)}>
|
||||||
|
<For each={ais()}>{(ai) => <option>{ai}</option>}</For>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="temperature">Temperature</label>
|
||||||
|
<input
|
||||||
|
id="temperature"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="2"
|
||||||
|
step="0.1"
|
||||||
|
value="1"
|
||||||
|
onChange={(e) => setTemperature(e.currentTarget.valueAsNumber)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label for="maxTokens">Max Tokens</label>
|
||||||
|
<input
|
||||||
|
id="maxTokens"
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
max="2000"
|
||||||
|
step="10"
|
||||||
|
value="1000"
|
||||||
|
onChange={(e) => setMaxTokens(e.currentTarget.valueAsNumber)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="io">
|
||||||
|
<textarea onInput={(e) => setInput(e.currentTarget.value)} />
|
||||||
|
<textarea readonly={true} value={output()} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,9 @@
|
|||||||
|
/* @refresh reload */
|
||||||
|
import { render } from "solid-js/web";
|
||||||
|
|
||||||
|
import "./index.scss";
|
||||||
|
import App from "./App";
|
||||||
|
|
||||||
|
const root = document.getElementById("root");
|
||||||
|
|
||||||
|
render(() => <App />, root!);
|
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "solid-js",
|
||||||
|
"noEmit": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import { defineConfig } from "vite";
|
||||||
|
import solidPlugin from "vite-plugin-solid";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [solidPlugin()],
|
||||||
|
server: {
|
||||||
|
port: 8080,
|
||||||
|
proxy: {
|
||||||
|
"/api": {
|
||||||
|
target: "http://localhost:3000/",
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
target: "esnext",
|
||||||
|
},
|
||||||
|
});
|
Reference in new issue