chore: import upstream snapshot with attribution
This commit is contained in:
Executable
+219
@@ -0,0 +1,219 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# Yuxi 版本号升级脚本
|
||||
# =============================================================================
|
||||
# 用法: ./scripts/bump-version.sh [--dev] <新版本号>
|
||||
# 示例: ./scripts/bump-version.sh 0.6.2
|
||||
# 示例: ./scripts/bump-version.sh --dev 0.6.2.dev1
|
||||
#
|
||||
# 该脚本从 backend/package/pyproject.toml 读取当前版本,
|
||||
# 自动同步所有需要硬编码版本号的位置。
|
||||
# --dev 模式不会更新 README.md、docs/intro/quick-start.md 和文档首页中 git clone --branch 的版本号。
|
||||
#
|
||||
# 更新 tag 标准流程(给人工和 agent 使用):
|
||||
#
|
||||
# 1. 先判断目标版本,不要直接打 tag。
|
||||
# - 用户给完整版本号时,直接使用该版本,例如 0.7.1.dev2。
|
||||
# - 用户只说“更新到 dev2”时,沿用当前主版本号 x.y.z,目标版本为 x.y.z.dev2。
|
||||
# 例如当前是 0.7.1.dev1,则运行: ./scripts/bump-version.sh --dev 0.7.1.dev2
|
||||
# - 用户只说“更新 tag”或“添加 tag”时,先读取 backend/package/pyproject.toml:
|
||||
# * 如果当前是 x.y.z.dev0,默认推断为要发布第一个开发 tag,目标版本是 x.y.z.dev1。
|
||||
# * 如果当前已经是 x.y.z.devN(N >= 1)或 x.y.z,默认给当前版本打 tag。
|
||||
# * 如果上下文里提到 dev2/dev3 等,则按提到的 devN 推断目标版本。
|
||||
#
|
||||
# 2. 如需升级版本,先运行本脚本。开发版必须带 --dev:
|
||||
# ./scripts/bump-version.sh --dev 0.7.1.dev2
|
||||
# 正式版不带 --dev:
|
||||
# ./scripts/bump-version.sh 0.7.1
|
||||
#
|
||||
# 3. 脚本运行后必须检查:
|
||||
# - git diff,确认只有预期版本文件变化。
|
||||
# - backend/package/pyproject.toml、backend/pyproject.toml、web/package.json、
|
||||
# docker-compose*.yml、backend/*uv.lock 中的 Yuxi 版本一致。
|
||||
# - dev 模式下 README.md、README.en.md、docs/intro/quick-start.md 和文档首页
|
||||
# 不应被更新。
|
||||
#
|
||||
# 4. 必须先提交版本更新,再创建 tag。tag 要指向包含版本更新的提交:
|
||||
# git add backend/package/pyproject.toml backend/package/uv.lock backend/pyproject.toml backend/uv.lock docker-compose.yml docker-compose.prod.yml web/package.json
|
||||
# git commit -m 'chore(release): 升级版本到 0.7.1.dev2'
|
||||
# git tag v0.7.1.dev2
|
||||
#
|
||||
# 5. 创建 tag 后必须检查:
|
||||
# - git status --short 应为空。
|
||||
# - git show --no-patch --decorate --oneline HEAD 应显示 tag。
|
||||
# - git tag --points-at HEAD 应包含刚创建的 tag。
|
||||
# - 如果 tag 已存在,不要强制覆盖,先停下来确认。
|
||||
#
|
||||
# 6. 推送时推荐显式推送当前分支和本次 tag,避免误推其它本地 tag:
|
||||
# git push origin main
|
||||
# git push origin v0.7.1.dev2
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# 检查参数
|
||||
DEV_MODE=false
|
||||
if [ "${1:-}" = "--dev" ]; then
|
||||
DEV_MODE=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "用法: $0 [--dev] <新版本号>"
|
||||
echo "示例: $0 0.6.2"
|
||||
echo "示例: $0 --dev 0.6.2.dev1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NEW_VERSION="$1"
|
||||
|
||||
# 验证版本号格式(支持 x.y.z 或 x.y.z.devN)
|
||||
if [[ ! "$NEW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[a-zA-Z0-9]+)?$ ]]; then
|
||||
echo "错误: 版本号格式无效,期望格式如 0.6.2 或 0.6.2.dev1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 读取当前版本号(以 backend/package/pyproject.toml 为 SSOT)
|
||||
PYPROJECT_FILE="${PROJECT_ROOT}/backend/package/pyproject.toml"
|
||||
if [ ! -f "$PYPROJECT_FILE" ]; then
|
||||
echo "错误: 找不到 ${PYPROJECT_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CURRENT_VERSION=$(grep -E '^version[[:space:]]*=[[:space:]]*"' "$PYPROJECT_FILE" | head -1 | sed -E 's/^version[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/')
|
||||
|
||||
if [ -z "$CURRENT_VERSION" ]; then
|
||||
echo "错误: 无法从 ${PYPROJECT_FILE} 读取当前版本号"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then
|
||||
echo "当前版本已经是 ${NEW_VERSION},无需更新"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "准备将版本号从 ${CURRENT_VERSION} 升级到 ${NEW_VERSION}"
|
||||
echo "受影响的文件:"
|
||||
echo " - backend/package/pyproject.toml"
|
||||
echo " - backend/pyproject.toml"
|
||||
echo " - web/package.json"
|
||||
echo " - docker-compose.yml"
|
||||
echo " - docker-compose.prod.yml"
|
||||
echo " - backend/uv.lock"
|
||||
echo " - backend/package/uv.lock"
|
||||
if [ "$DEV_MODE" = false ]; then
|
||||
echo " - README.md"
|
||||
echo " - README.en.md"
|
||||
echo " - docs/intro/quick-start.md"
|
||||
echo " - docs/.vitepress/theme/components/YuxiHome.vue"
|
||||
fi
|
||||
echo ""
|
||||
read -rp "确认继续? [y/N] " confirm
|
||||
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||
echo "已取消"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 1. 更新 Python 包版本 (backend/package/pyproject.toml)
|
||||
# -----------------------------------------------------------------------------
|
||||
echo "→ 更新 backend/package/pyproject.toml"
|
||||
perl -pi -e "s/^version = \"[^\"]+\"/version = \"${NEW_VERSION}\"/" \
|
||||
"${PROJECT_ROOT}/backend/package/pyproject.toml"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 2. 更新后端工作区版本 (backend/pyproject.toml)
|
||||
# -----------------------------------------------------------------------------
|
||||
echo "→ 更新 backend/pyproject.toml"
|
||||
perl -pi -e "s/^version = \"[^\"]+\"/version = \"${NEW_VERSION}\"/" \
|
||||
"${PROJECT_ROOT}/backend/pyproject.toml"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 3. 更新前端版本 (web/package.json)
|
||||
# -----------------------------------------------------------------------------
|
||||
echo "→ 更新 web/package.json"
|
||||
perl -pi -e "s/\"version\": \"[^\"]+\"/\"version\": \"${NEW_VERSION}\"/" \
|
||||
"${PROJECT_ROOT}/web/package.json"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 4. 更新 Docker Compose 镜像标签默认值
|
||||
# -----------------------------------------------------------------------------
|
||||
echo "→ 更新 docker-compose.yml"
|
||||
perl -pi -e "s/\\\$\\{YUXI_VERSION:-[^}]+\\}/\\\${YUXI_VERSION:-${NEW_VERSION}}/g" \
|
||||
"${PROJECT_ROOT}/docker-compose.yml"
|
||||
|
||||
echo "→ 更新 docker-compose.prod.yml"
|
||||
perl -pi -e "s/\\\$\\{YUXI_VERSION:-[^}]+\\}/\\\${YUXI_VERSION:-${NEW_VERSION}}/g" \
|
||||
"${PROJECT_ROOT}/docker-compose.prod.yml"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 5. 更新 uv.lock 中的项目版本号
|
||||
# -----------------------------------------------------------------------------
|
||||
echo "→ 更新 backend/uv.lock"
|
||||
# yuxi 包版本
|
||||
perl -0pi -e "s/(^name = \"yuxi\"\nversion = \")[^\"]+/\${1}${NEW_VERSION}/m" \
|
||||
"${PROJECT_ROOT}/backend/uv.lock"
|
||||
# yuxi-workspace 版本
|
||||
perl -0pi -e "s/(^name = \"yuxi-workspace\"\nversion = \")[^\"]+/\${1}${NEW_VERSION}/m" \
|
||||
"${PROJECT_ROOT}/backend/uv.lock"
|
||||
|
||||
echo "→ 更新 backend/package/uv.lock"
|
||||
perl -0pi -e "s/(^name = \"yuxi\"\nversion = \")[^\"]+/\${1}${NEW_VERSION}/m" \
|
||||
"${PROJECT_ROOT}/backend/package/uv.lock"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 6. 更新文档中的版本引用
|
||||
# -----------------------------------------------------------------------------
|
||||
# 只替换 git clone 命令中的版本标签(确保总是指向最新版本)
|
||||
# 发布历史记录(如 [2026/04/01] v0.6.1 版本发布)不修改,保持为历史版本记录
|
||||
if [ "$DEV_MODE" = false ]; then
|
||||
echo "→ 更新 README.md"
|
||||
perl -pi -e "s/(git clone --branch v)[0-9]+\\.[0-9]+\\.[0-9]+(\\.[a-zA-Z0-9]+)?/\${1}${NEW_VERSION}/g" \
|
||||
"${PROJECT_ROOT}/README.md"
|
||||
|
||||
echo "→ 更新 README.en.md"
|
||||
perl -pi -e "s/(git clone --branch v)[0-9]+\\.[0-9]+\\.[0-9]+(\\.[a-zA-Z0-9]+)?/\${1}${NEW_VERSION}/g" \
|
||||
"${PROJECT_ROOT}/README.en.md"
|
||||
|
||||
echo "→ 更新 docs/intro/quick-start.md"
|
||||
perl -pi -e "s/(git clone --branch v)[0-9]+\\.[0-9]+\\.[0-9]+(\\.[a-zA-Z0-9]+)?/\${1}${NEW_VERSION}/g" \
|
||||
"${PROJECT_ROOT}/docs/intro/quick-start.md"
|
||||
|
||||
echo "→ 更新 docs/.vitepress/theme/components/YuxiHome.vue"
|
||||
perl -pi -e "s/(git clone --branch v)[0-9]+\\.[0-9]+\\.[0-9]+(\\.[a-zA-Z0-9]+)?/\${1}${NEW_VERSION}/g" \
|
||||
"${PROJECT_ROOT}/docs/.vitepress/theme/components/YuxiHome.vue"
|
||||
else
|
||||
echo "→ dev 模式,跳过 README.md、README.en.md、docs/intro/quick-start.md 和文档首页的分支版本更新"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 7. 验证
|
||||
# -----------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "版本号升级完成,验证结果:"
|
||||
echo ""
|
||||
|
||||
echo " backend/package/pyproject.toml:"
|
||||
grep -E "^version = \"" "${PROJECT_ROOT}/backend/package/pyproject.toml" | head -1 | sed 's/^/ /'
|
||||
|
||||
echo " backend/pyproject.toml:"
|
||||
grep -E "^version = \"" "${PROJECT_ROOT}/backend/pyproject.toml" | head -1 | sed 's/^/ /'
|
||||
|
||||
echo " web/package.json:"
|
||||
grep -E '"version"' "${PROJECT_ROOT}/web/package.json" | head -1 | sed 's/^/ /'
|
||||
|
||||
echo " docker-compose.yml (api):"
|
||||
grep -E "image: yuxi-api:" "${PROJECT_ROOT}/docker-compose.yml" | head -1 | sed 's/^/ /'
|
||||
|
||||
echo " docker-compose.prod.yml (web):"
|
||||
grep -E "image: yuxi-web:" "${PROJECT_ROOT}/docker-compose.prod.yml" | head -1 | sed 's/^/ /'
|
||||
|
||||
echo ""
|
||||
echo "后续步骤:"
|
||||
echo " 1. 检查 git diff 确认修改无误"
|
||||
echo " 2. git add . && git commit -m 'chore(release): bump version to ${NEW_VERSION}'"
|
||||
echo " 3. git tag v${NEW_VERSION}"
|
||||
echo " 4. git push origin main --tags"
|
||||
@@ -0,0 +1,129 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from langfuse import Langfuse
|
||||
|
||||
|
||||
PYTHON_TASK_ITEMS = [
|
||||
{
|
||||
"id": "py-task-001",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定 nums = [7, -2, 5, 11, -8, 4],"
|
||||
"只保留正数,平方后求和。请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "211",
|
||||
},
|
||||
{
|
||||
"id": "py-task-002",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定文本 'alpha,beta;gamma delta\\nepsilon',"
|
||||
"按逗号、分号、空白和换行切分 token,统计 token 数。请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "5",
|
||||
},
|
||||
{
|
||||
"id": "py-task-003",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:计算 1 到 200 中所有能被 7 整除但不能被 5 整除的整数个数。"
|
||||
"请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "23",
|
||||
},
|
||||
{
|
||||
"id": "py-task-004",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定 records = [('a', 3), ('b', 5), ('a', 4), ('c', 2), ('b', -1)],"
|
||||
"按 key 汇总数值,并按 key 字母序输出形如 a=7,b=4,c=2 的字符串。"
|
||||
),
|
||||
"expected_output": "a=7,b=4,c=2",
|
||||
},
|
||||
{
|
||||
"id": "py-task-005",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定矩阵 [[1, 2, 3], [4, 5, 6], [7, 8, 9]],"
|
||||
"计算主对角线之和减去副对角线之和。请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "0",
|
||||
},
|
||||
{
|
||||
"id": "py-task-006",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定 s = 'Yuxi Agent Evaluation',"
|
||||
"忽略大小写统计元音字母 a/e/i/o/u 的总数。请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "10",
|
||||
},
|
||||
{
|
||||
"id": "py-task-007",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定区间 [10, 50],找出所有质数并求和。"
|
||||
"请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "311",
|
||||
},
|
||||
{
|
||||
"id": "py-task-008",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定 JSON 字符串 "
|
||||
"'{\"items\":[{\"price\":12.5,\"qty\":2},{\"price\":3,\"qty\":5},{\"price\":8,\"qty\":1}]}',"
|
||||
"计算所有 price * qty 的总和。请只输出最终数字,保留一位小数。"
|
||||
),
|
||||
"expected_output": "48.0",
|
||||
},
|
||||
{
|
||||
"id": "py-task-009",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:给定 words = ['graph', 'rag', 'agent', 'tool', 'trace'],"
|
||||
"按单词长度升序、长度相同时按字母序排序,并用 '-' 连接。"
|
||||
),
|
||||
"expected_output": "rag-tool-agent-graph-trace",
|
||||
},
|
||||
{
|
||||
"id": "py-task-010",
|
||||
"input": (
|
||||
"请用 Python 完成任务并给出最终答案:生成 Fibonacci 序列前 12 项(从 0, 1 开始),"
|
||||
"取偶数项求和。请只输出最终整数。"
|
||||
),
|
||||
"expected_output": "44",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Upload a Python task dataset to Langfuse.")
|
||||
parser.add_argument(
|
||||
"--dataset-name",
|
||||
default=f"yuxi-python-tasks-{datetime.now(UTC).strftime('%Y%m%dT%H%M%SZ')}",
|
||||
help="Langfuse dataset name. Defaults to a timestamped name.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
client = Langfuse()
|
||||
client.create_dataset(
|
||||
name=args.dataset_name,
|
||||
description="Yuxi agent evaluation dataset: deterministic Python programming tasks.",
|
||||
metadata={
|
||||
"source": "scripts/eval/upload_langfuse_python_tasks_dataset.py",
|
||||
"task_type": "python_programming",
|
||||
"item_count": len(PYTHON_TASK_ITEMS),
|
||||
},
|
||||
)
|
||||
for item in PYTHON_TASK_ITEMS:
|
||||
client.create_dataset_item(
|
||||
dataset_name=args.dataset_name,
|
||||
id=item["id"],
|
||||
input={"input": item["input"]},
|
||||
expected_output=item["expected_output"],
|
||||
metadata={"category": "python_programming", "source": "yuxi_eval_smoke"},
|
||||
)
|
||||
client.flush()
|
||||
print(args.dataset_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,170 @@
|
||||
# Yuxi Initialization Script for PowerShell
|
||||
# This script helps set up the environment for the Yuxi project
|
||||
# Note: API keys will be visible during input - use with care
|
||||
|
||||
function New-RandomHex($ByteCount) {
|
||||
$bytes = [byte[]]::new($ByteCount)
|
||||
$rng = [System.Security.Cryptography.RandomNumberGenerator]::Create()
|
||||
try {
|
||||
$rng.GetBytes($bytes)
|
||||
return -join ($bytes | ForEach-Object { $_.ToString("x2") })
|
||||
} finally {
|
||||
$rng.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
function Test-EnvValue($Name) {
|
||||
return [bool](Select-String -Path ".env" -Pattern "^$Name=.+" -Quiet)
|
||||
}
|
||||
|
||||
function Ensure-JwtEnv {
|
||||
if ((Test-EnvValue "JWT_SECRET_KEY") -and (Test-EnvValue "YUXI_INSTANCE_ID")) {
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "JWT security settings are missing in .env." -ForegroundColor Yellow
|
||||
$JWT_SECRET_KEY = Read-Host "Please enter your JWT_SECRET_KEY (press Enter to auto-generate)"
|
||||
if ([string]::IsNullOrEmpty($JWT_SECRET_KEY)) {
|
||||
$JWT_SECRET_KEY = New-RandomHex 32
|
||||
Write-Host "Generated JWT_SECRET_KEY and saved it to .env." -ForegroundColor Green
|
||||
}
|
||||
|
||||
$YUXI_INSTANCE_ID = Read-Host "Please enter your YUXI_INSTANCE_ID (press Enter to auto-generate)"
|
||||
if ([string]::IsNullOrEmpty($YUXI_INSTANCE_ID)) {
|
||||
$YUXI_INSTANCE_ID = "instance-$(New-RandomHex 8)"
|
||||
Write-Host "Generated YUXI_INSTANCE_ID and saved it to .env." -ForegroundColor Green
|
||||
}
|
||||
|
||||
@"
|
||||
|
||||
# JWT security settings
|
||||
JWT_SECRET_KEY=$JWT_SECRET_KEY
|
||||
YUXI_INSTANCE_ID=$YUXI_INSTANCE_ID
|
||||
"@ | Add-Content -Path ".env" -Encoding UTF8
|
||||
}
|
||||
|
||||
Write-Host "🚀 Initializing Yuxi project..." -ForegroundColor Cyan
|
||||
Write-Host "==================================" -ForegroundColor Cyan
|
||||
|
||||
# Check if .env file exists
|
||||
if (Test-Path ".env") {
|
||||
Write-Host "✅ .env file already exists. Skipping environment setup." -ForegroundColor Green
|
||||
Ensure-JwtEnv
|
||||
} else {
|
||||
Write-Host "📝 .env file not found. Let's set up your environment variables." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
# Get SILICONFLOW_API_KEY
|
||||
Write-Host "🔑 SiliconFlow API Key required" -ForegroundColor Yellow
|
||||
Write-Host "Get your API key from: https://cloud.siliconflow.cn/i/Eo5yTHGJ" -ForegroundColor Blue
|
||||
Write-Host "Note: Press Ctrl+C at any time to cancel" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
do {
|
||||
$apiKey = Read-Host "Please enter your SILICONFLOW_API_KEY"
|
||||
if ([string]::IsNullOrEmpty($apiKey)) {
|
||||
Write-Host "❌ API Key cannot be empty. Please try again." -ForegroundColor Red
|
||||
}
|
||||
} while ([string]::IsNullOrEmpty($apiKey))
|
||||
|
||||
# Get TAVILY_API_KEY (optional)
|
||||
Write-Host ""
|
||||
Write-Host "🔍 Tavily API Key (optional) - for search service" -ForegroundColor Yellow
|
||||
Write-Host "Get your API key from: https://app.tavily.com/" -ForegroundColor Blue
|
||||
|
||||
$TAVILY_API_KEY = Read-Host "Please enter your TAVILY_API_KEY (press Enter to skip)"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "JWT security settings" -ForegroundColor Yellow
|
||||
$JWT_SECRET_KEY = Read-Host "Please enter your JWT_SECRET_KEY (press Enter to auto-generate)"
|
||||
if ([string]::IsNullOrEmpty($JWT_SECRET_KEY)) {
|
||||
$JWT_SECRET_KEY = New-RandomHex 32
|
||||
Write-Host "Generated JWT_SECRET_KEY and saved it to .env." -ForegroundColor Green
|
||||
}
|
||||
|
||||
$YUXI_INSTANCE_ID = Read-Host "Please enter your YUXI_INSTANCE_ID (press Enter to auto-generate)"
|
||||
if ([string]::IsNullOrEmpty($YUXI_INSTANCE_ID)) {
|
||||
$YUXI_INSTANCE_ID = "instance-$(New-RandomHex 8)"
|
||||
Write-Host "Generated YUXI_INSTANCE_ID and saved it to .env." -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Create .env file
|
||||
$envContent = @"
|
||||
# SiliconFlow API Key (required)
|
||||
SILICONFLOW_API_KEY=$apiKey
|
||||
|
||||
# Tavily API Key (optional - for search service)
|
||||
"@
|
||||
|
||||
if (-not [string]::IsNullOrEmpty($TAVILY_API_KEY)) {
|
||||
$envContent += "`nTAVILY_API_KEY=$TAVILY_API_KEY"
|
||||
}
|
||||
|
||||
$envContent += @"
|
||||
|
||||
# JWT security settings
|
||||
JWT_SECRET_KEY=$JWT_SECRET_KEY
|
||||
YUXI_INSTANCE_ID=$YUXI_INSTANCE_ID
|
||||
"@
|
||||
|
||||
$envContent | Out-File -FilePath ".env" -Encoding UTF8
|
||||
Write-Host "✅ .env file created successfully!" -ForegroundColor Green
|
||||
|
||||
# Clear the variables from memory
|
||||
Remove-Variable -Name "apiKey" -ErrorAction SilentlyContinue
|
||||
Remove-Variable -Name "TAVILY_API_KEY" -ErrorAction SilentlyContinue
|
||||
Remove-Variable -Name "JWT_SECRET_KEY" -ErrorAction SilentlyContinue
|
||||
Remove-Variable -Name "YUXI_INSTANCE_ID" -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "📦 Pulling Docker images..." -ForegroundColor Cyan
|
||||
Write-Host "=========================" -ForegroundColor Cyan
|
||||
|
||||
# List of Docker images to pull
|
||||
$images = @(
|
||||
"python:3.13-slim",
|
||||
"node:24-slim",
|
||||
"node:24-alpine",
|
||||
"milvusdb/milvus:v2.5.6",
|
||||
"neo4j:5.26",
|
||||
"minio/minio:RELEASE.2023-03-20T20-16-18Z",
|
||||
"ghcr.io/astral-sh/uv:0.11.26",
|
||||
"nginx:alpine",
|
||||
"quay.io/coreos/etcd:v3.5.5",
|
||||
"postgres:16",
|
||||
"redis:7-alpine"
|
||||
)
|
||||
|
||||
# Pull each image
|
||||
foreach ($image in $images) {
|
||||
Write-Host "🔄 Pulling ${image}..." -ForegroundColor Yellow
|
||||
try {
|
||||
& scripts/pull_image.ps1 $image
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "✅ Successfully pulled ${image}" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ Failed to pull ${image}" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} catch {
|
||||
Write-Host "❌ Error pulling ${image}: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
$sandboxImage = "enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest"
|
||||
Write-Host "🔄 Pulling ${sandboxImage}..." -ForegroundColor Yellow
|
||||
docker pull $sandboxImage
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host "✅ Successfully pulled ${sandboxImage}" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ Failed to pull ${sandboxImage}" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "🎉 Initialization complete!" -ForegroundColor Green
|
||||
Write-Host "==========================" -ForegroundColor Green
|
||||
Write-Host "You can now run: docker compose up -d --build" -ForegroundColor Cyan
|
||||
Write-Host "This will start all services in development mode with hot-reload enabled." -ForegroundColor Cyan
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Yuxi Initialization Script for Bash/Linux/macOS
|
||||
# This script helps set up the environment for the Yuxi project
|
||||
|
||||
set -e
|
||||
|
||||
generate_hex() {
|
||||
local length="$1"
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
openssl rand -hex "$length"
|
||||
else
|
||||
tr -dc 'a-f0-9' < /dev/urandom | head -c $((length * 2))
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_jwt_env() {
|
||||
if grep -Eq '^JWT_SECRET_KEY=.+' .env && grep -Eq '^YUXI_INSTANCE_ID=.+' .env; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "JWT security settings are missing in .env."
|
||||
read -s -p "Please enter your JWT_SECRET_KEY (press Enter to auto-generate): " JWT_SECRET_KEY
|
||||
echo ""
|
||||
if [ -z "$JWT_SECRET_KEY" ]; then
|
||||
JWT_SECRET_KEY=$(generate_hex 32)
|
||||
echo "Generated JWT_SECRET_KEY and saved it to .env."
|
||||
fi
|
||||
|
||||
read -p "Please enter your YUXI_INSTANCE_ID (press Enter to auto-generate): " YUXI_INSTANCE_ID
|
||||
if [ -z "$YUXI_INSTANCE_ID" ]; then
|
||||
YUXI_INSTANCE_ID="instance-$(generate_hex 8)"
|
||||
echo "Generated YUXI_INSTANCE_ID and saved it to .env."
|
||||
fi
|
||||
|
||||
cat >> .env << EOF
|
||||
|
||||
# JWT security settings
|
||||
JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
||||
YUXI_INSTANCE_ID=${YUXI_INSTANCE_ID}
|
||||
EOF
|
||||
}
|
||||
|
||||
echo "🚀 Initializing Yuxi project..."
|
||||
echo "=================================="
|
||||
|
||||
# Check if .env file exists
|
||||
if [ -f ".env" ]; then
|
||||
echo "✅ .env file already exists. Skipping environment setup."
|
||||
ensure_jwt_env
|
||||
else
|
||||
echo "📝 .env file not found. Let's set up your environment variables."
|
||||
echo ""
|
||||
|
||||
# Get SILICONFLOW_API_KEY
|
||||
echo "🔑 SiliconFlow API Key required"
|
||||
echo "Get your API key from: https://cloud.siliconflow.cn/i/Eo5yTHGJ"
|
||||
while true; do
|
||||
read -s -p "Please enter your SILICONFLOW_API_KEY: " SILICONFLOW_API_KEY
|
||||
echo ""
|
||||
if [ -z "$SILICONFLOW_API_KEY" ]; then
|
||||
echo "❌ API Key cannot be empty. Please try again."
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Get TAVILY_API_KEY (optional)
|
||||
echo ""
|
||||
echo "🔍 Tavily API Key (optional) - for search service"
|
||||
echo "Get your API key from: https://app.tavily.com/"
|
||||
read -p "Please enter your TAVILY_API_KEY (press Enter to skip): " TAVILY_API_KEY
|
||||
|
||||
echo ""
|
||||
echo "JWT security settings"
|
||||
read -s -p "Please enter your JWT_SECRET_KEY (press Enter to auto-generate): " JWT_SECRET_KEY
|
||||
echo ""
|
||||
if [ -z "$JWT_SECRET_KEY" ]; then
|
||||
JWT_SECRET_KEY=$(generate_hex 32)
|
||||
echo "Generated JWT_SECRET_KEY and saved it to .env."
|
||||
fi
|
||||
|
||||
read -p "Please enter your YUXI_INSTANCE_ID (press Enter to auto-generate): " YUXI_INSTANCE_ID
|
||||
if [ -z "$YUXI_INSTANCE_ID" ]; then
|
||||
YUXI_INSTANCE_ID="instance-$(generate_hex 8)"
|
||||
echo "Generated YUXI_INSTANCE_ID and saved it to .env."
|
||||
fi
|
||||
|
||||
# Create .env file
|
||||
cat > .env << EOF
|
||||
# SiliconFlow API Key (required)
|
||||
SILICONFLOW_API_KEY=${SILICONFLOW_API_KEY}
|
||||
|
||||
# Tavily API Key (optional - for search service)
|
||||
EOF
|
||||
|
||||
if [ -n "$TAVILY_API_KEY" ]; then
|
||||
echo "TAVILY_API_KEY=${TAVILY_API_KEY}" >> .env
|
||||
fi
|
||||
|
||||
cat >> .env << EOF
|
||||
|
||||
# JWT security settings
|
||||
JWT_SECRET_KEY=${JWT_SECRET_KEY}
|
||||
YUXI_INSTANCE_ID=${YUXI_INSTANCE_ID}
|
||||
EOF
|
||||
|
||||
echo "✅ .env file created successfully!"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📦 Pulling Docker images..."
|
||||
echo "========================="
|
||||
|
||||
# List of Docker images to pull
|
||||
images=(
|
||||
"python:3.13-slim"
|
||||
"node:24-slim"
|
||||
"node:24-alpine"
|
||||
"milvusdb/milvus:v2.5.6"
|
||||
"neo4j:5.26"
|
||||
"minio/minio:RELEASE.2023-03-20T20-16-18Z"
|
||||
"ghcr.io/astral-sh/uv:0.11.26"
|
||||
"nginx:alpine"
|
||||
"quay.io/coreos/etcd:v3.5.5"
|
||||
"postgres:16"
|
||||
"redis:7-alpine"
|
||||
)
|
||||
|
||||
# Pull each image
|
||||
for image in "${images[@]}"; do
|
||||
echo "🔄 Pulling ${image}..."
|
||||
if bash scripts/pull_image.sh "$image"; then
|
||||
echo "✅ Successfully pulled ${image}"
|
||||
else
|
||||
echo "❌ Failed to pull ${image}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "🔄 Pulling enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest..."
|
||||
docker pull enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest
|
||||
echo "✅ Successfully pulled enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest"
|
||||
|
||||
echo ""
|
||||
echo "🎉 Initialization complete!"
|
||||
echo "=========================="
|
||||
echo "You can now run: docker compose up -d --build"
|
||||
echo "This will start all services in development mode with hot-reload enabled."
|
||||
@@ -0,0 +1,56 @@
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$ImageTag
|
||||
)
|
||||
|
||||
# 当命令失败时,立即退出脚本
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "Pulling image: $ImageTag" -ForegroundColor Green
|
||||
|
||||
# 计算斜杠数量来确定镜像格式
|
||||
$slashCount = ($ImageTag -split '/' | Measure-Object).Count - 1
|
||||
|
||||
# 根据镜像格式设置镜像 URL
|
||||
switch ($slashCount) {
|
||||
0 {
|
||||
# 无前缀 (例如: python:3.13-slim)
|
||||
$mirrorUrl = "m.daocloud.io/docker.io/library"
|
||||
Write-Host "Image format: Official image (no prefix)" -ForegroundColor Cyan
|
||||
}
|
||||
1 {
|
||||
# 一个前缀 (例如: milvusdb/milvus:latest)
|
||||
$mirrorUrl = "m.daocloud.io/docker.io"
|
||||
Write-Host "Image format: Hub repository (one prefix)" -ForegroundColor Cyan
|
||||
}
|
||||
default {
|
||||
# 两个或更多前缀 (例如: quay.io/coreos/etcd:v3.5.5)
|
||||
$mirrorUrl = "m.daocloud.io"
|
||||
Write-Host "Image format: Third-party registry (multiple prefixes)" -ForegroundColor Cyan
|
||||
}
|
||||
}
|
||||
|
||||
$fullMirrorUrl = "$mirrorUrl/$ImageTag"
|
||||
Write-Host "Mirror URL: $fullMirrorUrl" -ForegroundColor Yellow
|
||||
|
||||
try {
|
||||
# 从镜像加速器拉取镜像
|
||||
Write-Host "Step 1: Pulling image from mirror..." -ForegroundColor Blue
|
||||
docker pull $fullMirrorUrl
|
||||
|
||||
# 重新标记为原始名称
|
||||
Write-Host "Step 2: Tagging image with original name..." -ForegroundColor Blue
|
||||
docker tag $fullMirrorUrl $ImageTag
|
||||
|
||||
# 删除镜像加速器标签
|
||||
Write-Host "Step 3: Removing mirror tag..." -ForegroundColor Blue
|
||||
docker rmi $fullMirrorUrl
|
||||
|
||||
Write-Host "`nProcess completed successfully!" -ForegroundColor Green
|
||||
Write-Host "`nCurrent Docker images:" -ForegroundColor Yellow
|
||||
docker images
|
||||
|
||||
} catch {
|
||||
Write-Host "`nError occurred: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 <image:tag>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set -e # 当命令失败时,立即退出脚本
|
||||
|
||||
IMAGE_TAG=$1
|
||||
|
||||
# Count the number of slashes to determine the image format
|
||||
SLASH_COUNT=$(echo $IMAGE_TAG | tr -cd '/' | wc -c)
|
||||
|
||||
# Set mirror URL based on image format
|
||||
if [ $SLASH_COUNT -eq 0 ]; then
|
||||
# No prefix (e.g., python:3.13-slim)
|
||||
MIRROR_URL="m.daocloud.io/docker.io/library"
|
||||
elif [ $SLASH_COUNT -eq 1 ]; then
|
||||
# One prefix (e.g., milvusdb/milvus:latest)
|
||||
MIRROR_URL="m.daocloud.io/docker.io"
|
||||
else
|
||||
# Two or more prefixes (e.g., quay.io/coreos/etcd:v3.5.5)
|
||||
MIRROR_URL="m.daocloud.io"
|
||||
fi
|
||||
|
||||
# Pull image from mirror
|
||||
echo "Pulling image from mirror: $MIRROR_URL/$IMAGE_TAG"
|
||||
docker pull $MIRROR_URL/$IMAGE_TAG
|
||||
|
||||
# Tag image with original name
|
||||
docker tag $MIRROR_URL/$IMAGE_TAG $IMAGE_TAG
|
||||
|
||||
# Remove mirror image
|
||||
docker rmi $MIRROR_URL/$IMAGE_TAG
|
||||
|
||||
docker images
|
||||
|
||||
echo "Process completed successfully!"
|
||||
Reference in New Issue
Block a user