1+ #! /bin/bash
2+
3+ set -e
4+
5+ # Configuration
6+ # GITHUB_BASE_URL="https://raw.githubusercontent.com/livekit/livekit-cli/refs/heads/main/pkg/agentfs/examples/"
7+ # Temporary until this is merged: https://github.com/livekit/livekit-cli/pull/644
8+ GITHUB_BASE_URL=" https://raw.githubusercontent.com/livekit/livekit-cli/05790019cc1977abcc6452890811bda07f2e74b1/pkg/agentfs/examples"
9+ PROGRAM_MAIN=" src/agent.py"
10+
11+ # Color codes for output
12+ RED=' \033[0;31m'
13+ GREEN=' \033[0;32m'
14+ YELLOW=' \033[1;33m'
15+ NC=' \033[0m' # No Color
16+
17+ # Get the target package manager from command line
18+ TARGET_PM=" $1 "
19+
20+ if [ -z " $TARGET_PM " ]; then
21+ echo -e " ${RED} Error: No package manager specified${NC} "
22+ echo " Usage: $0 {pip|poetry|pipenv|pdm|hatch|uv}"
23+ exit 1
24+ fi
25+
26+ # Source the detection script
27+ source " $( dirname " $0 " ) /detect-package-manager.sh"
28+
29+ # Detect current package manager
30+ CURRENT_PM=$( detect_current_pm)
31+
32+ echo -e " ${GREEN} ✔${NC} Detected current package manager: ${YELLOW} $CURRENT_PM ${NC} "
33+
34+ # Create backup directory
35+ BACKUP_DIR=" .backup.$CURRENT_PM "
36+ if [ " $CURRENT_PM " = " unknown" ]; then
37+ BACKUP_DIR=" .backup.original"
38+ fi
39+
40+ echo " Creating backup: $BACKUP_DIR /"
41+
42+ # Create backup
43+ mkdir -p " $BACKUP_DIR "
44+
45+ # Backup existing files
46+ [ -f " Dockerfile" ] && cp " Dockerfile" " $BACKUP_DIR /"
47+ [ -f " .dockerignore" ] && cp " .dockerignore" " $BACKUP_DIR /"
48+ [ -f " pyproject.toml" ] && cp " pyproject.toml" " $BACKUP_DIR /"
49+ [ -f " requirements.txt" ] && cp " requirements.txt" " $BACKUP_DIR /"
50+ [ -f " Pipfile" ] && cp " Pipfile" " $BACKUP_DIR /"
51+ [ -f " Pipfile.lock" ] && cp " Pipfile.lock" " $BACKUP_DIR /"
52+ [ -f " poetry.lock" ] && cp " poetry.lock" " $BACKUP_DIR /"
53+ [ -f " pdm.lock" ] && cp " pdm.lock" " $BACKUP_DIR /"
54+ [ -f " uv.lock" ] && cp " uv.lock" " $BACKUP_DIR /"
55+
56+ echo " "
57+ echo -e " ${GREEN} ✔${NC} Fetching $TARGET_PM templates from GitHub"
58+
59+ # Download Dockerfile and dockerignore
60+ DOCKERFILE_URL=" $GITHUB_BASE_URL /python.$TARGET_PM .Dockerfile"
61+ DOCKERIGNORE_URL=" $GITHUB_BASE_URL /python.$TARGET_PM .dockerignore"
62+
63+ curl -sL " $DOCKERFILE_URL " -o Dockerfile.tmp
64+ if [ $? -ne 0 ]; then
65+ echo -e " ${RED} Error: Failed to download Dockerfile${NC} "
66+ exit 1
67+ fi
68+
69+ curl -sL " $DOCKERIGNORE_URL " -o .dockerignore
70+ if [ $? -ne 0 ]; then
71+ echo -e " ${RED} Error: Failed to download .dockerignore${NC} "
72+ exit 1
73+ fi
74+
75+ # Replace template variable in Dockerfile
76+ sed " s|{{\.ProgramMain}}|$PROGRAM_MAIN |g" Dockerfile.tmp > Dockerfile
77+ rm Dockerfile.tmp
78+
79+ echo " Downloaded: Dockerfile (from LiveKit template)"
80+ echo " Downloaded: .dockerignore (from LiveKit template)"
81+ echo " "
82+ echo -e " ${YELLOW} ⚠️ Note: Dockerfile has been reset to LiveKit template version${NC} "
83+ echo " Any custom modifications have been backed up"
84+
85+ # Generate package manager specific files
86+ echo " "
87+ echo -e " ${GREEN} ✔${NC} Generating $TARGET_PM configuration"
88+
89+ case " $TARGET_PM " in
90+ pip)
91+ # Generate requirements.txt from pyproject.toml
92+ if [ -f " pyproject.toml" ]; then
93+ python3 -c "
94+ import sys
95+ try:
96+ import tomllib
97+ except ImportError:
98+ try:
99+ import tomli as tomllib
100+ except ImportError:
101+ # Fallback to basic parsing
102+ import re
103+ with open('pyproject.toml', 'r') as f:
104+ content = f.read()
105+ # Extract dependencies with regex
106+ deps_match = re.search(r'dependencies = \[(.*?)\]', content, re.DOTALL)
107+ if deps_match:
108+ deps_str = deps_match.group(1)
109+ deps = re.findall(r'\" ([^\" ]+)\" ', deps_str)
110+ for dep in deps:
111+ print(dep)
112+ sys.exit(0)
113+
114+ with open('pyproject.toml', 'rb') as f:
115+ data = tomllib.load(f)
116+
117+ deps = data.get('project', {}).get('dependencies', [])
118+ for dep in deps:
119+ print(dep)
120+
121+ # Also include dev dependencies as comments
122+ dev_groups = data.get('dependency-groups', {})
123+ if dev_groups:
124+ print('\n# Development dependencies:')
125+ for group, deps in dev_groups.items():
126+ print(f'# [{group}]')
127+ for dep in deps:
128+ print(f'# {dep}')
129+ " > requirements.txt
130+ echo " Generated: requirements.txt"
131+ else
132+ echo -e " ${YELLOW} Warning: No pyproject.toml found to convert${NC} "
133+ fi
134+ ;;
135+
136+ poetry)
137+ # Poetry can work with existing pyproject.toml
138+ if [ -f " pyproject.toml" ]; then
139+ echo " Note: Poetry will use existing pyproject.toml"
140+ echo " You may need to run 'poetry init' to add Poetry-specific metadata"
141+ else
142+ echo -e " ${YELLOW} Warning: No pyproject.toml found${NC} "
143+ fi
144+ echo " Using: pyproject.toml"
145+ ;;
146+
147+ pipenv)
148+ # Generate Pipfile from pyproject.toml
149+ if [ -f " pyproject.toml" ]; then
150+ # Create a basic Pipfile
151+ cat > Pipfile << 'EOF '
152+ [[source]]
153+ url = "https://pypi.org/simple"
154+ verify_ssl = true
155+ name = "pypi"
156+
157+ [packages]
158+ livekit-agents = {extras = ["openai", "turn-detector", "silero", "cartesia", "deepgram"], version = "~=1.2"}
159+ livekit-plugins-noise-cancellation = "~=0.2"
160+ python-dotenv = "*"
161+
162+ [dev-packages]
163+ pytest = "*"
164+ pytest-asyncio = "*"
165+ ruff = "*"
166+
167+ [requires]
168+ python_version = "3.9"
169+ EOF
170+ echo " Generated: Pipfile"
171+ else
172+ echo -e " ${YELLOW} Warning: Creating basic Pipfile${NC} "
173+ cat > Pipfile << 'EOF '
174+ [[source]]
175+ url = "https://pypi.org/simple"
176+ verify_ssl = true
177+ name = "pypi"
178+
179+ [packages]
180+
181+ [dev-packages]
182+
183+ [requires]
184+ python_version = "3.9"
185+ EOF
186+ echo " Generated: Pipfile (basic template)"
187+ fi
188+ ;;
189+
190+ pdm|hatch|uv)
191+ # These use pyproject.toml, just ensure it exists
192+ if [ ! -f " pyproject.toml" ]; then
193+ echo -e " ${YELLOW} Warning: No pyproject.toml found${NC} "
194+ else
195+ echo " Using existing: pyproject.toml"
196+ fi
197+ ;;
198+ esac
199+
200+ echo " Entry point: $PROGRAM_MAIN "
201+
202+ # Display instructions based on package manager
203+ echo " "
204+ echo " Next steps:"
205+ echo " › Install $TARGET_PM :"
206+
207+ case " $TARGET_PM " in
208+ pip)
209+ echo " # pip is usually pre-installed with Python"
210+ echo " "
211+ echo " › Install dependencies:"
212+ echo " pip install -r requirements.txt"
213+ echo " "
214+ echo " › For reproducible builds, generate lock file:"
215+ echo " pip freeze > requirements.lock"
216+ ;;
217+ poetry)
218+ echo " curl -sSL https://install.python-poetry.org | python3 -"
219+ echo " "
220+ echo " › Generate lock file:"
221+ echo " poetry lock"
222+ echo " "
223+ echo " › Install dependencies:"
224+ echo " poetry install"
225+ ;;
226+ pipenv)
227+ echo " pip install pipenv"
228+ echo " "
229+ echo " › Generate lock file:"
230+ echo " pipenv lock"
231+ echo " "
232+ echo " › Install dependencies:"
233+ echo " pipenv install"
234+ ;;
235+ pdm)
236+ echo " pip install pdm"
237+ echo " "
238+ echo " › Generate lock file:"
239+ echo " pdm lock"
240+ echo " "
241+ echo " › Install dependencies:"
242+ echo " pdm install"
243+ ;;
244+ hatch)
245+ echo " pip install hatch"
246+ echo " "
247+ echo " › Create environment:"
248+ echo " hatch env create"
249+ echo " "
250+ echo " › Install dependencies:"
251+ echo " hatch env run pip install -e ."
252+ ;;
253+ uv)
254+ echo " curl -LsSf https://astral.sh/uv/install.sh | sh"
255+ echo " "
256+ echo " › Generate lock file:"
257+ echo " uv lock"
258+ echo " "
259+ echo " › Install dependencies:"
260+ echo " uv sync"
261+ ;;
262+ esac
263+
264+ echo " "
265+ echo " › Test locally:"
266+ echo " python $PROGRAM_MAIN dev"
267+ echo " "
268+ echo " › Build Docker image:"
269+ echo " docker build -t my-agent ."
270+ echo " "
271+ echo " To rollback: make rollback"
272+
273+ # List existing backups
274+ BACKUP_COUNT=$( ls -d .backup.* 2> /dev/null | wc -l)
275+ if [ $BACKUP_COUNT -gt 0 ]; then
276+ echo " Existing backups: $( ls -d .backup.* | tr ' \n' ' ' ) "
277+ fi
0 commit comments