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

Develop #38

Merged
merged 32 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
af62127
Use GunicornInternalPrometheusMetrics and example Gauge metric
Mar 22, 2024
3b9c7ca
Merge branch 'develop' of github.com:embernet/sidekick into prometheus
Apr 10, 2024
9806c3c
Merge pull request #37 from embernet/prometheus
karimtabet Apr 10, 2024
4477018
Merge branch 'mobile-ui' into develop
embernet Apr 24, 2024
63f4b20
Revert gunicorn prometheus work
Apr 25, 2024
f30cee7
Undo changes to Makefile
Apr 25, 2024
50fd9ff
Newline
Apr 25, 2024
ccb2988
Newline
Apr 25, 2024
4d3fcea
mermaid diagrams centre themselves
embernet May 7, 2024
3b65caa
Merge branch 'develop' of github.com:embernet/sidekick into develop
embernet May 7, 2024
5c2ef7f
Merge branch 'main' into develop
embernet May 7, 2024
f2c39d1
MermaidDiagram now detects markdown errors and replaces mermaid error…
embernet May 7, 2024
f2116eb
Markdown copy button now includes language designator
embernet May 8, 2024
521d5db
fixed race condition in MermaidDiagram render
embernet May 8, 2024
8fbdb70
added Diagrams sub-menu to Chat Prompt menu
embernet May 8, 2024
701b01c
added use case diagrams
embernet May 9, 2024
be3ce0b
fixed bug in chat context menu to delete this and subsequent messages
embernet May 9, 2024
8bc9226
Merge branch 'diagrams' into develop
embernet May 9, 2024
55f98c2
Moved delete all messages menu item to bottom
embernet May 9, 2024
dea1985
Run server in container as sidekick user
May 13, 2024
6afa1a3
Optionally set open ai base URL as env var
May 13, 2024
5be0818
Use open ai base url in routes
May 13, 2024
13fe63e
Note add to AI library tooltip expanded
embernet May 14, 2024
b5fa9b3
Gave AI Note Library a toolbar with a close button
embernet May 14, 2024
4866eb4
Merge branch 'diagrams' into develop
embernet May 14, 2024
33d1b63
added support for OpenAI gpt-4o model
embernet May 14, 2024
8ac7ed7
Merge branch 'develop' of github.com:embernet/sidekick into aig
May 14, 2024
feecede
Get openai api key from custom util
May 14, 2024
1b34190
system warnings now pop up a modal dialogue
embernet May 15, 2024
b429cba
fixed bug so note not corrupted in renderMarkdown mode
embernet May 15, 2024
91b47f3
Merge pull request #40 from embernet/aig
embernet May 15, 2024
2a8a6bc
Merge branch 'develop' of github.com:embernet/sidekick into develop
embernet May 15, 2024
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
6 changes: 6 additions & 0 deletions node_modules/.package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
25 changes: 19 additions & 6 deletions server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
FROM python:3.10-alpine
RUN apk add gcc musl-dev libffi-dev

RUN apk add --no-cache gcc musl-dev libffi-dev

RUN adduser -D -u 1000 sidekick

WORKDIR /sidekick_server

COPY Pipfile.lock ./
RUN pip install --upgrade pip
RUN pip install pipenv
RUN pipenv requirements > requirements.txt
RUN pip install --no-cache-dir --upgrade -r requirements.txt
RUN pip install --upgrade pip && \
pip install pipenv && \
pipenv requirements > requirements.txt && \
pip install --no-cache-dir --upgrade -r requirements.txt

COPY init.py app.py models.py routes.py utils.py docker-entrypoint.sh ./
COPY custom_utils ./custom_utils
COPY default_documents ./default_documents
COPY default_settings ./default_settings
COPY system_settings ./system_settings
COPY migrations ./migrations

RUN chmod +x docker-entrypoint.sh
ENTRYPOINT ["/bin/sh", "docker-entrypoint.sh"]

RUN chown -R sidekick:sidekick /sidekick_server

USER sidekick

ENTRYPOINT ["/bin/sh", "docker-entrypoint.sh"]
1 change: 1 addition & 0 deletions server/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = False
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["SQLALCHEMY_DATABASE_URI"]
app.config["OPENAI_API_KEY"] = os.environ["OPENAI_API_KEY"]
app.config["OPENAI_BASE_URL"] = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
app.config["OPENAI_PROXY"] = os.environ.get("OPENAI_PROXY")

# Optionallay count chat tokens if specified in the env var
Expand Down
4 changes: 4 additions & 0 deletions server/custom_utils/get_openai_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from app import app

def get_openai_token():
return app.config['OPENAI_API_KEY']
9 changes: 9 additions & 0 deletions server/default_settings/model_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
"providers": {
"OpenAI": {
"models": {
"gpt-4o": {
"temperature": 0.7,
"topP": 1,
"frequencyPenalty": 0,
"presencePenalty": 0,
"contextTokenSize": 128000,
"systemMessage": "You are a helpful advisor.",
"notes": "Points to the latest version of the gpt-4o (Omni) model. Cheaper and faster than gpt-4-turbo."
},
"gpt-4-turbo-preview": {
"temperature": 0.7,
"topP": 1,
Expand Down
18 changes: 9 additions & 9 deletions server/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import json
import requests
import socket
import uuid
import sseclient

from collections import OrderedDict
from datetime import datetime
from utils import DBUtils, construct_ai_request, RequestLogger,\
server_stats, increment_server_stat, openai_num_tokens_from_messages, \
get_random_string, num_characters_from_messages, update_default_settings
from custom_utils.get_openai_token import get_openai_token

from flask import request, jsonify, Response, stream_with_context, redirect, session, url_for
from flask_jwt_extended import get_jwt_identity, jwt_required, \
Expand Down Expand Up @@ -101,10 +101,10 @@ def test_ai():
with RequestLogger(request) as rl:
increment_server_stat(category="requests", stat_name="healthAi")
try:
url = 'https://api.openai.com/v1/chat/completions'
url = f"{app.config['OPENAI_BASE_URL']}/chat/completions"
headers = {
'content-type': 'application/json; charset=utf-8',
'Authorization': f"Bearer {app.config['OPENAI_API_KEY']}"
'Authorization': f"Bearer {get_openai_token()}"
}
ai_request = {
"model": "gpt-3.5-turbo",
Expand Down Expand Up @@ -337,10 +337,10 @@ def construct_name_topic_request(request):
return ai_request

try:
url = 'https://api.openai.com/v1/chat/completions'
url = f"{app.config['OPENAI_BASE_URL']}/chat/completions"
headers = {
'content-type': 'application/json; charset=utf-8',
'Authorization': f"Bearer {app.config['OPENAI_API_KEY']}"
'Authorization': f"Bearer {get_openai_token()}"
}
ai_request = construct_name_topic_request(request)
promptCharacters = num_characters_from_messages(ai_request["messages"])
Expand Down Expand Up @@ -416,10 +416,10 @@ def construct_query_ai_request(request):
promptCharacters = num_characters_from_messages(ai_request["messages"])
increment_server_stat(category="usage", stat_name="promptCharacters", increment=promptCharacters)
increment_server_stat(category="usage", stat_name="totalCharacters", increment=promptCharacters)
url = 'https://api.openai.com/v1/chat/completions'
url = f"{app.config['OPENAI_BASE_URL']}/chat/completions"
headers = {
'content-type': 'application/json; charset=utf-8',
'Authorization': f"Bearer {app.config['OPENAI_API_KEY']}"
'Authorization': f"Bearer {get_openai_token()}"
}
message_usage["prompt_characters"] = num_characters_from_messages(
ai_request["messages"])
Expand Down Expand Up @@ -473,10 +473,10 @@ def chat_v2():
increment_server_stat(category="requests", stat_name="chatV2")

def generate():
url = 'https://api.openai.com/v1/chat/completions'
url = f"{app.config['OPENAI_BASE_URL']}/chat/completions"
headers = {
'content-type': 'application/json; charset=utf-8',
'Authorization': f"Bearer {app.config['OPENAI_API_KEY']}"
'Authorization': f"Bearer {get_openai_token()}"
}
ai_request = construct_ai_request(request)
ai_request["stream"] = True
Expand Down
131 changes: 111 additions & 20 deletions web_ui/src/Chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import AddOutlinedIcon from '@mui/icons-material/AddOutlined';
import HighlightOffIcon from '@mui/icons-material/HighlightOff';
import SpeakerNotesOffIcon from '@mui/icons-material/SpeakerNotesOff';
import LibraryBooksIcon from '@mui/icons-material/LibraryBooks';
import SchemaIcon from '@mui/icons-material/Schema';

import { SystemContext } from './SystemContext';
import ContentFormatter from './ContentFormatter';
Expand Down Expand Up @@ -306,6 +307,7 @@ const Chat = ({
const [systemPrompt, setSystemPrompt] = useState("");
const [promptPlaceholder, setPromptPlaceholder] = useState(userPromptReady.current);
const [menuPromptsAnchorEl, setMenuPromptsAnchorEl] = useState(null);
const [menuDiagramsAnchorEl, setMenuDiagramsAnchorEl] = useState(null);
const [menuPanelAnchorEl, setMenuPanelAnchorEl] = useState(null);
const [menuPromptEditorAnchorEl, setMenuPromptEditorAnchorEl] = useState(null);
const [menuMessageContext, setMenuMessageContext] = useState(null);
Expand Down Expand Up @@ -1186,6 +1188,7 @@ const Chat = ({
handleMenuMessageContextClose();
handleMenuPromptEditorClose();
handleMenuPromptsClose();
handleMenuDiagramsClose();
}

const runMenuAction = (functionToRun, thenFocusOnPrompt=true) => {
Expand All @@ -1204,6 +1207,14 @@ const Chat = ({
setMenuPromptsAnchorEl(null);
};

const handleMenuDiagramsOpen = (event) => {
setMenuDiagramsAnchorEl(event.currentTarget);
};

const handleMenuDiagramsClose = () => {
setMenuDiagramsAnchorEl(null);
};

const handleMenuCommandsOpen = (event) => {
setMenuCommandsAnchorEl(event.currentTarget);
};
Expand Down Expand Up @@ -1362,6 +1373,20 @@ const Chat = ({
setMenuMessageContext(null);
};

const handleDeleteAllMessagesUpToHere = () => {
const updatedMessages = messages.slice(menuMessageContext.index + 1);
setMessages(updatedMessages);
setMenuMessageContext(null);
};

const handleDeleteAllMessagesFromHere = () => {
if (menuMessageContext.index > 0) {
const updatedMessages = messages.slice(0, menuMessageContext.index);
setMessages(updatedMessages);
setMenuMessageContext(null);
}
};

const handleUseAsChatInput = () => {
setChatPrompt(menuMessageContext.message.content);
setPromptFocus();
Expand Down Expand Up @@ -1461,7 +1486,7 @@ const Chat = ({
(event) =>
{
onClick && onClick();
if (event.altKey) {
if (event.altKey || messages.length === 0) {
runMenuAction(()=>{setChatPrompt(prompt)});
} else {
runMenuAction(()=>{sendPrompt(prompt)});
Expand All @@ -1471,11 +1496,8 @@ const Chat = ({
onKeyDown={
(event) => {
if (event.key === 'ArrowRight') {
setChatPrompt(prompt);
onClick && onClick();
if (chatPromptRef.current) {
chatPromptRef.current.focus();
}
runMenuAction(()=>{setChatPrompt(prompt)});
}
}
}
Expand Down Expand Up @@ -1505,6 +1527,7 @@ const Chat = ({
}

const promptSelectionInstructions = "Click on a prompt to run it, ALT+Click (or Right-Arrow when using via slash command) to place in prompt editor so you can edit it";
const diagramSelectionInstructions = "Click on a diagram (or press enter) to generate it based on context, ALT+Click (or Right-Arrow when using via slash command) to place in prompt editor so you can edit it and describe what you want";
const toolbar =
<StyledToolbar className={ClassNames.toolbar} sx={{ gap: 1 }}>
<IconButton edge="start" color="inherit" aria-label="Sidekick Chat Menu"
Expand Down Expand Up @@ -1663,6 +1686,26 @@ const Chat = ({
<KeyboardArrowRightIcon />
</IconButton>
</MenuItem>
<MenuItem
onClick={handleMenuDiagramsOpen}
onKeyDown={
(event) => {
if (event.key === 'ArrowRight') {
handleMenuDiagramsOpen(event);
}
}
}
>
<ListItemIcon><SchemaIcon/></ListItemIcon>
Diagrams
<IconButton edge="end" style={{ padding: 0 }}>
<KeyboardArrowRightIcon />
</IconButton>
</MenuItem>
<MenuItem onClick={() => {runMenuAction(togglePromptEngineerOpen, false);}}>
<ListItemIcon><BuildIcon/></ListItemIcon>
Prompt Engineer
</MenuItem>
<MenuItem onClick={() => {runMenuAction(handleReload);}}>
<ListItemIcon><RedoIcon/></ListItemIcon>
Reload last prompt for editing
Expand All @@ -1675,25 +1718,22 @@ const Chat = ({
<ListItemIcon><SpeakerNotesOffIcon/></ListItemIcon>
Delete last prompt/response
</MenuItem>
<MenuItem onClick={() => {runMenuAction(togglePromptEngineerOpen);}}>
<ListItemIcon><BuildIcon/></ListItemIcon>
Prompt Engineer
</MenuItem>
<MenuItem onClick={() => {runMenuAction(handleNewChat);}}>
<ListItemIcon><AddOutlinedIcon/></ListItemIcon>
New Chat
</MenuItem>
<MenuItem onClick={() => {runMenuAction(); handleToggleMarkdownRendering();}}>
<ListItemIcon>{ markdownRenderingOn ? <CodeOffIcon/> : <CodeIcon/> }</ListItemIcon>
{ markdownRenderingOn ? "Turn off markdown rendering" : "Turn on markdown rendering" }</MenuItem>
<MenuItem onClick={() => {runMenuAction(handleToggleMarkdownRendering);}}>
<ListItemIcon>{ markdownRenderingOn ? <CodeOffIcon/> : <CodeIcon/> }</ListItemIcon>
{ markdownRenderingOn ? "Turn off markdown rendering" : "Turn on markdown rendering" }
</MenuItem>
{
isMobile ? null :
<MenuItem onClick={() => {runMenuAction(); handleToggleWindowMaximise();}}>
<MenuItem onClick={() => {runMenuAction(handleToggleWindowMaximise);}}>
<ListItemIcon>{ windowMaximized ? <CloseFullscreenIcon/> : <OpenInFullIcon/> }</ListItemIcon>
{ windowMaximized ? "Shrink window" : "Expand window" }
</MenuItem>
}
<MenuItem onClick={() => {runMenuAction(); handleClose();}}>
<MenuItem onClick={() => {runMenuAction(handleClose, false);}}>
<ListItemIcon><CloseIcon/></ListItemIcon>
Close Window
</MenuItem>
Expand Down Expand Up @@ -1753,6 +1793,8 @@ const Chat = ({
<MenuItem divider style={{ minHeight: '10px' }} />
<MenuItem style={{ minHeight: '30px' }} onClick={handleDeleteThisMessage}>Delete this message</MenuItem>
<MenuItem style={{ minHeight: '30px' }} onClick={handleDeleteThisAndPreviousMessage}>Delete this and previous message</MenuItem>
<MenuItem style={{ minHeight: '30px' }} onClick={handleDeleteAllMessagesUpToHere}>Delete this and all previous messages</MenuItem>
<MenuItem style={{ minHeight: '30px' }} onClick={handleDeleteAllMessagesFromHere}>Delete this and all subseqeunt messages</MenuItem>
<MenuItem style={{ minHeight: '30px' }} onClick={handleDeleteAllMessages}>Delete all messages</MenuItem>
</Menu>
<Menu
Expand All @@ -1775,7 +1817,7 @@ const Chat = ({
vertical: 'top',
horizontal: 'left',
}}
>
>
<Tooltip title={promptSelectionInstructions} placement="right">
<MenuItem onClick={handleMenuPromptsClose}>
<Typography variant="subtitle1" component="div" style={{ flexGrow: 1, fontWeight: 'bold' }}>
Expand Down Expand Up @@ -1867,6 +1909,47 @@ const Chat = ({
</MenuItem>
</Tooltip>
</Menu>
<Menu
id="menu-diagrams"
anchorEl={menuDiagramsAnchorEl}
open={Boolean(menuDiagramsAnchorEl)}
onClose={handleMenuDiagramsClose}
onKeyDown={
(event) => {
if (event.key === 'ArrowLeft') {
handleMenuDiagramsClose(event);
}
}
}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
>
<Tooltip title={diagramSelectionInstructions} placement="right">
<MenuItem onClick={handleMenuDiagramsClose}>
<Typography variant="subtitle1" component="div" style={{ flexGrow: 1, fontWeight: 'bold' }}>
Diagrams
</Typography>
<IconButton edge="end" color="inherit" onClick={handleMenuDiagramsClose}>
<CloseIcon />
</IconButton>
</MenuItem>
</Tooltip>
<ActionMenu name="Flowchart" prompt="Provide mermaid markdown for a flowchart for this"/>
<ActionMenu name="Mind Map" prompt="Provide mermaid markdown for a mind map for this"/>
<ActionMenu name="Use Case Diagram" prompt="Provide mermaid markdown for a use case diagram based on a left to right flowchart diagram that uses stadium-shaped nodes by wrapping the node names in round and square brackets ([node name]) for this"/>
<ActionMenu name="Sequence Diagram" prompt="Provide mermaid markdown for a sequence diagram for this"/>
<ActionMenu name="Class Diagram" prompt="Provide mermaid markdown for a class diagram for this"/>
<ActionMenu name="Entity Relationship Diagram" prompt="Provide mermaid markdown for an entity relationship diagram for this"/>
<ActionMenu name="State Diagram" prompt="Provide mermaid markdown for a state diagram for this"/>
<ActionMenu name="Timeline" prompt="Provide mermaid markdown for a timeline for this"/>
<ActionMenu name="Gantt Chart" prompt="Provide mermaid markdown for a Gantt chart breaking it down into phases as appropriate for this"/>
</Menu>
<Menu
id="menu-commands"
anchorEl={menuCommandsAnchorEl}
Expand Down Expand Up @@ -2379,8 +2462,10 @@ const Chat = ({
</IconButton>
</span>
</Tooltip>
<Tooltip title={ aiLibraryOpen ? "Hide AI Library" : `Show AI Library (${Object.keys(selectedAiLibraryNotes).length} knowledge notes loaded)`}>
<IconButton edge="start" color="inherit" aria-label={ aiLibraryOpen ? "Hide AI Library" : "Show AI Library"}
<Tooltip title={ aiLibraryOpen ? "Hide AI Library" : `Show AI Library. You can then select notes to add to the chat context.
You can add individual notes to the AI library by opening them in the Note editor and clicking on the 'Add to AI Library' button.
(${Object.keys(selectedAiLibraryNotes).length} knowledge notes currently loaded)`}>
<IconButton edge="start" color="inherit" aria-label={ aiLibraryOpen ? "Hide AI Library" : "Show AI Library."}
onClick={handleToggleAILibraryOpen}>
{ Object.keys(selectedAiLibraryNotes).length === 0 ? <LocalLibraryOutlinedIcon/> : <LocalLibraryIcon/> }
</IconButton>
Expand Down Expand Up @@ -2469,11 +2554,17 @@ const Chat = ({
{ aiLibraryOpen ?
<Paper sx={{ margin: "2px 0px", padding: "2px 6px", display:"flex", gap: 1, backgroundColor: darkMode ? grey[900] : grey[100] }}>
<Box sx={{ mt: 2, display: "flex", flexDirection: "column", width: "100%" }}>
<FormLabel>
Loaded knowledge: { Object.keys(selectedAiLibraryNotes).length === 0 ? "None" : ""}
<SecondaryToolbar sx={{gap:1}} className={ClassNames.toolbar}>
<Typography fontWeight="bold">AI Library</Typography>
<Typography sx={{mr:1}}>Loaded notes: {Object.keys(selectedAiLibraryNotes).length}</Typography>
<TextStatsDisplay name="AI Library" sizeInCharacters={selectedAiLibraryFullTextSize}
maxTokenSize={myModelSettings.contextTokenSize}/>
</FormLabel>
<Tooltip title='Close AI library'>
<IconButton sx={{ml:'auto'}} onClick={()=>{setAiLibraryOpen(false)}}>
<CloseIcon />
</IconButton>
</Tooltip>
</SecondaryToolbar>
<List dense sx={{ width: "100%", overflow: "auto", maxHeight: "100px" }}>
{Object.values(selectedAiLibraryNotes).map(note =>(
<ListItem
Expand Down
Loading
Loading