/ Makefile
Makefile
  1  -include .env
  2  export
  3  
  4  .PHONY: start
  5  start:
  6  	uv run --no-group gpu uvicorn restai.main:app --host $${RESTAI_HOST:-127.0.0.1} --port $${RESTAI_PORT:-9000} --workers $${RESTAI_WORKERS:-2}
  7  
  8  .PHONY: database
  9  database:
 10  	uv run --no-group gpu database.py
 11  
 12  .PHONY: frontend
 13  frontend:
 14  	cd frontend && npm install
 15  	cd frontend && npm run build
 16  
 17  .PHONY: dev
 18  dev:
 19  	RESTAI_DEV=true uvicorn restai.main:app --reload --host $${RESTAI_HOST:-127.0.0.1} --port $${RESTAI_PORT:-9000}
 20  
 21  .PHONY: build
 22  build:
 23  	uv build
 24  
 25  .PHONY: install
 26  install:
 27  	mkdir -p frontend/build
 28  	uv sync --no-group gpu
 29  	make database
 30  	make frontend
 31  	@if command -v nvidia-smi > /dev/null 2>&1 && nvidia-smi > /dev/null 2>&1; then \
 32  		echo "GPU detected, running installgpu..."; \
 33  		$(MAKE) installgpu; \
 34  	fi
 35  	@echo ""
 36  	@echo "=== Installation complete ==="
 37  	@echo ""
 38  	@read -p "Install RESTai as a systemd service? [y/N] " answer; \
 39  	if [ "$$answer" = "y" ] || [ "$$answer" = "Y" ]; then \
 40  		$(MAKE) systemd; \
 41  	fi
 42  	@read -p "Install cron jobs (sync + telegram + docker cleanup)? [y/N] " answer; \
 43  	if [ "$$answer" = "y" ] || [ "$$answer" = "Y" ]; then \
 44  		$(MAKE) cron; \
 45  	fi
 46  
 47  .PHONY: systemd
 48  systemd:
 49  	@RESTAI_DIR=$$(pwd); \
 50  	RESTAI_USER=$$(whoami); \
 51  	RESTAI_UV=$$(which uv); \
 52  	echo "[Unit]" > /tmp/restai.service; \
 53  	echo "Description=RESTai AI Platform" >> /tmp/restai.service; \
 54  	echo "After=network.target" >> /tmp/restai.service; \
 55  	echo "" >> /tmp/restai.service; \
 56  	echo "[Service]" >> /tmp/restai.service; \
 57  	echo "Type=simple" >> /tmp/restai.service; \
 58  	echo "User=$$RESTAI_USER" >> /tmp/restai.service; \
 59  	echo "WorkingDirectory=$$RESTAI_DIR" >> /tmp/restai.service; \
 60  	echo "EnvironmentFile=$$RESTAI_DIR/.env" >> /tmp/restai.service; \
 61  	echo "ExecStart=$$RESTAI_UV run --no-group gpu uvicorn restai.main:app --host $${RESTAI_HOST:-127.0.0.1} --port $${RESTAI_PORT:-9000} --workers $${RESTAI_WORKERS:-4}" >> /tmp/restai.service; \
 62  	echo "Restart=always" >> /tmp/restai.service; \
 63  	echo "RestartSec=5" >> /tmp/restai.service; \
 64  	echo "" >> /tmp/restai.service; \
 65  	echo "[Install]" >> /tmp/restai.service; \
 66  	echo "WantedBy=multi-user.target" >> /tmp/restai.service; \
 67  	sudo cp /tmp/restai.service /etc/systemd/system/restai.service; \
 68  	rm /tmp/restai.service; \
 69  	sudo systemctl daemon-reload; \
 70  	sudo systemctl enable restai; \
 71  	sudo systemctl start restai; \
 72  	echo ""; \
 73  	echo "RESTai systemd service installed and started."; \
 74  	echo "  Status:  sudo systemctl status restai"; \
 75  	echo "  Logs:    sudo journalctl -u restai -f"; \
 76  	echo "  Stop:    sudo systemctl stop restai"; \
 77  	echo "  Restart: sudo systemctl restart restai"
 78  
 79  .PHONY: installgpu
 80  installgpu:
 81  	uv sync
 82  	make envs
 83  	uv run --no-group gpu download.py
 84  
 85  .PHONY: envs
 86  envs:
 87  	bash worker_envs/install.sh
 88  
 89  .PHONY: migrate
 90  migrate:
 91  	uv run --no-group gpu migrate.py upgrade
 92  
 93  .PHONY: cron
 94  cron:
 95  	@RESTAI_DIR=$$(pwd); \
 96  	CURRENT=$$(crontab -l 2>/dev/null || true); \
 97  	if echo "$$CURRENT" | grep -q "restai-sync\|restai-telegram\|restai-docker-cleanup\|restai-routines"; then \
 98  	  CURRENT=$$(echo "$$CURRENT" | grep -v "restai-sync\|restai-telegram\|restai-docker-cleanup\|restai-routines"); \
 99  	  echo "Removed old individual cron jobs"; \
100  	fi; \
101  	UV_PATH=$$(which uv); \
102  	ENTRY="* * * * * cd $$RESTAI_DIR && $$UV_PATH run --no-group gpu python crons/runner.py >> /var/log/restai-crons.log 2>&1 # restai-crons"; \
103  	if echo "$$CURRENT" | grep -q "restai-crons"; then \
104  	  echo "Already installed: restai-crons"; \
105  	elif [ -z "$$CURRENT" ]; then \
106  	  CURRENT="$$ENTRY"; \
107  	  echo "Added: restai-crons"; \
108  	else \
109  	  CURRENT="$$CURRENT"$$'\n'"$$ENTRY"; \
110  	  echo "Added: restai-crons"; \
111  	fi; \
112  	echo "$$CURRENT" | crontab -
113  	@echo "Cron jobs installed:"
114  	@crontab -l | grep restai || true
115  
116  .PHONY: cron-remove
117  cron-remove:
118  	@( crontab -l 2>/dev/null | grep -v "restai-crons" ) | crontab -
119  	@echo "RESTai cron jobs removed."
120  
121  
122  .PHONY: update
123  update:
124  	@echo "Fetching latest release from GitHub..."
125  	@LATEST=$$(git ls-remote --tags --sort=-v:refname origin 'refs/tags/v*' 2>/dev/null | head -1 | sed 's/.*refs\/tags\///'); \
126  	if [ -z "$$LATEST" ]; then \
127  		echo "No release tags found. Pulling latest from current branch..."; \
128  		git pull; \
129  	else \
130  		echo "Latest release: $$LATEST"; \
131  		git fetch --tags; \
132  		git checkout "$$LATEST"; \
133  	fi
134  	@echo "Installing dependencies..."
135  	uv sync --no-group gpu
136  	@echo "Running database migrations..."
137  	$(MAKE) migrate
138  	@echo "Building frontend..."
139  	$(MAKE) frontend
140  	@if command -v nvidia-smi > /dev/null 2>&1 && nvidia-smi > /dev/null 2>&1; then \
141  		echo "GPU detected, syncing GPU deps..."; \
142  		$(MAKE) installgpu; \
143  	fi
144  	@echo "Update complete."
145  
146  .PHONY: docs
147  docs:
148  	uv run --no-group gpu docs.py
149  
150  .PHONY: version
151  version:
152  	@CURRENT=$$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/'); \
153  	MAJOR=$$(echo $$CURRENT | cut -d. -f1); \
154  	MINOR=$$(echo $$CURRENT | cut -d. -f2); \
155  	PATCH=$$(echo $$CURRENT | cut -d. -f3); \
156  	NEW_PATCH=$$((PATCH + 1)); \
157  	NEW_VERSION="$$MAJOR.$$MINOR.$$NEW_PATCH"; \
158  	echo "Bumping version: $$CURRENT → $$NEW_VERSION"; \
159  	sed -i "s/^version = \"$$CURRENT\"/version = \"$$NEW_VERSION\"/" pyproject.toml; \
160  	echo "Syncing lock file..."; \
161  	uv sync --no-group gpu; \
162  	echo "Committing..."; \
163  	git add pyproject.toml uv.lock; \
164  	git commit -m "v$$NEW_VERSION"; \
165  	echo "Tagging v$$NEW_VERSION..."; \
166  	git tag "v$$NEW_VERSION"; \
167  	echo "Pushing..."; \
168  	git push && git push --tags; \
169  	echo "Creating GitHub release..."; \
170  	gh release create "v$$NEW_VERSION" --title "v$$NEW_VERSION" --generate-notes; \
171  	echo "Done: v$$NEW_VERSION released."
172  
173  .PHONY: test
174  test:
175  	pytest tests
176  
177  .PHONY: code
178  code:
179  	black app/*.py
180  
181  .PHONY: clean
182  clean:
183  	rm -rf frontend/build/*
184  
185  .PHONY: dockershell
186  dockershell:
187  	@docker run --rm -t -i -v $(shell pwd):/app restai bash
188  
189  .PHONY: dockerbuild
190  dockerbuild:
191  	@docker build -t restai .
192