Making UI progress; seeding lkml RAG
This commit is contained in:
parent
b25498f6a0
commit
1c56814a92
14
lkml/init.sh
Normal file
14
lkml/init.sh
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
fail() {
|
||||||
|
echo "FAIL: ${*}" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in {8..16}; do
|
||||||
|
if [[ -d "${i}" ]]; then
|
||||||
|
echo "Skipping lkml/git/$i -- already exists"
|
||||||
|
else
|
||||||
|
cmd="git clone https://erol.kernel.org/lkml/git/$i"
|
||||||
|
${cmd} || fail "cmd"
|
||||||
|
fi
|
||||||
|
done
|
@ -10,22 +10,13 @@ div {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
overflow: auto;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 1rem;
|
|
||||||
border: 1px solid green;
|
|
||||||
max-width: 80%;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
.ChatBox {
|
.ChatBox {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Controls {
|
.Controls {
|
||||||
|
@ -2,9 +2,8 @@ import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|||||||
import FormGroup from '@mui/material/FormGroup';
|
import FormGroup from '@mui/material/FormGroup';
|
||||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||||
import Switch from '@mui/material/Switch';
|
import Switch from '@mui/material/Switch';
|
||||||
import Card from '@mui/material/Card';
|
import Snackbar, { SnackbarCloseReason } from '@mui/material/Snackbar';
|
||||||
import CardHeader from '@mui/material/CardHeader';
|
import Alert from '@mui/material/Alert';
|
||||||
import CardContent from '@mui/material/CardContent';
|
|
||||||
import TextField from '@mui/material/TextField';
|
import TextField from '@mui/material/TextField';
|
||||||
import Accordion from '@mui/material/Accordion';
|
import Accordion from '@mui/material/Accordion';
|
||||||
import AccordionActions from '@mui/material/AccordionActions';
|
import AccordionActions from '@mui/material/AccordionActions';
|
||||||
@ -13,7 +12,13 @@ import AccordionDetails from '@mui/material/AccordionDetails';
|
|||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import Container from '@mui/material/Container';
|
import AppBar from '@mui/material/AppBar';
|
||||||
|
import Drawer from '@mui/material/Drawer';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
import MenuIcon from '@mui/icons-material/Menu';
|
||||||
|
import IconButton from '@mui/material/IconButton';
|
||||||
|
import Box from '@mui/material/Box';
|
||||||
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
|
|
||||||
import PropagateLoader from "react-spinners/PropagateLoader";
|
import PropagateLoader from "react-spinners/PropagateLoader";
|
||||||
import Markdown from 'react-markdown';
|
import Markdown from 'react-markdown';
|
||||||
@ -45,12 +50,15 @@ type Tool = {
|
|||||||
enabled: boolean
|
enabled: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SeverityType = 'error' | 'info' | 'success' | 'warning' | undefined;
|
||||||
|
|
||||||
interface ControlsParams {
|
interface ControlsParams {
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
connectionBase: string
|
connectionBase: string,
|
||||||
|
setSnack: (snackMessage: string, snackSeverity?: SeverityType) => void
|
||||||
};
|
};
|
||||||
|
|
||||||
const Controls = ({ sessionId, connectionBase }: ControlsParams) => {
|
const Controls = ({ sessionId, connectionBase, setSnack }: ControlsParams) => {
|
||||||
const [systemPrompt, setSystemPrompt] = useState<string>("");
|
const [systemPrompt, setSystemPrompt] = useState<string>("");
|
||||||
const [editSystemPrompt, setEditSystemPrompt] = useState<string>(systemPrompt);
|
const [editSystemPrompt, setEditSystemPrompt] = useState<string>(systemPrompt);
|
||||||
|
|
||||||
@ -68,7 +76,6 @@ const Controls = ({ sessionId, connectionBase }: ControlsParams) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log(data);
|
|
||||||
setSystemPrompt(data["system-prompt"]);
|
setSystemPrompt(data["system-prompt"]);
|
||||||
setEditSystemPrompt(data["system-prompt"]);
|
setEditSystemPrompt(data["system-prompt"]);
|
||||||
}
|
}
|
||||||
@ -119,9 +126,11 @@ const Controls = ({ sessionId, connectionBase }: ControlsParams) => {
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
if (data["system-prompt"] !== systemPrompt) {
|
if (data["system-prompt"] !== systemPrompt) {
|
||||||
setSystemPrompt(data["system-prompt"].trim());
|
setSystemPrompt(data["system-prompt"].trim());
|
||||||
|
setSnack("System prompt updated", "success");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fetch error:', error);
|
console.error('Fetch error:', error);
|
||||||
|
setSnack("System prompt update failed", "error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -142,6 +151,7 @@ const Controls = ({ sessionId, connectionBase }: ControlsParams) => {
|
|||||||
setEditSystemPrompt(systemPrompt)
|
setEditSystemPrompt(systemPrompt)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fetch error:', error);
|
console.error('Fetch error:', error);
|
||||||
|
setSnack("Unable to fetch system prompt", "error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -227,6 +237,19 @@ const App = () => {
|
|||||||
const [processing, setProcessing] = useState(false);
|
const [processing, setProcessing] = useState(false);
|
||||||
const [sessionId, setSessionId] = useState<string | undefined>(undefined);
|
const [sessionId, setSessionId] = useState<string | undefined>(undefined);
|
||||||
const [loc,] = useState<Location>(window.location)
|
const [loc,] = useState<Location>(window.location)
|
||||||
|
const [mobileOpen, setMobileOpen] = useState(false);
|
||||||
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
|
const [snackOpen, setSnackOpen] = useState(false);
|
||||||
|
const [snackMessage, setSnackMessage] = useState("");
|
||||||
|
const [snackSeverity, setSnackSeverity] = useState<SeverityType>("success");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (snackMessage === "") {
|
||||||
|
setSnackOpen(false);
|
||||||
|
} else {
|
||||||
|
setSnackOpen(true);
|
||||||
|
}
|
||||||
|
}, [snackMessage, setSnackOpen]);
|
||||||
|
|
||||||
// Scroll to bottom of conversation when conversation updates
|
// Scroll to bottom of conversation when conversation updates
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -269,6 +292,32 @@ const App = () => {
|
|||||||
|
|
||||||
}, [setSessionId, loc]);
|
}, [setSessionId, loc]);
|
||||||
|
|
||||||
|
const setSnack = (message: string, severity: SeverityType = "success") => {
|
||||||
|
setSnackMessage(message);
|
||||||
|
setSnackSeverity(severity);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDrawerClose = () => {
|
||||||
|
setIsClosing(true);
|
||||||
|
setMobileOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDrawerTransitionEnd = () => {
|
||||||
|
setIsClosing(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDrawerToggle = () => {
|
||||||
|
if (!isClosing) {
|
||||||
|
setMobileOpen(!mobileOpen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const drawer = (
|
||||||
|
<>
|
||||||
|
{sessionId !== undefined && <Controls setSnack={setSnack} sessionId={sessionId} connectionBase={getConnectionBase(loc)} />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
const handleKeyPress = (event: any) => {
|
const handleKeyPress = (event: any) => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
switch (event.target.id) {
|
switch (event.target.id) {
|
||||||
@ -298,6 +347,8 @@ const App = () => {
|
|||||||
const sendQuery = async () => {
|
const sendQuery = async () => {
|
||||||
if (!query.trim()) return;
|
if (!query.trim()) return;
|
||||||
|
|
||||||
|
setSnack("Query sent", "info");
|
||||||
|
|
||||||
const userMessage = [{ role: 'user', content: query }];
|
const userMessage = [{ role: 'user', content: query }];
|
||||||
|
|
||||||
// Add user message to conversation
|
// Add user message to conversation
|
||||||
@ -431,6 +482,7 @@ const App = () => {
|
|||||||
setProcessing(false);
|
setProcessing(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Fetch error:', error);
|
console.error('Fetch error:', error);
|
||||||
|
setSnack("Unable to process query", "error");
|
||||||
setConversation(prev => [
|
setConversation(prev => [
|
||||||
...prev.filter(msg => !msg.isProcessing),
|
...prev.filter(msg => !msg.isProcessing),
|
||||||
{ role: 'assistant', type: 'error', content: `Error: ${error}` }
|
{ role: 'assistant', type: 'error', content: `Error: ${error}` }
|
||||||
@ -439,16 +491,80 @@ const App = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const handleSnackClose = (
|
||||||
<Container className="Container">
|
event: React.SyntheticEvent | Event,
|
||||||
|
reason?: SnackbarCloseReason,
|
||||||
|
) => {
|
||||||
|
setSnackMessage("");
|
||||||
|
|
||||||
<div className="ChatBox">
|
if (reason === 'clickaway') {
|
||||||
<div className="Conversation" ref={conversationRef}>
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSnackOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', height: 1 }}>
|
||||||
|
<CssBaseline />
|
||||||
|
<AppBar
|
||||||
|
position="fixed"
|
||||||
|
sx={{
|
||||||
|
zIndex: (theme) => theme.zIndex.drawer + 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Toolbar>
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
aria-label="open drawer"
|
||||||
|
edge="start"
|
||||||
|
onClick={handleDrawerToggle}
|
||||||
|
sx={{ mr: 2 }}
|
||||||
|
>
|
||||||
|
<MenuIcon />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h6" noWrap component="div">
|
||||||
|
Ketr-Chat
|
||||||
|
</Typography>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
<Box
|
||||||
|
component="nav"
|
||||||
|
aria-label="mailbox folders"
|
||||||
|
>
|
||||||
|
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
|
||||||
|
<Drawer
|
||||||
|
container={window.document.body}
|
||||||
|
variant="temporary"
|
||||||
|
open={mobileOpen}
|
||||||
|
onTransitionEnd={handleDrawerTransitionEnd}
|
||||||
|
onClose={handleDrawerClose}
|
||||||
|
sx={{
|
||||||
|
display: 'block',
|
||||||
|
'& .MuiDrawer-paper': { boxSizing: 'border-box' },
|
||||||
|
}}
|
||||||
|
slotProps={{
|
||||||
|
root: {
|
||||||
|
keepMounted: true, // Better open performance on mobile.
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Toolbar />
|
||||||
|
{drawer}
|
||||||
|
</Drawer>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
component="main"
|
||||||
|
sx={{ flexGrow: 1, p: 3, height: '100vh' }}
|
||||||
|
className="ChatBox">
|
||||||
|
<Toolbar />
|
||||||
|
|
||||||
|
<Box className="Conversation"
|
||||||
|
sx={{ flexGrow: 1, p: 3 }}
|
||||||
|
ref={conversationRef}>
|
||||||
{conversation.map((message, index) => {
|
{conversation.map((message, index) => {
|
||||||
const formattedContent = message.content
|
const formattedContent = message.content.trim();
|
||||||
.split("\n")
|
|
||||||
.map((line) => line.replace(/^[^\s:]+:\s*/, ''))
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index} className={message.role === 'user' ? 'user-message' : 'assistant-message'}>
|
<div key={index} className={message.role === 'user' ? 'user-message' : 'assistant-message'}>
|
||||||
@ -491,9 +607,9 @@ const App = () => {
|
|||||||
data-testid="loader"
|
data-testid="loader"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Box>
|
||||||
|
|
||||||
<div className="Query" style={{ display: "flex", flexDirection: "row" }}>
|
<Box className="Query" style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<TextField
|
<TextField
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
disabled={processing}
|
disabled={processing}
|
||||||
@ -509,11 +625,19 @@ const App = () => {
|
|||||||
<AccordionActions>
|
<AccordionActions>
|
||||||
<Button variant="contained" onClick={sendQuery}>Send</Button>
|
<Button variant="contained" onClick={sendQuery}>Send</Button>
|
||||||
</AccordionActions>
|
</AccordionActions>
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</Box>
|
||||||
{sessionId !== undefined && <Controls sessionId={sessionId} connectionBase={getConnectionBase(loc)} />}
|
<Snackbar open={snackOpen} autoHideDuration={snackSeverity === "success" ? 1500 : 6000} onClose={handleSnackClose}>
|
||||||
|
<Alert
|
||||||
</Container>
|
onClose={handleSnackClose}
|
||||||
|
severity={snackSeverity}
|
||||||
|
variant="filled"
|
||||||
|
sx={{ width: '100%' }}
|
||||||
|
>
|
||||||
|
{snackMessage}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
</Box >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -373,7 +373,6 @@ class WebServer:
|
|||||||
async def get_system_prompt(context_id: str):
|
async def get_system_prompt(context_id: str):
|
||||||
context = self.upsert_context(context_id)
|
context = self.upsert_context(context_id)
|
||||||
system_prompt = context["system"][0]["content"];
|
system_prompt = context["system"][0]["content"];
|
||||||
logging.info(f"returning system prompt as '{system_prompt}'")
|
|
||||||
return JSONResponse({ "system-prompt": system_prompt })
|
return JSONResponse({ "system-prompt": system_prompt })
|
||||||
|
|
||||||
@self.app.post('/api/chat/{context_id}')
|
@self.app.post('/api/chat/{context_id}')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user