feat: Implement configurable OpenWebUI base URL for deployment scripts and update documentation.

This commit is contained in:
fujie
2026-03-11 23:32:00 +08:00
parent 5fe66a5803
commit fdf95a2825
13 changed files with 203 additions and 128 deletions

View File

@@ -9,6 +9,7 @@ This directory contains automated scripts for deploying plugins in development t
1. **OpenWebUI Running**: Make sure OpenWebUI is running locally (default `http://localhost:3000`)
2. **API Key**: You need a valid OpenWebUI API key
3. **Environment File**: Create a `.env` file in this directory containing your API key:
```
api_key=sk-xxxxxxxxxxxxx
```
@@ -42,12 +43,14 @@ python deploy_filter.py --list
Used to deploy Filter-type plugins (such as message filtering, context compression, etc.).
**Key Features**:
- ✅ Auto-extracts metadata from Python files (version, author, description, etc.)
- ✅ Attempts to update existing plugins, creates if not found
- ✅ Supports multiple Filter plugin management
- ✅ Detailed error messages and connection diagnostics
**Usage**:
```bash
# Deploy async_context_compression (default)
python deploy_filter.py
@@ -62,6 +65,7 @@ python deploy_filter.py -l
```
**Workflow**:
1. Load API key from `.env`
2. Find target Filter plugin directory
3. Read Python source file
@@ -76,6 +80,7 @@ python deploy_filter.py -l
Used to deploy Pipe-type plugins (such as GitHub Copilot SDK).
**Usage**:
```bash
python deploy_pipe.py
```
@@ -101,6 +106,7 @@ Create a dedicated long-term API key in OpenWebUI Settings for deployment purpos
**Cause**: OpenWebUI is not running or port is different
**Solution**:
- Make sure OpenWebUI is running
- Check which port OpenWebUI is actually listening on (usually 3000)
- Edit the URL in the script if needed
@@ -110,6 +116,7 @@ Create a dedicated long-term API key in OpenWebUI Settings for deployment purpos
**Cause**: `.env` file was not created
**Solution**:
```bash
echo "api_key=sk-your-api-key-here" > .env
```
@@ -119,6 +126,7 @@ echo "api_key=sk-your-api-key-here" > .env
**Cause**: Filter directory name is incorrect
**Solution**:
```bash
# List all available Filters
python deploy_filter.py --list
@@ -129,6 +137,7 @@ python deploy_filter.py --list
**Cause**: API key is invalid or expired
**Solution**:
1. Verify your API key is valid
2. Generate a new API key
3. Update the `.env` file
@@ -177,7 +186,8 @@ python deploy_filter.py async-context-compression
## Security Considerations
⚠️ **Important**:
⚠️ **Important**:
- ✅ Add `.env` file to `.gitignore` (avoid committing sensitive info)
- ✅ Never commit API keys to version control
- ✅ Use only on trusted networks

View File

@@ -7,6 +7,7 @@ Added a complete local deployment toolchain for the `async_context_compression`
## 📋 New Files
### 1. **deploy_filter.py** — Filter Plugin Deployment Script
- **Location**: `scripts/deploy_filter.py`
- **Function**: Auto-deploy Filter-type plugins to local OpenWebUI instance
- **Features**:
@@ -19,6 +20,7 @@ Added a complete local deployment toolchain for the `async_context_compression`
- **Code Lines**: ~300
### 2. **DEPLOYMENT_GUIDE.md** — Complete Deployment Guide
- **Location**: `scripts/DEPLOYMENT_GUIDE.md`
- **Contents**:
- Prerequisites and quick start
@@ -28,6 +30,7 @@ Added a complete local deployment toolchain for the `async_context_compression`
- Step-by-step workflow examples
### 3. **QUICK_START.md** — Quick Reference Card
- **Location**: `scripts/QUICK_START.md`
- **Contents**:
- One-line deployment command
@@ -37,6 +40,7 @@ Added a complete local deployment toolchain for the `async_context_compression`
- CI/CD integration examples
### 4. **test_deploy_filter.py** — Unit Test Suite
- **Location**: `tests/scripts/test_deploy_filter.py`
- **Test Coverage**:
- ✅ Filter file discovery (3 tests)
@@ -138,6 +142,7 @@ openwebui_id: b1655bc8-6de9-4cad-8cb5-a6f7829a02ce
```
**Supported Metadata Fields**:
- `title` — Filter display name ✅
- `id` — Unique identifier ✅
- `author` — Author name ✅
@@ -335,17 +340,20 @@ Metadata Extraction and Delivery
### Debugging Tips
1. **Enable Verbose Logging**:
```bash
python deploy_filter.py 2>&1 | tee deploy.log
```
2. **Test API Connection**:
```bash
curl -X GET http://localhost:3000/api/v1/functions \
-H "Authorization: Bearer $API_KEY"
```
3. **Verify .env File**:
```bash
grep "api_key=" scripts/.env
```

View File

@@ -73,12 +73,14 @@ python deploy_async_context_compression.py
```
**Features**:
- ✅ Optimized specifically for async_context_compression
- ✅ Clear deployment steps and confirmation
- ✅ Friendly error messages
- ✅ Shows next steps after successful deployment
**Sample Output**:
```
======================================================================
🚀 Deploying Async Context Compression Filter Plugin
@@ -117,6 +119,7 @@ python deploy_filter.py --list
```
**Features**:
- ✅ Generic Filter deployment tool
- ✅ Supports multiple plugins
- ✅ Auto metadata extraction
@@ -142,6 +145,7 @@ python deploy_tool.py openwebui-skills-manager
```
**Features**:
- ✅ Supports Tools plugin deployment
- ✅ Auto-detects `Tools` class definition
- ✅ Smart update/create logic
@@ -290,6 +294,7 @@ git status # should not show .env
```
**Solution**:
```bash
# 1. Check if OpenWebUI is running
curl http://localhost:3000
@@ -309,6 +314,7 @@ curl http://localhost:3000
```
**Solution**:
```bash
echo "api_key=sk-your-api-key" > .env
cat .env # verify file created
@@ -321,6 +327,7 @@ cat .env # verify file created
```
**Solution**:
```bash
# List all available Filters
python deploy_filter.py --list
@@ -337,6 +344,7 @@ python deploy_filter.py async-context-compression
```
**Solution**:
```bash
# 1. Verify API key is correct
grep "api_key=" .env
@@ -370,7 +378,7 @@ python deploy_async_context_compression.py
### Method 2: Verify in OpenWebUI
1. Open OpenWebUI: http://localhost:3000
1. Open OpenWebUI: <http://localhost:3000>
2. Go to Settings → Filters
3. Check if 'Async Context Compression' is listed
4. Verify version number is correct (should be latest)
@@ -380,6 +388,7 @@ python deploy_async_context_compression.py
1. Open a new conversation
2. Enable 'Async Context Compression' Filter
3. Have multiple-turn conversation and verify compression/summarization works
## 💡 Advanced Usage
### Automated Deploy & Test
@@ -473,4 +482,3 @@ Newly created deployment-related files:
**Last Updated**: 2026-03-09
**Script Status**: ✅ Ready for production
**Test Coverage**: 10/10 passed ✅

View File

@@ -5,6 +5,7 @@
**Yes, re-deploying automatically updates the plugin!**
The deployment script uses a **smart two-stage strategy**:
1. 🔄 **Try UPDATE First** (if plugin exists)
2. 📝 **Auto CREATE** (if update fails — plugin doesn't exist)
@@ -54,6 +55,7 @@ if response.status_code == 200:
```
**What Happens**:
- Send **POST** to `/api/v1/functions/id/{filter_id}/update`
- If returns **HTTP 200**, plugin exists and update succeeded
- Includes:
@@ -84,6 +86,7 @@ if response.status_code != 200:
```
**What Happens**:
- If update fails (HTTP ≠ 200), auto-attempt create
- Send **POST** to `/api/v1/functions/create`
- Uses **same payload** (code, metadata identical)
@@ -103,6 +106,7 @@ $ python deploy_async_context_compression.py
```
**What Happens**:
1. Try UPDATE → fails (HTTP 404 — plugin doesn't exist)
2. Auto-try CREATE → succeeds (HTTP 200)
3. Plugin created in OpenWebUI
@@ -121,6 +125,7 @@ $ python deploy_async_context_compression.py
```
**What Happens**:
1. Read modified code
2. Try UPDATE → succeeds (HTTP 200 — plugin exists)
3. Plugin in OpenWebUI updated to latest code
@@ -147,6 +152,7 @@ $ python deploy_async_context_compression.py
```
**Characteristics**:
- 🚀 Each update takes only 5 seconds
- 📝 Each is an incremental update
- ✅ No need to restart OpenWebUI
@@ -181,11 +187,13 @@ version: 1.3.0
```
**Each deployment**:
1. Script reads version from docstring
2. Sends this version in manifest to OpenWebUI
3. If you change version in code, deployment updates to new version
**Best Practice**:
```bash
# 1. Modify code
vim async_context_compression.py
@@ -300,6 +308,7 @@ Usually **not needed** because:
4. ✅ Failures auto-rollback
但如果真的需要控制,可以:
- 手动修改脚本 (修改 `deploy_filter.py`)
- 或分别使用 UPDATE/CREATE 的具体 API 端点
@@ -323,6 +332,7 @@ Usually **not needed** because:
### Q: 可以同时部署多个插件吗?
**可以!**
```bash
python deploy_filter.py async-context-compression
python deploy_filter.py folder-memory
@@ -337,6 +347,7 @@ python deploy_filter.py context_enhancement_filter
---
**总结**: 部署脚本的更新机制完全自动化,开发者只需修改代码,每次运行 `deploy_async_context_compression.py` 就会自动:
1. ✅ 创建(第一次)或更新(后续)插件
2. ✅ 从代码提取最新的元数据和版本号
3. ✅ 立即生效,无需重启 OpenWebUI

View File

@@ -11,9 +11,9 @@ Usage:
To get started:
1. Create .env file with your OpenWebUI API key:
echo "api_key=sk-your-key-here" > .env
2. Make sure OpenWebUI is running on localhost:3000
3. Run this script:
python deploy_async_context_compression.py
"""
@@ -34,10 +34,10 @@ def main():
print("🚀 Deploying Async Context Compression Filter Plugin")
print("=" * 70)
print()
# Deploy the filter
success = deploy_filter("async-context-compression")
if success:
print()
print("=" * 70)
@@ -63,7 +63,7 @@ def main():
print(" • Check network connectivity")
print()
return 1
return 0

View File

@@ -49,53 +49,78 @@ def _load_api_key() -> str:
raise ValueError("api_key not found in .env file.")
def _load_openwebui_base_url() -> str:
"""Load OpenWebUI base URL from .env file or environment.
Checks in order:
1. OPENWEBUI_BASE_URL in .env
2. OPENWEBUI_BASE_URL environment variable
3. Default to http://localhost:3000
"""
if ENV_FILE.exists():
for line in ENV_FILE.read_text(encoding="utf-8").splitlines():
line = line.strip()
if line.startswith("OPENWEBUI_BASE_URL="):
url = line.split("=", 1)[1].strip()
if url:
return url
# Try environment variable
url = os.environ.get("OPENWEBUI_BASE_URL")
if url:
return url
# Default
return "http://localhost:3000"
def _find_filter_file(filter_name: str) -> Optional[Path]:
"""Find the main Python file for a filter.
Args:
filter_name: Directory name of the filter (e.g., 'async-context-compression')
Returns:
Path to the main Python file, or None if not found.
"""
filter_dir = FILTERS_DIR / filter_name
if not filter_dir.exists():
return None
# Try to find a .py file matching the filter name
py_files = list(filter_dir.glob("*.py"))
# Prefer a file with the filter name (with hyphens converted to underscores)
preferred_name = filter_name.replace("-", "_") + ".py"
for py_file in py_files:
if py_file.name == preferred_name:
return py_file
# Otherwise, return the first .py file (usually the only one)
if py_files:
return py_files[0]
return None
def _extract_metadata(content: str) -> Dict[str, Any]:
"""Extract metadata from the plugin docstring.
Args:
content: Python file content
Returns:
Dictionary with extracted metadata (title, author, version, etc.)
"""
metadata = {}
# Extract docstring
match = re.search(r'"""(.*?)"""', content, re.DOTALL)
if not match:
return metadata
docstring = match.group(1)
# Extract key-value pairs
for line in docstring.split("\n"):
line = line.strip()
@@ -104,7 +129,7 @@ def _extract_metadata(content: str) -> Dict[str, Any]:
key = parts[0].strip().lower()
value = parts[1].strip()
metadata[key] = value
return metadata
@@ -112,13 +137,13 @@ def _build_filter_payload(
filter_name: str, file_path: Path, content: str, metadata: Dict[str, Any]
) -> Dict[str, Any]:
"""Build the payload for the filter update/create API.
Args:
filter_name: Directory name of the filter
file_path: Path to the plugin file
content: File content
metadata: Extracted metadata
Returns:
Payload dictionary ready for API submission
"""
@@ -126,12 +151,14 @@ def _build_filter_payload(
filter_id = metadata.get("id", filter_name).replace("-", "_")
title = metadata.get("title", filter_name)
author = metadata.get("author", "Fu-Jie")
author_url = metadata.get("author_url", "https://github.com/Fu-Jie/openwebui-extensions")
author_url = metadata.get(
"author_url", "https://github.com/Fu-Jie/openwebui-extensions"
)
funding_url = metadata.get("funding_url", "https://github.com/open-webui")
description = metadata.get("description", f"Filter plugin: {title}")
version = metadata.get("version", "1.0.0")
openwebui_id = metadata.get("openwebui_id", "")
payload = {
"id": filter_id,
"name": title,
@@ -150,20 +177,20 @@ def _build_filter_payload(
},
"content": content,
}
# Add openwebui_id if available
if openwebui_id:
payload["meta"]["manifest"]["openwebui_id"] = openwebui_id
return payload
def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
"""Deploy a filter plugin to OpenWebUI.
Args:
filter_name: Directory name of the filter to deploy
Returns:
True if successful, False otherwise
"""
@@ -191,7 +218,7 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
content = file_path.read_text(encoding="utf-8")
metadata = _extract_metadata(content)
if not metadata:
print(f"[ERROR] Could not extract metadata from {file_path}")
return False
@@ -211,12 +238,14 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
}
# 6. Send update request
update_url = "http://localhost:3000/api/v1/functions/id/{}/update".format(filter_id)
create_url = "http://localhost:3000/api/v1/functions/create"
base_url = _load_openwebui_base_url()
update_url = "{}/api/v1/functions/id/{}/update".format(base_url, filter_id)
create_url = "{}/api/v1/functions/create".format(base_url)
print(f"📦 Deploying filter '{title}' (version {version})...")
print(f" File: {file_path}")
print(f" Target: {base_url}")
try:
# Try update first
response = requests.post(
@@ -225,7 +254,7 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
data=json.dumps(payload),
timeout=10,
)
if response.status_code == 200:
print(f"✅ Successfully updated '{title}' filter!")
return True
@@ -234,7 +263,7 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
f"⚠️ Update failed with status {response.status_code}, "
"attempting to create instead..."
)
# Try create if update fails
res_create = requests.post(
create_url,
@@ -242,23 +271,24 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
data=json.dumps(payload),
timeout=10,
)
if res_create.status_code == 200:
print(f"✅ Successfully created '{title}' filter!")
return True
else:
print(f"❌ Failed to update or create. Status: {res_create.status_code}")
print(
f"❌ Failed to update or create. Status: {res_create.status_code}"
)
try:
error_msg = res_create.json()
print(f" Error: {error_msg}")
except:
print(f" Response: {res_create.text[:500]}")
return False
except requests.exceptions.ConnectionError:
print(
"❌ Connection error: Could not reach OpenWebUI at localhost:3000"
)
base_url = _load_openwebui_base_url()
print(f"❌ Connection error: Could not reach OpenWebUI at {base_url}")
print(" Make sure OpenWebUI is running and accessible.")
return False
except requests.exceptions.Timeout:
@@ -272,16 +302,20 @@ def deploy_filter(filter_name: str = DEFAULT_FILTER) -> bool:
def list_filters() -> None:
"""List all available filters."""
print("📋 Available filters:")
filters = [d.name for d in FILTERS_DIR.iterdir() if d.is_dir() and not d.name.startswith("_")]
filters = [
d.name
for d in FILTERS_DIR.iterdir()
if d.is_dir() and not d.name.startswith("_")
]
if not filters:
print(" (No filters found)")
return
for filter_name in sorted(filters):
filter_dir = FILTERS_DIR / filter_name
py_file = _find_filter_file(filter_name)
if py_file:
content = py_file.read_text(encoding="utf-8")
metadata = _extract_metadata(content)

View File

@@ -76,52 +76,51 @@ def _get_base_url() -> str:
if not base_url:
raise ValueError(
f"Missing url. Please create {ENV_FILE} with: "
"url=http://localhost:3000"
f"Missing url. Please create {ENV_FILE} with: " "url=http://localhost:3000"
)
return base_url.rstrip("/")
def _find_tool_file(tool_name: str) -> Optional[Path]:
"""Find the main Python file for a tool.
Args:
tool_name: Directory name of the tool (e.g., 'openwebui-skills-manager')
Returns:
Path to the main Python file, or None if not found.
"""
tool_dir = TOOLS_DIR / tool_name
if not tool_dir.exists():
return None
# Try to find a .py file matching the tool name
py_files = list(tool_dir.glob("*.py"))
# Prefer a file with the tool name (with hyphens converted to underscores)
preferred_name = tool_name.replace("-", "_") + ".py"
for py_file in py_files:
if py_file.name == preferred_name:
return py_file
# Otherwise, return the first .py file (usually the only one)
if py_files:
return py_files[0]
return None
def _extract_metadata(content: str) -> Dict[str, Any]:
"""Extract metadata from the plugin docstring."""
metadata = {}
# Extract docstring
match = re.search(r'"""(.*?)"""', content, re.DOTALL)
if not match:
return metadata
docstring = match.group(1)
# Extract key-value pairs
for line in docstring.split("\n"):
line = line.strip()
@@ -130,7 +129,7 @@ def _extract_metadata(content: str) -> Dict[str, Any]:
key = parts[0].strip().lower()
value = parts[1].strip()
metadata[key] = value
return metadata
@@ -141,12 +140,14 @@ def _build_tool_payload(
tool_id = metadata.get("id", tool_name).replace("-", "_")
title = metadata.get("title", tool_name)
author = metadata.get("author", "Fu-Jie")
author_url = metadata.get("author_url", "https://github.com/Fu-Jie/openwebui-extensions")
author_url = metadata.get(
"author_url", "https://github.com/Fu-Jie/openwebui-extensions"
)
funding_url = metadata.get("funding_url", "https://github.com/open-webui")
description = metadata.get("description", f"Tool plugin: {title}")
version = metadata.get("version", "1.0.0")
openwebui_id = metadata.get("openwebui_id", "")
payload = {
"id": tool_id,
"name": title,
@@ -165,20 +166,20 @@ def _build_tool_payload(
},
"content": content,
}
# Add openwebui_id if available
if openwebui_id:
payload["meta"]["manifest"]["openwebui_id"] = openwebui_id
return payload
def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
"""Deploy a tool plugin to OpenWebUI.
Args:
tool_name: Directory name of the tool to deploy
Returns:
True if successful, False otherwise
"""
@@ -207,7 +208,7 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
content = file_path.read_text(encoding="utf-8")
metadata = _extract_metadata(content)
if not metadata:
print(f"[ERROR] Could not extract metadata from {file_path}")
return False
@@ -229,10 +230,10 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
# 6. Send update request through the native tool endpoints
update_url = f"{base_url}/api/v1/tools/id/{tool_id}/update"
create_url = f"{base_url}/api/v1/tools/create"
print(f"📦 Deploying tool '{title}' (version {version})...")
print(f" File: {file_path}")
try:
# Try update first
response = requests.post(
@@ -241,7 +242,7 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
data=json.dumps(payload),
timeout=10,
)
if response.status_code == 200:
print(f"✅ Successfully updated '{title}' tool!")
return True
@@ -250,7 +251,7 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
f"⚠️ Update failed with status {response.status_code}, "
"attempting to create instead..."
)
# Try create if update fails
res_create = requests.post(
create_url,
@@ -258,23 +259,23 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
data=json.dumps(payload),
timeout=10,
)
if res_create.status_code == 200:
print(f"✅ Successfully created '{title}' tool!")
return True
else:
print(f"❌ Failed to update or create. Status: {res_create.status_code}")
print(
f"❌ Failed to update or create. Status: {res_create.status_code}"
)
try:
error_msg = res_create.json()
print(f" Error: {error_msg}")
except:
print(f" Response: {res_create.text[:500]}")
return False
except requests.exceptions.ConnectionError:
print(
"❌ Connection error: Could not reach OpenWebUI at {base_url}"
)
print("❌ Connection error: Could not reach OpenWebUI at {base_url}")
print(" Make sure OpenWebUI is running and accessible.")
return False
except requests.exceptions.Timeout:
@@ -288,16 +289,18 @@ def deploy_tool(tool_name: str = DEFAULT_TOOL) -> bool:
def list_tools() -> None:
"""List all available tools."""
print("📋 Available tools:")
tools = [d.name for d in TOOLS_DIR.iterdir() if d.is_dir() and not d.name.startswith("_")]
tools = [
d.name for d in TOOLS_DIR.iterdir() if d.is_dir() and not d.name.startswith("_")
]
if not tools:
print(" (No tools found)")
return
for tool_name in sorted(tools):
tool_dir = TOOLS_DIR / tool_name
py_file = _find_tool_file(tool_name)
if py_file:
content = py_file.read_text(encoding="utf-8")
metadata = _extract_metadata(content)

View File

@@ -187,9 +187,7 @@ def build_payload(candidate: PluginCandidate) -> Dict[str, object]:
manifest = dict(candidate.metadata)
manifest.setdefault("title", candidate.title)
manifest.setdefault("author", "Fu-Jie")
manifest.setdefault(
"author_url", "https://github.com/Fu-Jie/openwebui-extensions"
)
manifest.setdefault("author_url", "https://github.com/Fu-Jie/openwebui-extensions")
manifest.setdefault("funding_url", "https://github.com/open-webui")
manifest.setdefault(
"description", f"{candidate.plugin_type.title()} plugin: {candidate.title}"
@@ -233,7 +231,9 @@ def build_api_urls(base_url: str, candidate: PluginCandidate) -> Tuple[str, str]
)
def discover_plugins(plugin_types: Sequence[str]) -> Tuple[List[PluginCandidate], List[Tuple[Path, str]]]:
def discover_plugins(
plugin_types: Sequence[str],
) -> Tuple[List[PluginCandidate], List[Tuple[Path, str]]]:
candidates: List[PluginCandidate] = []
skipped: List[Tuple[Path, str]] = []
@@ -344,7 +344,9 @@ def print_skipped_summary(skipped: Sequence[Tuple[Path, str]]) -> None:
for _, reason in skipped:
counts[reason] = counts.get(reason, 0) + 1
summary = ", ".join(f"{reason}: {count}" for reason, count in sorted(counts.items()))
summary = ", ".join(
f"{reason}: {count}" for reason, count in sorted(counts.items())
)
print(f"Skipped {len(skipped)} files ({summary}).")
@@ -421,19 +423,19 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
failed_candidates.append(candidate)
print(f" [FAILED] {message}")
print(f"\n" + "="*80)
print(f"\n" + "=" * 80)
print(
f"Finished: {success_count}/{len(candidates)} plugins installed successfully."
)
if failed_candidates:
print(f"\n{len(failed_candidates)} plugin(s) failed to install:")
for candidate in failed_candidates:
print(f"{candidate.title} ({candidate.plugin_type})")
print(f" → Check the error message above")
print()
print("="*80)
print("=" * 80)
return 0 if success_count == len(candidates) else 1

View File

@@ -9,14 +9,15 @@ local deployment are present and functional.
import sys
from pathlib import Path
def main():
"""Check all deployment tools are ready."""
base_dir = Path(__file__).parent.parent
print("\n" + "="*80)
print("\n" + "=" * 80)
print("✨ Async Context Compression Local Deployment Tools — Verification Status")
print("="*80 + "\n")
print("=" * 80 + "\n")
files_to_check = {
"🐍 Python Scripts": [
"scripts/deploy_async_context_compression.py",
@@ -34,56 +35,56 @@ def main():
"tests/scripts/test_deploy_filter.py",
],
}
all_exist = True
for category, files in files_to_check.items():
print(f"\n{category}:")
print("-" * 80)
for file_path in files:
full_path = base_dir / file_path
exists = full_path.exists()
status = "" if exists else ""
print(f" {status} {file_path}")
if exists and file_path.endswith(".py"):
size = full_path.stat().st_size
lines = len(full_path.read_text().split('\n'))
lines = len(full_path.read_text().split("\n"))
print(f" └─ [{size} bytes, ~{lines} lines]")
if not exists:
all_exist = False
print("\n" + "="*80)
print("\n" + "=" * 80)
if all_exist:
print("✅ All deployment tool files are ready!")
print("="*80 + "\n")
print("=" * 80 + "\n")
print("🚀 Quick Start (3 ways):\n")
print(" Method 1: Easiest (Recommended)")
print(" ─────────────────────────────────────────────────────────")
print(" cd scripts")
print(" python deploy_async_context_compression.py")
print()
print(" Method 2: Generic Tool")
print(" ─────────────────────────────────────────────────────────")
print(" cd scripts")
print(" python deploy_filter.py")
print()
print(" Method 3: Deploy Other Filters")
print(" ─────────────────────────────────────────────────────────")
print(" cd scripts")
print(" python deploy_filter.py --list")
print(" python deploy_filter.py folder-memory")
print()
print("="*80 + "\n")
print("=" * 80 + "\n")
print("📚 Documentation References:\n")
print(" • Quick Start: scripts/QUICK_START.md")
print(" • Complete Guide: scripts/DEPLOYMENT_GUIDE.md")
@@ -91,12 +92,12 @@ def main():
print(" • Script Info: scripts/README.md")
print(" • Test Coverage: pytest tests/scripts/test_deploy_filter.py -v")
print()
print("="*80 + "\n")
print("=" * 80 + "\n")
return 0
else:
print("❌ Some files are missing!")
print("="*80 + "\n")
print("=" * 80 + "\n")
return 1