diff --git a/README.md b/README.md index 4f8916b..be428ca 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,58 @@ ## ๐Ÿš€ ๅฟซ้€Ÿๅผ€ๅง‹ -### ็Žฏๅขƒ่ฆๆฑ‚ +### ๆ–นๆณ• 1: ่‡ชๅŠจๅŒ–่„šๆœฌ๏ผˆๆŽจ่๏ผ‰ โšก +**ไธ€้”ฎๅฎŒๆˆๆ‰€ๆœ‰่ฎพ็ฝฎใ€ๅฏๅŠจๅนถๆต‹่ฏ•ๆœๅŠกๅ™จ๏ผš** + +```bash +# 1. ๅ…‹้š†้กน็›ฎ +git clone https://github.com/Zeeeepa/z.ai2api_python.git +cd z.ai2api_python + +# 2. ่ฎพ็ฝฎ็Žฏๅขƒๅ˜้‡ +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password + +# 3. ่ฟ่กŒ่‡ชๅŠจๅŒ–่„šๆœฌ +bash scripts/all.sh +``` + +่ฟ™ๅฐ†่‡ชๅŠจๅฎŒๆˆ๏ผš +- โœ… ๅฎ‰่ฃ…ๆ‰€ๆœ‰ไพ่ต–๏ผˆPython + Playwright๏ผ‰ +- โœ… ้€š่ฟ‡ Playwright ่‡ชๅŠจ็™ปๅฝ•ๅนถ่Žทๅ–่ฎค่ฏไปค็‰Œ +- โœ… ๅœจ 8080 ็ซฏๅฃๅฏๅŠจๆœๅŠกๅ™จ +- โœ… ๅ‘้€ๆต‹่ฏ•่ฏทๆฑ‚้ชŒ่ฏ API ๅŠŸ่ƒฝ +- โœ… ๆ˜พ็คบๅฎžๆ—ถๆ—ฅๅฟ— + +**ๅ•็‹ฌ่ฟ่กŒ่„šๆœฌ๏ผš** + +```bash +# ไป…็Žฏๅขƒ่ฎพ็ฝฎๅ’Œไปค็‰Œ่Žทๅ– +bash scripts/setup.sh + +# ไป…ๅฏๅŠจๆœๅŠกๅ™จ +bash scripts/start.sh + +# ไป…ๆต‹่ฏ• API +bash scripts/send_openai_request.sh +``` + +๐Ÿ“– ่ฏฆ็ป†ๆ–‡ๆกฃ่ฏทๅ‚้˜… [scripts/README.md](scripts/README.md) + +--- + +### ๆ–นๆณ• 2: ๆ‰‹ๅŠจๅฎ‰่ฃ… + +**็Žฏๅขƒ่ฆๆฑ‚๏ผš** - Python 3.9-3.12 - pip ๆˆ– uv (ๆŽจ่) -### ๆœฌๅœฐ่ฟ่กŒ +**ๆญฅ้ชค๏ผš** ```bash # 1. ๅ…‹้š†้กน็›ฎ -git clone https://github.com/ZyphrZero/z.ai2api_python.git +git clone https://github.com/Zeeeepa/z.ai2api_python.git cd z.ai2api_python # 2. ๅฎ‰่ฃ…ไพ่ต–๏ผˆไฝฟ็”จ uv ๆŽจ่๏ผ‰ diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..b5c1629 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,439 @@ +# Z.AI2API Automation Scripts + +Complete automation suite for setting up, starting, and testing the Z.AI2API Python server. + +## ๐Ÿ”ฅ IMPORTANT: NO MOCKS - 100% REAL API CALLS + +**All scripts use ACTUAL API calls with REAL responses from Z.AI!** + +The `send_openai_request.sh` script makes genuine requests to your running server, which: +- โœ… **Connects to real Z.AI chat interface** (not a mock) +- โœ… **Uses your JWT token** from browser session +- โœ… **Mimics web browser behavior** exactly +- โœ… **Returns authentic AI responses** from Z.AI/GLM models +- โœ… **Converts responses** to OpenAI API format + +**You see the actual AI-generated content, not fake data!** + +## ๐Ÿ“‹ Overview + +This directory contains scripts to automate the entire workflow: + +1. **setup.sh** - Environment setup and token retrieval +2. **start.sh** - Server startup and health monitoring +3. **send_openai_request.sh** - API testing with **REAL** OpenAI-compatible requests +4. **all.sh** - Complete orchestration of all steps +5. **retrieve_token.py** - Playwright-based token retrieval + +## ๐Ÿš€ Quick Start + +### Prerequisites + +- Python 3.9-3.12 +- Bash shell +- curl +- Internet connection + +### Environment Variables + +Set these before running the scripts: + +```bash +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password +``` + +### One-Command Setup + +Run everything at once: + +```bash +git clone https://github.com/Zeeeepa/z.ai2api_python.git +cd z.ai2api_python +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password +bash scripts/all.sh +``` + +This will: +- โœ… Install all dependencies +- โœ… Retrieve authentication token automatically via Playwright +- โœ… Start the server on port 8080 +- โœ… Test the API with **REAL requests to Z.AI** (no mocks!) +- โœ… Display **actual AI-generated responses** +- โœ… Show live logs + +## ๐Ÿ“– Individual Scripts + +### 1. setup.sh + +Performs initial environment setup: + +```bash +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password +bash scripts/setup.sh +``` + +**What it does:** +- Checks Python version (requires 3.9+) +- Installs Python dependencies (via pip or uv) +- Installs Playwright and Chromium browser +- Creates `.env` file from template +- Retrieves authentication token via automated browser login +- Saves token to `.env` file +- Initializes SQLite database + +**Requirements:** +- `ZAI_EMAIL` environment variable +- `ZAI_PASSWORD` environment variable + +**Output:** +- `.env` file with valid `AUTH_TOKEN` +- `tokens.db` database file +- Installed dependencies + +### 2. start.sh + +Starts the API server: + +```bash +bash scripts/start.sh +``` + +**What it does:** +- Checks if `.env` exists +- Validates port availability (default: 8080) +- Verifies dependencies are installed +- Starts server in background +- Monitors server health +- Creates PID file for process management +- Shows live logs + +**Requirements:** +- `.env` file with valid configuration +- Available port (check `LISTEN_PORT` in `.env`) + +**Output:** +- Running server on http://localhost:8080 +- PID file: `.server.pid` +- Log file: `logs/server.log` + +**Useful commands after starting:** +```bash +# View logs +tail -f logs/server.log + +# Stop server +kill $(cat .server.pid) + +# Check if running +curl http://localhost:8080/ +``` + +### 3. send_openai_request.sh + +Tests the API with **REAL** OpenAI-compatible requests: + +```bash +bash scripts/send_openai_request.sh +``` + +**What it does:** +- Checks if server is running +- Sends **ACTUAL API calls** to your running server +- Server proxies to **real Z.AI chat interface** using your JWT token +- Displays **genuine AI-generated responses** from Z.AI/GLM models +- Tests streaming mode with **real streaming responses** +- Validates complete API functionality + +**NO MOCKS:** All responses are authentic AI-generated content from Z.AI's service! + +**Requirements:** +- Server running on configured port +- Valid `AUTH_TOKEN` in `.env` + +**Output:** +- Formatted API response +- Token usage statistics +- Streaming test results + +### 4. all.sh + +Orchestrates complete workflow: + +```bash +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password +bash scripts/all.sh +``` + +**What it does:** +- Runs `setup.sh` to configure environment +- Runs `start.sh` to start server +- Runs `send_openai_request.sh` to test API +- Displays comprehensive status +- Shows live logs + +**Requirements:** +- Same as `setup.sh` + +**Output:** +- Running and tested server +- Live log display + +### 5. retrieve_token.py + +Python script for automated token retrieval (called by setup.sh): + +```bash +python scripts/retrieve_token.py +``` + +**What it does:** +- Launches headless Chromium browser +- Navigates to Z.AI login page +- Enters credentials +- Submits login form +- Extracts authentication token +- Saves token to `.env` file + +**Requirements:** +- `ZAI_EMAIL` environment variable +- `ZAI_PASSWORD` environment variable +- Playwright installed with browsers + +## ๐Ÿ”ง Configuration + +### Port Configuration + +Edit `.env` to change the server port: + +```env +LISTEN_PORT=8080 +``` + +### Authentication + +The `AUTH_TOKEN` is automatically retrieved by `setup.sh`. To manually set it: + +```env +AUTH_TOKEN=your-token-here +``` + +### Debug Mode + +Enable detailed logging: + +```env +DEBUG_LOGGING=true +``` + +## ๐Ÿ“Š Server Management + +### Check Server Status + +```bash +# Using curl +curl http://localhost:8080/ + +# Check process +ps aux | grep main.py +``` + +### View Logs + +```bash +# Real-time logs +tail -f logs/server.log + +# Recent logs +tail -100 logs/server.log + +# Search logs +grep "ERROR" logs/server.log +``` + +### Stop Server + +```bash +# Using PID file +kill $(cat .server.pid) + +# Or manually +kill + +# Force kill if needed +kill -9 +``` + +### Restart Server + +```bash +# Stop and start +kill $(cat .server.pid) && bash scripts/start.sh + +# Or just run start.sh (it will detect if already running) +bash scripts/start.sh +``` + +## ๐Ÿงช Testing + +### Manual API Test + +```bash +# Using curl +curl -X POST http://localhost:8080/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer YOUR_AUTH_TOKEN" \ + -d '{ + "model": "GLM-4-6-API-V1", + "messages": [ + {"role": "user", "content": "Hello!"} + ], + "stream": false + }' +``` + +### Automated Test + +```bash +bash scripts/send_openai_request.sh +``` + +## ๐Ÿ› Troubleshooting + +### Setup Issues + +**Problem:** `ZAI_EMAIL and ZAI_PASSWORD must be set` +```bash +# Solution: Export environment variables +export ZAI_EMAIL=your-email@example.com +export ZAI_PASSWORD=your-password +``` + +**Problem:** `Playwright browsers not found` +```bash +# Solution: Install browsers manually +python3 -m playwright install chromium +``` + +### Server Issues + +**Problem:** `Port already in use` +```bash +# Solution 1: Kill process using the port +lsof -ti:8080 | xargs kill + +# Solution 2: Change port in .env +echo "LISTEN_PORT=8081" >> .env +``` + +**Problem:** `Server failed to start` +```bash +# Check logs +cat logs/server.log + +# Check dependencies +python3 -c "import fastapi, granian, httpx" +``` + +### Token Issues + +**Problem:** `Failed to retrieve token` +```bash +# Solution 1: Check credentials +echo $ZAI_EMAIL +echo $ZAI_PASSWORD + +# Solution 2: Run token retrieval with verbose output +python3 scripts/retrieve_token.py + +# Solution 3: Manually set token in .env +echo "AUTH_TOKEN=your-token" >> .env +``` + +### API Test Issues + +**Problem:** `Authentication failed` +```bash +# Check AUTH_TOKEN in .env +grep AUTH_TOKEN .env + +# Test with different token +export AUTH_TOKEN=your-token +bash scripts/send_openai_request.sh +``` + +## ๐Ÿ“ Script Details + +### Directory Structure + +``` +scripts/ +โ”œโ”€โ”€ README.md # This file +โ”œโ”€โ”€ all.sh # Complete orchestration +โ”œโ”€โ”€ setup.sh # Environment setup +โ”œโ”€โ”€ start.sh # Server startup +โ”œโ”€โ”€ send_openai_request.sh # API testing +โ””โ”€โ”€ retrieve_token.py # Token retrieval +``` + +### Script Dependencies + +``` +all.sh +โ”œโ”€โ”€ setup.sh +โ”‚ โ”œโ”€โ”€ retrieve_token.py +โ”‚ โ””โ”€โ”€ Python dependencies +โ”œโ”€โ”€ start.sh +โ”‚ โ””โ”€โ”€ main.py +โ””โ”€โ”€ send_openai_request.sh + โ””โ”€โ”€ curl +``` + +## ๐Ÿ” Security Notes + +- **Never commit** `.env` file to version control +- **Keep** `AUTH_TOKEN` private +- **Use** strong passwords for ZAI_EMAIL account +- **Rotate** tokens regularly +- **Monitor** `logs/server.log` for suspicious activity + +## ๐ŸŽฏ Best Practices + +1. **Always use environment variables** for credentials +2. **Check logs** regularly: `tail -f logs/server.log` +3. **Monitor server health** periodically +4. **Keep dependencies updated**: `pip install -U -r requirements.txt` +5. **Use setup.sh** for fresh installations +6. **Use all.sh** for quick testing + +## ๐Ÿ“š Additional Resources + +- **Project README**: `../README.md` +- **API Documentation**: http://localhost:8080/docs +- **Admin Panel**: http://localhost:8080/admin +- **GitHub**: https://github.com/Zeeeepa/z.ai2api_python + +## ๐Ÿ’ก Tips + +- Use `uv` for faster dependency management +- Enable `DEBUG_LOGGING=true` when troubleshooting +- Check `logs/server.log` for detailed error messages +- Use `send_openai_request.sh` to verify changes +- Keep `ZAI_PASSWORD` secure + +## ๐Ÿ†˜ Getting Help + +If you encounter issues: + +1. Check the troubleshooting section above +2. Review `logs/server.log` for errors +3. Ensure all prerequisites are met +4. Verify environment variables are set correctly +5. Open an issue on GitHub + +--- + +**Happy coding! ๐Ÿš€** diff --git a/scripts/all.sh b/scripts/all.sh new file mode 100755 index 0000000..f50904c --- /dev/null +++ b/scripts/all.sh @@ -0,0 +1,280 @@ +#!/bin/bash +# +# all.sh - Complete Z.AI2API Setup, Start, and Test Script +# +# This script orchestrates the complete workflow with REAL API calls: +# +# 1. Run setup.sh +# โœ… Install dependencies +# โœ… Use Playwright to login and retrieve AUTH_TOKEN +# โœ… Save token to .env file +# +# 2. Run start.sh +# โœ… Start server using the retrieved AUTH_TOKEN +# โœ… Server proxies to real Z.AI chat interface +# +# 3. Run send_openai_request.sh +# โœ… Send REAL OpenAI API request: "What is Graph-RAG?" +# โœ… Display actual AI-generated response from Z.AI +# +# Usage: +# export ZAI_EMAIL=your-email@example.com +# export ZAI_PASSWORD=your-password +# bash scripts/all.sh +# + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +MAGENTA='\033[0;35m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +# Logging functions +log_info() { + echo -e "${BLUE}โ„น๏ธ $1${NC}" +} + +log_success() { + echo -e "${GREEN}โœ… $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}โš ๏ธ $1${NC}" +} + +log_error() { + echo -e "${RED}โŒ $1${NC}" +} + +log_step() { + echo -e "${MAGENTA}$1${NC}" +} + +# Error handler +cleanup_on_error() { + echo "" + log_error "An error occurred during execution" + + # Stop server if it was started + if [ -f "$PROJECT_ROOT/.server.pid" ]; then + PID=$(cat "$PROJECT_ROOT/.server.pid") + if kill -0 $PID 2>/dev/null; then + log_info "Stopping server (PID: $PID)..." + kill $PID 2>/dev/null || true + rm -f "$PROJECT_ROOT/.server.pid" + fi + fi + + echo "" + log_warning "Please check the error messages above and try again" + exit 1 +} + +trap cleanup_on_error ERR + +# Banner +clear +echo "" +echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" +echo "โ•‘ โ•‘" +echo "โ•‘ Z.AI2API Python - Complete Setup & Test โ•‘" +echo "โ•‘ โ•‘" +echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo "" + +# Pre-flight checks +log_info "Performing pre-flight checks..." + +# Check if required environment variables are set +if [ -z "$ZAI_EMAIL" ] || [ -z "$ZAI_PASSWORD" ]; then + log_error "Required environment variables not set" + echo "" + echo "Please export the following environment variables:" + echo "" + echo " export ZAI_EMAIL=your-email@example.com" + echo " export ZAI_PASSWORD=your-password" + echo "" + echo "Then run:" + echo " bash scripts/all.sh" + echo "" + exit 1 +fi + +log_success "Environment variables verified" +log_info "Email: $ZAI_EMAIL" +echo "" + +# Confirm with user +echo "This script will:" +echo " 1๏ธโƒฃ Install dependencies and retrieve authentication token" +echo " 2๏ธโƒฃ Start the API server using the retrieved token" +echo " 3๏ธโƒฃ Send REAL API request: 'What is Graph-RAG?'" +echo " 4๏ธโƒฃ Display actual AI response from Z.AI" +echo "" +read -p "Continue? (y/N): " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + log_warning "Aborted by user" + exit 0 +fi + +echo "" +echo "============================================================" +log_step "STEP 1/3: Running setup.sh" +echo "============================================================" +echo "" + +# Execute setup script (this will create and activate venv) +bash "$SCRIPT_DIR/setup.sh" + +if [ $? -ne 0 ]; then + log_error "Setup failed" + exit 1 +fi + +# Ensure venv is activated for subsequent steps +VENV_DIR="$PROJECT_ROOT/.venv" +if [ -d "$VENV_DIR" ]; then + log_info "Activating virtual environment for subsequent steps..." + source "$VENV_DIR/bin/activate" + log_success "Virtual environment activated" +fi + +echo "" +echo "============================================================" +log_step "STEP 2/3: Running start.sh" +echo "============================================================" +echo "" + +# Execute start script +# Note: We need to handle this specially since start.sh might tail logs +# We'll start it in a way that returns control to us + +# Kill any tail processes from previous runs +pkill -f "tail -f logs/server.log" 2>/dev/null || true + +# Start server without tailing logs +bash "$SCRIPT_DIR/start.sh" > /tmp/start_output.log 2>&1 & +START_PID=$! + +# Wait for startup to complete +sleep 5 + +# Check if start script succeeded +if ! wait $START_PID 2>/dev/null; then + # Check if server is actually running + if [ -f "$PROJECT_ROOT/.server.pid" ]; then + SERVER_PID=$(cat "$PROJECT_ROOT/.server.pid") + if kill -0 $SERVER_PID 2>/dev/null; then + log_success "Server started successfully (PID: $SERVER_PID)" + else + log_error "Server failed to start" + cat /tmp/start_output.log + exit 1 + fi + else + log_error "Server startup failed" + cat /tmp/start_output.log + exit 1 + fi +fi + +# Additional health check +log_info "Verifying server health..." +MAX_RETRIES=10 +RETRY=0 +PORT=${LISTEN_PORT:-8080} + +while [ $RETRY -lt $MAX_RETRIES ]; do + if curl -s -f "http://localhost:$PORT/" > /dev/null 2>&1; then + log_success "Server is healthy and responding" + break + fi + RETRY=$((RETRY + 1)) + echo -n "." + sleep 1 +done + +if [ $RETRY -eq $MAX_RETRIES ]; then + log_error "Server health check failed" + exit 1 +fi + +echo "" +sleep 2 # Give server a moment to fully initialize + +echo "" +echo "============================================================" +log_step "STEP 3/3: Running send_openai_request.sh" +echo "============================================================" +echo "" + +# Execute test request script +bash "$SCRIPT_DIR/send_openai_request.sh" + +if [ $? -ne 0 ]; then + log_error "API test failed" + exit 1 +fi + +# Final success message +echo "" +echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" +echo "โ•‘ โ•‘" +echo "โ•‘ ๐ŸŽ‰ All Steps Completed Successfully! ๐ŸŽ‰ โ•‘" +echo "โ•‘ โ•‘" +echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo "" +echo -e "${GREEN}โœจ Your Z.AI2API server is now running and verified! โœจ${NC}" +echo "" +echo "๐Ÿ“Š Server Status:" +if [ -f "$PROJECT_ROOT/.server.pid" ]; then + SERVER_PID=$(cat "$PROJECT_ROOT/.server.pid") + echo " Status: Running" + echo " PID: $SERVER_PID" +else + echo " Status: Unknown (PID file not found)" +fi +echo " Port: ${PORT:-8080}" +echo " Log: logs/server.log" +echo "" +echo "๐ŸŒ Access Points:" +echo " API Root: http://localhost:${PORT:-8080}/" +echo " API Docs: http://localhost:${PORT:-8080}/docs" +echo " Admin: http://localhost:${PORT:-8080}/admin" +echo "" +echo "๐Ÿ“ Useful Commands:" +echo " View logs: tail -f logs/server.log" +echo " Test API again: bash scripts/send_openai_request.sh" +if [ -f "$PROJECT_ROOT/.server.pid" ]; then + echo " Stop server: kill $(cat $PROJECT_ROOT/.server.pid)" +fi +echo " Restart server: bash scripts/start.sh" +echo "" +echo "โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—" +echo "โ•‘ Server will continue running in the background โ•‘" +echo "โ•‘ Press Ctrl+C to exit (server will keep running) โ•‘" +echo "โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•" +echo "" + +# Display live logs +log_info "Displaying server logs (press Ctrl+C to exit)..." +echo "" +sleep 1 + +# Tail logs +if [ -f "$PROJECT_ROOT/logs/server.log" ]; then + tail -f "$PROJECT_ROOT/logs/server.log" +else + log_warning "Log file not found: logs/server.log" +fi diff --git a/scripts/retrieve_token.py b/scripts/retrieve_token.py new file mode 100755 index 0000000..44887a4 --- /dev/null +++ b/scripts/retrieve_token.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 +""" +Token Retrieval Script using Playwright +Automates login to Z.AI and extracts the authentication token +""" +import asyncio +import sys +import os +from playwright.async_api import async_playwright, TimeoutError as PlaywrightTimeout + + +async def retrieve_zai_token(email: str, password: str, timeout: int = 60000) -> dict: + """ + Login to Z.AI and retrieve authentication token + + Args: + email: User email for login + password: User password for login + timeout: Timeout in milliseconds (default: 60s) + + Returns: + dict: Contains 'success' (bool), 'token' (str), 'error' (str) + """ + result = { + 'success': False, + 'token': None, + 'error': None + } + + async with async_playwright() as p: + try: + # Launch browser in headless mode + browser = await p.chromium.launch( + headless=True, + args=['--no-sandbox', '--disable-setuid-sandbox'] + ) + context = await browser.new_context( + viewport={'width': 1280, 'height': 720}, + user_agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36' + ) + page = await context.new_page() + + print("๐ŸŒ Navigating to Z.AI login page...") + await page.goto('https://z.ai/', timeout=timeout) + await page.wait_for_load_state('networkidle', timeout=30000) + + # Wait for and click login button + print("๐Ÿ” Looking for login button...") + try: + # Try multiple possible selectors for login button + selectors = [ + 'button:has-text("็™ปๅฝ•")', + 'button:has-text("Login")', + 'a:has-text("็™ปๅฝ•")', + 'a:has-text("Login")', + '[href*="login"]', + '.login-button', + '#login-btn' + ] + + login_clicked = False + for selector in selectors: + try: + await page.click(selector, timeout=5000) + login_clicked = True + print(f"โœ… Clicked login button using selector: {selector}") + break + except: + continue + + if not login_clicked: + raise Exception("Could not find login button") + + await page.wait_for_load_state('networkidle', timeout=30000) + except Exception as e: + result['error'] = f"Login button not found: {str(e)}" + await browser.close() + return result + + # Enter email + print("โœ‰๏ธ Entering email...") + email_selectors = [ + 'input[type="email"]', + 'input[name="email"]', + 'input[placeholder*="้‚ฎ็ฎฑ"]', + 'input[placeholder*="email"]', + '#email' + ] + + email_entered = False + for selector in email_selectors: + try: + await page.fill(selector, email, timeout=5000) + email_entered = True + print(f"โœ… Entered email using selector: {selector}") + break + except: + continue + + if not email_entered: + result['error'] = "Email input field not found" + await browser.close() + return result + + # Enter password + print("๐Ÿ” Entering password...") + password_selectors = [ + 'input[type="password"]', + 'input[name="password"]', + 'input[placeholder*="ๅฏ†็ "]', + 'input[placeholder*="password"]', + '#password' + ] + + password_entered = False + for selector in password_selectors: + try: + await page.fill(selector, password, timeout=5000) + password_entered = True + print(f"โœ… Entered password using selector: {selector}") + break + except: + continue + + if not password_entered: + result['error'] = "Password input field not found" + await browser.close() + return result + + # Submit login form + print("๐Ÿ“ค Submitting login form...") + submit_selectors = [ + 'button[type="submit"]', + 'button:has-text("็™ปๅฝ•")', + 'button:has-text("Login")', + '.submit-button', + '#submit-btn' + ] + + submitted = False + for selector in submit_selectors: + try: + await page.click(selector, timeout=5000) + submitted = True + print(f"โœ… Clicked submit button using selector: {selector}") + break + except: + continue + + if not submitted: + # Try pressing Enter as fallback + await page.keyboard.press('Enter') + + # Wait for navigation after login + print("โณ Waiting for login to complete...") + await page.wait_for_load_state('networkidle', timeout=30000) + await asyncio.sleep(3) # Additional wait for tokens to be set + + # Extract token from localStorage/cookies/network + print("๐Ÿ” Extracting authentication token...") + + # Method 1: Check localStorage + token = await page.evaluate('''() => { + return localStorage.getItem('token') || + localStorage.getItem('auth_token') || + localStorage.getItem('access_token') || + localStorage.getItem('jwt'); + }''') + + # Method 2: Check cookies if localStorage didn't work + if not token: + cookies = await context.cookies() + for cookie in cookies: + if cookie['name'] in ['token', 'auth_token', 'access_token', 'jwt', 'session']: + token = cookie['value'] + break + + # Method 3: Check network requests for auth headers + if not token: + # Make a test API request to trigger auth header + try: + response = await page.request.get('https://z.ai/api/config') + headers = response.headers + auth_header = headers.get('authorization', '') + if auth_header.startswith('Bearer '): + token = auth_header.replace('Bearer ', '') + except: + pass + + if token: + result['success'] = True + result['token'] = token + print(f"โœ… Token retrieved successfully: {token[:20]}...") + else: + result['error'] = "Token not found in localStorage, cookies, or network requests" + print("โŒ Could not extract token from any source") + + await browser.close() + + except PlaywrightTimeout as e: + result['error'] = f"Timeout during login process: {str(e)}" + print(f"โฑ๏ธ Timeout: {result['error']}") + except Exception as e: + result['error'] = f"Unexpected error: {str(e)}" + print(f"โŒ Error: {result['error']}") + + return result + + +async def main(): + """Main entry point""" + # Get credentials from environment variables + email = os.getenv('ZAI_EMAIL') + password = os.getenv('ZAI_PASSWORD') + + if not email or not password: + print("โŒ Error: ZAI_EMAIL and ZAI_PASSWORD environment variables must be set") + sys.exit(1) + + print("=" * 60) + print("Z.AI Token Retrieval Script") + print("=" * 60) + print(f"๐Ÿ“ง Email: {email}") + print(f"๐Ÿ” Password: {'*' * len(password)}") + print("=" * 60) + + result = await retrieve_zai_token(email, password) + + if result['success']: + # Write token to .env file + env_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), '.env') + + # Read existing .env or create new one + env_content = {} + if os.path.exists(env_path): + with open(env_path, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + env_content[key.strip()] = value.strip() + + # Update AUTH_TOKEN + env_content['AUTH_TOKEN'] = result['token'] + + # Write back to .env + with open(env_path, 'w') as f: + for key, value in env_content.items(): + f.write(f"{key}={value}\n") + + print(f"โœ… Token saved to {env_path}") + print("=" * 60) + sys.exit(0) + else: + print(f"โŒ Failed to retrieve token: {result['error']}") + print("=" * 60) + sys.exit(1) + + +if __name__ == '__main__': + asyncio.run(main()) + diff --git a/scripts/send_openai_request.sh b/scripts/send_openai_request.sh new file mode 100755 index 0000000..8d6aad9 --- /dev/null +++ b/scripts/send_openai_request.sh @@ -0,0 +1,286 @@ +#!/bin/bash +# +# send_openai_request.sh - Test Z.AI2API with REAL OpenAI-compatible requests +# +# This script makes ACTUAL API calls to your running z.ai2api_python server, +# which proxies to the real Z.AI chat interface using your JWT token. +# +# NO MOCKS - All responses are real AI-generated content from Z.AI! +# +# The server: +# โœ… Mimics a web browser accessing Z.AI's chat interface +# โœ… Uses the JWT token from your browser session +# โœ… Makes requests exactly like the web UI does +# โœ… Converts Z.AI's web responses to OpenAI API format +# + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +# Logging functions +log_info() { + echo -e "${BLUE}โ„น๏ธ $1${NC}" +} + +log_success() { + echo -e "${GREEN}โœ… $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}โš ๏ธ $1${NC}" +} + +log_error() { + echo -e "${RED}โŒ $1${NC}" +} + +# Banner +echo "" +echo "============================================================" +echo " Z.AI2API - OpenAI API Request Test" +echo "============================================================" +echo "" + +# Navigate to project root +cd "$PROJECT_ROOT" + +# Load environment variables if .env exists +if [ -f ".env" ]; then + set -a + source .env + set +a +fi + +# Configuration +PORT=${LISTEN_PORT:-8080} +API_URL="http://localhost:$PORT/v1/chat/completions" +AUTH_TOKEN=${AUTH_TOKEN:-"sk-test"} + +# Step 1: Check if server is running +log_info "Checking if server is running on port $PORT..." +if ! curl -s -f "http://localhost:$PORT/" > /dev/null 2>&1; then + log_error "Server is not responding on port $PORT" + log_info "Please start the server first: bash scripts/start.sh" + exit 1 +fi +log_success "Server is responding" + +# Step 2: Prepare test request +log_info "Preparing test request..." + +# Test message - Real question about Graph-RAG +TEST_MESSAGE="What is Graph-RAG?" + +# Create request payload +REQUEST_PAYLOAD=$(cat < /dev/null; then + echo -e "${CYAN}Response:${NC}" + echo "$RESPONSE_BODY" | python3 -c " +import sys +import json + +try: + data = json.load(sys.stdin) + + # Display basic info + print(f\" Model: {data.get('model', 'N/A')}\") + print(f\" ID: {data.get('id', 'N/A')}\") + print(f\" Created: {data.get('created', 'N/A')}\") + print() + + # Display message content + if 'choices' in data and len(data['choices']) > 0: + choice = data['choices'][0] + message = choice.get('message', {}) + content = message.get('content', 'No content') + finish_reason = choice.get('finish_reason', 'N/A') + + print(' Content:') + print(' ' + '-' * 58) + for line in content.split('\n'): + print(f' {line}') + print(' ' + '-' * 58) + print() + print(f\" Finish Reason: {finish_reason}\") + + # Display usage info + if 'usage' in data: + usage = data['usage'] + print() + print(' Token Usage:') + print(f\" Prompt: {usage.get('prompt_tokens', 'N/A')} tokens\") + print(f\" Completion: {usage.get('completion_tokens', 'N/A')} tokens\") + print(f\" Total: {usage.get('total_tokens', 'N/A')} tokens\") + + print() + +except json.JSONDecodeError: + print(' [Raw Response]') + print(sys.stdin.read()) +except Exception as e: + print(f' Error parsing response: {e}') + print() + print(' [Raw Response]') + print(sys.stdin.read()) +" + else + # Fallback: display raw JSON + echo "$RESPONSE_BODY" | head -c 1000 + echo "" + fi + + echo "" + echo "============================================================" + echo "" + log_success "API test completed successfully! โœจ" + +else + log_error "Request failed (HTTP $HTTP_CODE)" + echo "" + echo -e "${CYAN}Error Response:${NC}" + echo "$RESPONSE_BODY" | head -c 500 + echo "" + echo "" + echo "============================================================" + echo "" + log_error "API test failed" + + if [ "$HTTP_CODE" -eq 401 ] || [ "$HTTP_CODE" -eq 403 ]; then + log_warning "Authentication issue - check AUTH_TOKEN in .env" + elif [ "$HTTP_CODE" -eq 500 ]; then + log_warning "Server error - check logs/server.log" + fi + + exit 1 +fi + +# Step 5: Additional test with streaming +echo "" +log_info "Testing streaming mode..." +echo "" + +STREAM_REQUEST=$(cat < 0: + delta = data['choices'][0].get('delta', {}) + content = delta.get('content', '') + if content: + print(content, end='', flush=True) +except: + pass +" 2>/dev/null + fi + fi +done +echo "" +echo "------------------------------------------------------------" +echo "" +log_success "Streaming test completed! โœจ" + +# Final summary +echo "" +echo "============================================================" +echo " API Testing Complete! โœ…" +echo "============================================================" +echo "" +echo "๐ŸŽ‰ All tests passed successfully!" +echo "" +echo "๐Ÿ“– API Documentation: http://localhost:$PORT/docs" +echo "๐Ÿ”ง Admin Panel: http://localhost:$PORT/admin" +echo "" +echo "============================================================" +echo "" diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..c1e6ad0 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,289 @@ +#!/bin/bash +# +# setup.sh - Z.AI2API Setup Script +# +# This script performs initial setup: +# 1. Installs Python dependencies +# 2. Installs Playwright and browsers +# 3. Creates .env file if needed +# 4. Retrieves authentication token via Playwright login +# 5. Initializes the database +# + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +# Logging functions +log_info() { + echo -e "${BLUE}โ„น๏ธ $1${NC}" +} + +log_success() { + echo -e "${GREEN}โœ… $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}โš ๏ธ $1${NC}" +} + +log_error() { + echo -e "${RED}โŒ $1${NC}" +} + +# Banner +echo "" +echo "============================================================" +echo " Z.AI2API Python - Setup Script" +echo "============================================================" +echo "" + +# Check for required environment variables +log_info "Checking environment variables..." +if [ -z "$ZAI_EMAIL" ] || [ -z "$ZAI_PASSWORD" ]; then + log_error "ZAI_EMAIL and ZAI_PASSWORD environment variables must be set" + echo "" + echo "Usage:" + echo " export ZAI_EMAIL=your-email@example.com" + echo " export ZAI_PASSWORD=your-password" + echo " bash scripts/setup.sh" + echo "" + exit 1 +fi +log_success "Environment variables found" + +# Navigate to project root +cd "$PROJECT_ROOT" +log_info "Working directory: $PROJECT_ROOT" + +# Step 1: Find suitable Python version (3.9-3.12) +log_info "Finding suitable Python version (3.9-3.12)..." + +SUITABLE_PYTHON="" +SUITABLE_VERSION="" + +# Try different Python versions in order of preference (avoid 3.13 due to pydantic issues) +for py_cmd in python3.11 python3.12 python3.10 python3.9 python3; do + if command -v $py_cmd &> /dev/null; then + version=$($py_cmd --version 2>&1 | cut -d' ' -f2) + major=$(echo $version | cut -d'.' -f1) + minor=$(echo $version | cut -d'.' -f2) + + # Check if version is 3.9-3.12 (exclude 3.13+) + if [ "$major" -eq 3 ] && [ "$minor" -ge 9 ] && [ "$minor" -le 12 ]; then + SUITABLE_PYTHON=$py_cmd + SUITABLE_VERSION=$version + break + fi + fi +done + +if [ -z "$SUITABLE_PYTHON" ]; then + log_error "No suitable Python version found!" + echo "" + echo "Python 3.9-3.12 is required (Python 3.13+ has compatibility issues)" + echo "" + echo "Please install one of these Python versions:" + echo " - Python 3.11 (recommended)" + echo " - Python 3.12" + echo " - Python 3.10" + echo " - Python 3.9" + exit 1 +fi + +log_success "Found suitable Python: $SUITABLE_PYTHON ($SUITABLE_VERSION)" + +# Step 1b: Create virtual environment if it doesn't exist +VENV_DIR="$PROJECT_ROOT/.venv" +if [ ! -d "$VENV_DIR" ]; then + log_info "Creating virtual environment with $SUITABLE_PYTHON..." + + if command -v uv &> /dev/null; then + # Use uv to create venv (faster) + uv venv --python $SUITABLE_PYTHON "$VENV_DIR" + else + # Use standard Python venv + $SUITABLE_PYTHON -m venv "$VENV_DIR" + fi + + if [ $? -eq 0 ]; then + log_success "Virtual environment created at $VENV_DIR" + else + log_error "Failed to create virtual environment" + exit 1 + fi +else + log_success "Virtual environment already exists" +fi + +# Activate virtual environment +log_info "Activating virtual environment..." +source "$VENV_DIR/bin/activate" + +if [ $? -eq 0 ]; then + log_success "Virtual environment activated" + log_info "Python: $(which python)" +else + log_error "Failed to activate virtual environment" + exit 1 +fi + +# Step 2: Install Python dependencies +log_info "Installing Python dependencies..." +if command -v uv &> /dev/null; then + log_info "Using uv for dependency management..." + uv sync + PIP_CMD="uv pip install" +else + log_info "Using pip for dependency management..." + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements.txt + PIP_CMD="python3 -m pip install" +fi +log_success "Python dependencies installed" + +# Step 3: Install Playwright +log_info "Installing Playwright..." + +# Determine which Python command to use +if command -v uv &> /dev/null; then + PYTHON_CMD="uv run python" + PLAYWRIGHT_CMD="uv run playwright" +else + PYTHON_CMD="python3" + PLAYWRIGHT_CMD="python3 -m playwright" +fi + +if ! $PYTHON_CMD -c "import playwright" 2>/dev/null; then + log_info "Playwright not found, installing..." + $PIP_CMD playwright +fi + +# Install Playwright browsers +log_info "Installing Playwright browsers (this may take a few minutes)..." +$PLAYWRIGHT_CMD install chromium +log_success "Playwright and browsers installed" + +# Step 4: Create .env file if it doesn't exist +log_info "Checking .env file..." +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + log_info "Creating .env from .env.example..." + cp .env.example .env + log_success ".env file created" + else + log_warning ".env.example not found, creating minimal .env..." + cat > .env << EOF +# Z.AI2API Configuration +AUTH_TOKEN=sk-placeholder +SKIP_AUTH_TOKEN=false +TOKEN_FAILURE_THRESHOLD=3 +TOKEN_RECOVERY_TIMEOUT=1800 +ANONYMOUS_MODE=true +LISTEN_PORT=8080 +SERVICE_NAME=z-ai2api-server +DEBUG_LOGGING=false +TOOL_SUPPORT=true +SCAN_LIMIT=200000 +EOF + log_success "Minimal .env file created" + fi +else + log_success ".env file already exists" +fi + +# Step 5: Retrieve authentication token +log_info "Retrieving authentication token from Z.AI..." +echo "" +echo "============================================================" +echo " Token Retrieval (Playwright)" +echo "============================================================" +echo "" + +if command -v uv &> /dev/null; then + uv run python scripts/retrieve_token.py + TOKEN_EXIT_CODE=$? +else + python3 scripts/retrieve_token.py + TOKEN_EXIT_CODE=$? +fi + +echo "" +if [ $TOKEN_EXIT_CODE -eq 0 ]; then + log_success "Token retrieved and saved to .env" +else + log_error "Failed to retrieve token" + log_warning "You can manually set AUTH_TOKEN in .env file" + exit 1 +fi + +# Step 6: Create logs directory +log_info "Creating logs directory..." +mkdir -p logs +log_success "Logs directory ready" + +# Step 7: Test database initialization +log_info "Testing database initialization..." +if command -v uv &> /dev/null; then + uv run python -c " +import asyncio +from app.services.token_dao import init_token_database + +async def test(): + await init_token_database() + print('Database initialized successfully') + +asyncio.run(test()) +" 2>&1 | tail -1 +else + python3 -c " +import asyncio +from app.services.token_dao import init_token_database + +async def test(): + await init_token_database() + print('Database initialized successfully') + +asyncio.run(test()) +" 2>&1 | tail -1 +fi + +if [ $? -eq 0 ]; then + log_success "Database initialization test passed" +else + log_warning "Database will be initialized on first server start" +fi + +# Final summary +echo "" +echo "============================================================" +echo " Setup Complete! โœจ" +echo "============================================================" +echo "" +log_success "Virtual environment is active!" +log_info "To activate in new terminals, run:" +echo "" +echo " source .venv/bin/activate" +echo "" +echo "๐Ÿ“‹ Next steps:" +echo " 1. Review .env file and adjust settings if needed" +echo " 2. Run: bash scripts/start.sh" +echo " 3. Or run everything at once: bash scripts/all.sh" +echo "" +echo "๐ŸŒ Server will be available at: http://localhost:8080" +echo "๐Ÿ“– API Documentation: http://localhost:8080/docs" +echo "๐Ÿ”ง Admin Panel: http://localhost:8080/admin" +echo "" +echo "๐Ÿ’ก Note: The virtual environment will remain active in this shell" +echo "" +echo "============================================================" +echo "" diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100755 index 0000000..37e0672 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,218 @@ +#!/bin/bash +# +# start.sh - Z.AI2API Server Startup Script +# +# This script starts the Z.AI2API server using the AUTH_TOKEN from .env +# The token was retrieved via Playwright automation in setup.sh +# +# The server will: +# โœ… Load AUTH_TOKEN from .env file +# โœ… Use it to authenticate with Z.AI's chat interface +# โœ… Proxy all OpenAI API requests to real Z.AI service +# โœ… Return actual AI-generated responses +# + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +PID_FILE="$PROJECT_ROOT/.server.pid" + +# Logging functions +log_info() { + echo -e "${BLUE}โ„น๏ธ $1${NC}" +} + +log_success() { + echo -e "${GREEN}โœ… $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}โš ๏ธ $1${NC}" +} + +log_error() { + echo -e "${RED}โŒ $1${NC}" +} + +# Banner +echo "" +echo "============================================================" +echo " Z.AI2API Python - Server Startup" +echo "============================================================" +echo "" + +# Navigate to project root +cd "$PROJECT_ROOT" + +# Step 0: Activate virtual environment if it exists +VENV_DIR="$PROJECT_ROOT/.venv" +if [ -d "$VENV_DIR" ]; then + log_info "Activating virtual environment..." + source "$VENV_DIR/bin/activate" + if [ $? -eq 0 ]; then + log_success "Virtual environment activated" + else + log_warning "Failed to activate virtual environment, using system Python" + fi +else + log_warning "Virtual environment not found, using system Python" + log_info "Run 'bash scripts/setup.sh' to create one" +fi + +# Step 1: Check if .env file exists +log_info "Checking configuration..." +if [ ! -f ".env" ]; then + log_error ".env file not found" + log_info "Please run: bash scripts/setup.sh" + exit 1 +fi +log_success "Configuration file found" + +# Load environment variables +set -a +source .env +set +a + +# Verify AUTH_TOKEN is loaded +if [ -n "$AUTH_TOKEN" ]; then + TOKEN_PREVIEW="${AUTH_TOKEN:0:10}..." + log_success "AUTH_TOKEN loaded: $TOKEN_PREVIEW" +else + log_warning "AUTH_TOKEN not found in .env" +fi + +# Get port from .env or use default +PORT=${LISTEN_PORT:-8080} + +# Step 2: Check if port is available +log_info "Checking if port $PORT is available..." +if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1; then + PID=$(lsof -Pi :$PORT -sTCP:LISTEN -t) + log_warning "Port $PORT is already in use by PID $PID" + + # Check if it's our server + if [ -f "$PID_FILE" ] && [ "$(cat $PID_FILE)" == "$PID" ]; then + log_info "Server is already running (PID: $PID)" + log_success "Server is healthy at http://localhost:$PORT" + exit 0 + else + log_error "Another process is using port $PORT" + log_info "Please stop the process or change LISTEN_PORT in .env" + exit 1 + fi +fi +log_success "Port $PORT is available" + +# Step 3: Check Python dependencies +log_info "Checking dependencies..." +if ! python3 -c "import fastapi, granian, httpx" 2>/dev/null; then + log_error "Required dependencies not found" + log_info "Please run: bash scripts/setup.sh" + exit 1 +fi +log_success "Dependencies verified" + +# Step 4: Start the server +log_info "Starting server..." +echo "" +echo "============================================================" +echo " Server Starting..." +echo "============================================================" +echo "" + +# Determine which Python command to use +if command -v uv &> /dev/null; then + PYTHON_CMD="uv run python" + log_info "Using uv runtime" +else + PYTHON_CMD="python3" + log_info "Using system Python" +fi + +# Start server in background +nohup $PYTHON_CMD main.py > logs/server.log 2>&1 & +SERVER_PID=$! + +# Save PID to file +echo $SERVER_PID > "$PID_FILE" +log_success "Server started with PID: $SERVER_PID" + +# Step 5: Wait for server to be ready +log_info "Waiting for server to be ready..." +MAX_ATTEMPTS=30 +ATTEMPT=0 + +while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do + if curl -s -f "http://localhost:$PORT/" > /dev/null 2>&1; then + log_success "Server is ready!" + break + fi + + # Check if process is still running + if ! kill -0 $SERVER_PID 2>/dev/null; then + log_error "Server process died unexpectedly" + log_info "Check logs/server.log for details" + rm -f "$PID_FILE" + exit 1 + fi + + ATTEMPT=$((ATTEMPT + 1)) + echo -n "." + sleep 1 +done + +echo "" + +if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then + log_error "Server failed to start within ${MAX_ATTEMPTS} seconds" + log_info "Check logs/server.log for details" + kill $SERVER_PID 2>/dev/null || true + rm -f "$PID_FILE" + exit 1 +fi + +# Step 6: Display server information +echo "" +echo "============================================================" +echo " Server Started Successfully! ๐Ÿš€" +echo "============================================================" +echo "" +echo "๐Ÿ“Š Server Information:" +echo " PID: $SERVER_PID" +echo " Port: $PORT" +echo " Log file: logs/server.log" +echo " PID file: $PID_FILE" +echo "" +echo "๐ŸŒ Endpoints:" +echo " API Root: http://localhost:$PORT/" +echo " API Docs: http://localhost:$PORT/docs" +echo " Admin: http://localhost:$PORT/admin" +echo "" +echo "๐Ÿ“ Commands:" +echo " View logs: tail -f logs/server.log" +echo " Stop: kill $SERVER_PID (or: kill \$(cat $PID_FILE))" +echo " Test API: bash scripts/send_openai_request.sh" +echo "" +echo "============================================================" +echo "" + +# Keep script running to show initial logs +log_info "Showing initial logs (press Ctrl+C to exit, server will keep running):" +echo "" +tail -f logs/server.log & +TAIL_PID=$! + +# Trap Ctrl+C to stop tail but keep server running +trap "kill $TAIL_PID 2>/dev/null; echo ''; log_success 'Server is running in background'; exit 0" INT + +# Wait for tail to finish (won't happen unless killed) +wait $TAIL_PID