Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add draft of extraction UI #23

Merged
merged 1 commit into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🦜</text></svg>"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LangChain Extract</title>
</head>
<body>
<div data-theme="light" id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
61 changes: 61 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "langchain-extract",
"private": true,
"version": "0.0.0",
"type": "module",
"license": "MIT",
"scripts": {
"fix": "eslint --fix --ext=js,jsx,ts,tsx . && prettier --write .",
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0 && prettier --check"
},
"dependencies": {
"@chakra-ui/card": "^2.2.0",
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8",
"@codemirror/lang-json": "^6.0.1",
"@emotion/react": "^11",
"@emotion/styled": "^11",
"@heroicons/react": "^2.1.1",
"@mui/material": "^5.15.10",
"@rjsf/chakra-ui": "^5.17.1",
"@rjsf/core": "^5.17.1",
"@rjsf/utils": "^5.17.1",
"@rjsf/validator-ajv8": "^5.17.1",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@tanstack/react-query": "^5.22.2",
"@uiw/react-codemirror": "^4.21.24",
"axios": "^1.6.7",
"chakra-react-select": "^4.7.6",
"eslint-plugin-react": "^7.34.1",
"framer-motion": "^5",
"orval": "^6.25.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"react-syntax-highlighter": "^15.5.0",
"swr": "^2.2.5",
"vite-plugin-eslint": "^1.8.1",
"yarn": "^1.22.21"
},
"devDependencies": {
"@types/react": "^18.2.56",
"@types/react-dom": "^18.2.19",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.17",
"daisyui": "^4.7.2",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"typescript": "^5.4.2",
"typescript-eslint": "^7.2.0",
"vite": "^5.1.4"
}
}
6 changes: 6 additions & 0 deletions frontend/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
66 changes: 66 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { ChakraProvider, useDisclosure } from "@chakra-ui/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import React from "react";
import { BrowserRouter, Outlet, Route, Routes } from "react-router-dom";
import CreateExtractor from "./components/CreateExtractor";
import { Playground } from "./components/Playground";
import { Sidebar } from "./components/Sidebar";
import "./index.css";

const queryClient = new QueryClient();

const Root = () => {
const { isOpen, onOpen, onClose } = useDisclosure();

return (
<>
<div className="flex flex-col w-100% h-full">
<div className="flex justify-between bg-slate-200 mb-4 p-3 items-center gap-2">
<div className="font-semibold">🦜⛏️ LangChain Extract</div>
<div className="text-s text-rose-800">
<strong>Research Preview</strong>: this app is unauthenticated and all data can be found. Do not use with
sensitive data.
</div>
</div>
<div className="flex gap-3 ml-5 mr-5">
<div className="w-1/6">
<Sidebar isOpen={isOpen} onOpen={onOpen} onClose={onClose} />
</div>
<div className="m-auto w-5/6">
<Outlet />
</div>
</div>
</div>
</>
);
};

const Main = () => {
return (
<>
<BrowserRouter>
<Routes>
<Route element={<Root />}>
<Route path="/" element={<CreateExtractor />} />
<Route path="/e/:extractorId" element={<Playground />} />
<Route path="/new" element={<CreateExtractor />} />
</Route>
</Routes>
</BrowserRouter>
</>
);
};

const App = () => {
return (
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ChakraProvider>
<Main />
</ChakraProvider>
</QueryClientProvider>
</React.StrictMode>
);
};

export default App;
72 changes: 72 additions & 0 deletions frontend/src/api.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* Expose API hooks for use in components */
import axios from "axios";
import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";

export type ExtractorData = {
uuid: string;
name: string;
description: string;
schema: any;
};

const getExtractor = async ({ queryKey }): ExtractorData => {
const [_, uuid] = queryKey;
const response = await axios.get(`/extractors/${uuid}`);
return response.data;
};

const listExtractors = async () => {
const response = await axios.get("/extractors");
return response.data;
};

const createExtractor = async (extractor) => {
const response = await axios.post("/extractors", extractor);
return response.data;
};

export const suggestExtractor = async ({ description, jsonSchema }) => {
if (description === "") {
return {};
}
const response = await axios.post("/suggest", { description, jsonSchema });
return response.data;
};

export const runExtraction = async (extractionRequest) => {
const response = await axios.postForm("/extract", extractionRequest);
return response.data;
};

export const useRunExtraction = () => {
return useMutation({ mutationFn: runExtraction });
};

export const useGetExtractor = (uuid: string) => {
return useQuery({ queryKey: ["getExtractor", uuid], queryFn: getExtractor });
};

export const useGetExtractors = () => {
return useQuery({ queryKey: ["getExtractors"], queryFn: listExtractors });
};

export const useDeleteExtractor = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (uuid: string) => axios.delete(`/extractors/${uuid}`),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["getExtractors"] });
},
});
};

export const useCreateExtractor = ({ onSuccess }) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createExtractor,
onSuccess: (data) => {
queryClient.invalidateQueries({ queryKey: ["getExtractors"] });
onSuccess(data);
},
});
};
Loading
Loading