feat: add track point
This commit is contained in:
BIN
app.cloud/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2
Normal file
BIN
app.cloud/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_AMS-Regular-DMm9YOAa.woff
Normal file
BIN
app.cloud/assets/KaTeX_AMS-Regular-DMm9YOAa.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_AMS-Regular-DRggAlZN.ttf
Normal file
BIN
app.cloud/assets/KaTeX_AMS-Regular-DRggAlZN.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-CB_wures.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-CB_wures.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff
Normal file
BIN
app.cloud/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Bold-Cx986IdX.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Main-Bold-Cx986IdX.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Bold-Jm3AIy58.woff
Normal file
BIN
app.cloud/assets/KaTeX_Main-Bold-Jm3AIy58.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Bold-waoOVXN0.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Main-Bold-waoOVXN0.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff
Normal file
BIN
app.cloud/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Italic-3WenGoN9.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Main-Italic-3WenGoN9.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Italic-BMLOBm91.woff
Normal file
BIN
app.cloud/assets/KaTeX_Main-Italic-BMLOBm91.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Regular-B22Nviop.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Main-Regular-B22Nviop.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Regular-Dr94JaBh.woff
Normal file
BIN
app.cloud/assets/KaTeX_Main-Regular-Dr94JaBh.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Main-Regular-ypZvNtVU.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Main-Regular-ypZvNtVU.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff
Normal file
BIN
app.cloud/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-Italic-DA0__PXp.woff
Normal file
BIN
app.cloud/assets/KaTeX_Math-Italic-DA0__PXp.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-Italic-flOr_0UB.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Math-Italic-flOr_0UB.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Math-Italic-t53AETM-.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Math-Italic-t53AETM-.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2
Normal file
BIN
app.cloud/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Script-Regular-C5JkGWo-.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Script-Regular-C5JkGWo-.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Script-Regular-D3wIWfF6.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Script-Regular-D3wIWfF6.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Script-Regular-D5yQViql.woff
Normal file
BIN
app.cloud/assets/KaTeX_Script-Regular-D5yQViql.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size1-Regular-C195tn64.woff
Normal file
BIN
app.cloud/assets/KaTeX_Size1-Regular-C195tn64.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size2-Regular-oD1tc_U0.woff
Normal file
BIN
app.cloud/assets/KaTeX_Size2-Regular-oD1tc_U0.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size3-Regular-CTq5MqoE.woff
Normal file
BIN
app.cloud/assets/KaTeX_Size3-Regular-CTq5MqoE.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size4-Regular-BF-4gkZK.woff
Normal file
BIN
app.cloud/assets/KaTeX_Size4-Regular-BF-4gkZK.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size4-Regular-DWFBv043.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Size4-Regular-DWFBv043.ttf
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff
Normal file
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2
Normal file
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2
Normal file
Binary file not shown.
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf
Normal file
BIN
app.cloud/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf
Normal file
Binary file not shown.
1
app.cloud/assets/index-DKZ56yfB.css
Normal file
1
app.cloud/assets/index-DKZ56yfB.css
Normal file
File diff suppressed because one or more lines are too long
191
app.cloud/assets/index-NjWMZQkP.js
Normal file
191
app.cloud/assets/index-NjWMZQkP.js
Normal file
File diff suppressed because one or more lines are too long
261
app.cloud/assets/vendor-katex-p018AHG0.js
Normal file
261
app.cloud/assets/vendor-katex-p018AHG0.js
Normal file
File diff suppressed because one or more lines are too long
28
app.cloud/assets/vendor-markdown-C0b4qDwm.js
Normal file
28
app.cloud/assets/vendor-markdown-C0b4qDwm.js
Normal file
File diff suppressed because one or more lines are too long
32
app.cloud/assets/vendor-react-C6WG4Va-.js
Normal file
32
app.cloud/assets/vendor-react-C6WG4Va-.js
Normal file
File diff suppressed because one or more lines are too long
1
app.cloud/assets/vendor-supabase-l0sNRNKZ.js
Normal file
1
app.cloud/assets/vendor-supabase-l0sNRNKZ.js
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
44
app.cloud/index.html
Normal file
44
app.cloud/index.html
Normal file
@@ -0,0 +1,44 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>⚡️ TexPixel - 公式识别工具</title>
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<meta name="description" content="在线公式识别工具,支持印刷体和手写体数学公式识别,快速准确地将图片中的数学公式转换为可编辑文本。" />
|
||||
<meta name="keywords"
|
||||
content="公式识别,数学公式,OCR,手写公式识别,印刷体识别,AI识别,数学工具,免费,handwriting,formula,recognition,ocr,handwriting,recognition,math,handwriting,free" />
|
||||
<meta name="author" content="TexPixel Team" />
|
||||
<meta name="robots" content="index, follow" />
|
||||
|
||||
<!-- Open Graph Meta Tags -->
|
||||
<meta property="og:title" content="TexPixel - 公式识别工具" />
|
||||
<meta property="og:description" content="在线公式识别工具,支持印刷体和手写体数学公式识别,快速准确地将图片中的数学公式转换为可编辑文本。" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://texpixel.com/" />
|
||||
<meta property="og:image" content="https://cdn.texpixel.com/public/logo.png?x-oss-process=image/resize,w_600" />
|
||||
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="TexPixel - 公式识别工具" />
|
||||
<meta name="twitter:description" content="在线公式识别工具,支持印刷体和手写体数学公式识别。" />
|
||||
<meta name="twitter:image" content="https://cdn.texpixel.com/public/logo.png?x-oss-process=image/resize,w_600" />
|
||||
|
||||
<!-- baidu -->
|
||||
<meta name="baidu-site-verification" content="codeva-8zU93DeGgH" />
|
||||
|
||||
<script type="module" crossorigin src="/assets/index-NjWMZQkP.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-react-C6WG4Va-.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-katex-p018AHG0.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/vendor-markdown-C0b4qDwm.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DKZ56yfB.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
203
deploy_dev.sh
Executable file
203
deploy_dev.sh
Executable file
@@ -0,0 +1,203 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Document AI Frontend 部署脚本
|
||||
# 功能:构建项目并部署到 ubuntu 服务器
|
||||
|
||||
set -e # 遇到错误立即退出
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 服务器配置
|
||||
ubuntu_HOST="ubuntu"
|
||||
DEPLOY_PATH="/var/www"
|
||||
DEPLOY_NAME="app.cloud"
|
||||
# Sudo 密码(如果需要,建议配置无密码 sudo 更安全)
|
||||
# 配置无密码 sudo: 在服务器上运行: echo "username ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/username
|
||||
SUDO_PASSWORD="1231"
|
||||
|
||||
# 打印带颜色的消息
|
||||
print_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 检查命令是否存在
|
||||
check_command() {
|
||||
if ! command -v $1 &> /dev/null; then
|
||||
print_error "$1 命令未找到,请先安装"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 部署到服务器
|
||||
deploy_to_server() {
|
||||
local server=$1
|
||||
print_info "开始部署到 ${server}..."
|
||||
|
||||
# 上传构建产物(app.cloud 目录)
|
||||
print_info "上传 ${DEPLOY_NAME} 目录到 ${server}..."
|
||||
scp_output=$(scp -r ${DEPLOY_NAME} ${server}:~ 2>&1)
|
||||
scp_exit_code=$?
|
||||
if [ $scp_exit_code -eq 0 ]; then
|
||||
print_success "文件上传成功"
|
||||
else
|
||||
print_error "文件上传失败,请检查 SSH 连接和权限"
|
||||
echo "$scp_output" | sed 's/^/ /'
|
||||
return 1
|
||||
fi
|
||||
|
||||
# SSH 执行部署操作
|
||||
print_info "在 ${server} 上执行部署操作..."
|
||||
print_info "部署路径: ${DEPLOY_PATH}/${DEPLOY_NAME}"
|
||||
# 注意:密码通过环境变量传递,避免在命令行中暴露
|
||||
ssh_output=$(SSH_SUDO_PASSWORD="${SUDO_PASSWORD}" ssh ${server} bash << SSH_EOF
|
||||
set -e
|
||||
DEPLOY_PATH="${DEPLOY_PATH}"
|
||||
DEPLOY_NAME="${DEPLOY_NAME}"
|
||||
SUDO_PASSWORD="\${SSH_SUDO_PASSWORD}"
|
||||
|
||||
# 检查部署目录是否存在
|
||||
if [ ! -d "\${DEPLOY_PATH}" ]; then
|
||||
echo "错误:部署目录 \${DEPLOY_PATH} 不存在,请检查路径是否正确"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查是否有权限写入(尝试创建测试文件)
|
||||
if ! touch "\${DEPLOY_PATH}/.deploy_test" 2>/dev/null; then
|
||||
echo "提示:没有直接写入权限,将使用 sudo 执行操作"
|
||||
USE_SUDO=1
|
||||
else
|
||||
rm -f "\${DEPLOY_PATH}/.deploy_test"
|
||||
USE_SUDO=0
|
||||
fi
|
||||
|
||||
# 备份旧版本(如果存在)
|
||||
if [ -d "\${DEPLOY_PATH}/\${DEPLOY_NAME}" ]; then
|
||||
echo "备份旧版本..."
|
||||
if [ "\$USE_SUDO" = "1" ]; then
|
||||
echo "\${SUDO_PASSWORD}" | sudo -S rm -rf "\${DEPLOY_PATH}/\${DEPLOY_NAME}_bak" 2>/dev/null || true
|
||||
echo "\${SUDO_PASSWORD}" | sudo -S mv "\${DEPLOY_PATH}/\${DEPLOY_NAME}" "\${DEPLOY_PATH}/\${DEPLOY_NAME}_bak" || { echo "错误:备份失败,权限不足"; exit 1; }
|
||||
else
|
||||
rm -rf "\${DEPLOY_PATH}/\${DEPLOY_NAME}_bak" 2>/dev/null || true
|
||||
mv "\${DEPLOY_PATH}/\${DEPLOY_NAME}" "\${DEPLOY_PATH}/\${DEPLOY_NAME}_bak" || { echo "错误:备份失败"; exit 1; }
|
||||
fi
|
||||
fi
|
||||
|
||||
# 移动新版本到部署目录(覆盖现有目录)
|
||||
if [ -d ~/\${DEPLOY_NAME} ]; then
|
||||
echo "移动新版本到部署目录..."
|
||||
if [ "\$USE_SUDO" = "1" ]; then
|
||||
echo "\${SUDO_PASSWORD}" | sudo -S mv ~/\${DEPLOY_NAME} "\${DEPLOY_PATH}/" || { echo "错误:移动文件失败,权限不足"; exit 1; }
|
||||
else
|
||||
mv ~/\${DEPLOY_NAME} "\${DEPLOY_PATH}/" || { echo "错误:移动文件失败"; exit 1; }
|
||||
fi
|
||||
echo "部署完成!"
|
||||
else
|
||||
echo "错误:找不到 ~/\${DEPLOY_NAME} 目录"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 重新加载 nginx(如果配置了)
|
||||
if command -v nginx &> /dev/null; then
|
||||
echo "重新加载 nginx..."
|
||||
echo "\${SUDO_PASSWORD}" | sudo -S nginx -t && echo "\${SUDO_PASSWORD}" | sudo -S nginx -s reload || echo "警告:nginx 重新加载失败,请手动检查"
|
||||
fi
|
||||
SSH_EOF
|
||||
)
|
||||
|
||||
ssh_exit_code=$?
|
||||
|
||||
# 显示 SSH 输出
|
||||
if [ -n "$ssh_output" ]; then
|
||||
echo "$ssh_output" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
if [ $ssh_exit_code -eq 0 ]; then
|
||||
print_success "${server} 部署成功!"
|
||||
else
|
||||
print_error "${server} 部署失败!"
|
||||
print_error "请检查:"
|
||||
print_error " 1. SSH 连接是否正常"
|
||||
print_error " 2. 部署目录 ${DEPLOY_PATH} 是否存在"
|
||||
print_error " 3. 是否有 sudo 权限(如果需要)"
|
||||
print_error " 4. 上传的文件 ~/${DEPLOY_NAME} 是否存在"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
print_info "=========================================="
|
||||
print_info "Document AI Frontend 部署脚本"
|
||||
print_info "=========================================="
|
||||
echo ""
|
||||
|
||||
# 检查必要的命令
|
||||
print_info "检查环境..."
|
||||
check_command "npm"
|
||||
check_command "scp"
|
||||
check_command "ssh"
|
||||
|
||||
# 步骤1: 构建项目
|
||||
print_info "步骤 1/2: 构建项目(测试环境)..."
|
||||
if npm run build:dev; then
|
||||
print_success "构建完成!"
|
||||
else
|
||||
print_error "构建失败!"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 检查 dist 目录是否存在
|
||||
if [ ! -d "dist" ]; then
|
||||
print_error "dist 目录不存在,构建可能失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 重命名 dist 为 app.cloud
|
||||
print_info "重命名 dist 为 ${DEPLOY_NAME}..."
|
||||
if [ -d "${DEPLOY_NAME}" ]; then
|
||||
rm -rf "${DEPLOY_NAME}"
|
||||
fi
|
||||
mv dist "${DEPLOY_NAME}"
|
||||
print_success "重命名完成"
|
||||
echo ""
|
||||
|
||||
# 步骤2: 部署到 ubuntu
|
||||
print_info "步骤 2/2: 部署到 ubuntu..."
|
||||
if deploy_to_server ${ubuntu_HOST}; then
|
||||
print_success "ubuntu 部署完成"
|
||||
else
|
||||
print_error "ubuntu 部署失败"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 完成
|
||||
print_info "清理临时文件..."
|
||||
# 可以选择是否删除本地的 app.cloud 目录
|
||||
# rm -rf ${DEPLOY_NAME}
|
||||
|
||||
print_success "=========================================="
|
||||
print_success "部署完成!"
|
||||
print_success "=========================================="
|
||||
}
|
||||
|
||||
# 运行主函数
|
||||
main
|
||||
@@ -106,8 +106,8 @@ main() {
|
||||
check_command "ssh"
|
||||
|
||||
# 步骤1: 构建项目
|
||||
print_info "步骤 1/2: 构建项目..."
|
||||
if npm run build; then
|
||||
print_info "步骤 1/2: 构建项目(生产环境)..."
|
||||
if npm run build:prod; then
|
||||
print_success "构建完成!"
|
||||
else
|
||||
print_error "构建失败!"
|
||||
@@ -5,6 +5,7 @@ import { convertMathmlToOmml, wrapOmmlForClipboard } from '../lib/ommlConverter'
|
||||
import { generateImageFromElement, copyImageToClipboard, downloadImage } from '../lib/imageGenerator';
|
||||
import { API_BASE_URL } from '../config/env';
|
||||
import { tokenManager } from '../lib/api';
|
||||
import { trackExportEvent } from '../lib/analytics';
|
||||
import { useLanguage } from '../contexts/LanguageContext';
|
||||
|
||||
interface ExportSidebarProps {
|
||||
@@ -24,6 +25,87 @@ interface ExportOption {
|
||||
extension?: string;
|
||||
}
|
||||
|
||||
// Helper function to add mml: prefix to MathML
|
||||
const addMMLPrefix = (mathml: string): string | null => {
|
||||
try {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(mathml, 'application/xml');
|
||||
|
||||
// Check for parse errors
|
||||
const parseError = xmlDoc.getElementsByTagName("parsererror");
|
||||
if (parseError.length > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create new document with mml namespace
|
||||
const newDoc = document.implementation.createDocument(
|
||||
'http://www.w3.org/1998/Math/MathML',
|
||||
'mml:math',
|
||||
null
|
||||
);
|
||||
|
||||
const newMathElement = newDoc.documentElement;
|
||||
|
||||
// Copy display attribute if present
|
||||
const displayAttr = xmlDoc.documentElement.getAttribute('display');
|
||||
if (displayAttr) {
|
||||
newMathElement.setAttribute('display', displayAttr);
|
||||
}
|
||||
|
||||
// Recursive function to process nodes
|
||||
const processNode = (node: Node, newParent: Element) => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE) {
|
||||
const element = node as Element;
|
||||
// Create new element with mml: prefix in the target document
|
||||
const newElement = newDoc.createElementNS(
|
||||
'http://www.w3.org/1998/Math/MathML',
|
||||
'mml:' + element.localName
|
||||
);
|
||||
|
||||
// Copy attributes
|
||||
for (let i = 0; i < element.attributes.length; i++) {
|
||||
const attr = element.attributes[i];
|
||||
// Skip xmlns attributes as we handle them explicitly
|
||||
if (attr.name.startsWith('xmlns')) continue;
|
||||
|
||||
newElement.setAttributeNS(
|
||||
attr.namespaceURI,
|
||||
attr.name,
|
||||
attr.value
|
||||
);
|
||||
}
|
||||
|
||||
// Process children
|
||||
Array.from(element.childNodes).forEach(child => {
|
||||
processNode(child, newElement);
|
||||
});
|
||||
|
||||
newParent.appendChild(newElement);
|
||||
} else if (node.nodeType === Node.TEXT_NODE) {
|
||||
newParent.appendChild(newDoc.createTextNode(node.nodeValue || ''));
|
||||
}
|
||||
};
|
||||
|
||||
// Process all children of the root math element
|
||||
Array.from(xmlDoc.documentElement.childNodes).forEach(child => {
|
||||
processNode(child, newMathElement);
|
||||
});
|
||||
|
||||
// Serialize
|
||||
const serializer = new XMLSerializer();
|
||||
let prefixedMathML = serializer.serializeToString(newDoc);
|
||||
|
||||
// Clean up xmlns
|
||||
prefixedMathML = prefixedMathML.replace(/ xmlns(:mml)?="[^"]*"/g, '');
|
||||
prefixedMathML = prefixedMathML.replace(/<mml:math>/, '<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML">');
|
||||
|
||||
return prefixedMathML;
|
||||
} catch (err) {
|
||||
console.error('Failed to process MathML:', err);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebarProps) {
|
||||
const { t } = useLanguage();
|
||||
const [copiedId, setCopiedId] = useState<string | null>(null);
|
||||
@@ -62,6 +144,12 @@ export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebar
|
||||
category: 'Code',
|
||||
getContent: (r) => r.mathml_content
|
||||
},
|
||||
{
|
||||
id: 'mathml_mml',
|
||||
label: 'MathML (MML)',
|
||||
category: 'Code',
|
||||
getContent: (r) => r.mathml_content ? addMMLPrefix(r.mathml_content) : null
|
||||
},
|
||||
{
|
||||
id: 'mathml_word',
|
||||
label: 'Word MathML',
|
||||
@@ -169,6 +257,15 @@ export default function ExportSidebar({ isOpen, onClose, result }: ExportSidebar
|
||||
};
|
||||
|
||||
const handleAction = async (option: ExportOption) => {
|
||||
// Analytics tracking
|
||||
if (result?.id) {
|
||||
trackExportEvent(
|
||||
result.id,
|
||||
option.id,
|
||||
exportOptions.map(o => o.id)
|
||||
);
|
||||
}
|
||||
|
||||
// Handle DOCX export via API
|
||||
if (option.id === 'docx') {
|
||||
await handleFileExport('docx');
|
||||
|
||||
63
src/lib/analytics.ts
Normal file
63
src/lib/analytics.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import http from './api';
|
||||
|
||||
interface AnalyticsPayload {
|
||||
task_no: string;
|
||||
event_name: string;
|
||||
properties: Record<string, any>;
|
||||
meta_data?: Record<string, any>;
|
||||
device_info: {
|
||||
ip: string;
|
||||
"use-agent": string;
|
||||
browser: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const trackExportEvent = (
|
||||
taskNo: string,
|
||||
selectedOption: string,
|
||||
availableOptions: string[]
|
||||
) => {
|
||||
try {
|
||||
const payload: AnalyticsPayload = {
|
||||
task_no: taskNo,
|
||||
event_name: 'export_selected_event',
|
||||
properties: {
|
||||
option: availableOptions,
|
||||
selected: selectedOption
|
||||
},
|
||||
meta_data: {
|
||||
task_no: taskNo
|
||||
},
|
||||
device_info: {
|
||||
ip: '',
|
||||
"use-agent": navigator.userAgent,
|
||||
browser: getBrowserName()
|
||||
}
|
||||
};
|
||||
|
||||
// Fire and forget - do not await
|
||||
http.post('/analytics/track', payload).catch(err => {
|
||||
// Silently ignore errors to not block business flow
|
||||
console.debug('Analytics tracking failed:', err);
|
||||
});
|
||||
} catch (error) {
|
||||
console.debug('Analytics error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
function getBrowserName(): string {
|
||||
const userAgent = navigator.userAgent;
|
||||
if (userAgent.match(/chrome|chromium|crios/i)) {
|
||||
return "Chrome";
|
||||
} else if (userAgent.match(/firefox|fxios/i)) {
|
||||
return "Firefox";
|
||||
} else if (userAgent.match(/safari/i)) {
|
||||
return "Safari";
|
||||
} else if (userAgent.match(/opr\//i)) {
|
||||
return "Opera";
|
||||
} else if (userAgent.match(/edg/i)) {
|
||||
return "Edge";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
43
src/main.tsx
43
src/main.tsx
@@ -5,12 +5,37 @@ import './index.css';
|
||||
import { AuthProvider } from './contexts/AuthContext';
|
||||
import { LanguageProvider } from './contexts/LanguageContext';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<AuthProvider>
|
||||
<LanguageProvider>
|
||||
<App />
|
||||
</LanguageProvider>
|
||||
</AuthProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
// 错误处理:捕获未处理的错误
|
||||
window.addEventListener('error', (event) => {
|
||||
console.error('Global error:', event.error);
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('Unhandled promise rejection:', event.reason);
|
||||
});
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
if (!rootElement) {
|
||||
throw new Error('Root element not found');
|
||||
}
|
||||
|
||||
try {
|
||||
createRoot(rootElement).render(
|
||||
<StrictMode>
|
||||
<AuthProvider>
|
||||
<LanguageProvider>
|
||||
<App />
|
||||
</LanguageProvider>
|
||||
</AuthProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to render app:', error);
|
||||
rootElement.innerHTML = `
|
||||
<div style="padding: 20px; font-family: sans-serif;">
|
||||
<h1>应用启动失败</h1>
|
||||
<p>错误信息: ${error instanceof Error ? error.message : String(error)}</p>
|
||||
<p>请检查浏览器控制台获取更多信息。</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user