Compare commits
No commits in common. "6b2ef1137a0bc345cd055d7704884f690c3042a6" and "26905ad62367e0dda9d8553046be0d378f0cc506" have entirely different histories.
6b2ef1137a
...
26905ad623
@ -224,7 +224,7 @@ async def init_agent(config: AgentConfig):
|
|||||||
middleware.append(ToolUseCleanupMiddleware())
|
middleware.append(ToolUseCleanupMiddleware())
|
||||||
# 添加工具输出长度控制中间件
|
# 添加工具输出长度控制中间件
|
||||||
tool_output_middleware = ToolOutputLengthMiddleware(
|
tool_output_middleware = ToolOutputLengthMiddleware(
|
||||||
max_length=(getattr(config.generate_cfg, 'tool_output_max_length', None) if config.generate_cfg else None) or TOOL_OUTPUT_MAX_LENGTH,
|
max_length=getattr(config.generate_cfg, 'tool_output_max_length', None) if config.generate_cfg else None or TOOL_OUTPUT_MAX_LENGTH,
|
||||||
truncation_strategy=getattr(config.generate_cfg, 'tool_output_truncation_strategy', 'smart') if config.generate_cfg else 'smart',
|
truncation_strategy=getattr(config.generate_cfg, 'tool_output_truncation_strategy', 'smart') if config.generate_cfg else 'smart',
|
||||||
tool_filters=getattr(config.generate_cfg, 'tool_output_filters', None) if config.generate_cfg else None,
|
tool_filters=getattr(config.generate_cfg, 'tool_output_filters', None) if config.generate_cfg else None,
|
||||||
exclude_tools=getattr(config.generate_cfg, 'tool_output_exclude', []) if config.generate_cfg else [],
|
exclude_tools=getattr(config.generate_cfg, 'tool_output_exclude', []) if config.generate_cfg else [],
|
||||||
|
|||||||
@ -356,18 +356,7 @@ class Mem0Middleware(AgentMiddleware):
|
|||||||
# 获取当前系统提示词
|
# 获取当前系统提示词
|
||||||
current_system_prompt = ""
|
current_system_prompt = ""
|
||||||
if request.system_message:
|
if request.system_message:
|
||||||
content = request.system_message.content if hasattr(request.system_message, "content") else str(request.system_message)
|
current_system_prompt = request.system_message.content if hasattr(request.system_message, "content") else str(request.system_message)
|
||||||
# content 可能是 list 或 str,确保转换为 str
|
|
||||||
if isinstance(content, list):
|
|
||||||
current_system_prompt = "\n".join(str(item) for item in content)
|
|
||||||
else:
|
|
||||||
current_system_prompt = str(content) if content else ""
|
|
||||||
|
|
||||||
# 确保 memory_prompt 也是字符串
|
|
||||||
if isinstance(memory_prompt, list):
|
|
||||||
memory_prompt = "\n".join(str(item) for item in memory_prompt)
|
|
||||||
else:
|
|
||||||
memory_prompt = str(memory_prompt) if memory_prompt else ""
|
|
||||||
|
|
||||||
# 修改系统提示词
|
# 修改系统提示词
|
||||||
new_system_prompt = current_system_prompt + memory_prompt
|
new_system_prompt = current_system_prompt + memory_prompt
|
||||||
@ -395,18 +384,7 @@ class Mem0Middleware(AgentMiddleware):
|
|||||||
# 获取当前系统提示词
|
# 获取当前系统提示词
|
||||||
current_system_prompt = ""
|
current_system_prompt = ""
|
||||||
if request.system_message:
|
if request.system_message:
|
||||||
content = request.system_message.content if hasattr(request.system_message, "content") else str(request.system_message)
|
current_system_prompt = request.system_message.content if hasattr(request.system_message, "content") else str(request.system_message)
|
||||||
# content 可能是 list 或 str,确保转换为 str
|
|
||||||
if isinstance(content, list):
|
|
||||||
current_system_prompt = "\n".join(str(item) for item in content)
|
|
||||||
else:
|
|
||||||
current_system_prompt = str(content) if content else ""
|
|
||||||
|
|
||||||
# 确保 memory_prompt 也是字符串
|
|
||||||
if isinstance(memory_prompt, list):
|
|
||||||
memory_prompt = "\n".join(str(item) for item in memory_prompt)
|
|
||||||
else:
|
|
||||||
memory_prompt = str(memory_prompt) if memory_prompt else ""
|
|
||||||
|
|
||||||
# 修改系统提示词
|
# 修改系统提示词
|
||||||
new_system_prompt = current_system_prompt + memory_prompt
|
new_system_prompt = current_system_prompt + memory_prompt
|
||||||
|
|||||||
@ -53,7 +53,7 @@ class ToolOutputLengthMiddleware(AgentMiddleware):
|
|||||||
preserve_json: Whether to preserve JSON structure in smart mode
|
preserve_json: Whether to preserve JSON structure in smart mode
|
||||||
ellipsis: Text to append when truncating
|
ellipsis: Text to append when truncating
|
||||||
"""
|
"""
|
||||||
self.max_length = max_length if max_length is not None else 2000 # 确保 max_length 不为 None
|
self.max_length = max_length
|
||||||
self.truncation_strategy = truncation_strategy
|
self.truncation_strategy = truncation_strategy
|
||||||
self.tool_filters = tool_filters
|
self.tool_filters = tool_filters
|
||||||
self.exclude_tools = exclude_tools or []
|
self.exclude_tools = exclude_tools or []
|
||||||
|
|||||||
@ -71,19 +71,6 @@
|
|||||||
- dxcore_update_device_status(device_id="[B设备id]",running_control=0) → 灯光亮度调整为0
|
- dxcore_update_device_status(device_id="[B设备id]",running_control=0) → 灯光亮度调整为0
|
||||||
**响应**:"已为您关闭Define Room4的灯光"
|
**响应**:"已为您关闭Define Room4的灯光"
|
||||||
|
|
||||||
### 人员位置查询(在離判定)场景
|
|
||||||
**用户**:"浜田さんはどこ?"
|
|
||||||
- find_employee_location(name="浜田")
|
|
||||||
- 检查返回结果中的 `last_communication_time` 字段
|
|
||||||
- **场景A**:last_communication_time 在5分钟以内 → 在館
|
|
||||||
**响应**:「浜田さんはNOVAREハブ1階のDefine Room 3にいらっしゃいます。メッセージを送りますか?」
|
|
||||||
|
|
||||||
- **场景B**:last_communication_time 超过5分钟(例如2小时前)→ 不在
|
|
||||||
**响应**:「浜田さんは現在NOVAREにいらっしゃらないようです。最後に確認されたのは本日14時30分頃です。WowTalkでメッセージを送りますか?」
|
|
||||||
|
|
||||||
- **场景C**:last_communication_time 超过24小时 → 長時間不在
|
|
||||||
**响应**:「浜田さんの位置情報が長時間更新されていないため、現在の所在を確認できません。」
|
|
||||||
|
|
||||||
</scenarios>
|
</scenarios>
|
||||||
|
|
||||||
|
|
||||||
@ -157,26 +144,11 @@
|
|||||||
|
|
||||||
4. 查询人员信息/wowtalk账号/人员位置
|
4. 查询人员信息/wowtalk账号/人员位置
|
||||||
- **条件**:用户意图为查找某人、员工、同事或房间位置。
|
- **条件**:用户意图为查找某人、员工、同事或房间位置。
|
||||||
- **动作**:立即调用【人员检索】进行查询,并根据查询结果中的 `last_communication_time` 字段进行**在離判定**后回复。
|
- **动作**:立即调用【人员检索】进行查询,并直接根据查询结果回复。
|
||||||
- **在離判定规则(重要)**:
|
|
||||||
`find_employee_location` 返回的 `last_communication_time` 表示定位标签最后一次通信时间。利用此字段判断人员是否仍在 NOVARE 楼内:
|
|
||||||
1. **在館判定(5分钟以内)**:如果 `当前时刻 - last_communication_time ≤ 5分钟`,判定为「在館」,正常回答位置。
|
|
||||||
- 回复格式:「○○さんはNOVAREハブ[階数]の[部屋名]にいらっしゃいます。」
|
|
||||||
2. **不在判定(5分钟~24小时)**:如果 `当前时刻 - last_communication_time > 5分钟` 且 `≤ 24小时`,判定为「不在」,提示不在馆内并告知最后确认时刻。
|
|
||||||
- 回复格式:「○○さんは現在NOVAREにいらっしゃらないようです。最後に確認されたのは[本日/昨日]○○時○○分頃です。」
|
|
||||||
- 时间格式化:使用日语自然表达(如「本日14時30分頃」「昨日18時頃」)
|
|
||||||
3. **長時間不在判定(24小时以上)**:如果 `当前时刻 - last_communication_time > 24小时`,判定为「位置情報が長時間更新されていない」。
|
|
||||||
- 回复格式:「○○さんの位置情報が長時間更新されていないため、現在の所在を確認できません。」
|
|
||||||
4. **注意事項**:
|
|
||||||
- `last_communication_time` 与 `last_measurement.time` 不同:前者在标签静止时也会持续更新(只要在检测范围内),后者仅在坐标变化时更新。在離判定必须使用 `last_communication_time`
|
|
||||||
- 不要向用户展示 `last_communication_time` 的原始值,需转换为用户友好的日语时间表达
|
|
||||||
- 如果 `last_communication_time` 字段不存在或为空,按照「在館」处理,正常回答位置
|
|
||||||
- **主动追问逻辑**:
|
- **主动追问逻辑**:
|
||||||
1. **在館时成功定位后主动询问**:如果在離判定为「在館」且成功获取到位置信息,在告知位置后主动询问用户是否需要向对方发送消息。
|
1. **成功定位后主动询问**:如果成功找到目标人物且获取到位置信息,在告知位置后主动询问用户是否需要向对方发送消息。
|
||||||
- 回复格式:"○○さんは[位置]にいらっしゃいます。メッセージを送りますか?"
|
- 回复格式:"○○さんは[位置]にいらっしゃいます。メッセージを送りますか?"
|
||||||
2. **不在時の追加案内**:如果在離判定为「不在」,在告知不在后,主动询问用户是否需要通过 WowTalk 发送消息联系对方。
|
2. **无法获取用户位置时**:如果操作需要基于用户当前位置(如"我附近的设备"、"離れたところ"),但无法获取用户位置信息,主动询问用户当前所在位置。
|
||||||
- 回复格式:「○○さんは現在NOVAREにいらっしゃらないようです。最後に確認されたのは○○時○○分頃です。WowTalkでメッセージを送りますか?」
|
|
||||||
3. **无法获取用户位置时**:如果操作需要基于用户当前位置(如"我附近的设备"、"離れたところ"),但无法获取用户位置信息,主动询问用户当前所在位置。
|
|
||||||
- 回复格式:"お客様の現在地が確認できませんでした。今どちらにいらっしゃいますか?"
|
- 回复格式:"お客様の現在地が確認できませんでした。今どちらにいらっしゃいますか?"
|
||||||
|
|
||||||
5. 消息通知(此操作需要确认)
|
5. 消息通知(此操作需要确认)
|
||||||
|
|||||||
@ -727,7 +727,7 @@ async def chat_completions_v2(request: ChatRequestV2, authorization: Optional[st
|
|||||||
# 处理消息
|
# 处理消息
|
||||||
messages = process_messages(request.messages, request.language)
|
messages = process_messages(request.messages, request.language)
|
||||||
# 收集额外参数作为 generate_cfg
|
# 收集额外参数作为 generate_cfg
|
||||||
exclude_fields = {'messages', 'model', 'model_server', 'dataset_ids', 'language', 'tool_response', 'system_prompt', 'mcp_settings', 'stream', 'robot_type', 'bot_id', 'user_identifier', 'session_id', 'enable_thinking', 'skills', 'enable_memory', 'n'}
|
exclude_fields = {'messages', 'stream', 'tool_response', 'bot_id', 'language', 'user_identifier', 'session_id', 'n'}
|
||||||
generate_cfg = {k: v for k, v in request.model_dump().items() if k not in exclude_fields}
|
generate_cfg = {k: v for k, v in request.model_dump().items() if k not in exclude_fields}
|
||||||
# 创建 AgentConfig 对象
|
# 创建 AgentConfig 对象
|
||||||
config = await AgentConfig.from_v2_request(request, bot_config, project_dir, messages, generate_cfg)
|
config = await AgentConfig.from_v2_request(request, bot_config, project_dir, messages, generate_cfg)
|
||||||
|
|||||||
@ -1,132 +0,0 @@
|
|||||||
---
|
|
||||||
name: static-site-deploy
|
|
||||||
description: |-
|
|
||||||
Deploy, download, and browse static HTML sites on VPS via FTP.
|
|
||||||
triggers:
|
|
||||||
- deploy static site
|
|
||||||
- deploy html
|
|
||||||
- deploy to vps
|
|
||||||
- static deploy
|
|
||||||
- download from vps
|
|
||||||
- list files on vps
|
|
||||||
- browse ftp
|
|
||||||
- 部署静态网站
|
|
||||||
- 部署HTML
|
|
||||||
- 部署到VPS
|
|
||||||
- 从服务器下载
|
|
||||||
- 浏览服务器文件
|
|
||||||
---
|
|
||||||
|
|
||||||
# Static Site Deploy
|
|
||||||
|
|
||||||
Upload, download, and browse static HTML files on a VPS via FTP.
|
|
||||||
|
|
||||||
## Use when
|
|
||||||
|
|
||||||
- Deploying static HTML/CSS/JS files to a VPS
|
|
||||||
- Downloading deployed files from VPS
|
|
||||||
- Browsing files and directories on VPS
|
|
||||||
- Publishing a single-page app, landing page, or documentation site
|
|
||||||
- User says "deploy", "upload to server", "publish site", "download from server", or "list files"
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- ASSISTANT_ID environment variable must be set (bot_id)
|
|
||||||
- Deployment script configured with FTP credentials
|
|
||||||
|
|
||||||
## Deployment Workflow
|
|
||||||
|
|
||||||
### Phase 1: Prepare
|
|
||||||
|
|
||||||
1. Identify the source directory (e.g., `./dist/`, `./build/`, `./public/`, or user-specified)
|
|
||||||
2. Determine `project-name`:
|
|
||||||
- From user input, OR
|
|
||||||
- From the source directory's parent folder name
|
|
||||||
3. Verify ASSISTANT_ID environment variable is set
|
|
||||||
|
|
||||||
### Phase 2: Deploy
|
|
||||||
|
|
||||||
Execute the deploy script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Basic usage
|
|
||||||
bash scripts/deploy.sh <source-dir> <project-name>
|
|
||||||
|
|
||||||
# With custom config
|
|
||||||
bash scripts/deploy.sh <source-dir> <project-name> --config /path/to/config.yml
|
|
||||||
|
|
||||||
# Dry run (preview without uploading)
|
|
||||||
bash scripts/deploy.sh <source-dir> <project-name> --dry-run
|
|
||||||
```
|
|
||||||
|
|
||||||
The script will:
|
|
||||||
- Upload files to VPS
|
|
||||||
- Show deployment summary and progress
|
|
||||||
- Verify deployment via FTP and HTTP checks
|
|
||||||
|
|
||||||
### Phase 3: Verify
|
|
||||||
|
|
||||||
The script automatically verifies:
|
|
||||||
1. **FTP verification** - confirms files are present on server
|
|
||||||
2. **HTTP verification** - confirms site is accessible (expects HTTP 200)
|
|
||||||
|
|
||||||
Final output shows:
|
|
||||||
```
|
|
||||||
=== Deploy Complete ===
|
|
||||||
URL: https://domain/path/to/deploy/
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
| Error | Detection | Fix |
|
|
||||||
|-------|-----------|-----|
|
|
||||||
| FTP connection refused | curl returns "connection refused" | Check FTP service is running, verify port |
|
|
||||||
| FTP auth failed | curl returns 530 | Check username/password in config |
|
|
||||||
| Upload permission denied | curl returns 553 | Check FTP user write permission on web_root |
|
|
||||||
| HTTP 404 | curl returns 404 | Confirm Nginx root matches FTP upload path |
|
|
||||||
| HTTP 403 | curl returns 403 | Fix permissions: files 644, directories 755 |
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
|
|
||||||
- Use `scripts/deploy.sh` for uploading files to VPS
|
|
||||||
- Use `scripts/download.sh` for downloading files from VPS
|
|
||||||
- Use `scripts/list.sh` for browsing FTP directory contents
|
|
||||||
- Verify ASSISTANT_ID environment variable is set before calling scripts
|
|
||||||
- Show the command to the user before executing
|
|
||||||
- The scripts handle all FTP operations, progress display, and verification
|
|
||||||
|
|
||||||
## List Files Workflow
|
|
||||||
|
|
||||||
To browse files on VPS:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# List all projects under bot directory
|
|
||||||
bash scripts/list.sh
|
|
||||||
|
|
||||||
# List files in a specific project
|
|
||||||
bash scripts/list.sh <project-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
The list script will:
|
|
||||||
- Read bot_id from ASSISTANT_ID environment variable
|
|
||||||
- Show directory contents from `/{bot_id}/` or `/{bot_id}/{project_name}/`
|
|
||||||
- Mark directories with trailing `/`
|
|
||||||
- Only list current directory level (non-recursive)
|
|
||||||
|
|
||||||
## Download Workflow
|
|
||||||
|
|
||||||
To download files from VPS:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Basic usage
|
|
||||||
bash scripts/download.sh <project-name> <target-dir>
|
|
||||||
|
|
||||||
# With custom config
|
|
||||||
bash scripts/download.sh <project-name> <target-dir> --config /path/to/config.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
The download script will:
|
|
||||||
- Read bot_id from ASSISTANT_ID environment variable
|
|
||||||
- Download files from `/{bot_id}/{project_name}/`
|
|
||||||
- Save to the specified target directory
|
|
||||||
- Show download summary and file count
|
|
||||||
@ -1,177 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Static Site Deploy - FTP upload helper script
|
|
||||||
# Usage: deploy.sh <source-dir> <project-name> [--config path] [--dry-run]
|
|
||||||
|
|
||||||
# ─── Argument Parsing ───────────────────────────────────────────────
|
|
||||||
|
|
||||||
SOURCE_DIR=""
|
|
||||||
PROJECT_NAME=""
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
CONFIG_FILE="${SCRIPT_DIR}/static-site-deploy.yml"
|
|
||||||
DRY_RUN=false
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--config)
|
|
||||||
CONFIG_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--dry-run)
|
|
||||||
DRY_RUN=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [[ -z "$SOURCE_DIR" ]]; then
|
|
||||||
SOURCE_DIR="$1"
|
|
||||||
elif [[ -z "$PROJECT_NAME" ]]; then
|
|
||||||
PROJECT_NAME="$1"
|
|
||||||
else
|
|
||||||
echo "Error: unexpected argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ -z "$SOURCE_DIR" || -z "$PROJECT_NAME" ]]; then
|
|
||||||
echo "Usage: deploy.sh <source-dir> <project-name> [--config path] [--dry-run]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -d "$SOURCE_DIR" ]]; then
|
|
||||||
echo "Error: source directory '$SOURCE_DIR' does not exist" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Read bot_id from environment variable
|
|
||||||
BOT_ID="${ASSISTANT_ID:-}"
|
|
||||||
if [[ -z "$BOT_ID" ]]; then
|
|
||||||
echo "Error: ASSISTANT_ID environment variable is not set" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── Config Parsing ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
||||||
echo "Error: config file '$CONFIG_FILE' not found" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Simple YAML parser (no external dependencies)
|
|
||||||
parse_yaml() {
|
|
||||||
local key="$1"
|
|
||||||
grep "^${key}:" "$CONFIG_FILE" | sed "s/^${key}:[[:space:]]*//" | sed 's/[[:space:]]*#.*//' | sed 's/[[:space:]]*$//' | sed 's/^["'\'']\(.*\)["'\'']$/\1/'
|
|
||||||
}
|
|
||||||
|
|
||||||
HOST=$(parse_yaml "host")
|
|
||||||
FTP_USER=$(parse_yaml "ftp_user")
|
|
||||||
FTP_PASS=$(parse_yaml "ftp_pass")
|
|
||||||
FTP_PORT=$(parse_yaml "ftp_port")
|
|
||||||
USE_FTPS=$(parse_yaml "use_ftps")
|
|
||||||
WEB_ROOT=$(parse_yaml "web_root")
|
|
||||||
DOMAIN=$(parse_yaml "domain")
|
|
||||||
|
|
||||||
# Defaults
|
|
||||||
FTP_PORT="${FTP_PORT:-21}"
|
|
||||||
USE_FTPS="${USE_FTPS:-true}"
|
|
||||||
|
|
||||||
# Validate required fields
|
|
||||||
for field in HOST FTP_USER FTP_PASS WEB_ROOT DOMAIN; do
|
|
||||||
if [[ -z "${!field}" ]]; then
|
|
||||||
echo "Error: missing required config field: $(echo "$field" | tr '[:upper:]' '[:lower:]')" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
REMOTE_PATH="${WEB_ROOT}/${BOT_ID}/${PROJECT_NAME}"
|
|
||||||
SITE_URL="https://${DOMAIN}/${BOT_ID}/${PROJECT_NAME}/"
|
|
||||||
|
|
||||||
# ─── Summary ────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
FILE_COUNT=$(find "$SOURCE_DIR" -type f | wc -l | tr -d ' ')
|
|
||||||
TOTAL_SIZE=$(du -sh "$SOURCE_DIR" 2>/dev/null | cut -f1)
|
|
||||||
|
|
||||||
echo "=== Static Site Deploy ==="
|
|
||||||
echo "Bot ID: $BOT_ID"
|
|
||||||
echo "Source: $SOURCE_DIR ($FILE_COUNT files, $TOTAL_SIZE)"
|
|
||||||
echo "Project: $PROJECT_NAME"
|
|
||||||
echo "Remote: ftp://${FTP_USER}@${HOST}:${FTP_PORT}${REMOTE_PATH}/"
|
|
||||||
echo "URL: $SITE_URL"
|
|
||||||
echo "FTPS: $USE_FTPS"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == "true" ]]; then
|
|
||||||
echo "[DRY RUN] Files that would be uploaded:"
|
|
||||||
find "$SOURCE_DIR" -type f | while read -r file; do
|
|
||||||
rel_path="${file#"$SOURCE_DIR"}"
|
|
||||||
rel_path="${rel_path#/}"
|
|
||||||
echo " $rel_path"
|
|
||||||
done
|
|
||||||
echo ""
|
|
||||||
echo "[DRY RUN] No files were uploaded."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── Upload ─────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
echo "Uploading with curl..."
|
|
||||||
|
|
||||||
curl_ssl_flag=""
|
|
||||||
if [[ "$USE_FTPS" == "true" ]]; then
|
|
||||||
curl_ssl_flag="--ssl-reqd"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ftp_base="ftp://${FTP_USER}:${FTP_PASS}@${HOST}:${FTP_PORT}"
|
|
||||||
|
|
||||||
# Upload files one by one
|
|
||||||
uploaded=0
|
|
||||||
failed=0
|
|
||||||
|
|
||||||
find "$SOURCE_DIR" -type f | while read -r file; do
|
|
||||||
rel_path="${file#"$SOURCE_DIR"}"
|
|
||||||
rel_path="${rel_path#/}"
|
|
||||||
remote_url="${ftp_base}${REMOTE_PATH}/${rel_path}"
|
|
||||||
|
|
||||||
if curl -s -T "$file" --ftp-create-dirs $curl_ssl_flag "$remote_url"; then
|
|
||||||
echo " OK: $rel_path"
|
|
||||||
uploaded=$((uploaded + 1))
|
|
||||||
else
|
|
||||||
echo " FAIL: $rel_path" >&2
|
|
||||||
failed=$((failed + 1))
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ $failed -gt 0 ]]; then
|
|
||||||
echo "Warning: $failed file(s) failed to upload" >&2
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# ─── Verify ─────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
echo "=== Verification ==="
|
|
||||||
|
|
||||||
# FTP verification
|
|
||||||
echo -n "FTP check... "
|
|
||||||
ftp_list_url="ftp://${FTP_USER}:${FTP_PASS}@${HOST}:${FTP_PORT}${REMOTE_PATH}/"
|
|
||||||
if curl -s --list-only "$ftp_list_url" --connect-timeout 5 >/dev/null 2>&1; then
|
|
||||||
echo "OK (files present on server)"
|
|
||||||
else
|
|
||||||
echo "WARN (could not list remote directory)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# HTTP verification
|
|
||||||
echo -n "HTTP check... "
|
|
||||||
http_code=$(curl -sL -o /dev/null -w '%{http_code}' "$SITE_URL" --connect-timeout 10 2>/dev/null || echo "000")
|
|
||||||
if [[ "$http_code" == "200" ]]; then
|
|
||||||
echo "OK (HTTP $http_code)"
|
|
||||||
else
|
|
||||||
echo "WARN (HTTP $http_code - check Nginx config if not 200)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Deploy Complete ==="
|
|
||||||
echo "URL: $SITE_URL"
|
|
||||||
@ -1,152 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Static Site Download - FTP download helper script
|
|
||||||
# Usage: download.sh <project-name> <target-dir> [--config path]
|
|
||||||
|
|
||||||
# ─── Argument Parsing ───────────────────────────────────────────────
|
|
||||||
|
|
||||||
PROJECT_NAME=""
|
|
||||||
TARGET_DIR=""
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
CONFIG_FILE="${SCRIPT_DIR}/static-site-deploy.yml"
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--config)
|
|
||||||
CONFIG_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [[ -z "$PROJECT_NAME" ]]; then
|
|
||||||
PROJECT_NAME="$1"
|
|
||||||
elif [[ -z "$TARGET_DIR" ]]; then
|
|
||||||
TARGET_DIR="$1"
|
|
||||||
else
|
|
||||||
echo "Error: unexpected argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ -z "$PROJECT_NAME" || -z "$TARGET_DIR" ]]; then
|
|
||||||
echo "Usage: download.sh <project-name> <target-dir> [--config path]" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Read bot_id from environment variable
|
|
||||||
BOT_ID="${ASSISTANT_ID:-}"
|
|
||||||
if [[ -z "$BOT_ID" ]]; then
|
|
||||||
echo "Error: ASSISTANT_ID environment variable is not set" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── Config Parsing ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
||||||
echo "Error: config file '$CONFIG_FILE' not found" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Simple YAML parser (no external dependencies)
|
|
||||||
parse_yaml() {
|
|
||||||
local key="$1"
|
|
||||||
grep "^${key}:" "$CONFIG_FILE" | sed "s/^${key}:[[:space:]]*//" | sed 's/[[:space:]]*#.*//' | sed 's/[[:space:]]*$//' | sed 's/^[\"'\'']\(.*\)[\"'\'']$/\1/'
|
|
||||||
}
|
|
||||||
|
|
||||||
HOST=$(parse_yaml "host")
|
|
||||||
FTP_USER=$(parse_yaml "ftp_user")
|
|
||||||
FTP_PASS=$(parse_yaml "ftp_pass")
|
|
||||||
FTP_PORT=$(parse_yaml "ftp_port")
|
|
||||||
USE_FTPS=$(parse_yaml "use_ftps")
|
|
||||||
WEB_ROOT=$(parse_yaml "web_root")
|
|
||||||
DOMAIN=$(parse_yaml "domain")
|
|
||||||
|
|
||||||
# Defaults
|
|
||||||
FTP_PORT="${FTP_PORT:-21}"
|
|
||||||
USE_FTPS="${USE_FTPS:-true}"
|
|
||||||
|
|
||||||
# Validate required fields
|
|
||||||
for field in HOST FTP_USER FTP_PASS WEB_ROOT DOMAIN; do
|
|
||||||
if [[ -z "${!field}" ]]; then
|
|
||||||
echo "Error: missing required config field: $(echo "$field" | tr '[:upper:]' '[:lower:]')" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
REMOTE_PATH="${WEB_ROOT}/${BOT_ID}/${PROJECT_NAME}"
|
|
||||||
SITE_URL="https://${DOMAIN}/${BOT_ID}/${PROJECT_NAME}/"
|
|
||||||
|
|
||||||
# ─── Summary ────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
echo "=== Static Site Download ==="
|
|
||||||
echo "Bot ID: $BOT_ID"
|
|
||||||
echo "Project: $PROJECT_NAME"
|
|
||||||
echo "Remote: ftp://${FTP_USER}@${HOST}:${FTP_PORT}${REMOTE_PATH}/"
|
|
||||||
echo "Target: $TARGET_DIR"
|
|
||||||
echo "FTPS: $USE_FTPS"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Create target directory
|
|
||||||
mkdir -p "$TARGET_DIR"
|
|
||||||
|
|
||||||
# ─── Download ───────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
echo "Downloading with curl..."
|
|
||||||
|
|
||||||
curl_ssl_flag=""
|
|
||||||
if [[ "$USE_FTPS" == "true" ]]; then
|
|
||||||
curl_ssl_flag="--ssl-reqd"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ftp_base="ftp://${FTP_USER}:${FTP_PASS}@${HOST}:${FTP_PORT}"
|
|
||||||
|
|
||||||
# List all files
|
|
||||||
echo "Listing remote files..."
|
|
||||||
file_list=$(curl -s --list-only $curl_ssl_flag "${ftp_base}${REMOTE_PATH}/" 2>/dev/null || echo "")
|
|
||||||
|
|
||||||
if [[ -z "$file_list" ]]; then
|
|
||||||
echo "Error: Could not list remote directory or directory is empty" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
downloaded=0
|
|
||||||
failed=0
|
|
||||||
|
|
||||||
# Download each file
|
|
||||||
while IFS= read -r file; do
|
|
||||||
# Skip . and ..
|
|
||||||
if [[ "$file" == "." || "$file" == ".." ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
remote_url="${ftp_base}${REMOTE_PATH}/${file}"
|
|
||||||
local_file="${TARGET_DIR}/${file}"
|
|
||||||
|
|
||||||
if curl -s -o "$local_file" $curl_ssl_flag "$remote_url" 2>/dev/null; then
|
|
||||||
echo " OK: $file"
|
|
||||||
downloaded=$((downloaded + 1))
|
|
||||||
else
|
|
||||||
echo " FAIL: $file" >&2
|
|
||||||
failed=$((failed + 1))
|
|
||||||
fi
|
|
||||||
done <<< "$file_list"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Downloaded: $downloaded file(s)"
|
|
||||||
if [[ $failed -gt 0 ]]; then
|
|
||||||
echo "Warning: $failed file(s) failed to download" >&2
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# ─── Summary ────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
FILE_COUNT=$(find "$TARGET_DIR" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
||||||
TOTAL_SIZE=$(du -sh "$TARGET_DIR" 2>/dev/null | cut -f1)
|
|
||||||
|
|
||||||
echo "=== Download Complete ==="
|
|
||||||
echo "Target: $TARGET_DIR ($FILE_COUNT files, $TOTAL_SIZE)"
|
|
||||||
echo "Source URL: $SITE_URL"
|
|
||||||
@ -1,122 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Static Site List - FTP directory listing helper script
|
|
||||||
# Usage: list.sh [project-name] [--config path]
|
|
||||||
|
|
||||||
# ─── Argument Parsing ───────────────────────────────────────────────
|
|
||||||
|
|
||||||
PROJECT_NAME=""
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
CONFIG_FILE="${SCRIPT_DIR}/static-site-deploy.yml"
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--config)
|
|
||||||
CONFIG_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [[ -z "$PROJECT_NAME" ]]; then
|
|
||||||
PROJECT_NAME="$1"
|
|
||||||
else
|
|
||||||
echo "Error: unexpected argument '$1'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Read bot_id from environment variable
|
|
||||||
BOT_ID="${ASSISTANT_ID:-}"
|
|
||||||
if [[ -z "$BOT_ID" ]]; then
|
|
||||||
echo "Error: ASSISTANT_ID environment variable is not set" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── Config Parsing ─────────────────────────────────────────────────
|
|
||||||
|
|
||||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
|
||||||
echo "Error: config file '$CONFIG_FILE' not found" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Simple YAML parser (no external dependencies)
|
|
||||||
parse_yaml() {
|
|
||||||
local key="$1"
|
|
||||||
grep "^${key}:" "$CONFIG_FILE" | sed "s/^${key}:[[:space:]]*//" | sed 's/[[:space:]]*#.*//' | sed 's/[[:space:]]*$//' | sed 's/^[\"'\'']\(.*\)[\"'\'']$/\1/'
|
|
||||||
}
|
|
||||||
|
|
||||||
HOST=$(parse_yaml "host")
|
|
||||||
FTP_USER=$(parse_yaml "ftp_user")
|
|
||||||
FTP_PASS=$(parse_yaml "ftp_pass")
|
|
||||||
FTP_PORT=$(parse_yaml "ftp_port")
|
|
||||||
USE_FTPS=$(parse_yaml "use_ftps")
|
|
||||||
WEB_ROOT=$(parse_yaml "web_root")
|
|
||||||
DOMAIN=$(parse_yaml "domain")
|
|
||||||
|
|
||||||
# Defaults
|
|
||||||
FTP_PORT="${FTP_PORT:-21}"
|
|
||||||
USE_FTPS="${USE_FTPS:-true}"
|
|
||||||
|
|
||||||
# Validate required fields
|
|
||||||
for field in HOST FTP_USER FTP_PASS WEB_ROOT DOMAIN; do
|
|
||||||
if [[ -z "${!field}" ]]; then
|
|
||||||
echo "Error: missing required config field: $(echo "$field" | tr '[:upper:]' '[:lower:]')" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Determine remote path
|
|
||||||
if [[ -z "$PROJECT_NAME" ]]; then
|
|
||||||
# List bot directory
|
|
||||||
REMOTE_PATH="${WEB_ROOT}/${BOT_ID}"
|
|
||||||
DISPLAY_PATH="/${BOT_ID}/"
|
|
||||||
else
|
|
||||||
# List specific project
|
|
||||||
REMOTE_PATH="${WEB_ROOT}/${BOT_ID}/${PROJECT_NAME}"
|
|
||||||
DISPLAY_PATH="/${BOT_ID}/${PROJECT_NAME}/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ─── List Files ─────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
echo "=== FTP Directory Listing ==="
|
|
||||||
echo "Bot ID: $BOT_ID"
|
|
||||||
echo "Path: $DISPLAY_PATH"
|
|
||||||
echo "Remote: ftp://${FTP_USER}@${HOST}:${FTP_PORT}${REMOTE_PATH}/"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
curl_ssl_flag=""
|
|
||||||
if [[ "$USE_FTPS" == "true" ]]; then
|
|
||||||
curl_ssl_flag="--ssl-reqd"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ftp_url="ftp://${FTP_USER}:${FTP_PASS}@${HOST}:${FTP_PORT}${REMOTE_PATH}/"
|
|
||||||
|
|
||||||
# List directory
|
|
||||||
listing=$(curl -s --list-only $curl_ssl_flag "$ftp_url" 2>&1)
|
|
||||||
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
echo "Error: Failed to list directory" >&2
|
|
||||||
echo "$listing" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Format output
|
|
||||||
echo "$listing" | while IFS= read -r item; do
|
|
||||||
# Skip . and ..
|
|
||||||
if [[ "$item" == "." || "$item" == ".." ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if it's a directory by trying to list it
|
|
||||||
if curl -s --list-only $curl_ssl_flag "${ftp_url}${item}/" >/dev/null 2>&1; then
|
|
||||||
echo "${item}/"
|
|
||||||
else
|
|
||||||
echo "$item"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "=== Listing Complete ==="
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
host: 1.94.251.96
|
|
||||||
ftp_user: deploy_aitravelmaster
|
|
||||||
ftp_pass: yWBJr3PWpJSZsJYe
|
|
||||||
ftp_port: 21 # optional, default 21
|
|
||||||
use_ftps: false # optional, default true (FTP over TLS)
|
|
||||||
|
|
||||||
# Web settings
|
|
||||||
web_root: / # remote base directory for uploads
|
|
||||||
domain: deploy.aitravelmaster.com # domain for generating access URLs
|
|
||||||
Loading…
Reference in New Issue
Block a user