Compare commits
4 Commits
a2f32dc7c4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
791a19839a | ||
|
|
88ae4affa4 | ||
|
|
3dabd23dd7 | ||
|
|
7c7076f4ef |
@@ -206,17 +206,19 @@ sed -i 's/\r$//' "$SCRIPT_FILE" 2>/dev/null || true
|
|||||||
|
|
||||||
# 检查是否要后台运行
|
# 检查是否要后台运行
|
||||||
BACKGROUND=false
|
BACKGROUND=false
|
||||||
if [ "$1" = "--background" ] || [ "$1" = "-b" ] || [ "$1" = "--daemon" ] || [ "$1" = "-d" ]; then
|
ARGS=()
|
||||||
BACKGROUND=true
|
for arg in "$@"; do
|
||||||
shift # 移除后台运行参数
|
if [ "$arg" = "--background" ] || [ "$arg" = "-b" ] || [ "$arg" = "--daemon" ] || [ "$arg" = "-d" ]; then
|
||||||
fi
|
BACKGROUND=true
|
||||||
|
else
|
||||||
|
ARGS+=("$arg")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# 运行脚本
|
# 运行脚本
|
||||||
echo "使用 Python: $PYTHON_CMD"
|
echo "使用 Python: $PYTHON_CMD"
|
||||||
echo "运行脚本: $SCRIPT_FILE"
|
echo "运行脚本: $SCRIPT_FILE"
|
||||||
echo "脚本大小: $(wc -c < "$SCRIPT_FILE") 字节"
|
echo "脚本大小: $(wc -c < "$SCRIPT_FILE") 字节"
|
||||||
echo "参数: $@"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if [ "$BACKGROUND" = "true" ]; then
|
if [ "$BACKGROUND" = "true" ]; then
|
||||||
# 后台运行模式
|
# 后台运行模式
|
||||||
@@ -227,22 +229,26 @@ if [ "$BACKGROUND" = "true" ]; then
|
|||||||
echo "日志文件: $LOG_FILE"
|
echo "日志文件: $LOG_FILE"
|
||||||
echo "PID 文件: $PID_FILE"
|
echo "PID 文件: $PID_FILE"
|
||||||
echo ""
|
echo ""
|
||||||
echo "使用以下命令管理服务:"
|
|
||||||
echo " 查看日志: tail -f $LOG_FILE"
|
|
||||||
echo " 停止服务: kill \$(cat $PID_FILE)"
|
|
||||||
echo " 查看进程: ps aux | grep fetch_logistics_ubuntu"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 使用 nohup 后台运行
|
# 使用 nohup 后台运行,确保使用虚拟环境的 Python
|
||||||
nohup $PYTHON_CMD -u "$SCRIPT_FILE" "$@" > "$LOG_FILE" 2>&1 &
|
# 注意:不传递 --background 参数给 Python 脚本
|
||||||
|
nohup $PYTHON_CMD -u "$SCRIPT_FILE" "${ARGS[@]}" > "$LOG_FILE" 2>&1 &
|
||||||
PID=$!
|
PID=$!
|
||||||
echo $PID > "$PID_FILE"
|
echo $PID > "$PID_FILE"
|
||||||
|
|
||||||
# 等待一下,检查进程是否启动成功
|
# 等待一下,检查进程是否启动成功
|
||||||
sleep 2
|
sleep 3
|
||||||
if ps -p $PID > /dev/null 2>&1; then
|
if ps -p $PID > /dev/null 2>&1; then
|
||||||
echo "✅ 服务已启动,PID: $PID"
|
echo "✅ 服务已启动,PID: $PID"
|
||||||
echo "查看日志: tail -f $LOG_FILE"
|
echo ""
|
||||||
|
echo "使用以下命令管理服务:"
|
||||||
|
echo " 查看日志: tail -f $LOG_FILE"
|
||||||
|
echo " 停止服务: ./manage_service.sh stop"
|
||||||
|
echo " 查看状态: ./manage_service.sh status"
|
||||||
|
echo ""
|
||||||
|
# 后台模式下,不退出虚拟环境(因为后台进程已经独立运行)
|
||||||
|
# 直接退出脚本
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
echo "❌ 服务启动失败,请查看日志: $LOG_FILE"
|
echo "❌ 服务启动失败,请查看日志: $LOG_FILE"
|
||||||
rm -f "$PID_FILE"
|
rm -f "$PID_FILE"
|
||||||
@@ -251,20 +257,18 @@ if [ "$BACKGROUND" = "true" ]; then
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# 前台运行模式
|
# 前台运行模式
|
||||||
|
echo "参数: ${ARGS[@]}"
|
||||||
|
echo ""
|
||||||
echo "以前台模式启动服务(按 Ctrl+C 停止)..."
|
echo "以前台模式启动服务(按 Ctrl+C 停止)..."
|
||||||
echo ""
|
echo ""
|
||||||
# 使用 -u 参数确保输出不被缓冲,并明确指定以脚本模式运行
|
# 使用 -u 参数确保输出不被缓冲,并明确指定以脚本模式运行
|
||||||
exec $PYTHON_CMD -u "$SCRIPT_FILE" "$@"
|
# 使用 exec 替换当前进程,这样 deactivate 不会执行
|
||||||
|
exec $PYTHON_CMD -u "$SCRIPT_FILE" "${ARGS[@]}"
|
||||||
|
# 如果 exec 失败(不应该发生),才会执行到这里
|
||||||
|
EXIT_CODE=$?
|
||||||
|
deactivate
|
||||||
|
exit $EXIT_CODE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 保存退出码
|
|
||||||
EXIT_CODE=$?
|
|
||||||
|
|
||||||
# 退出虚拟环境
|
|
||||||
deactivate
|
|
||||||
|
|
||||||
# 返回脚本的退出码
|
|
||||||
exit $EXIT_CODE
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x run_logistics.sh
|
chmod +x run_logistics.sh
|
||||||
@@ -292,7 +296,22 @@ case "$1" in
|
|||||||
rm -f "$PID_FILE"
|
rm -f "$PID_FILE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
./run_logistics.sh --background
|
# 重定向输出,避免显示在终端
|
||||||
|
./run_logistics.sh --background > /dev/null 2>&1
|
||||||
|
sleep 2
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
PID=$(cat "$PID_FILE")
|
||||||
|
if ps -p $PID > /dev/null 2>&1; then
|
||||||
|
echo "✅ 服务已启动,PID: $PID"
|
||||||
|
echo "查看日志: tail -f $LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "❌ 服务启动失败,请查看日志: $LOG_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ 服务启动失败,请查看日志: $LOG_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
stop)
|
stop)
|
||||||
echo "停止物流服务..."
|
echo "停止物流服务..."
|
||||||
|
|||||||
@@ -148,23 +148,31 @@ public class JDInnerController {
|
|||||||
|
|
||||||
Comment commentToUse = null;
|
Comment commentToUse = null;
|
||||||
|
|
||||||
// 按优先级获取评论:
|
// 按优先级获取评论,确保有图片:
|
||||||
// 1️⃣ 先尝试使用未使用过的京东评论
|
// 1️⃣ 先尝试使用未使用过的京东评论
|
||||||
if (!availableComments.isEmpty()) {
|
if (!availableComments.isEmpty()) {
|
||||||
Collections.shuffle(availableComments);
|
Collections.shuffle(availableComments);
|
||||||
commentToUse = availableComments.get(0);
|
for (Comment comment : availableComments) {
|
||||||
logger.info("使用未使用过的京东评论");
|
List<String> imageUrls = parsePictureUrls(comment.getPictureUrls());
|
||||||
|
List<String> convertedImageUrls = imageConvertService.convertImageUrls(imageUrls);
|
||||||
|
if (convertedImageUrls != null && !convertedImageUrls.isEmpty()) {
|
||||||
|
commentToUse = comment;
|
||||||
|
logger.info("使用未使用过的京东评论(有图片)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2️⃣ 尝试使用未使用过的淘宝评论
|
// 2️⃣ 尝试使用未使用过的淘宝评论
|
||||||
else {
|
if (commentToUse == null) {
|
||||||
String taobaoProductIdMap = tbMap.getOrDefault(productId, null);
|
String taobaoProductIdMap = tbMap.getOrDefault(productId, null);
|
||||||
if (taobaoProductIdMap != null && !taobaoProductIdMap.isEmpty()) {
|
if (taobaoProductIdMap != null && !taobaoProductIdMap.isEmpty()) {
|
||||||
logger.info("发现淘宝映射ID,尝试获取未使用过的淘宝评论");
|
logger.info("发现淘宝映射ID,尝试获取未使用过的淘宝评论(有图片)");
|
||||||
Comment taobaoComment = generateTaobaoComment(productType, false);
|
Comment taobaoComment = generateTaobaoCommentWithImages(productType, false);
|
||||||
if (taobaoComment != null) {
|
if (taobaoComment != null) {
|
||||||
commentToUse = taobaoComment;
|
commentToUse = taobaoComment;
|
||||||
isTb = true;
|
isTb = true;
|
||||||
logger.info("使用未使用过的淘宝评论");
|
logger.info("使用未使用过的淘宝评论(有图片)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,22 +183,29 @@ public class JDInnerController {
|
|||||||
List<Comment> candidateComments = new ArrayList<>();
|
List<Comment> candidateComments = new ArrayList<>();
|
||||||
List<String> candidateSources = new ArrayList<>(); // 记录来源,用于标识是京东还是淘宝
|
List<String> candidateSources = new ArrayList<>(); // 记录来源,用于标识是京东还是淘宝
|
||||||
|
|
||||||
// 添加已使用过的京东评论
|
// 添加已使用过的京东评论(确保有图片)
|
||||||
if (!usedComments.isEmpty()) {
|
if (!usedComments.isEmpty()) {
|
||||||
Collections.shuffle(usedComments);
|
Collections.shuffle(usedComments);
|
||||||
candidateComments.add(usedComments.get(0));
|
for (Comment comment : usedComments) {
|
||||||
candidateSources.add("JD");
|
List<String> imageUrls = parsePictureUrls(comment.getPictureUrls());
|
||||||
logger.info("已添加已使用过的京东评论到候选列表");
|
List<String> convertedImageUrls = imageConvertService.convertImageUrls(imageUrls);
|
||||||
|
if (convertedImageUrls != null && !convertedImageUrls.isEmpty()) {
|
||||||
|
candidateComments.add(comment);
|
||||||
|
candidateSources.add("JD");
|
||||||
|
logger.info("已添加已使用过的京东评论到候选列表(有图片)");
|
||||||
|
break; // 只添加第一个有图片的
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加已使用过的淘宝评论
|
// 添加已使用过的淘宝评论(确保有图片)
|
||||||
String taobaoProductIdMap = tbMap.getOrDefault(productId, null);
|
String taobaoProductIdMap = tbMap.getOrDefault(productId, null);
|
||||||
if (taobaoProductIdMap != null && !taobaoProductIdMap.isEmpty()) {
|
if (taobaoProductIdMap != null && !taobaoProductIdMap.isEmpty()) {
|
||||||
Comment taobaoComment = generateTaobaoComment(productType, true);
|
Comment taobaoComment = generateTaobaoCommentWithImages(productType, true);
|
||||||
if (taobaoComment != null) {
|
if (taobaoComment != null) {
|
||||||
candidateComments.add(taobaoComment);
|
candidateComments.add(taobaoComment);
|
||||||
candidateSources.add("TB");
|
candidateSources.add("TB");
|
||||||
logger.info("已添加已使用过的淘宝评论到候选列表");
|
logger.info("已添加已使用过的淘宝评论到候选列表(有图片)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,22 +218,23 @@ public class JDInnerController {
|
|||||||
|
|
||||||
if ("TB".equals(selectedSource)) {
|
if ("TB".equals(selectedSource)) {
|
||||||
isTb = true;
|
isTb = true;
|
||||||
logger.info("随机选择:使用已使用过的淘宝评论");
|
logger.info("随机选择:使用已使用过的淘宝评论(有图片)");
|
||||||
} else {
|
} else {
|
||||||
logger.info("随机选择:使用已使用过的京东评论");
|
logger.info("随机选择:使用已使用过的京东评论(有图片)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (commentToUse == null) {
|
if (commentToUse == null) {
|
||||||
return error("no comment available");
|
return error("no comment with images available");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject item = new JSONObject();
|
|
||||||
item.put("commentText", commentToUse.getCommentText());
|
|
||||||
// 解析图片URL并转换webp格式为jpg
|
// 解析图片URL并转换webp格式为jpg
|
||||||
List<String> imageUrls = parsePictureUrls(commentToUse.getPictureUrls());
|
List<String> imageUrls = parsePictureUrls(commentToUse.getPictureUrls());
|
||||||
List<String> convertedImageUrls = imageConvertService.convertImageUrls(imageUrls);
|
List<String> convertedImageUrls = imageConvertService.convertImageUrls(imageUrls);
|
||||||
|
|
||||||
|
JSONObject item = new JSONObject();
|
||||||
|
item.put("commentText", commentToUse.getCommentText());
|
||||||
item.put("images", convertedImageUrls);
|
item.put("images", convertedImageUrls);
|
||||||
|
|
||||||
JSONArray arr = new JSONArray();
|
JSONArray arr = new JSONArray();
|
||||||
@@ -230,12 +246,28 @@ public class JDInnerController {
|
|||||||
// 添加评论统计信息到响应中
|
// 添加评论统计信息到响应中
|
||||||
JSONObject stats = new JSONObject();
|
JSONObject stats = new JSONObject();
|
||||||
if (!isTb) {
|
if (!isTb) {
|
||||||
|
// 查询最后一条京东评论的创建时间
|
||||||
|
List<Comment> allComments = commentRepository.findByProductIdAndPictureUrlsIsNotNull(productId);
|
||||||
|
java.time.LocalDateTime lastCommentUpdateTime = null;
|
||||||
|
if (!allComments.isEmpty()) {
|
||||||
|
lastCommentUpdateTime = allComments.stream()
|
||||||
|
.map(Comment::getCreatedAt)
|
||||||
|
.filter(createdAt -> createdAt != null)
|
||||||
|
.max(java.time.LocalDateTime::compareTo)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
stats.put("source", "京东评论");
|
stats.put("source", "京东评论");
|
||||||
stats.put("productType", productType);
|
stats.put("productType", productType);
|
||||||
stats.put("newAdded", addCommentCount);
|
stats.put("newAdded", addCommentCount);
|
||||||
stats.put("used", usedCommentCount);
|
stats.put("used", usedCommentCount);
|
||||||
stats.put("available", canUseCommentCount);
|
stats.put("available", canUseCommentCount);
|
||||||
stats.put("total", allCommentCount);
|
stats.put("total", allCommentCount);
|
||||||
|
if (lastCommentUpdateTime != null) {
|
||||||
|
// 转换为Date格式(前端期望的格式)
|
||||||
|
java.util.Date updateDate = java.sql.Timestamp.valueOf(lastCommentUpdateTime);
|
||||||
|
stats.put("lastCommentUpdateTime", updateDate.getTime());
|
||||||
|
}
|
||||||
stats.put("statisticsText",
|
stats.put("statisticsText",
|
||||||
"京东评论统计:\n" +
|
"京东评论统计:\n" +
|
||||||
"型号 " + productType + "\n" +
|
"型号 " + productType + "\n" +
|
||||||
@@ -244,11 +276,27 @@ public class JDInnerController {
|
|||||||
"可用:" + canUseCommentCount + "\n" +
|
"可用:" + canUseCommentCount + "\n" +
|
||||||
"总数:" + allCommentCount);
|
"总数:" + allCommentCount);
|
||||||
} else {
|
} else {
|
||||||
|
// 查询最后一条淘宝评论的创建时间
|
||||||
|
List<TaobaoComment> allTbComments = taobaoCommentRepository.findByProductIdAndPictureUrlsIsNotNull(taobaoProductId);
|
||||||
|
java.time.LocalDateTime lastCommentUpdateTime = null;
|
||||||
|
if (!allTbComments.isEmpty()) {
|
||||||
|
lastCommentUpdateTime = allTbComments.stream()
|
||||||
|
.map(TaobaoComment::getCreatedAt)
|
||||||
|
.filter(createdAt -> createdAt != null)
|
||||||
|
.max(java.time.LocalDateTime::compareTo)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
stats.put("source", "淘宝评论");
|
stats.put("source", "淘宝评论");
|
||||||
stats.put("productType", productType);
|
stats.put("productType", productType);
|
||||||
stats.put("used", usedTbCommentCount);
|
stats.put("used", usedTbCommentCount);
|
||||||
stats.put("available", canUseTbCommentCount);
|
stats.put("available", canUseTbCommentCount);
|
||||||
stats.put("total", allTbCommentCount);
|
stats.put("total", allTbCommentCount);
|
||||||
|
if (lastCommentUpdateTime != null) {
|
||||||
|
// 转换为Date格式(前端期望的格式)
|
||||||
|
java.util.Date updateDate = java.sql.Timestamp.valueOf(lastCommentUpdateTime);
|
||||||
|
stats.put("lastCommentUpdateTime", updateDate.getTime());
|
||||||
|
}
|
||||||
stats.put("statisticsText",
|
stats.put("statisticsText",
|
||||||
"淘宝评论统计:\n" +
|
"淘宝评论统计:\n" +
|
||||||
"型号 " + productType + "\n" +
|
"型号 " + productType + "\n" +
|
||||||
@@ -279,6 +327,15 @@ public class JDInnerController {
|
|||||||
* @param includeUsed 是否包含已使用的评论(true=获取已使用的,false=获取未使用的)
|
* @param includeUsed 是否包含已使用的评论(true=获取已使用的,false=获取未使用的)
|
||||||
*/
|
*/
|
||||||
private Comment generateTaobaoComment(String productType, boolean includeUsed) {
|
private Comment generateTaobaoComment(String productType, boolean includeUsed) {
|
||||||
|
return generateTaobaoCommentWithImages(productType, includeUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从淘宝评论中生成Comment对象,确保有图片
|
||||||
|
* @param productType 商品类型
|
||||||
|
* @param includeUsed 是否包含已使用的评论(true=获取已使用的,false=获取未使用的)
|
||||||
|
*/
|
||||||
|
private Comment generateTaobaoCommentWithImages(String productType, boolean includeUsed) {
|
||||||
HashMap<String, String> map = jdUtil.getProductTypeMap(); // 加载京东的 productTypeMap
|
HashMap<String, String> map = jdUtil.getProductTypeMap(); // 加载京东的 productTypeMap
|
||||||
HashMap<String, String> tbMap = jdUtil.getProductTypeMapForTB(); // 加载淘宝的 productTypeMapTB
|
HashMap<String, String> tbMap = jdUtil.getProductTypeMapForTB(); // 加载淘宝的 productTypeMapTB
|
||||||
|
|
||||||
@@ -306,31 +363,37 @@ public class JDInnerController {
|
|||||||
|
|
||||||
if (!taobaoComments.isEmpty()) {
|
if (!taobaoComments.isEmpty()) {
|
||||||
Collections.shuffle(taobaoComments);
|
Collections.shuffle(taobaoComments);
|
||||||
TaobaoComment selected = taobaoComments.get(0);
|
// 循环查找有图片的评论
|
||||||
// 将淘宝评论转换为京东评论返回
|
for (TaobaoComment selected : taobaoComments) {
|
||||||
Comment comment = new Comment();
|
// 检查图片是否存在
|
||||||
comment.setCommentText(selected.getCommentText());
|
List<String> imageUrls = parsePictureUrls(selected.getPictureUrls());
|
||||||
String pictureUrls = selected.getPictureUrls();
|
List<String> convertedImageUrls = imageConvertService.convertImageUrls(imageUrls);
|
||||||
if (pictureUrls != null) {
|
if (convertedImageUrls != null && !convertedImageUrls.isEmpty()) {
|
||||||
pictureUrls = pictureUrls.replace("//img.", "https://img.");
|
// 将淘宝评论转换为京东评论返回
|
||||||
}
|
Comment comment = new Comment();
|
||||||
comment.setPictureUrls(pictureUrls);
|
comment.setCommentText(selected.getCommentText());
|
||||||
comment.setCommentId(selected.getCommentId());
|
String pictureUrls = selected.getPictureUrls();
|
||||||
comment.setProductId(product_id);
|
if (pictureUrls != null) {
|
||||||
comment.setUserName(selected.getUserName());
|
pictureUrls = pictureUrls.replace("//img.", "https://img.");
|
||||||
comment.setCreatedAt(selected.getCreatedAt());
|
}
|
||||||
|
comment.setPictureUrls(pictureUrls);
|
||||||
|
comment.setCommentId(selected.getCommentId());
|
||||||
|
comment.setProductId(product_id);
|
||||||
|
comment.setUserName(selected.getUserName());
|
||||||
|
comment.setCreatedAt(selected.getCreatedAt());
|
||||||
|
|
||||||
// 只在获取未使用的评论时才标记为已使用
|
// 只在获取未使用的评论时才标记为已使用
|
||||||
if (!includeUsed) {
|
if (!includeUsed) {
|
||||||
selected.setIsUse(1);
|
selected.setIsUse(1);
|
||||||
taobaoCommentRepository.save(selected);
|
taobaoCommentRepository.save(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回京东评论
|
// 返回京东评论
|
||||||
return comment;
|
return comment;
|
||||||
} else {
|
}
|
||||||
return null;
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<String> parsePictureUrls(String raw) {
|
private static List<String> parsePictureUrls(String raw) {
|
||||||
|
|||||||
Reference in New Issue
Block a user