Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/test_lemonade_client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,38 @@ jobs:
run: |
python test/lemonade_client_unit.py

- name: Download and install lemonade-server (Windows)
if: runner.os == 'Windows'
shell: powershell
run: |
Write-Host "Downloading lemonade-server MSI installer..."
Invoke-WebRequest -Uri "https://github.com/lemonade-sdk/lemonade/releases/latest/download/lemonade-server-minimal.msi" -OutFile "lemonade-server-minimal.msi"
Write-Host "Installing lemonade-server to C:\lemonade-server..."
Start-Process msiexec.exe -ArgumentList "/i", "lemonade-server-minimal.msi", "/qn", "/norestart", "INSTALLDIR=C:\lemonade-server" -Wait
Write-Host "Adding lemonade-server to PATH..."
Add-Content -Path $env:GITHUB_PATH -Value "C:\lemonade-server\bin"
Write-Host "lemonade-server installation complete"

- name: Download and install lemonade-server (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
echo "Getting latest release info..."
# Get the latest release tag and find the .deb asset
LATEST_RELEASE=$(curl -s https://api.github.com/repos/lemonade-sdk/lemonade/releases/latest)
DEB_URL=$(echo "$LATEST_RELEASE" | grep -o 'https://github.com/lemonade-sdk/lemonade/releases/download/[^"]*\.deb' | head -1)

if [ -z "$DEB_URL" ]; then
echo "Error: Could not find .deb package in latest release"
echo "Skipping lemonade-server installation for Linux tests"
else
echo "Downloading lemonade-server .deb package from: $DEB_URL"
curl -L -o lemonade-server.deb "$DEB_URL"
echo "Installing lemonade-server..."
sudo dpkg -i lemonade-server.deb || sudo apt-get install -f -y
echo "lemonade-server installation complete"
fi

- name: Run integration tests
run: |
python test/lemonade_client_integration.py
Expand Down
79 changes: 20 additions & 59 deletions docs/lemonade_client_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ Here's the typical sequence of API calls for setting up a lemonade-server-based
from lemonade_client import LemonadeClient

# Create client with minimum version requirement
client = LemonadeClient(minimum_version="8.1.9")
client = LemonadeClient(minimum_version="9.0.3")

# Check deployment environment
is_pyinstaller = client.is_pyinstaller_environment()

# Check if SDK is available (for development environments)
sdk_available = await client.check_lemonade_sdk_available()
```

### 2. Installation Status Check
Expand Down Expand Up @@ -83,11 +80,11 @@ Once the above steps complete successfully, your application can make inference

## Constructor

#### `LemonadeClient(minimum_version: str = "8.1.0", logger=None)`
#### `LemonadeClient(minimum_version: str = "9.0.3", logger=None)`
Initialize a new LemonadeClient instance.

**Parameters:**
- `minimum_version` (str, optional): Minimum required version of lemonade-server. Defaults to "8.1.0". The client will check server compatibility against this version.
- `minimum_version` (str, optional): Minimum required version of lemonade-server. Defaults to "9.0.3". The client will check server compatibility against this version.
- `logger` (logging.Logger, optional): Logger instance to use for logging. If None, creates a default logger named "lemonade_client".

**When to use:** Create a client instance at the start of your application. Specify the minimum version your application requires to ensure compatibility.
Expand All @@ -96,15 +93,15 @@ Initialize a new LemonadeClient instance.
```python
import logging

# Use default minimum version (8.1.0) and default logger
# Use default minimum version (9.0.3) and default logger
client = LemonadeClient()

# Specify custom minimum version
client = LemonadeClient(minimum_version="8.1.9")
client = LemonadeClient(minimum_version="9.0.5")

# Use custom logger
custom_logger = logging.getLogger("my_app")
client = LemonadeClient(minimum_version="8.1.9", logger=custom_logger)
client = LemonadeClient(minimum_version="9.0.5", logger=custom_logger)

# Version checking will use your specified minimum
version_info = await client.check_lemonade_server_version()
Expand All @@ -121,18 +118,16 @@ print(f"Compatible: {version_info['compatible']}") # True if server >= mini
#### `is_pyinstaller_environment()`
Check if the application is running in a PyInstaller bundle environment.

**When to use:** Determine installation method preferences or adjust behavior based on deployment type. PyInstaller environments typically prefer installer-based server installation over pip.
**When to use:** Determine installation method preferences or adjust behavior based on deployment type.

**Returns:** `bool` - True if running in PyInstaller bundle, False otherwise

**Example:**
```python
if client.is_pyinstaller_environment():
print("Running as packaged executable")
# Prefer installer-based installation
else:
print("Running in development environment")
# Can use pip installation
print("Running in development environment")
```

---
Expand Down Expand Up @@ -185,7 +180,7 @@ client.reset_server_state()
#### `execute_lemonade_server_command(args, timeout=10, use_popen=False, stdout_file=None, stderr_file=None)`
Execute lemonade-server commands using the best available method for the system.

**When to use:** As the primary interface for running any lemonade-server command. The method automatically tries different installation methods (pip, installer, dev) and caches the successful command for future use. Essential for cross-platform compatibility.
**When to use:** As the primary interface for running any lemonade-server command. The method automatically discovers the lemonade-server installation and caches the successful command for future use. Essential for cross-platform compatibility.

**Parameters:**
- `args: List[str]` - Command arguments to pass to lemonade-server (e.g., `["--version"]`, `["serve"]`)
Expand Down Expand Up @@ -214,23 +209,6 @@ process = await client.execute_lemonade_server_command(

### Installation and Setup

#### `check_lemonade_sdk_available()`
Check if the lemonade-sdk Python package is installed and importable.

**When to use:** Determine if pip-based installation is available before attempting SDK-based operations. Helpful for showing installation options to users or choosing between different installation methods.

**Returns:** `bool` - True if lemonade-sdk package can be imported, False otherwise

**Example:**
```python
if await client.check_lemonade_sdk_available():
print("Can use lemonade-server-dev command")
else:
print("Need to install via pip or use installer")
```

---

#### `check_lemonade_server_version()`
Check lemonade-server installation status and version compatibility.

Expand All @@ -253,37 +231,20 @@ else:

---

#### `install_lemonade_sdk_package()`
Install the lemonade-sdk Python package using pip.

**When to use:** Install lemonade-server via pip when in development environments or when the SDK approach is preferred. Provides access to lemonade-server-dev command after successful installation.

**Returns:** `dict` with keys:
- `success: bool` - Whether installation succeeded
- `message: str` - Success message or error details

**Example:**
```python
result = await client.install_lemonade_sdk_package()
if result["success"]:
print("SDK installed successfully")
client.refresh_environment()
else:
print(f"Installation failed: {result['message']}")
```

---

#### `download_and_install_lemonade_server()`
Download and install lemonade-server using the best method for the environment.
Download and install lemonade-server using the platform-specific installer.

**When to use:** As the primary installation method. On Windows, downloads and launches the MSI installer. On Linux, directs users to the installation options page for manual .deb package installation.

**When to use:** As the primary installation method. Automatically chooses between pip installation (development environments) or executable installer (PyInstaller bundles). Handles the complete installation process including download and setup.
**Platform Behavior:**
- **Windows**: Downloads `lemonade-server-minimal.msi` and launches it with `msiexec`
- **Linux**: Returns instructions to visit `https://lemonade-server.ai/install_options.html` for .deb package download

**Returns:** `dict` with keys:
- `success: bool` - Whether installation succeeded
- `success: bool` - Whether installation succeeded or launched successfully
- `message: str` - Status message or error details
- `interactive: bool` (optional) - Whether installer requires user interaction
- `github_link: str` (optional) - Link for manual installation if automated fails
- `interactive: bool` (optional) - Whether installer requires user interaction (Windows only)
- `install_link: str` (optional) - Link for manual installation if automated fails

**Example:**
```python
Expand All @@ -296,8 +257,8 @@ if result["success"]:
client.reset_server_state()
else:
print(f"Installation failed: {result['message']}")
if "github_link" in result:
print(f"Manual installation: {result['github_link']}")
if "install_link" in result:
print(f"Manual installation: {result['install_link']}")
```

---
Expand Down
16 changes: 8 additions & 8 deletions src/infinity_arcade/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from infinity_arcade.llm_service import LLMService

# Minimum required version of lemonade-server
LEMONADE_MINIMUM_VERSION = "8.1.12"
LEMONADE_MINIMUM_VERSION = "9.0.3"


# Pygame will be imported on-demand to avoid early DLL loading issues
Expand Down Expand Up @@ -239,16 +239,16 @@ async def model_loading_status():
async def installation_environment():
logger.info("Installation environment endpoint called")
is_pyinstaller = self.lemonade_handle.is_pyinstaller_environment()
sdk_available = (
await self.lemonade_handle.check_lemonade_sdk_available()
if not is_pyinstaller
else False
)
# Determine preferred installation method based on platform
if sys.platform == "win32":
preferred_method = "installer"
else:
preferred_method = "manual"

result = {
"is_pyinstaller": is_pyinstaller,
"sdk_available": sdk_available,
"platform": sys.platform,
"preferred_method": "pip" if not is_pyinstaller else "installer",
"preferred_method": preferred_method,
}
logger.info(f"Returning installation environment: {result}")
return JSONResponse(result)
Expand Down
2 changes: 1 addition & 1 deletion src/infinity_arcade/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.2.2"
__version__ = "0.3.0"
Loading
Loading