Jon Taylor commited on
Commit
ad5d266
1 Parent(s): 94f1dbe

base setup

Browse files
Dockerfile CHANGED
@@ -23,19 +23,25 @@ RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg -
23
  RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list > /dev/null
24
  RUN apt-get update && apt-get install nodejs -y
25
 
26
- COPY ./requirements.txt /code/requirements.txt
27
-
28
  # Expose Flask port
29
- ENV FLASK_PORT=7860
30
  EXPOSE 7860
31
 
 
 
32
  RUN pip3 install --no-cache-dir --upgrade -r /code/requirements.txt
33
 
34
- # Copy the current directory contents into the container at $HOME/app setting the owner to the user
35
- COPY app/ app/
 
 
 
36
  COPY frontend/ frontend/
 
 
 
 
37
  COPY server.py server.py
38
- COPY build-run.sh build-run.sh
39
 
40
  #ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4
41
- CMD ["./build-run.sh"]
 
23
  RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list > /dev/null
24
  RUN apt-get update && apt-get install nodejs -y
25
 
 
 
26
  # Expose Flask port
27
+ ENV FAST_API_PORT=7860
28
  EXPOSE 7860
29
 
30
+ # Install Python dependencies
31
+ COPY ./requirements.txt /code/requirements.txt
32
  RUN pip3 install --no-cache-dir --upgrade -r /code/requirements.txt
33
 
34
+ # Copy package.json and package-lock.json (or yarn.lock)
35
+ COPY frontend/package*.json frontend/
36
+ RUN cd frontend && npm install
37
+
38
+ # Copy frontend app and install Node.js dependencies
39
  COPY frontend/ frontend/
40
+ RUN cd frontend && npm install
41
+
42
+ # Copy everything else
43
+ COPY app/ app/
44
  COPY server.py server.py
 
45
 
46
  #ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc.so.4
47
+ CMD ["python3", "server.py"]
_server.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, send_from_directory, jsonify, request
2
+ from flask_cors import CORS
3
+ from dotenv import load_dotenv
4
+ import os
5
+ import requests
6
+ import subprocess
7
+ import time
8
+
9
+ from app.auth import get_meeting_token
10
+
11
+ load_dotenv()
12
+
13
+ app = Flask(__name__, static_url_path="/", static_folder="frontend/out")
14
+ CORS(app)
15
+
16
+ def _start_bot(bot_path, args=None):
17
+ daily_api_key = os.getenv("DAILY_API_KEY") or ""
18
+ api_path = os.getenv("DAILY_API_PATH") or "https://api.daily.co/v1"
19
+
20
+ timeout = int(os.getenv("ROOM_TIMEOUT") or os.getenv("BOT_MAX_DURATION") or 300)
21
+ exp = time.time() + timeout
22
+
23
+ '''
24
+ res = requests.post(
25
+ f"{api_path}/rooms",
26
+ headers={"Authorization": f"Bearer {daily_api_key}"},
27
+ json={
28
+ "properties": {
29
+ "exp": exp,
30
+ "enable_chat": True,
31
+ "enable_emoji_reactions": True,
32
+ "eject_at_room_exp": True,
33
+ "enable_prejoin_ui": False,
34
+ }
35
+ },
36
+ )
37
+ if res.status_code != 200:
38
+ return (
39
+ jsonify(
40
+ {
41
+ "error": "Unable to create room",
42
+ "status_code": res.status_code,
43
+ "text": res.text,
44
+ }
45
+ ),
46
+ 500,
47
+ )
48
+ '''
49
+ room_url = os.getenv("DAILY_ROOM_URL") #res.json()["url"]
50
+ room_name = os.getenv("DAILY_ROOM_NAME") #res.json()["name"]
51
+
52
+ meeting_token = get_meeting_token(room_url, daily_api_key, exp)
53
+
54
+ if args:
55
+ extra_args = " ".join([f'-{x[0]} "{x[1]}"' for x in args])
56
+ else:
57
+ extra_args = ""
58
+
59
+ proc = subprocess.Popen(
60
+ [
61
+ f"python3 {bot_path} -u {room_url} -t {meeting_token} {extra_args}"
62
+ ],
63
+ shell=True,
64
+ bufsize=1,
65
+ )
66
+
67
+ # Don't return until the bot has joined the room, but wait for at most 2 seconds.
68
+ attempts = 0
69
+ while attempts < 20:
70
+ time.sleep(0.1)
71
+ attempts += 1
72
+ res = requests.get(
73
+ f"{api_path}/rooms/{room_name}/get-session-data",
74
+ headers={"Authorization": f"Bearer {daily_api_key}"},
75
+ )
76
+ if res.status_code == 200:
77
+ break
78
+ print(f"Took {attempts} attempts to join room {room_name}")
79
+
80
+ return jsonify({"room_url": room_url, "token": meeting_token}), 200
81
+
82
+ # Routes
83
+ #@app.route("/start-bot", methods=["POST"])
84
+ #def start_bot():
85
+ # return _start_bot("./app/bot.py")
86
+
87
+
88
+ @app.route('/', defaults={'path': ''})
89
+ @app.route('/<path:path>')
90
+ def catch_all(path):
91
+ full_path = os.path.join(app.static_folder, path)
92
+ # Check if path is a directory and index.html exists
93
+ if os.path.isdir(full_path) and os.path.exists(os.path.join(full_path, 'index.html')):
94
+ return send_from_directory(full_path, 'index.html')
95
+ # Check if path.html exists
96
+ elif os.path.exists(full_path + '.html'):
97
+ return send_from_directory(app.static_folder, path + '.html')
98
+ # Serve index.html by default
99
+ else:
100
+ return send_from_directory(app.static_folder, 'index.html')
build-run.sh DELETED
@@ -1,14 +0,0 @@
1
- #!/bin/bash
2
- cd frontend
3
- echo "Installing node modules..."
4
- npm install
5
- echo "Building frontend..."
6
- npm run build
7
- if [ $? -eq 0 ]; then
8
- echo -e "\033[1;32m\nfrontend build success \033[0m"
9
- else
10
- echo -e "\033[1;31m\nfrontend build failed\n\033[0m" >&2 exit 1
11
- fi
12
- cd ../
13
-
14
- gunicorn --workers=2 --log-level debug server:app --bind=0.0.0.0:$FLASK_PORT
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/app/page.js CHANGED
@@ -1,113 +1,11 @@
1
- import Image from 'next/image'
2
 
3
  export default function Home() {
4
  return (
5
  <main className="flex min-h-screen flex-col items-center justify-between p-24">
6
- <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
7
- <p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
8
- Get started by editing&nbsp;
9
- <code className="font-mono font-bold">app/page.js</code>
10
- </p>
11
- <div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:h-auto lg:w-auto lg:bg-none">
12
- <a
13
- className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0"
14
- href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
15
- target="_blank"
16
- rel="noopener noreferrer"
17
- >
18
- By{' '}
19
- <Image
20
- src="/vercel.svg"
21
- alt="Vercel Logo"
22
- className="dark:invert"
23
- width={100}
24
- height={24}
25
- priority
26
- />
27
- </a>
28
- </div>
29
- </div>
30
-
31
- <div className="relative flex place-items-center before:absolute before:h-[300px] before:w-[480px] before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-[240px] after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 before:lg:h-[360px] z-[-1]">
32
- <Image
33
- className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
34
- src="/next.svg"
35
- alt="Next.js Logo"
36
- width={180}
37
- height={37}
38
- priority
39
- />
40
- </div>
41
-
42
- <div className="mb-32 grid text-center lg:max-w-5xl lg:w-full lg:mb-0 lg:grid-cols-4 lg:text-left">
43
- <a
44
- href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
45
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
46
- target="_blank"
47
- rel="noopener noreferrer"
48
- >
49
- <h2 className={`mb-3 text-2xl font-semibold`}>
50
- Docs{' '}
51
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
52
- -&gt;
53
- </span>
54
- </h2>
55
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
56
- Find in-depth information about Next.js features and API.
57
- </p>
58
- </a>
59
-
60
- <a
61
- href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
62
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800 hover:dark:bg-opacity-30"
63
- target="_blank"
64
- rel="noopener noreferrer"
65
- >
66
- <h2 className={`mb-3 text-2xl font-semibold`}>
67
- Learn{' '}
68
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
69
- -&gt;
70
- </span>
71
- </h2>
72
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
73
- Learn about Next.js in an interactive course with&nbsp;quizzes!
74
- </p>
75
- </a>
76
-
77
- <a
78
- href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
79
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
80
- target="_blank"
81
- rel="noopener noreferrer"
82
- >
83
- <h2 className={`mb-3 text-2xl font-semibold`}>
84
- Templates{' '}
85
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
86
- -&gt;
87
- </span>
88
- </h2>
89
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
90
- Explore starter templates for Next.js.
91
- </p>
92
- </a>
93
-
94
- <a
95
- href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
96
- className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30"
97
- target="_blank"
98
- rel="noopener noreferrer"
99
- >
100
- <h2 className={`mb-3 text-2xl font-semibold`}>
101
- Deploy{' '}
102
- <span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
103
- -&gt;
104
- </span>
105
- </h2>
106
- <p className={`m-0 max-w-[30ch] text-sm opacity-50`}>
107
- Instantly deploy your Next.js site to a shareable URL with Vercel.
108
- </p>
109
- </a>
110
- </div>
111
  </main>
112
- )
113
  }
 
1
+ import Link from "next/link";
2
 
3
  export default function Home() {
4
  return (
5
  <main className="flex min-h-screen flex-col items-center justify-between p-24">
6
+ Hello
7
+ <hr />
8
+ <Link href="/test">Test</Link>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  </main>
10
+ );
11
  }
frontend/app/test/page.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ export default function Test() {
2
+ return (
3
+ <main className="flex min-h-screen flex-col items-center justify-between p-24">
4
+ Hi
5
+ </main>
6
+ );
7
+ }
frontend/package-lock.json DELETED
The diff for this file is too large to render. See raw diff
 
frontend/yarn.lock ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt CHANGED
@@ -1,15 +1,7 @@
1
  daily-python
2
- blinker==1.7.0
3
- click==8.1.7
4
- Flask==3.0.0
5
- Flask-Cors==4.0.0
6
- gunicorn==21.2.0
7
- itsdangerous==2.1.2
8
- Jinja2==3.1.2
9
- MarkupSafe==2.1.3
10
- packaging==23.2
11
- Werkzeug==3.0.1
12
  python-dotenv
13
  imageio-ffmpeg
14
  imageio
15
- requests
 
 
 
1
  daily-python
 
 
 
 
 
 
 
 
 
 
2
  python-dotenv
3
  imageio-ffmpeg
4
  imageio
5
+ requests
6
+ fastapi
7
+ uvicorn[standard]
server.py CHANGED
@@ -1,91 +1,52 @@
1
- from flask import Flask, send_from_directory, jsonify, request
2
- from flask_cors import CORS
 
 
3
  from dotenv import load_dotenv
 
4
  import os
5
- import requests
6
- import subprocess
7
- import time
8
-
9
- from app.auth import get_meeting_token
10
 
11
  load_dotenv()
12
 
13
- app = Flask(__name__, static_url_path="/", static_folder="frontend/out")
14
- CORS(app)
15
-
16
- def _start_bot(bot_path, args=None):
17
- daily_api_key = os.getenv("DAILY_API_KEY") or ""
18
- api_path = os.getenv("DAILY_API_PATH") or "https://api.daily.co/v1"
19
-
20
- timeout = int(os.getenv("ROOM_TIMEOUT") or os.getenv("BOT_MAX_DURATION") or 300)
21
- exp = time.time() + timeout
22
-
23
- '''
24
- res = requests.post(
25
- f"{api_path}/rooms",
26
- headers={"Authorization": f"Bearer {daily_api_key}"},
27
- json={
28
- "properties": {
29
- "exp": exp,
30
- "enable_chat": True,
31
- "enable_emoji_reactions": True,
32
- "eject_at_room_exp": True,
33
- "enable_prejoin_ui": False,
34
- }
35
- },
36
- )
37
- if res.status_code != 200:
38
- return (
39
- jsonify(
40
- {
41
- "error": "Unable to create room",
42
- "status_code": res.status_code,
43
- "text": res.text,
44
- }
45
- ),
46
- 500,
47
- )
48
- '''
49
- room_url = os.getenv("DAILY_ROOM_URL") #res.json()["url"]
50
- room_name = os.getenv("DAILY_ROOM_NAME") #res.json()["name"]
51
-
52
- meeting_token = get_meeting_token(room_url, daily_api_key, exp)
53
-
54
- if args:
55
- extra_args = " ".join([f'-{x[0]} "{x[1]}"' for x in args])
56
  else:
57
- extra_args = ""
58
-
59
- proc = subprocess.Popen(
60
- [
61
- f"python3 {bot_path} -u {room_url} -t {meeting_token} {extra_args}"
62
- ],
63
- shell=True,
64
- bufsize=1,
 
 
 
 
 
 
65
  )
66
-
67
- # Don't return until the bot has joined the room, but wait for at most 2 seconds.
68
- attempts = 0
69
- while attempts < 20:
70
- time.sleep(0.1)
71
- attempts += 1
72
- res = requests.get(
73
- f"{api_path}/rooms/{room_name}/get-session-data",
74
- headers={"Authorization": f"Bearer {daily_api_key}"},
75
- )
76
- if res.status_code == 200:
77
- break
78
- print(f"Took {attempts} attempts to join room {room_name}")
79
-
80
- return jsonify({"room_url": room_url, "token": meeting_token}), 200
81
-
82
- # Routes
83
- @app.route("/start-bot", methods=["POST"])
84
- def start_bot():
85
- return _start_bot("./app/bot.py")
86
-
87
- @app.route("/")
88
- def home():
89
- print(f'Static folder path: {app.static_folder}')
90
- return send_from_directory(app.static_folder, 'index.html')
91
-
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.staticfiles import StaticFiles
4
+ from fastapi.responses import FileResponse
5
  from dotenv import load_dotenv
6
+ from pathlib import Path
7
  import os
 
 
 
 
 
8
 
9
  load_dotenv()
10
 
11
+ app = FastAPI()
12
+
13
+ app.add_middleware(
14
+ CORSMiddleware,
15
+ allow_origins=["*"],
16
+ allow_credentials=True,
17
+ allow_methods=["*"],
18
+ allow_headers=["*"],
19
+ )
20
+
21
+ # Mount the static directory
22
+ app.mount("/static", StaticFiles(directory="frontend/out", html=True), name="static")
23
+
24
+ @app.get("/{path_name:path}")
25
+ async def catch_all(path_name: str):
26
+ # Default route for the root
27
+ if path_name == "":
28
+ path_name = "index"
29
+
30
+ # Construct file path with .html extension
31
+ file_path = Path("frontend/out") / f"{path_name}.html"
32
+
33
+ if file_path.is_file():
34
+ # Serve the .html file if it exists
35
+ return FileResponse(file_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  else:
37
+ # If the specific .html file does not exist, raise a 404 error
38
+ raise HTTPException(status_code=404, detail="Item not found")
39
+
40
+ # Run the application using Uvicorn
41
+ if __name__ == "__main__":
42
+ import uvicorn
43
+
44
+ uvicorn.run(
45
+ "server:app",
46
+ host="0.0.0.0",
47
+ port=int(os.getenv('FAST_API_PORT', 8000)),
48
+ reload=os.getenv('FAST_API_RELOAD', 'false').lower() == 'true',
49
+ #ssl_certfile=args.ssl_certfile,
50
+ #ssl_keyfile=args.ssl_keyfile,
51
  )
52
+