Compare commits

...

10 Commits

Author SHA1 Message Date
Gitea Actions Bot
7fb90ace65 [skip ci] Update version to v1.5.71 2025-11-04 17:05:46 +08:00
kris 郝
01aed205fe [patch] 正式环境代码提交 2025-11-04 16:44:56 +08:00
Gitea Actions Bot
14991ae2aa [skip ci] Update version to v1.5.70 2025-11-04 14:35:46 +08:00
kris 郝
1de233b197 [patch] 更新PDD过滤消息基础逻辑 过滤部分系统机器人消息 2025-11-04 14:23:53 +08:00
Gitea Actions Bot
32a17fb255 [skip ci] Update version to v1.5.69 2025-11-03 16:13:35 +08:00
kris 郝
4f17092305 [patch] 修复因自动更新回归代码config.py因覆盖逻辑导致的新增代码被覆盖的逻辑 2025-11-03 15:51:00 +08:00
kris 郝
58868c9c18 [patch] 修复因自动更新回归代码config.py因覆盖逻辑导致的新增代码被覆盖的逻辑 2025-11-03 14:56:01 +08:00
Gitea Actions Bot
7054beebeb [skip ci] Update version to v1.5.67 2025-11-03 11:52:42 +08:00
kris 郝
8a5da5e906 [patch] 新增多实例测试开关控制流 逻辑 2025-11-03 11:31:20 +08:00
Gitea Actions Bot
2083516b8c [skip ci] Update version to v1.5.66 2025-10-31 14:01:18 +08:00
6 changed files with 283 additions and 198 deletions

View File

@@ -472,54 +472,86 @@ jobs:
Write-Host "Remote: $REMOTE"; Write-Host "Remote: $REMOTE";
Write-Host ""; Write-Host "";
# Unstage to avoid merge conflicts # FIX: Stash local changes before pull to avoid conflicts
git reset HEAD config.py version_history.json; Write-Host "Stashing local version changes...";
git stash push -m "CI-CD-temp-stash" config.py version_history.json;
# Backup our version files
Copy-Item "config.py" "config.py.new" -Force;
Copy-Item "version_history.json" "version_history.json.new" -Force;
Write-Host "Backed up new version files";
Write-Host "Pulling remote changes...";
# Pull remote changes (use merge strategy to avoid rebase conflicts) # Pull remote changes (use merge strategy to avoid rebase conflicts)
git pull origin $BRANCH --no-rebase; git pull origin $BRANCH --no-rebase;
if ($LASTEXITCODE -ne 0) { # Pop stashed changes back
Write-Host "WARNING: Pull failed, attempting manual conflict resolution..."; Write-Host "Restoring version changes...";
$stashPopResult = git stash pop 2>&1;
$stashPopExitCode = $LASTEXITCODE;
if ($stashPopExitCode -ne 0) {
Write-Host "WARNING: Stash pop encountered conflicts, resolving...";
Write-Host "$stashPopResult";
# Check conflict files # Check conflict files
$conflicts = git diff --name-only --diff-filter=U; $conflicts = git diff --name-only --diff-filter=U;
Write-Host "Conflict files: $conflicts"; Write-Host "Conflict files: $conflicts";
# Manually resolve config.py conflict (use our new version) # FIX: Smart conflict resolution to preserve user code
if (Test-Path "config.py.new") { # For config.py: use remote version (user code), then re-apply version update
Copy-Item "config.py.new" "config.py" -Force; if ($conflicts -match "config.py") {
Write-Host "Resolving config.py conflict...";
# Use remote version (preserve user code)
git checkout --theirs config.py;
# Re-apply version update only
python .gitea/scripts/gui_version_creator.py;
git add config.py; git add config.py;
Write-Host "OK: Resolved config.py conflict (using new version)"; Write-Host "OK: Resolved config.py (preserved user code + updated version)";
} }
# Manually resolve version_history.json conflict (use our new version) # For version_history.json: use CI/CD version (append record)
if (Test-Path "version_history.json.new") { if ($conflicts -match "version_history.json") {
Copy-Item "version_history.json.new" "version_history.json" -Force; Write-Host "Resolving version_history.json conflict...";
git checkout --ours version_history.json;
git add version_history.json; git add version_history.json;
Write-Host "OK: Resolved version_history.json conflict (using new version)"; Write-Host "OK: Resolved version_history.json (using CI/CD version)";
} }
# Complete the merge # Drop the stash after resolving
git commit -m "[skip ci] Merge and update version to v$VERSION" --no-edit --no-verify; git stash drop 2>$null;
} else { } else {
Write-Host "OK: Pull successful, applying our changes..."; Write-Host "OK: Stash pop successful";
# Apply our version files # FIX: After stash pop, files are automatically merged
Copy-Item "config.py.new" "config.py" -Force; # config.py now contains:
Copy-Item "version_history.json.new" "version_history.json" -Force; # 1. User's code from remote (from pull)
# 2. Version update from stash (from gui_version_creator.py)
Write-Host "Checking if version update is preserved...";
# Verify version number is correct
$configContent = Get-Content "config.py" -Raw;
if ($configContent -match 'APP_VERSION\s*=\s*"([\d.]+)"') {
$currentVersion = $matches[1];
Write-Host "Current APP_VERSION in config.py: $currentVersion";
Write-Host "Expected version: $VERSION";
if ($currentVersion -ne $VERSION) {
Write-Host "WARNING: Version mismatch, re-applying version update...";
# Re-execute version update (only modify APP_VERSION line)
python .gitea/scripts/gui_version_creator.py;
} else {
Write-Host "OK: Version is correct";
}
}
# Add current files (includes user code + version update)
git add config.py version_history.json; git add config.py version_history.json;
Write-Host "Files staged successfully";
} }
# Cleanup backup files
Remove-Item "config.py.new" -ErrorAction SilentlyContinue;
Remove-Item "version_history.json.new" -ErrorAction SilentlyContinue;
} else { } else {
Write-Host "No remote changes, proceeding with commit..."; Write-Host "No remote changes, proceeding with commit...";
# FIX: Ensure files are staged even if no remote changes
git add config.py version_history.json;
Write-Host "Files staged for commit";
} }
Write-Host ""; Write-Host "";
@@ -577,27 +609,23 @@ jobs:
Write-Host "Fetching latest remote state..."; Write-Host "Fetching latest remote state...";
git fetch origin $BRANCH; git fetch origin $BRANCH;
# Step 4: Backup our version files again # Step 4: Record current version number
Copy-Item "config.py" "config.py.retry" -Force; $currentVersionMatch = (Get-Content "config.py" -Raw) -match 'APP_VERSION\s*=\s*"([\d.]+)"';
Copy-Item "version_history.json" "version_history.json.retry" -Force; $targetVersion = $matches[1];
Write-Host "Target version to apply: $targetVersion";
# Step 5: Reset to remote state # Step 5: Reset to remote state
Write-Host "Resetting to remote state..."; Write-Host "Resetting to remote state...";
git reset --hard origin/$BRANCH; git reset --hard origin/$BRANCH;
# Step 6: Apply our version files # Step 6: FIX - Re-apply version update only, do not overwrite entire file
Write-Host "Applying our version files..."; Write-Host "Re-applying version update only...";
Copy-Item "config.py.retry" "config.py" -Force; python .gitea/scripts/gui_version_creator.py;
Copy-Item "version_history.json.retry" "version_history.json" -Force;
# Step 7: Stage and commit again # Step 7: Stage and commit again
git add config.py version_history.json; git add config.py version_history.json;
git commit -m "[skip ci] Update version to v$VERSION" --no-verify; git commit -m "[skip ci] Update version to v$VERSION" --no-verify;
# Step 8: Clean up retry backup files
Remove-Item "config.py.retry" -ErrorAction SilentlyContinue;
Remove-Item "version_history.json.retry" -ErrorAction SilentlyContinue;
Write-Host "Retry preparation complete"; Write-Host "Retry preparation complete";
Start-Sleep -Seconds 1; Start-Sleep -Seconds 1;
} }

View File

@@ -3353,74 +3353,83 @@ class ChatPdd:
return False return False
def should_filter_robot_message(self, message_data): def should_filter_robot_message(self, message_data):
"""专门判断是否为机器人消息需要过滤""" """专门判断是否为机器人消息需要过滤
🎯 当前过滤规则仅过滤机器人系统提示消息type=31, template_name='merchant_robot_system_hint_to_merchant_alone_text'
示例:'消费者近期咨询过重要售后问题,机器人担心回答不好,本次会话机器人不再回复,请及时跟进'
"""
try: try:
message_info = message_data.get("message", {}) message_info = message_data.get("message", {})
# 1. 基于消息类型过滤机器人特殊消息 # ✅ 【保留】1. 过滤机器人系统提示消息type=31商家机器人提示类消息
msg_type = message_info.get("type") msg_type = message_info.get("type")
if msg_type == 31: # 机器人干预消息(如:机器人已暂停接待)
return True
if msg_type == 8: # 平台系统卡片消息(如:售后提醒、平台通知等)
self._log(f"🚫 过滤系统卡片消息(type=8): {message_info.get('content', '')[:50]}", "DEBUG")
return True
if msg_type == 64: # 🔥 新增:售后卡片消息(如:消费者申请售后)
self._log(f"🚫 过滤售后卡片消息(type=64): {message_info.get('content', '')[:50]}", "DEBUG")
return True
# 2. 基于模板名称识别机器人消息
template_name = message_info.get("template_name", "") template_name = message_info.get("template_name", "")
robot_templates = [
"mall_robot_man_intervention_and_restart", # 机器人暂停接待消息 # 精确匹配type=31 且 template_name 包含机器人系统提示
"mall_robot_text_msg", # 机器人自动回复消息 if msg_type == 31:
"aftersales_hosting_warning_card", # 售后托管警告卡片 # 机器人干预提示消息(如:机器人担心回答不好、机器人已暂停接待等)
"apply_for_consultation_card_new", # 🔥 新增:售后协商申请卡片 if template_name == "merchant_robot_system_hint_to_merchant_alone_text":
# 可根据实际情况添加更多机器人模板 content = message_info.get("content", "")
] self._log(f"🚫 过滤机器人系统提示消息(type=31): {content[:50]}...", "DEBUG")
if template_name in robot_templates:
self._log(f"🚫 过滤模板消息: {template_name}", "DEBUG")
return True
# 3. 基于info字段识别系统卡片消息售后提醒、订单提醒等
info = message_info.get("info", {})
if info and isinstance(info, dict):
# 如果info中包含mbtn_list按钮列表通常是系统卡片
if info.get("mbtn_list") or info.get("text_list"):
self._log(f"🚫 过滤系统卡片消息(含info.mbtn_list): {message_info.get('content', '')[:50]}", "DEBUG")
return True return True
# ❌ 【暂时注释】其他类型的系统消息过滤(后续如需恢复,取消注释即可)
# if msg_type == 8: # 平台系统卡片消息(如:售后提醒、平台通知等)
# self._log(f"🚫 过滤系统卡片消息(type=8): {message_info.get('content', '')[:50]}", "DEBUG")
# return True
# if msg_type == 64: # 售后卡片消息(如:消费者申请售后)
# self._log(f"🚫 过滤售后卡片消息(type=64): {message_info.get('content', '')[:50]}", "DEBUG")
# return True
# 4. 基于机器人特殊标志过滤 # ❌ 【暂时注释】2. 基于模板名称识别其他机器人消息
if message_info.get("conv_silent") is True: # 静默会话标志 # template_name = message_info.get("template_name", "")
return True # robot_templates = [
# "mall_robot_man_intervention_and_restart", # 机器人暂停接待消息
# "mall_robot_text_msg", # 机器人自动回复消息
# "aftersales_hosting_warning_card", # 售后托管警告卡片
# "apply_for_consultation_card_new", # 售后协商申请卡片
# ]
# if template_name in robot_templates:
# self._log(f"🚫 过滤模板消息: {template_name}", "DEBUG")
# return True
if message_info.get("no_unreply_hint") == 1: # 无需回复提示标志 # ❌ 【暂时注释】3. 基于info字段识别系统卡片消息
return True # info = message_info.get("info", {})
# if info and isinstance(info, dict):
# if info.get("mbtn_list") or info.get("text_list"):
# self._log(f"🚫 过滤系统卡片消息(含info.mbtn_list): {message_info.get('content', '')[:50]}", "DEBUG")
# return True
# 5. 基于消息内容识别机器人提示消息和平台系统消息 # ❌ 【暂时注释】4. 基于机器人特殊标志过滤
content = message_info.get("content", "") # if message_info.get("conv_silent") is True: # 静默会话标志
robot_content_patterns = [ # return True
"机器人未找到对应的回复", # if message_info.get("no_unreply_hint") == 1: # 无需回复提示标志
"机器人已暂停接待", # return True
">>点此【立即恢复接待】<<",
"点击添加",
"[当前用户来自",
"请尽快解决售后问题", # 平台售后提醒
"平台介入退款", # 平台售后提醒
"请尽快处理售后", # 平台售后提醒
"消费者申请售后", # 🔥 新增:售后申请通知
"建议先与消费者友好协商", # 🔥 新增:售后协商提示
]
if any(pattern in content for pattern in robot_content_patterns): # ❌ 【暂时注释】5. 基于消息内容识别机器人提示消息
self._log(f"🚫 过滤系统提示消息: {content[:50]}", "DEBUG") # content = message_info.get("content", "")
return True # robot_content_patterns = [
# "机器人未找到对应的回复",
# "机器人已暂停接待",
# ">>点此【立即恢复接待】<<",
# "点击添加",
# "[当前用户来自",
# "请尽快解决售后问题",
# "平台介入退款",
# "请尽快处理售后",
# "消费者申请售后",
# "建议先与消费者友好协商",
# ]
# if any(pattern in content for pattern in robot_content_patterns):
# self._log(f"🚫 过滤系统提示消息: {content[:50]}", "DEBUG")
# return True
# 6. 基于biz_context中的机器人标识 # ❌ 【暂时注释】6. 基于biz_context中的机器人标识
biz_context = message_info.get("biz_context", {}) # biz_context = message_info.get("biz_context", {})
if biz_context.get("robot_msg_id"): # 有机器人消息ID # if biz_context.get("robot_msg_id"):
return True # return True
# 不是机器人消息,不过滤 # 不是需要过滤的消息,放行
return False return False
except Exception as e: except Exception as e:
@@ -3450,9 +3459,9 @@ class ChatPdd:
"""处理接收到的消息""" """处理接收到的消息"""
try: try:
# 🔥 过滤机器人消息 # 🔥 过滤机器人消息
# if self.should_filter_robot_message(message_data): if self.should_filter_robot_message(message_data):
# self._log("🤖 检测到机器人消息,已过滤不发送给后端", "DEBUG") self._log("🤖 检测到机器人消息,已过滤不发送给后端", "DEBUG")
# return return
message_info = message_data.get("message", {}) message_info = message_data.get("message", {})
if not message_info: if not message_info:

View File

@@ -194,12 +194,19 @@ class WebSocketManager:
"""连接后端WebSocket""" """连接后端WebSocket"""
try: try:
# 1 保存token到配置 # 🔥 根据配置决定是否保存token
try: # 生产模式保存token方便用户下次自动加载
from config import set_saved_token # 测试模式:不保存,避免多实例冲突
set_saved_token(token) import config as cfg
except Exception: if not cfg.is_multi_instance_mode():
pass try:
from config import set_saved_token
set_saved_token(token)
self._log("生产模式已保存token到配置文件", "INFO")
except Exception as e:
self._log(f"保存token失败: {e}", "WARNING")
else:
self._log("测试模式不保存token支持多实例运行", "INFO")
# 2 获取或创建后端客户端 # 2 获取或创建后端客户端
backend = get_backend_client() backend = get_backend_client()

View File

@@ -10,13 +10,13 @@ import json # 用于将令牌保存为 JSON 格式
# 后端服务器配置 # 后端服务器配置
# BACKEND_HOST = "192.168.5.233" # BACKEND_HOST = "192.168.5.233"
# BACKEND_HOST = "192.168.5.106" # BACKEND_HOST = "192.168.5.106"
BACKEND_HOST = "192.168.5.12" # BACKEND_HOST = "192.168.5.12"
# BACKEND_HOST = "shuidrop.com" BACKEND_HOST = "shuidrop.com"
# BACKEND_HOST = "test.shuidrop.com" # BACKEND_HOST = "test.shuidrop.com"
BACKEND_PORT = "8000" # BACKEND_PORT = "8000"
# BACKEND_PORT = "" BACKEND_PORT = ""
BACKEND_WS_URL = f"ws://{BACKEND_HOST}:{BACKEND_PORT}" # BACKEND_WS_URL = f"ws://{BACKEND_HOST}:{BACKEND_PORT}"
# BACKEND_WS_URL = f"wss://{BACKEND_HOST}" BACKEND_WS_URL = f"wss://{BACKEND_HOST}"
# WebSocket配置 # WebSocket配置
WS_CONNECT_TIMEOUT = 16.0 WS_CONNECT_TIMEOUT = 16.0
@@ -43,7 +43,42 @@ VERSION = "1.0"
WINDOW_TITLE = "AI回复连接入口-V1.0" WINDOW_TITLE = "AI回复连接入口-V1.0"
# 应用版本号(用于版本检查) # 应用版本号(用于版本检查)
APP_VERSION = "1.5.65" APP_VERSION = "1.5.71"
# 🔥 多实例运行模式开关
# - True: 测试模式多实例不保存token避免冲突
# - False: 生产模式单实例保存token自动加载
#
# 使用方法:
# 1. 修改此值MULTI_INSTANCE_MODE = False # 改为生产模式
# 2. 或设置环境变量SHUIDROP_MULTI_INSTANCE=0 # 临时切换到生产模式
MULTI_INSTANCE_MODE = True # 默认:测试模式
def is_multi_instance_mode() -> bool:
"""
检查是否为多实例模式(支持环境变量覆盖)
优先级:
1. 环境变量 SHUIDROP_MULTI_INSTANCE0=生产1=测试)
2. 配置文件 MULTI_INSTANCE_MODE
Returns:
bool: True=多实例模式False=单实例模式
"""
# 检查环境变量
env_value = os.getenv('SHUIDROP_MULTI_INSTANCE')
if env_value is not None:
# 0, false, False, no, No → 生产模式
if env_value.lower() in ('0', 'false', 'no'):
return False
# 1, true, True, yes, Yes → 测试模式
if env_value.lower() in ('1', 'true', 'yes'):
return True
# 使用配置文件值 (如果不做设置我们可以直接用编码变量进行控制是否可以允许多实例的方式运行)
return MULTI_INSTANCE_MODE
# 平台特定配置 # 平台特定配置
PLATFORMS = { PLATFORMS = {

22
main.py
View File

@@ -145,14 +145,20 @@ class LoginWindow(QMainWindow):
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
self.token_input.returnPressed.connect(self.login) # 表示回车提交 self.token_input.returnPressed.connect(self.login) # 表示回车提交
self.token_input.setMinimumHeight(34) # 最小输入框高度 self.token_input.setMinimumHeight(34) # 最小输入框高度
# 预填已保存的令牌(如果存在) # 🔥 根据配置决定是否自动加载token
try: # 生产模式自动加载保存的token方便用户
from config import get_saved_token # 测试模式:不加载,避免多实例冲突
saved = get_saved_token() if not config.is_multi_instance_mode():
if saved: try:
self.token_input.setText(saved) from config import get_saved_token
except Exception: saved = get_saved_token()
pass if saved:
self.token_input.setText(saved)
print("[INFO] 生产模式已自动加载保存的token")
except Exception:
pass
else:
print("[INFO] 测试模式不自动加载token支持多实例运行")
token_layout.addWidget(token_label) token_layout.addWidget(token_label)
token_layout.addWidget(self.token_input) token_layout.addWidget(self.token_input)

View File

@@ -1,4 +1,84 @@
[ [
{
"version": "1.5.71",
"update_type": "patch",
"content": "[skip ci] Update version to v1.5.70",
"author": "Gitea Actions Bot",
"commit_hash": "14991ae2aa2c36ee51e4b8ef080d333712e4faac",
"commit_short_hash": "14991ae2",
"branch": "develop",
"release_time": "2025-11-04 16:45:16",
"download_url": "https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.71.exe",
"stats": {
"files_changed": 2,
"lines_added": 17,
"lines_deleted": 17
}
},
{
"version": "1.5.70",
"update_type": "patch",
"content": "[skip ci] Update version to v1.5.69",
"author": "Gitea Actions Bot",
"commit_hash": "32a17fb255f3ace34262c8b34679b2129147f01c",
"commit_short_hash": "32a17fb2",
"branch": "jiang",
"release_time": "2025-11-04 14:24:14",
"download_url": "https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.70.exe",
"stats": {
"files_changed": 2,
"lines_added": 17,
"lines_deleted": 17
}
},
{
"version": "1.5.69",
"update_type": "patch",
"content": "[patch] 修复因自动更新回归代码config.py因覆盖逻辑导致的新增代码被覆盖的逻辑",
"author": "kris 郝",
"commit_hash": "4f17092305e1f73e7c19b28d751d5bbaf6895022",
"commit_short_hash": "4f170923",
"branch": "develop",
"release_time": "2025-11-03 15:51:19",
"download_url": "https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.69.exe",
"stats": {
"files_changed": 1,
"lines_added": 25,
"lines_deleted": 15
}
},
{
"version": "1.5.67",
"update_type": "patch",
"content": "[skip ci] Update version to v1.5.66",
"author": "Gitea Actions Bot",
"commit_hash": "2083516b8c66377b5f13df0989fce0eeb82c105e",
"commit_short_hash": "2083516b",
"branch": "develop",
"release_time": "2025-11-03 11:31:45",
"download_url": "https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.67.exe",
"stats": {
"files_changed": 2,
"lines_added": 17,
"lines_deleted": 17
}
},
{
"version": "1.5.66",
"update_type": "patch",
"content": "[skip ci] Update version to v1.5.65",
"author": "Gitea Actions Bot",
"commit_hash": "27b15773e0fffa15a65e4a69f3b9cd2097d8c24b",
"commit_short_hash": "27b15773",
"branch": "develop",
"release_time": "2025-10-31 13:49:16",
"download_url": "https://shuidrop-chat-server.ks3-cn-guangzhou.ksyuncs.com/installers/ShuiDi_AI_Assistant_Setup_v1.5.66.exe",
"stats": {
"files_changed": 2,
"lines_added": 17,
"lines_deleted": 17
}
},
{ {
"version": "1.5.65", "version": "1.5.65",
"update_type": "patch", "update_type": "patch",
@@ -718,85 +798,5 @@
"lines_added": 0, "lines_added": 0,
"lines_deleted": 1 "lines_deleted": 1
} }
},
{
"version": "1.4.27",
"update_type": "patch",
"content": "[patch] PDD登录状态GUI回调优化",
"author": "haosicheng",
"commit_hash": "b80e205680655a3c7ea33ae9a5262ebdaeaaf3a2",
"commit_short_hash": "b80e2056",
"branch": "develop",
"release_time": "2025-10-11 10:15:01",
"download_url": "https://shuidrop.com/download/gui/ShuiDi_AI_Assistant_Setup_v1.4.27.exe",
"stats": {
"files_changed": 1,
"lines_added": 4,
"lines_deleted": 0
}
},
{
"version": "1.4.26",
"update_type": "patch",
"content": "[patch] PDD登录状态GUI回调优化",
"author": "haosicheng",
"commit_hash": "80e9bba722b0f4ffcd0b93c8bf301d356b2e6b40",
"commit_short_hash": "80e9bba7",
"branch": "develop",
"release_time": "2025-10-11 10:13:06",
"download_url": "https://shuidrop.com/download/gui/ShuiDi_AI_Assistant_Setup_v1.4.26.exe",
"stats": {
"files_changed": 1,
"lines_added": 11,
"lines_deleted": 2
}
},
{
"version": "1.4.24",
"update_type": "patch",
"content": "[patch] 优化打包逻辑 控制变量为日志产出 和 安装包整合路径统一",
"author": "haosicheng",
"commit_hash": "31ca5d0819f8f7da907a78f99a22bcc09fb12296",
"commit_short_hash": "31ca5d08",
"branch": "develop",
"release_time": "2025-10-10 16:17:35",
"download_url": "https://shuidrop.com/download/gui/ShuiDi_AI_Assistant_Setup_v1.4.24.exe",
"stats": {
"files_changed": 2,
"lines_added": 31,
"lines_deleted": 47
}
},
{
"version": "1.4.23",
"update_type": "patch",
"content": "Merge remote-tracking branch 'origin/develop' into develop",
"author": "haosicheng",
"commit_hash": "0d9ab498b1bb8df1372e028978f69ad096f47869",
"commit_short_hash": "0d9ab498",
"branch": "develop",
"release_time": "2025-10-10 15:35:22",
"download_url": "https://shuidrop.com/download/gui/ShuiDi_AI_Assistant_Setup_v1.4.23.exe",
"stats": {
"files_changed": 5,
"lines_added": 200,
"lines_deleted": 11
}
},
{
"version": "1.4.22",
"update_type": "patch",
"content": "强制空提交",
"author": "Gitea Actions",
"commit_hash": "8c150054a05a7b0d4795c43d0f2ff8ffade5ae15",
"commit_short_hash": "8c150054",
"branch": "develop",
"release_time": "2025-10-10 14:42:05",
"download_url": "https://www.baidu.com",
"stats": {
"files_changed": 0,
"lines_added": 0,
"lines_deleted": 0
}
} }
] ]