Merge branch 'refs/heads/main' into feature-multipart

# Conflicts:
#	src/apps/chat/AppChat.tsx
This commit is contained in:
Enrico Ros
2024-07-08 17:55:30 -07:00
14 changed files with 292 additions and 65 deletions
+4 -1
View File
@@ -41,4 +41,7 @@ yarn-error.log*
next-env.d.ts
# other
.idea/
.idea/
# Ingore k8s/env-secret.yaml
./k8s/env-secret.yaml
+1
View File
@@ -61,6 +61,7 @@ Test your application thoroughly using local development (refer to README.md for
- [deploy-cloudflare.md](deploy-cloudflare.md): for Cloudflare Workers deployment
- [deploy-docker.md](deploy-docker.md): for Docker deployment instructions and examples
- [deploy-k8s.md](deploy-k8s.md): for Kubernetes deployment instructions and examples
## Debugging
+82
View File
@@ -0,0 +1,82 @@
# Deploy `big-AGI` with Kubernetes ☸️
In this tutorial, we will guide you through the process of deploying big-AGI
in a Kubernetes environment using the kubectl command-line tool.
## First Deployment
### Step 1: Clone the big-AGI repository
```bash
$ git clone https://github.com/enricoros/big-agi
$ cd ./big-agi/docs/k8s
```
### Step 2: Create the namespace
```bash
$ kubectl create namespace ns-big-agi
```
### Step 3: Fill in the key information into env-secret.yaml
All variables are optional. By default, Kubernetes Secret uses Base64 for
encode/decode, so please don't do a git commit after filling in the keys
to avoid leaking sensitive information.
We provide an empty `env-secret.yaml` file as a template.
You can fill in the necessary information using a text editor.
```bash
$ nano env-secret.yaml
```
### Step 4: Deploying Kubernetes Resources
```bash
$ kubectl apply -f big-agi-deployment.yaml -f env-secret.yaml
```
### Step 5: Verifying the Resource Statuses
```bash
$ kubectl -n ns-big-agi get svc,pod,deployment
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/svc-big-agi ClusterIP 10.0.198.118 <none> 3000/TCP 63m
NAME READY STATUS RESTARTS AGE
pod/deployment-big-agi-xxxxxxxx-yyyyy 1/1 Running 0 39m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment-big-agi 1/1 1 1 63m
```
### Step 6: Testing the Service
You can test the service by port-forwarding the service to your local machine:
```bash
$ kubectl -n ns-big-agi port-forward service/svc-big-agi 3000
Forwarding from 127.0.0.1:3000 -> 3000
Forwarding from [::1]:3000 -> 3000
```
Now you can access the service at `http://localhost:3000`, and you should see the big-AGI homepage.
## Updating big-AGI
To update big-AGI to the latest version:
1. Pull the latest changes from the repository:
```bash
$ git pull origin main
```
2. Apply the updated deployment:
```bash
$ kubectl apply -f big-agi-deployment.yaml
```
This will trigger a rolling update of the deployment with the latest image.
Note: For production use, consider setting up an Ingress Controller or Load Balancer instead of using port-forward.
+16 -11
View File
@@ -27,6 +27,7 @@ AZURE_OPENAI_API_ENDPOINT=
AZURE_OPENAI_API_KEY=
ANTHROPIC_API_KEY=
ANTHROPIC_API_HOST=
DEEPSEEK_API_KEY=
GEMINI_API_KEY=
GROQ_API_KEY=
LOCALAI_API_HOST=
@@ -40,25 +41,28 @@ TOGETHERAI_API_KEY=
# Model Observability: Helicone
HELICONE_API_KEY=
# Text-To-Speech
ELEVENLABS_API_KEY=
ELEVENLABS_API_HOST=
ELEVENLABS_VOICE_ID=
# Text-To-Image
PRODIA_API_KEY=
# Google Custom Search
GOOGLE_CLOUD_API_KEY=
GOOGLE_CSE_ID=
# Browse
PUPPETEER_WSS_ENDPOINT=
# Backend Analytics
BACKEND_ANALYTICS=
# Search
GOOGLE_CLOUD_API_KEY=
GOOGLE_CSE_ID=
# Text-To-Speech: ElevenLabs
ELEVENLABS_API_KEY=
ELEVENLABS_API_HOST=
ELEVENLABS_VOICE_ID=
# Text-To-Image: Prodia
PRODIA_API_KEY=
# Backend HTTP Basic Authentication (see `deploy-authentication.md` for turning on authentication)
HTTP_BASIC_AUTH_USERNAME=
HTTP_BASIC_AUTH_PASSWORD=
# Backend Analytics Flags
BACKEND_ANALYTICS=
# Frontend variables
NEXT_PUBLIC_GA4_MEASUREMENT_ID=
NEXT_PUBLIC_PLANTUML_SERVER_URL=
@@ -89,6 +93,7 @@ requiring the user to enter an API key
| `AZURE_OPENAI_API_KEY` | Azure OpenAI API key, see [config-azure-openai.md](config-azure-openai.md) | Optional, but if set `AZURE_OPENAI_API_ENDPOINT` must also be set |
| `ANTHROPIC_API_KEY` | The API key for Anthropic | Optional |
| `ANTHROPIC_API_HOST` | Changes the backend host for the Anthropic vendor, to enable platforms such as [config-aws-bedrock.md](config-aws-bedrock.md) | Optional |
| `DEEPSEEK_API_KEY` | The API key for Deepseek AI | Optional |
| `GEMINI_API_KEY` | The API key for Google AI's Gemini | Optional |
| `GROQ_API_KEY` | The API key for Groq Cloud | Optional |
| `LOCALAI_API_HOST` | Sets the URL of the LocalAI server, or defaults to http://127.0.0.1:8080 | Optional |
+35
View File
@@ -99,6 +99,41 @@ or follow the steps below for a quick start.
```
Access your big-AGI instance at `http://localhost:3000`.
### Kubernetes Deployment
Deploy big-AGI on a Kubernetes cluster for enhanced scalability and management. Follow these steps for a Kubernetes deployment:
1. Clone the big-AGI repository:
```bash
git clone https://github.com/enricoros/big-AGI.git
cd big-AGI
```
2. Configure the environment variables:
```bash
cp docs/k8s/env-secret.yaml env-secret.yaml
vim env-secret.yaml # Edit the file to set your environment variables
```
3. Apply the Kubernetes configurations:
```bash
kubectl create namespace ns-big-agi
kubectl apply -f docs/k8s/big-agi-deployment.yaml -f env-secret.yaml
```
4. Verify the deployment:
```bash
kubectl -n ns-big-agi get svc,pod,deployment
```
5. Access the big-AGI application:
```bash
kubectl -n ns-big-agi port-forward service/svc-big-agi 3000:3000
```
Your big-AGI instance is now accessible at `http://localhost:3000`.
For more detailed instructions on Kubernetes deployment, including updating and troubleshooting, refer to our [Kubernetes Deployment Guide](deploy-k8s.md).
### Midori AI Subsystem for Docker Deployment
Follow the instructions found on [Midori AI Subsystem Site](https://io.midori-ai.xyz/subsystem/manager/)
+52
View File
@@ -0,0 +1,52 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: ns-big-agi
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: big-agi
name: deployment-big-agi
namespace: ns-big-agi
spec:
replicas: 1
selector:
matchLabels:
app: big-agi
strategy: {}
template:
metadata:
labels:
app: big-agi
spec:
containers:
- image: ghcr.io/enricoros/big-agi:latest
name: big-agi
ports:
- containerPort: 3000
args:
- next
- start
- -p
- "3000"
envFrom:
- secretRef:
name: env
---
apiVersion: v1
kind: Service
metadata:
labels:
app: big-agi
name: svc-big-agi
namespace: ns-big-agi
spec:
ports:
- name: "http"
port: 3000
targetPort: 3000
selector:
app: big-agi
+47
View File
@@ -0,0 +1,47 @@
---
apiVersion: v1
kind: Secret
metadata:
name: env
namespace: ns-big-agi
type: Opaque
stringData:
# IMPORTANT: This file contains sensitive information. Do not commit changes to version control.
# All variables are optional. Fill in only the ones you need.
#
# For the latest information on all the environment variables, see /docs/environment-variables.md
#
# LLMs
OPENAI_API_KEY: ""
OPENAI_API_HOST: ""
OPENAI_API_ORG_ID: ""
AZURE_OPENAI_API_ENDPOINT: ""
AZURE_OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
ANTHROPIC_API_HOST: ""
GEMINI_API_KEY: ""
GROQ_API_KEY: ""
LOCALAI_API_HOST: ""
LOCALAI_API_KEY: ""
MISTRAL_API_KEY: ""
OLLAMA_API_HOST: ""
OPENROUTER_API_KEY: ""
PERPLEXITY_API_KEY: ""
TOGETHERAI_API_KEY: ""
DEEPSEEK_API_KEY: ""
# Browse
PUPPETEER_WSS_ENDPOINT: ""
# Search
GOOGLE_CLOUD_API_KEY: ""
GOOGLE_CSE_ID: ""
# Text-To-Speech: Eleven Labs
ELEVENLABS_API_KEY: ""
ELEVENLABS_API_HOST: ""
ELEVENLABS_VOICE_ID: ""
# Text-To-Image: Prodia
PRODIA_API_KEY: ""
+8 -9
View File
@@ -19,7 +19,7 @@ import { ConfirmationModal } from '~/common/components/ConfirmationModal';
import { ConversationsManager } from '~/common/chats/ConversationsManager';
import { DConversation, DConversationId } from '~/common/stores/chat/chat.conversation';
import { DMessageAttachmentFragment, DMessageContentFragment, duplicateDMessageFragments } from '~/common/stores/chat/chat.fragments';
import { GlobalShortcutDefinition, ShortcutKeyName, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { GlobalShortcutDefinition, useGlobalShortcuts } from '~/common/components/useGlobalShortcuts';
import { PanelResizeInset } from '~/common/components/panes/GoodPanelResizeHandler';
import { PreferencesTab, useOptimaLayout, usePluggableOptimaLayout } from '~/common/layout/optima/useOptimaLayout';
import { ScrollToBottom } from '~/common/scroll-to-bottom/ScrollToBottom';
@@ -397,20 +397,19 @@ export function AppChat() {
const shortcuts = React.useMemo((): GlobalShortcutDefinition[] => [
// focused conversation
['b', true, true, false, handleMessageBeamLastInFocusedPane],
['r', true, true, false, handleMessageRegenerateLastInFocusedPane],
['n', true, false, true, handleConversationNewInFocusedPane],
['g', true, true, false, handleMessageRegenerateLastInFocusedPane],
['o', true, false, false, handleFileOpenConversation],
['s', true, false, false, () => handleFileSaveConversation(focusedPaneConversationId)],
['b', true, false, true, () => isFocusedChatEmpty || (focusedPaneConversationId && handleConversationBranch(focusedPaneConversationId, null))],
['x', true, false, true, () => isFocusedChatEmpty || (focusedPaneConversationId && handleConversationClear(focusedPaneConversationId))],
['d', true, false, true, () => focusedPaneConversationId && handleDeleteConversations([focusedPaneConversationId], false)],
[ShortcutKeyName.Left, true, false, true, () => handleNavigateHistoryInFocusedPane('back')],
[ShortcutKeyName.Right, true, false, true, () => handleNavigateHistoryInFocusedPane('forward')],
['n', true, true, false, handleConversationNewInFocusedPane],
['x', true, true, false, () => isFocusedChatEmpty || (focusedPaneConversationId && handleConversationClear(focusedPaneConversationId))],
['d', true, true, false, () => focusedPaneConversationId && handleDeleteConversations([focusedPaneConversationId], false)],
['[', true, false, false, () => handleNavigateHistoryInFocusedPane('back')],
[']', true, false, false, () => handleNavigateHistoryInFocusedPane('forward')],
// global
['o', true, true, false, handleOpenChatLlmOptions],
['+', true, true, false, useUIPreferencesStore.getState().increaseContentScaling],
['-', true, true, false, useUIPreferencesStore.getState().decreaseContentScaling],
], [focusedPaneConversationId, handleConversationBranch, handleConversationClear, handleConversationNewInFocusedPane, handleFileOpenConversation, handleFileSaveConversation, handleDeleteConversations, handleMessageBeamLastInFocusedPane, handleMessageRegenerateLastInFocusedPane, handleNavigateHistoryInFocusedPane, handleOpenChatLlmOptions, isFocusedChatEmpty]);
], [focusedPaneConversationId, handleConversationClear, handleConversationNewInFocusedPane, handleFileOpenConversation, handleFileSaveConversation, handleDeleteConversations, handleMessageBeamLastInFocusedPane, handleMessageRegenerateLastInFocusedPane, handleNavigateHistoryInFocusedPane, handleOpenChatLlmOptions, isFocusedChatEmpty]);
useGlobalShortcuts(shortcuts);
@@ -143,7 +143,7 @@ export function ChatPageMenuItems(props: {
<ListItemDecorator><ClearIcon /></ListItemDecorator>
<Box sx={{ flexGrow: 1, display: 'flex', justifyContent: 'space-between', gap: 1 }}>
Reset Chat
{!props.disableItems && <KeyStroke combo='Ctrl + Alt + X' />}
{!props.disableItems && <KeyStroke combo='Ctrl + Shift + X' />}
</Box>
</MenuItem>
@@ -756,7 +756,7 @@ export function ChatMessage(props: {
? <>Restart <span style={{ opacity: 0.5 }}>from here</span></>
: !props.isBottom
? <>Retry <span style={{ opacity: 0.5 }}>from here</span></>
: <Box sx={{ flexGrow: 1, display: 'flex', justifyContent: 'space-between', gap: 1 }}>Retry<KeyStroke combo='Ctrl + Shift + R' /></Box>}
: <Box sx={{ flexGrow: 1, display: 'flex', justifyContent: 'space-between', gap: 1 }}>Retry<KeyStroke combo='Ctrl + Shift + G' /></Box>}
</MenuItem>
)}
{!!props.onMessageBeam && (
+24 -26
View File
@@ -3,38 +3,36 @@ import * as React from 'react';
import { AutoBlocksRenderer } from '~/modules/blocks/AutoBlocksRenderer';
import { GoodModal } from '~/common/components/GoodModal';
import { isMacUser } from '~/common/util/pwaUtils';
import { platformAwareKeystrokes } from '~/common/components/KeyStroke';
import { useIsMobile } from '~/common/components/useMatchMedia';
const shortcutsMd = platformAwareKeystrokes(`
| Shortcut | Description |
|-----------------------------------------|-------------------------------------------------|
| **Edit** | |
| Shift + Enter | Newline |
| Alt + Enter | Append (no response) |
| Ctrl + Shift + B | **Beam** last message |
| Ctrl + Shift + R | **Regenerate** last message |
| Ctrl + Shift + V | Attach clipboard (better than Ctrl + V) |
| Ctrl + M | Microphone (voice typing) |
| **Chats** | |
| Ctrl + O | Open Chat ... |
| Ctrl + S | Save Chat ... |
| Ctrl + ${isMacUser ? '' : 'Alt +'} N | **New** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} X | **Reset** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} D | **Delete** chat |
| Ctrl + ${isMacUser ? '' : 'Alt +'} B | **Branch** chat |
| Ctrl + Alt + Left | **Previous** chat (in history) |
| Ctrl + Alt + Right | **Next** chat (in history) |
| **Settings** | |
| Ctrl + Shift + P | ⚙️ Preferences |
| Ctrl + Shift + M | 🧠 Models |
| Ctrl + Shift + O | 💬 Options (current Chat Model) |
| Ctrl + Shift + + | Increase Text Size |
| Ctrl + Shift + - | Decrease Text Size |
| Ctrl + Shift + ${isMacUser ? '/' : '?'} | Shortcuts |
| Shortcut | Description |
|------------------|-----------------------------------------|
| **Edit** | |
| Shift + Enter | Newline |
| Alt + Enter | Append (no response) |
| Ctrl + Shift + B | **Beam** last message |
| Ctrl + Shift + G | Re**generate** last message |
| Ctrl + Shift + V | Attach clipboard (better than Ctrl + V) |
| Ctrl + M | Microphone (voice typing) |
| **Chats** | |
| Ctrl + O | Open Chat ... |
| Ctrl + S | Save Chat ... |
| Ctrl + Shift + N | **New** chat |
| Ctrl + Shift + X | **Reset** chat |
| Ctrl + Shift + D | **Delete** chat |
| Ctrl + [ | **Previous** chat (in history) |
| Ctrl + ] | **Next** chat (in history) |
| **Settings** | |
| Ctrl + , | ⚙️ Preferences |
| Ctrl + Shift + M | 🧠 Models |
| Ctrl + Shift + O | 💬 Options (current Chat Model) |
| Ctrl + Shift + + | Increase Text Size |
| Ctrl + Shift + - | Decrease Text Size |
| Ctrl + Shift + / | Shortcuts |
`).trim();
+1 -1
View File
@@ -64,7 +64,7 @@ function CommonPageMenuItems(props: { onClose: () => void }) {
{/*</MenuItem>*/}
{/* Preferences |...| Dark Mode Toggle */}
{/*<Tooltip title={<KeyStroke combo='Ctrl + Shift + P' />}>*/}
{/*<Tooltip title={<KeyStroke combo='Ctrl + ,' />}>*/}
<MenuItem onClick={handleShowSettings}>
<ListItemDecorator><SettingsIcon /></ListItemDecorator>
Preferences
+1 -1
View File
@@ -117,8 +117,8 @@ export function OptimaLayoutProvider(props: { children: React.ReactNode }) {
// global shortcuts for Optima
const shortcuts = React.useMemo((): GlobalShortcutDefinition[] => [
[isMacUser ? '/' : '?', true, true, false, actions.openShortcuts],
[',', true, false, false, actions.openPreferencesTab],
['m', true, true, false, actions.openModelsSetup],
['p', true, true, false, actions.openPreferencesTab],
], [actions]);
useGlobalShortcuts(shortcuts);
+19 -14
View File
@@ -15,6 +15,7 @@ export const env = createEnv({
// Backend MongoDB, for a more complete developer data platform.
MDB_URI: z.string().optional(),
// LLM: OpenAI
OPENAI_API_KEY: z.string().optional(),
OPENAI_API_HOST: z.string().url().optional(),
@@ -28,6 +29,9 @@ export const env = createEnv({
ANTHROPIC_API_KEY: z.string().optional(),
ANTHROPIC_API_HOST: z.string().url().optional(),
// LLM: Deepseek AI
DEEPSEEK_API_KEY: z.string().optional(),
// LLM: Google AI's Gemini
GEMINI_API_KEY: z.string().optional(),
@@ -50,38 +54,39 @@ export const env = createEnv({
// LLM: Perplexity
PERPLEXITY_API_KEY: z.string().optional(),
// LLM: Toghether AI
// LLM: Together AI
TOGETHERAI_API_KEY: z.string().optional(),
// LLM: Deepseek AI
DEEPSEEK_API_KEY: z.string().optional(),
// Helicone - works on both OpenAI and Anthropic vendors
HELICONE_API_KEY: z.string().optional(),
// ElevenLabs - speech.ts
ELEVENLABS_API_KEY: z.string().optional(),
ELEVENLABS_API_HOST: z.string().url().optional(),
ELEVENLABS_VOICE_ID: z.string().optional(),
// Prodia
PRODIA_API_KEY: z.string().optional(),
// Browsing Service
PUPPETEER_WSS_ENDPOINT: z.string().url().optional(),
// Google Custom Search
GOOGLE_CLOUD_API_KEY: z.string().optional(),
GOOGLE_CSE_ID: z.string().optional(),
// Browsing Service
PUPPETEER_WSS_ENDPOINT: z.string().url().optional(),
// Backend: Analytics flags (e.g. which hostname responds) for managed installs
BACKEND_ANALYTICS: z.string().optional().transform(list => (list || '').split(';').filter(flag => !!flag)),
// Text-To-Speech: ElevenLabs - speech.ts
ELEVENLABS_API_KEY: z.string().optional(),
ELEVENLABS_API_HOST: z.string().url().optional(),
ELEVENLABS_VOICE_ID: z.string().optional(),
// Text-To-Image: Prodia
PRODIA_API_KEY: z.string().optional(),
// Backend: HTTP Basic Authentication
HTTP_BASIC_AUTH_USERNAME: z.string().optional(),
HTTP_BASIC_AUTH_PASSWORD: z.string().optional(),
// Build-time configuration
// Backend: Analytics flags (e.g. which hostname responds) for managed installs
BACKEND_ANALYTICS: z.string().optional().transform(list => (list || '').split(';').filter(flag => !!flag)),
// Build-time configuration (ignore)
BIG_AGI_BUILD: z.enum(['standalone', 'static']).optional(),
},