-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support sidebar Max AI - not yet integrated
- Loading branch information
Showing
15 changed files
with
16,239 additions
and
11,979 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelMaxAILogic.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { actions, kea, path, reducers } from 'kea' | ||
import { loaders } from 'kea-loaders' | ||
|
||
import type { sidePanelMaxAILogicType } from './sidePanelMaxAILogicType' | ||
import { sidePanelMaxAPI } from './sidePanelMaxAPI' | ||
|
||
export interface ChatMessage { | ||
role: 'user' | 'assistant' | ||
content: string | ||
timestamp: string | ||
isRateLimited?: boolean | ||
} | ||
|
||
interface MaxResponse { | ||
content: string | { text: string; type: string } | ||
isRateLimited?: boolean | ||
} | ||
|
||
export const sidePanelMaxAILogic = kea<sidePanelMaxAILogicType>([ | ||
path(['scenes', 'navigation', 'sidepanel', 'sidePanelMaxAILogic']), | ||
|
||
actions({ | ||
submitMessage: (message: string) => ({ message }), | ||
clearChatHistory: true, | ||
appendAssistantMessage: (content: string) => ({ content }), | ||
setSearchingThinking: (isSearching: boolean) => ({ isSearching }), | ||
setRateLimited: (isLimited: boolean) => ({ isLimited }), | ||
}), | ||
|
||
reducers({ | ||
currentMessages: [ | ||
[] as ChatMessage[], | ||
{ | ||
submitMessage: (state, { message }) => | ||
message.trim() | ||
? [ | ||
...state, | ||
{ | ||
role: 'user', | ||
content: message, | ||
timestamp: new Date().toISOString(), | ||
}, | ||
] | ||
: state, | ||
appendAssistantMessage: (state, { content }) => [ | ||
...state, | ||
{ | ||
role: 'assistant', | ||
content, | ||
timestamp: new Date().toISOString(), | ||
isRateLimited: content.includes('Rate limit exceeded') || content.includes('rate-limited'), | ||
}, | ||
], | ||
clearChatHistory: () => [], | ||
}, | ||
], | ||
isSearchingThinking: [ | ||
false, | ||
{ | ||
setSearchingThinking: (_, { isSearching }) => isSearching, | ||
}, | ||
], | ||
isRateLimited: [ | ||
false, | ||
{ | ||
setRateLimited: (_, { isLimited }) => isLimited, | ||
}, | ||
], | ||
}), | ||
|
||
loaders(({ actions, values }) => ({ | ||
assistantResponse: [ | ||
null as string | null, | ||
{ | ||
submitMessage: async ({ message }, breakpoint) => { | ||
try { | ||
actions.setSearchingThinking(true) | ||
if (!values.isRateLimited) { | ||
actions.setRateLimited(false) | ||
} | ||
const response = (await sidePanelMaxAPI.sendMessage(message)) as MaxResponse | ||
await breakpoint(100) | ||
|
||
const content = typeof response.content === 'string' ? response.content : response.content.text | ||
|
||
if (response.isRateLimited) { | ||
actions.setRateLimited(true) | ||
} else { | ||
actions.setRateLimited(false) | ||
} | ||
|
||
actions.appendAssistantMessage(content) | ||
return content | ||
} catch (error: unknown) { | ||
if ( | ||
error && | ||
typeof error === 'object' && | ||
'message' in error && | ||
typeof error.message === 'string' && | ||
(error.message.includes('429') || error.message.includes('rate limit')) | ||
) { | ||
actions.setRateLimited(true) | ||
// Keep searching state true while rate limited | ||
} else { | ||
actions.setSearchingThinking(false) | ||
actions.setRateLimited(false) | ||
} | ||
console.error('Error sending message:', error) | ||
return null | ||
} | ||
}, | ||
}, | ||
], | ||
})), | ||
]) |
27 changes: 27 additions & 0 deletions
27
frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelMaxAPI.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
const MAX_API_HOST = 'http://localhost:3000' // Default port used in sidebar_max_AI.py | ||
|
||
let currentSessionId: string | null = null | ||
|
||
export const sidePanelMaxAPI = { | ||
async sendMessage(message: string): Promise<{ content: string }> { | ||
const response = await fetch(`${MAX_API_HOST}/chat`, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
body: JSON.stringify({ | ||
message, | ||
role: 'user', | ||
session_id: currentSessionId, | ||
}), | ||
}) | ||
|
||
if (!response.ok) { | ||
throw new Error('Failed to send message to Max') | ||
} | ||
|
||
const data = await response.json() | ||
currentSessionId = data.session_id // Store the session ID for next request | ||
return { content: data.content } | ||
}, | ||
} |
61 changes: 61 additions & 0 deletions
61
frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelMaxChatInterface.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
.SidePanelMaxChatInterface { | ||
&__label { | ||
margin-top: 0.5rem; | ||
margin-right: 0.5rem; | ||
font-size: 0.875rem; | ||
color: var(--muted); | ||
white-space: nowrap; | ||
} | ||
|
||
&__message-container { | ||
display: flex; | ||
width: 100%; | ||
|
||
&--user { | ||
justify-content: flex-end; | ||
} | ||
|
||
&--assistant { | ||
justify-content: flex-start; | ||
} | ||
} | ||
|
||
&__message-content { | ||
width: 90%; | ||
min-width: 90%; | ||
max-width: 90%; | ||
padding: 0.5rem; | ||
word-break: break-word; | ||
border-radius: 0.5rem; | ||
|
||
&--assistant { | ||
color: var(--default); | ||
background: var(--bg-light); | ||
|
||
.dark & { | ||
background: var(--bg-depth); | ||
} | ||
} | ||
|
||
&--user { | ||
color: var(--default); | ||
background: var(--bg-light); | ||
|
||
.dark & { | ||
background: var(--bg-side); | ||
} | ||
} | ||
} | ||
|
||
code { | ||
padding: 0.125rem 0.25rem; | ||
font-family: var(--font-mono); | ||
font-size: 0.75rem; | ||
background: color-mix(in sRGB, var(--bg-light) 85%, var(--primary) 15%); | ||
border-radius: 0.25rem; | ||
|
||
.dark & { | ||
background: color-mix(in sRGB, var(--bg-depth) 85%, var(--primary) 15%); | ||
} | ||
} | ||
} |
Oops, something went wrong.
55b8ac9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Max is not yet integrated into the platform in this commit. If you'd like to try running him locally, the steps below should work (assumes you already have python3 and pip3 installed.):
After spinning up docker containers, migrate and start, in a new terminal cd to /posthog/sidebar-max-unintegrated/ then:
If you hit errors with that, try this instead:
Next:
Then edit
.env
and drop an Anthropic API key into it.Then do:
Then run it!
In a browser on your local, open the help sidebar, click the
Chat with Max
button, and have a chat. 😊 🦔 ✌️