Skip to content

Commit 92d7fe2

Browse files
aixierclaude
andcommitted
feat: 添加 HTTPS 部署脚本
- 新增 setup-https.sh 一键 HTTPS 配置脚本 - 支持自动配置 Nginx 反向代理 - 支持 Docker 容器端口自动调整(避免端口冲突) - 集成 SSL 证书配置 - 修复 cardExtractor 服务 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b93c3c5 commit 92d7fe2

2 files changed

Lines changed: 185 additions & 23 deletions

File tree

setup-https.sh

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/bin/bash
2+
3+
echo "================================"
4+
echo "配置 HTTPS 访问"
5+
echo "================================"
6+
7+
# 1. 安装 Nginx(如果未安装)
8+
if ! command -v nginx &> /dev/null; then
9+
echo "正在安装 Nginx..."
10+
apt update && apt install nginx -y
11+
else
12+
echo "Nginx 已安装"
13+
fi
14+
15+
# 2. 检查证书文件
16+
if [ ! -f "/etc/nginx/ssl/card.paitongai.com.pem" ]; then
17+
echo "错误: 证书文件不存在!"
18+
exit 1
19+
fi
20+
21+
if [ ! -f "/etc/nginx/ssl/card.paitongai.com.key" ]; then
22+
echo "错误: 密钥文件不存在!"
23+
exit 1
24+
fi
25+
26+
echo "证书文件检查通过"
27+
28+
# 3. 检查 80 端口占用情况
29+
echo "检查端口占用..."
30+
netstat -tlnp | grep :80
31+
32+
# 4. 停止旧容器并重新映射端口
33+
echo "重新配置 Docker 容器端口..."
34+
35+
# 删除已存在的容器(无论是否运行)
36+
if docker ps -a | grep -q ai_terminal_container; then
37+
echo "删除现有容器..."
38+
docker stop ai_terminal_container 2>/dev/null || true
39+
docker rm ai_terminal_container 2>/dev/null || true
40+
fi
41+
42+
# 启动容器,映射到 9080 端口(避免端口冲突)
43+
echo "启动容器到 9080 端口..."
44+
docker run -d \
45+
-p 9080:6009 \
46+
--name ai_terminal_container \
47+
--restart unless-stopped \
48+
-v /data/ai-terminal:/app/data \
49+
-v /logs/ai-terminal:/app/logs \
50+
registry.cn-hangzhou.aliyuncs.com/pentron_docker/ai-terminal-01:v4.8.27
51+
52+
# 等待容器启动
53+
echo "等待容器启动..."
54+
sleep 3
55+
56+
# 5. 创建 Nginx 配置
57+
echo "创建 Nginx 配置文件..."
58+
cat > /etc/nginx/sites-enabled/default << 'NGINX_EOF'
59+
server {
60+
listen 80;
61+
server_name card.paitongai.com;
62+
return 301 https://$server_name$request_uri;
63+
}
64+
65+
server {
66+
listen 443 ssl;
67+
server_name card.paitongai.com;
68+
69+
ssl_certificate /etc/nginx/ssl/card.paitongai.com.pem;
70+
ssl_certificate_key /etc/nginx/ssl/card.paitongai.com.key;
71+
72+
ssl_protocols TLSv1.2 TLSv1.3;
73+
ssl_ciphers HIGH:!aNULL:!MD5;
74+
75+
location / {
76+
proxy_pass http://localhost:9080;
77+
proxy_set_header Host $host;
78+
proxy_set_header X-Real-IP $remote_addr;
79+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
80+
proxy_set_header X-Forwarded-Proto $scheme;
81+
}
82+
83+
location /socket.io {
84+
proxy_pass http://localhost:9080;
85+
proxy_http_version 1.1;
86+
proxy_set_header Upgrade $http_upgrade;
87+
proxy_set_header Connection "upgrade";
88+
proxy_set_header Host $host;
89+
}
90+
91+
location /ws {
92+
proxy_pass http://localhost:9080;
93+
proxy_http_version 1.1;
94+
proxy_set_header Upgrade $http_upgrade;
95+
proxy_set_header Connection "upgrade";
96+
}
97+
}
98+
NGINX_EOF
99+
100+
# 6. 测试配置
101+
echo "测试 Nginx 配置..."
102+
nginx -t
103+
104+
if [ $? -ne 0 ]; then
105+
echo "配置文件有错误,请检查!"
106+
exit 1
107+
fi
108+
109+
# 7. 重启 Nginx
110+
echo "重启 Nginx..."
111+
systemctl restart nginx
112+
113+
# 8. 显示状态
114+
echo ""
115+
echo "Docker 容器状态:"
116+
docker ps | grep ai_terminal
117+
118+
echo ""
119+
echo "Nginx 状态:"
120+
systemctl status nginx --no-pager -l
121+
122+
echo ""
123+
echo "================================"
124+
echo "配置完成!"
125+
echo "================================"
126+
echo "Docker 容器端口: 9080"
127+
echo "Nginx HTTP: 80 (自动重定向到 HTTPS)"
128+
echo "Nginx HTTPS: 443"
129+
echo ""
130+
echo "现在可以访问: https://card.paitongai.com"
131+
echo ""
132+
echo "测试命令:"
133+
echo " curl https://card.paitongai.com/health"
134+
echo " curl -I http://card.paitongai.com (测试重定向)"

terminal-backend/src/services/cardExtractor.js

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class CardExtractorService {
2929
{ pattern: /^content-card$/, weight: 1.0 },
3030
{ pattern: /^cover-card$/, weight: 1.0 },
3131
{ pattern: /^card-container$/, weight: 0.9 },
32+
// 添加Pod2Post常用的卡片样式
33+
{ pattern: /\bstyle[1-5]\b/i, weight: 0.8 },
34+
{ pattern: /\bstyle\d+-\w+/i, weight: 0.8 },
3235
{ pattern: /\bcard\b/i, weight: 0.7 },
3336
{ pattern: /\bpanel\b/i, weight: 0.5 },
3437
{ pattern: /\btile\b/i, weight: 0.5 },
@@ -83,11 +86,11 @@ class CardExtractorService {
8386
browser = await this.launchBrowser();
8487
const page = await browser.newPage();
8588

86-
// 设置视口
89+
// 设置视口(降低像素比以减少资源消耗)
8790
await page.setViewport({
8891
width: 1920,
8992
height: 1080,
90-
deviceScaleFactor: 2
93+
deviceScaleFactor: 1 // 降低像素比
9194
});
9295

9396
// 注入字体样式以确保中文显示
@@ -101,8 +104,17 @@ class CardExtractorService {
101104
});
102105

103106
// 设置更长的默认导航超时(适应慢速OSS访问)
104-
page.setDefaultNavigationTimeout(180000); // 3分钟
105-
page.setDefaultTimeout(180000); // 3分钟
107+
page.setDefaultNavigationTimeout(300000); // 5分钟
108+
page.setDefaultTimeout(300000); // 5分钟
109+
110+
// 设置页面的额外HTTP头,可能有助于OSS资源加载
111+
await page.setExtraHTTPHeaders({
112+
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
113+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
114+
});
115+
116+
// 增加页面的资源加载设置
117+
await page.setBypassCSP(true); // 绕过CSP限制
106118

107119
// 监听页面的console输出
108120
page.on('console', msg => console.log('[Browser Console]:', msg.text()));
@@ -140,7 +152,7 @@ class CardExtractorService {
140152
}
141153

142154
let checkCount = 0;
143-
const maxChecks = 60; // 最多检查60次(60秒)
155+
const maxChecks = 120; // 增加到120次(120秒),给予充足的图片加载时间
144156

145157
const checkStatus = () => {
146158
checkCount++;
@@ -149,9 +161,10 @@ class CardExtractorService {
149161

150162
console.log(`Check ${checkCount}: ${currentLoaded} loaded, ${currentErrors} failed, ${totalImages - currentLoaded - currentErrors} pending`);
151163

152-
// 如果所有图片都处理完,或已加载50%,或检查次数达到上限
164+
// 如果所有图片都处理完,或已加载80%(提高要求确保完整加载),或检查次数达到上限
165+
// 对于OSS图片,等待大部分加载完成
153166
if (currentLoaded + currentErrors >= totalImages ||
154-
currentLoaded >= totalImages * 0.5 ||
167+
currentLoaded >= totalImages * 0.8 ||
155168
checkCount >= maxChecks) {
156169
resolve({ total: totalImages, loaded: currentLoaded, errors: currentErrors });
157170
} else {
@@ -163,12 +176,12 @@ class CardExtractorService {
163176
checkStatus();
164177
});
165178
}),
166-
// 强制超时保护(考虑到OSS图片加载慢,延长到60秒
179+
// 强制超时保护(增加到120秒,确保图片有足够时间加载
167180
new Promise((resolve) => {
168181
setTimeout(() => {
169-
console.log('[CardExtractor] Force timeout after 60 seconds');
182+
console.log('[CardExtractor] Force timeout after 120 seconds - proceeding with card detection');
170183
resolve({ total: -1, loaded: -1, errors: -1, timeout: true });
171-
}, 60000);
184+
}, 120000);
172185
})
173186
]);
174187

@@ -178,9 +191,9 @@ class CardExtractorService {
178191
console.log('[CardExtractor] Page load error:', err.message);
179192
}
180193

181-
// 等待一下确保渲染完成
194+
// 等待更长时间确保渲染完成(特别是对于包含大量图片的页面)
182195
console.log('[CardExtractor] Waiting for rendering...');
183-
await new Promise(resolve => setTimeout(resolve, 2000));
196+
await new Promise(resolve => setTimeout(resolve, 5000)); // 增加到5秒
184197
console.log('[CardExtractor] Rendering wait complete, proceeding to card detection...');
185198

186199
// 识别卡片
@@ -194,9 +207,9 @@ class CardExtractorService {
194207
console.log('[Card Detection] Starting simplified evaluation...');
195208
const candidates = [];
196209

197-
// 只查找最具体的选择器
198-
const cardElements = document.querySelectorAll('.card-container, .tutorial-card, .content-card');
199-
console.log(`[Card Detection] Found ${cardElements.length} card elements`);
210+
// 只查找最具体的选择器(包含Pod2Post的卡片类型)
211+
const cardElements = document.querySelectorAll('.card-container, .tutorial-card, .content-card, .cover-card');
212+
console.log(`[Card Detection] Found ${cardElements.length} card elements with primary selectors`);
200213

201214
// 如果没找到,尝试更通用的选择器
202215
let elements = Array.from(cardElements);
@@ -221,9 +234,12 @@ class CardExtractorService {
221234

222235
const rect = element.getBoundingClientRect();
223236

224-
// 跳过太小的元素
237+
// 跳过太小的元素(但保留合理的卡片尺寸)
225238
if (rect.width < 100 || rect.height < 100) {
226-
return;
239+
// 特殊处理:如果类名明确包含card,降低尺寸要求
240+
if (!/card|cover|content/i.test(element.className)) {
241+
return;
242+
}
227243
}
228244

229245
// 计算得分
@@ -252,7 +268,7 @@ class CardExtractorService {
252268
if (element.querySelector('img')) score += 5;
253269
if (element.querySelector('h1, h2, h3, h4, h5, h6')) score += 5;
254270

255-
if (score >= 30) { // 阈值
271+
if (score >= 25) { // 降低阈值,提高检测灵敏度
256272
candidates.push({
257273
score: score,
258274
className: className,
@@ -299,12 +315,12 @@ class CardExtractorService {
299315
console.log(`[Card Detection] Found ${filtered.length} cards after filtering`);
300316
return filtered;
301317
}, this.cardPatterns),
302-
// 30秒超时保护(给卡片检测更多时间
318+
// 120秒超时保护(给予充足时间处理复杂页面和大量图片
303319
new Promise((resolve) => {
304320
setTimeout(() => {
305-
console.log('[CardExtractor] Card detection timeout after 30 seconds');
321+
console.log('[CardExtractor] Card detection timeout after 120 seconds');
306322
resolve([]);
307-
}, 30000);
323+
}, 120000);
308324
})
309325
]);
310326
} catch (err) {
@@ -367,7 +383,7 @@ class CardExtractorService {
367383
async launchBrowser() {
368384
const options = {
369385
headless: 'new', // 使用新的 headless 模式
370-
protocolTimeout: 180000, // 增加协议超时到3分钟
386+
protocolTimeout: 300000, // 增加协议超时到5分钟
371387
args: [
372388
'--no-sandbox',
373389
'--disable-setuid-sandbox',
@@ -398,7 +414,19 @@ class CardExtractorService {
398414
'--memory-pressure-off',
399415
'--max_old_space_size=4096',
400416
'--max-http-connections=100',
401-
'--max-http-connections-per-host=20'
417+
'--max-http-connections-per-host=32', // 增加每个主机的连接数
418+
// 增加资源限制和网络优化,解决ERR_INSUFFICIENT_RESOURCES
419+
'--max-old-space-size=4096', // 增加V8堆内存到4GB
420+
'--js-flags=--max-old-space-size=4096',
421+
'--disable-features=IsolateOrigins', // 允许跨域
422+
'--disable-site-isolation-trials',
423+
'--disable-web-security', // 允许跨域资源
424+
'--allow-running-insecure-content',
425+
'--ignore-certificate-errors',
426+
'--ignore-certificate-errors-spki-list',
427+
'--enable-features=NetworkService,NetworkServiceInProcess',
428+
'--aggressive-cache-discard',
429+
'--disable-blink-features=AutomationControlled' // 避免被检测为自动化
402430
],
403431
// 添加更多配置以确保在容器中正常运行
404432
ignoreDefaultArgs: ['--enable-automation'],

0 commit comments

Comments
 (0)