diff --git a/VERSION b/VERSION index 3eefcb9..6d984fb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +2.0.0b1 diff --git a/docker/Dockerfile b/docker/Dockerfile index 5d4de6f..d763c75 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,23 +1,30 @@ ARG INTERPRETER_IMAGE -FROM $INTERPRETER_IMAGE -SHELL ["/bin/bash", "-c"] - -RUN apt update && apt install -y nodejs npm +FROM node:18-alpine WORKDIR /opt/app -COPY interpreter interpreter -RUN python3 -m venv venv_backend && \ - source venv_backend/bin/activate && \ - pip3 install ./interpreter - COPY ui ui +COPY VERSION VERSION + RUN cd ui && \ npm install && \ - npm run build && \ - cd .. + npm run build + +FROM $INTERPRETER_IMAGE +SHELL ["/bin/bash", "-c"] + +WORKDIR /opt/app +COPY --from=0 /opt/app/ui/out /opt/app/ui + +RUN apt update && apt install -y nginx + +COPY services services +RUN python3 -m venv venv_services && \ + source venv_services/bin/activate && \ + pip3 install ./services + +COPY docker/nginx.conf /etc/nginx/ -COPY VERSION VERSION COPY docker/start* . RUN chmod 755 start* CMD ["/opt/app/start.sh"] diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..97a96d0 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,41 @@ +user www-data; +worker_processes auto; +pid /run/nginx.pid; +include /etc/nginx/modules-enabled/*.conf; + +events { + worker_connections 768; +} + +http { + sendfile on; + tcp_nopush on; + types_hash_max_size 2048; + include /etc/nginx/mime.types; + default_type application/octet-stream; + + server { + listen 80; + listen [::]:80; + + root /opt/app/ui; + index index.html index.htm index.nginx-debian.html; + + location /api/llm { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_pass http://localhost:8081; + } + + location /api/interpreter { + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_pass http://localhost:8080; + } + + location / { + try_files $uri $uri/ =404; + } + } + +} diff --git a/docker/start.sh b/docker/start.sh index c5d37b4..403b2b5 100644 --- a/docker/start.sh +++ b/docker/start.sh @@ -1,4 +1,6 @@ #!/bin/bash /opt/app/start_interpreter.sh & -/opt/app/start_ui.sh +/opt/app/start_llm.sh & + +nginx -g "daemon off;" diff --git a/docker/start_interpreter.sh b/docker/start_interpreter.sh index d370b9e..9f6150d 100644 --- a/docker/start_interpreter.sh +++ b/docker/start_interpreter.sh @@ -1,11 +1,11 @@ #!/bin/bash cd /opt/app -. venv_backend/bin/activate -cd interpreter +. venv_services/bin/activate +cd services mkdir -p /mnt/data export WORKING_DIRECTORY=/mnt/data export IPYTHON_PATH=/opt/app/venv_interpreter/bin/ipython -uvicorn main:app --host 0.0.0.0 --port 3031 +uvicorn main_interpreter:app --host 0.0.0.0 --port 8080 diff --git a/docker/start_llm.sh b/docker/start_llm.sh new file mode 100644 index 0000000..070d44c --- /dev/null +++ b/docker/start_llm.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +cd /opt/app +. venv_services/bin/activate +cd services + +uvicorn main_llm:app --host 0.0.0.0 --port 8081 diff --git a/docker/start_ui.sh b/docker/start_ui.sh deleted file mode 100644 index 7cd63fc..0000000 --- a/docker/start_ui.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -cd /opt/app/ui - -if [[ -z "${INTERPRETER_PORT}" ]]; then - export INTERPRETER_URL="localhost:3031" -else - export INTERPRETER_URL="localhost:${INTERPRETER_PORT}" -fi - -npm run start diff --git a/services/main_interpreter.py b/services/main_interpreter.py index 35683b2..fbf21ac 100644 --- a/services/main_interpreter.py +++ b/services/main_interpreter.py @@ -25,7 +25,7 @@ def get_interpreter() -> IPythonInterpreter: return interpreter -@app.websocket("/run") +@app.websocket("/api/interpreter/run") async def run(websocket: WebSocket): ws_exceptions = WebSocketDisconnect, ConnectionClosedError diff --git a/services/main_llm.py b/services/main_llm.py index 01b5e52..544b50c 100644 --- a/services/main_llm.py +++ b/services/main_llm.py @@ -19,7 +19,7 @@ class Request(BaseModel): history: list[Message] -@app.websocket("/chat") +@app.websocket("/api/llm/chat") async def chat(websocket: WebSocket): ws_exceptions = WebSocketDisconnect, ConnectionClosedError diff --git a/ui/app/page.tsx b/ui/app/page.tsx index a0e3b58..540bd85 100644 --- a/ui/app/page.tsx +++ b/ui/app/page.tsx @@ -3,24 +3,6 @@ import SessionManager from "@/app/session/session_manager"; import path from "path"; import * as fs from "fs"; -export const dynamic = "force-dynamic"; - -function getInterpreterUrl() { - const interpreterUrl = process.env.INTERPRETER_URL; - if (interpreterUrl === undefined) { - throw new Error("INTERPRETER_URL is undefined"); - } - return interpreterUrl; -} - -function getLlmUrl() { - const llmUrl = process.env.LLM_URL; - if (llmUrl === undefined) { - throw new Error("LLM_URL is undefined"); - } - return llmUrl; -} - function getVersion(): Promise { const versionDir = path.dirname( path.dirname(path.dirname(path.dirname(__dirname))), @@ -38,11 +20,5 @@ function getVersion(): Promise { } export default async function Home() { - return ( - - ); + return ; } diff --git a/ui/app/session/chat/brand.tsx b/ui/app/session/chat/brand.tsx index 092bf4f..a832e32 100644 --- a/ui/app/session/chat/brand.tsx +++ b/ui/app/session/chat/brand.tsx @@ -1,11 +1,8 @@ -import Image from "next/image"; -import iconColor from "./icon_color.png"; - export default function Brand() { return (
- Brand + Brand
Incognito Pilot
diff --git a/ui/app/session/chat/chat_history.tsx b/ui/app/session/chat/chat_history.tsx index 82f46fe..9f14d13 100644 --- a/ui/app/session/chat/chat_history.tsx +++ b/ui/app/session/chat/chat_history.tsx @@ -1,7 +1,5 @@ import { Message } from "@/app/session/communication/message"; import { TbUser } from "react-icons/tb"; -import Image from "next/image"; -import robotIcon from "../../icon.png"; import React from "react"; export default function ChatHistory({ history }: { history: Message[] }) { @@ -25,7 +23,7 @@ export default function ChatHistory({ history }: { history: Message[] }) {
{msg.role === "model" ? (
- robot + robot
) : (
diff --git a/ui/app/session/chat/chat_input.tsx b/ui/app/session/chat/chat_input.tsx index f53c85e..b539b84 100644 --- a/ui/app/session/chat/chat_input.tsx +++ b/ui/app/session/chat/chat_input.tsx @@ -1,7 +1,5 @@ import React from "react"; import { BiSend } from "react-icons/bi"; -import thinkingImg from "./thinking.gif"; -import Image from "next/image"; export default function ChatInput({ innerRef, @@ -61,7 +59,7 @@ export default function ChatInput({
{llmAnimation && (
- thinking + thinking
)}
diff --git a/ui/app/session/communication/chat_round.tsx b/ui/app/session/communication/chat_round.tsx index 5c253b1..8850584 100644 --- a/ui/app/session/communication/chat_round.tsx +++ b/ui/app/session/communication/chat_round.tsx @@ -20,8 +20,16 @@ export class ChatRound { private readonly interpreter: Interpreter, private readonly setState: (state: ChatRoundState) => void, private readonly setCodeResult: (result: string) => void, - llmUrl: string, ) { + let llmUrl = process.env.NEXT_PUBLIC_LLM_URL ?? ""; + if (llmUrl === "") { + try { + llmUrl = location.host; + } catch (e) { + llmUrl = "localhost"; + } + } + llmUrl += "/api/llm"; this.llm = new LLM(llmUrl); } diff --git a/ui/app/session/communication/interpreter.tsx b/ui/app/session/communication/interpreter.tsx index ef29991..b149547 100644 --- a/ui/app/session/communication/interpreter.tsx +++ b/ui/app/session/communication/interpreter.tsx @@ -1,7 +1,18 @@ export default class Interpreter { private ws: WebSocket | null = null; + private readonly interpreterUrl: string; - constructor(private readonly interpreterUrl: string) {} + constructor() { + this.interpreterUrl = process.env.NEXT_PUBLIC_INTERPRETER_URL ?? ""; + if (this.interpreterUrl === "") { + try { + this.interpreterUrl = location.host; + } catch (e) { + this.interpreterUrl = "localhost"; + } + } + this.interpreterUrl += "/api/interpreter"; + } private connect(): Promise { return new Promise((resolve, reject) => { diff --git a/ui/app/session/session.tsx b/ui/app/session/session.tsx index a37377b..ca2bc64 100644 --- a/ui/app/session/session.tsx +++ b/ui/app/session/session.tsx @@ -13,13 +13,9 @@ import { Header } from "@/app/session/chat/header"; import Brand from "@/app/session/chat/brand"; export default function Session({ - interpreterUrl, - llmUrl, refreshSession, version, }: { - interpreterUrl: string; - llmUrl: string; refreshSession: () => void; version: string; }) { @@ -36,7 +32,7 @@ export default function Session({ const chatInputRef = React.useRef(null); const interpreterRef = React.useRef(null); if (interpreterRef.current === null) { - interpreterRef.current = new Interpreter(interpreterUrl); + interpreterRef.current = new Interpreter(); } const code = history.findLast((msg) => msg.code !== undefined)?.code ?? null; @@ -60,7 +56,6 @@ export default function Session({ interpreterRef.current!, setChatRoundState, setCodeResult, - llmUrl, ); chatRound .run(message) diff --git a/ui/app/session/session_manager.tsx b/ui/app/session/session_manager.tsx index 152e813..630c360 100644 --- a/ui/app/session/session_manager.tsx +++ b/ui/app/session/session_manager.tsx @@ -3,23 +3,13 @@ import React from "react"; import Session from "@/app/session/session"; -export default function SessionManager({ - interpreterUrl, - llmUrl, - version, -}: { - interpreterUrl: string; - llmUrl: string; - version: string; -}) { +export default function SessionManager({ version }: { version: string }) { const [sessionCnt, setSessionCnt] = React.useState(0); const refreshSession = () => setSessionCnt(sessionCnt + 1); return ( ); diff --git a/ui/next.config.js b/ui/next.config.js index 658404a..a35bfad 100644 --- a/ui/next.config.js +++ b/ui/next.config.js @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: "export", +}; module.exports = nextConfig; diff --git a/ui/package.json b/ui/package.json index 817e115..17c4cd6 100644 --- a/ui/package.json +++ b/ui/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "next dev", "build": "next build", - "start": "next start -p 3030", + "start": "next start", "lint": "next lint" }, "dependencies": { diff --git a/ui/app/icon.png b/ui/public/icon.png similarity index 100% rename from ui/app/icon.png rename to ui/public/icon.png diff --git a/ui/app/session/chat/icon_color.png b/ui/public/icon_color.png similarity index 100% rename from ui/app/session/chat/icon_color.png rename to ui/public/icon_color.png diff --git a/ui/app/session/chat/thinking.gif b/ui/public/thinking.gif similarity index 100% rename from ui/app/session/chat/thinking.gif rename to ui/public/thinking.gif