[运维] 接入内网 searxng + 清理启动脚本 + 修 log-trim 权限
搜索接口:
- duckduckgo_search.py / ZhipuSearchAPI.py 切换到内网 searxng (原 43.251.225.121 / 134.122.191.214 已失效)
启动脚本清理:
- 删除废弃 backend/ 目录 (与 chat_web_backend/ 编译产物 jar MD5 相同,仅是改名副本)
- 删除 start_all.sh 与 langchain-chat/{start,stop,stop_quick,shutdown_all,restart}.sh (被 scripts/*-restart.sh 覆盖)
- 删除 chat_web_backend/{start,test_mysql}.sh
修复:
- scripts/backend-restart.sh 对齐当前实际在跑的 chat_web_backend.jar (profile=dev)
- scripts/log-trim-daemon.sh 把 LOCK 移到 /tmp 按用户命名,修复非首次用户跑时的 Permission denied
新增:
- scripts/start-all.sh:一键启动入口,串联 mysql/redis/milvus/langchain/backend/frontend,含端口自检
- chat_web_backend/application-local.yml.archived:原 backend/ 下 yj profile 覆盖配置的归档备份
其他:
- .gitignore 忽略 scripts/pptist-deploy/PPTist/ (323M 第三方源码树)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -57,3 +57,6 @@ Thumbs.db
|
|||||||
|
|
||||||
# Claude
|
# Claude
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
# PPTist 源码树(pptist-deploy 期间 git clone 下来的 323M 依赖,含 node_modules + .git)
|
||||||
|
scripts/pptist-deploy/PPTist/
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 启动 Java 后端。profile=yj。
|
|
||||||
# MySQL 33306 / Redis 等统一见同目录 application-local.yml(与 scripts/backend-restart.sh 一致,勿再写 -D 数据源以免和 yml 冲突)。
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
|
||||||
export PATH="$JAVA_HOME/bin:$PATH"
|
|
||||||
|
|
||||||
PROJECT_DIR=/opt/download/oss_files/gangyan-deploy/gangyan/backend
|
|
||||||
JAR_FILE="$PROJECT_DIR/chat_web_yj.jar"
|
|
||||||
LOCAL_CFG="$PROJECT_DIR/application-local.yml"
|
|
||||||
|
|
||||||
if [[ ! -f "$JAR_FILE" ]]; then
|
|
||||||
echo "Error: JAR file not found at $JAR_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
pkill -f "chat_web_yj.jar" 2>/dev/null || true
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
# 日志目录(logback 写 /opt/apps/...);非 root 启动时需可写
|
|
||||||
mkdir -p "$PROJECT_DIR/logs" /opt/apps/logs/chat-server-backend-cast 2>/dev/null || true
|
|
||||||
|
|
||||||
LOG_OUT="$PROJECT_DIR/nohup.out"
|
|
||||||
if ! ( umask 022; : >>"$LOG_OUT" ) 2>/dev/null; then
|
|
||||||
LOG_OUT="/tmp/chat_web_yj_nohup.log"
|
|
||||||
fi
|
|
||||||
|
|
||||||
EXTRA_JAVA=()
|
|
||||||
[[ -f "$LOCAL_CFG" ]] && EXTRA_JAVA=(-Dspring.config.additional-location="file:${LOCAL_CFG}")
|
|
||||||
|
|
||||||
nohup java \
|
|
||||||
-Djava.net.useSystemProxies=false \
|
|
||||||
-Dhttp.nonProxyHosts="localhost|127.*|[::1]|*.local" \
|
|
||||||
-Xms512m \
|
|
||||||
-Xmx2048m \
|
|
||||||
"${EXTRA_JAVA[@]}" \
|
|
||||||
-Dspring.profiles.active=yj \
|
|
||||||
-jar "$JAR_FILE" >>"$LOG_OUT" 2>&1 &
|
|
||||||
|
|
||||||
sleep 10
|
|
||||||
|
|
||||||
if pgrep -f "chat_web_yj.jar" > /dev/null; then
|
|
||||||
echo "OK PID $(pgrep -n -f 'java .*chat_web_yj\.jar' | head -1) log:$LOG_OUT"
|
|
||||||
else
|
|
||||||
tail -50 "$LOG_OUT" 2>/dev/null || true
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
nohup /home/gc/gangyan/backend/jdk1.8.0_161/bin/java -jar -Xms8g -Xmx8g -DserverUrlPrefix=http://localhost:3000 -DserverFrontUrlPrefix=/chat_web -Dspring.profiles.active=yj -Dspring.redis.database=3 -Dspring.redis.password=Redis_897653 -Dchat.modelName=zhipu-api /home/gc/gangyan/backend/chat_web_yj.jar > /home/gc/gangyan/backend/nohup.out 2>&1 &
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ps -ef|grep chat_web_yj | grep -v grep | awk '{print $2}' | xargs kill -9
|
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
# 原始位置:/opt/download/oss_files/gangyan-deploy/gangyan/backend/application-local.yml
|
||||||
|
# 归档时间:2026-04-20
|
||||||
|
# 用途:yj profile 的本地覆盖(mysql 33306 Docker 映射),启动时通过 -Dspring.config.additional-location 叠加
|
||||||
|
|
||||||
# 覆盖 jar 内过期的 application-yj.yml(当前 jar 仍含远程库 123.57.146.97,不配本会长时间卡 Druid)。
|
# 覆盖 jar 内过期的 application-yj.yml(当前 jar 仍含远程库 123.57.146.97,不配本会长时间卡 Druid)。
|
||||||
# 完整 spring.redis + spring.datasource 与源码 application-yj.yml 对齐(本地 Docker 33306)。
|
# 完整 spring.redis + spring.datasource 与源码 application-yj.yml 对齐(本地 Docker 33306)。
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Java后端启动脚本
|
|
||||||
|
|
||||||
# 使用 Java 11 运行(兼容性更好)
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
|
||||||
export PATH=$JAVA_HOME/bin:$PATH
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
echo "=========================================="
|
|
||||||
echo "启动 Chat Web Backend"
|
|
||||||
echo "=========================================="
|
|
||||||
echo ""
|
|
||||||
echo "Java版本:"
|
|
||||||
java -version
|
|
||||||
echo ""
|
|
||||||
echo "启动端口: 8099"
|
|
||||||
echo "访问地址: http://localhost:8099/chat_web_backend"
|
|
||||||
echo ""
|
|
||||||
echo "按 Ctrl+C 停止服务"
|
|
||||||
echo "=========================================="
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# 启动应用
|
|
||||||
nohup java -jar target/chat_web_backend.jar --spring.profiles.active=dev > ./nohup.out 2>&1 &
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
echo "测试MySQL连接..."
|
|
||||||
echo "密码: 1234567890"
|
|
||||||
mysql -uroot -p1234567890 -h127.0.0.1 -e "SHOW DATABASES;" 2>&1 | head -20
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 确保使用 bash 运行
|
|
||||||
if [ -z "$BASH_VERSION" ]; then
|
|
||||||
exec bash "$0" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 颜色定义
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# 打印带颜色的消息
|
|
||||||
print_yellow() { printf "${YELLOW}%s${NC}\n" "$1"; }
|
|
||||||
print_green() { printf "${GREEN}%s${NC}\n" "$1"; }
|
|
||||||
print_red() { printf "${RED}%s${NC}\n" "$1"; }
|
|
||||||
|
|
||||||
print_yellow "=== 停止 7861 和 8501 端口服务 ==="
|
|
||||||
|
|
||||||
for port in 7861 8501; do
|
|
||||||
pids=$(lsof -t -i:"$port" 2>/dev/null)
|
|
||||||
if [ -n "$pids" ]; then
|
|
||||||
print_yellow "正在停止端口 $port 的进程: $pids"
|
|
||||||
kill -9 $pids 2>/dev/null
|
|
||||||
print_green "端口 $port 已停止"
|
|
||||||
else
|
|
||||||
echo "端口 $port 无运行中的服务"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 也停止所有 startup.py 进程
|
|
||||||
pids=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
if [ -n "$pids" ]; then
|
|
||||||
print_yellow "正在停止 startup.py 进程: $pids"
|
|
||||||
kill -9 $pids 2>/dev/null
|
|
||||||
print_green "startup.py 进程已停止"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
print_yellow "=== 启动服务 ==="
|
|
||||||
|
|
||||||
cd /home/gc/gangyan/langchain-chat
|
|
||||||
|
|
||||||
# 初始化 conda(确保 PATH 中包含 conda 路径)
|
|
||||||
CONDA_INIT="/root/miniconda3/etc/profile.d/conda.sh"
|
|
||||||
if [ -f "$CONDA_INIT" ]; then
|
|
||||||
# 初始化 conda,将 conda 路径添加到 PATH
|
|
||||||
. "$CONDA_INIT" 2>/dev/null || source "$CONDA_INIT" 2>/dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 查找 conda 可执行文件(按优先级)
|
|
||||||
if command -v conda &> /dev/null; then
|
|
||||||
CONDA_EXE="conda"
|
|
||||||
elif [ -f "/root/miniconda3/bin/conda" ]; then
|
|
||||||
CONDA_EXE="/root/miniconda3/bin/conda"
|
|
||||||
elif [ -f "/root/miniconda3/condabin/conda" ]; then
|
|
||||||
CONDA_EXE="/root/miniconda3/condabin/conda"
|
|
||||||
else
|
|
||||||
print_red "错误: 未找到 conda 命令"
|
|
||||||
print_red "请检查 conda 是否已安装: /root/miniconda3"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 使用 conda 环境启动
|
|
||||||
print_yellow "使用环境: gangyan"
|
|
||||||
print_yellow "日志文件: nohup.out"
|
|
||||||
print_yellow "Conda路径: $CONDA_EXE"
|
|
||||||
|
|
||||||
# 获取 python 的完整路径
|
|
||||||
PYTHON_EXE="/root/miniconda3/envs/gangyan/bin/python"
|
|
||||||
if [ ! -f "$PYTHON_EXE" ]; then
|
|
||||||
# 尝试通过 conda run 获取路径
|
|
||||||
PYTHON_EXE="$($CONDA_EXE run -n gangyan which python 2>/dev/null)"
|
|
||||||
if [ -z "$PYTHON_EXE" ] || [ ! -f "$PYTHON_EXE" ]; then
|
|
||||||
print_red "错误: 无法找到 python 可执行文件"
|
|
||||||
print_red "请检查 conda 环境 gangyan 是否已安装"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
print_yellow "Python路径: $PYTHON_EXE"
|
|
||||||
|
|
||||||
# 直接使用 python 完整路径启动(不依赖 conda activate,更可靠)
|
|
||||||
# 设置 PYTHONPATH 确保能正确导入模块
|
|
||||||
export PYTHONPATH="/home/gc/gangyan/langchain-chat:$PYTHONPATH"
|
|
||||||
cd /home/gc/gangyan/langchain-chat
|
|
||||||
nohup "$PYTHON_EXE" startup.py -a >> nohup.out 2>&1 &
|
|
||||||
PID=$!
|
|
||||||
|
|
||||||
print_green "服务已启动,PID: $PID"
|
|
||||||
print_yellow "日志文件: /home/gc/gangyan/langchain-chat/nohup.out"
|
|
||||||
print_yellow "查看日志: tail -f nohup.out"
|
|
||||||
|
|
||||||
# 等待几秒后显示日志
|
|
||||||
sleep 2
|
|
||||||
echo ""
|
|
||||||
print_yellow "=== 最近日志 ==="
|
|
||||||
tail -20 nohup.out
|
|
||||||
@@ -1,186 +1,148 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
import aiohttp
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import requests
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from server.chat import utils
|
from server.chat import utils
|
||||||
|
|
||||||
# 配置日志记录器
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
async def duckduckgo_search_iter(query: str, uuid: str = "",time: str = "", resource_type: str = None, limit: int = 3):
|
# 新接口:内网 searxng 服务(原 43.251.225.121 已下线)
|
||||||
# 定义三个API的URL
|
# aiohttp 与该 searxng 配合会 30s 超时(疑似 header/UA 被拦),所以改用 requests。
|
||||||
text_url = 'http://43.251.225.121/inspur/search_text'
|
SEARXNG_URL = 'http://118.196.92.255/searxng/search'
|
||||||
video_url = 'http://43.251.225.121/inspur/search_video'
|
SEARXNG_HEADERS = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) gangyan-langchain'}
|
||||||
news_url = 'http://43.251.225.121/inspur/search_new'
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"query": query,
|
|
||||||
"time": time
|
|
||||||
}
|
|
||||||
|
|
||||||
async def fetch(session, url, json_payload,limit):
|
def _searxng_results_to_items(results, mapping, limit):
|
||||||
logger.info(f"从 {url} 获取数据,请求参数: {json_payload}")
|
"""把 searxng 统一的 {url,title,content} 映射成老接口期望的字段格式"""
|
||||||
try:
|
out = []
|
||||||
json_payload["limit"] = limit
|
for r in results[:limit]:
|
||||||
async with session.post(url, json=json_payload) as response:
|
title = r.get('title', '') or ''
|
||||||
if response.status != 200:
|
url = r.get('url', '') or ''
|
||||||
logger.error(f"向 {url} 请求失败,状态码 {response.status}")
|
content = r.get('content', '') or ''
|
||||||
data = await response.json()
|
item = {}
|
||||||
logger.info(f"从 {url} 获取的资料数: {len(data) if isinstance(data, list) else '未知'}")
|
for dst_key, src in mapping.items():
|
||||||
return data
|
if src == 'title':
|
||||||
except Exception as e:
|
item[dst_key] = title
|
||||||
logger.error(f"获取 {url} 数据时发生错误: {e}")
|
elif src == 'url':
|
||||||
|
item[dst_key] = url
|
||||||
|
elif src == 'content':
|
||||||
|
item[dst_key] = content
|
||||||
|
out.append(item)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _sync_fetch(params, limit_n, kind):
|
||||||
|
logger.info(f"searxng 请求 {kind}: params={params}")
|
||||||
|
try:
|
||||||
|
r = requests.get(SEARXNG_URL, params=params, headers=SEARXNG_HEADERS, timeout=15)
|
||||||
|
if r.status_code != 200:
|
||||||
|
logger.error(f"searxng {kind} HTTP {r.status_code}")
|
||||||
return []
|
return []
|
||||||
|
data = r.json()
|
||||||
|
results = data.get('results', []) if isinstance(data, dict) else []
|
||||||
|
logger.info(f"searxng {kind} 条数: {len(results)}")
|
||||||
|
if kind == 'text':
|
||||||
|
return _searxng_results_to_items(results, {'title': 'title', 'href': 'url', 'body': 'content'}, limit_n)
|
||||||
|
if kind == 'video':
|
||||||
|
return _searxng_results_to_items(results, {'title': 'title', 'content': 'url', 'description': 'content'}, limit_n)
|
||||||
|
if kind == 'news':
|
||||||
|
return _searxng_results_to_items(results, {'title': 'title', 'url': 'url', 'body': 'content'}, limit_n)
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"searxng {kind} 请求异常: {type(e).__name__}: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
# 根据 resource_type 确定要请求的 API
|
|
||||||
# 默认并发请求三个API
|
|
||||||
# 视频只请求 video_url
|
|
||||||
# 新闻只请求 news_url
|
|
||||||
# 其他类型只请求 text_url
|
|
||||||
async with aiohttp.ClientSession() as session:
|
|
||||||
logger.info("发起请求duckduckgo...")
|
|
||||||
|
|
||||||
n = limit % 3
|
async def duckduckgo_search_iter(query: str, uuid: str = "", time: str = "", resource_type: str = None, limit: int = 3):
|
||||||
limit1 = 0
|
logger.info("发起 searxng 搜索请求...")
|
||||||
limit2 = 0
|
|
||||||
limit3 = 0
|
|
||||||
match n:
|
|
||||||
case 0:
|
|
||||||
limit1 = limit//3
|
|
||||||
limit2 = limit1
|
|
||||||
limit3 = limit1
|
|
||||||
case 1:
|
|
||||||
limit1 = limit//3 +1
|
|
||||||
limit2 = limit//3
|
|
||||||
limit3 = limit2
|
|
||||||
case 2:
|
|
||||||
limit1 = limit//3 +1
|
|
||||||
limit2 = limit1
|
|
||||||
limit2 = limit
|
|
||||||
|
|
||||||
if resource_type is None or not resource_type == 'video':
|
# 三类按 limit 平均分配
|
||||||
text_task = asyncio.create_task(fetch(session, text_url, payload,limit1))
|
n = limit % 3
|
||||||
video_task = asyncio.create_task(fetch(session, video_url, payload, limit3))
|
if n == 0:
|
||||||
news_task = asyncio.create_task(fetch(session, news_url, payload, limit2))
|
limit1 = limit2 = limit3 = limit // 3
|
||||||
text_result, video_result, news_result = await asyncio.gather(text_task, video_task, news_task)
|
elif n == 1:
|
||||||
logger.info("合并结果...")
|
limit1 = limit // 3 + 1
|
||||||
|
limit2 = limit3 = limit // 3
|
||||||
logger.info("合并结果完成")
|
else:
|
||||||
combined_result = {
|
limit1 = limit2 = limit // 3 + 1
|
||||||
"text": text_result,
|
limit3 = limit // 3
|
||||||
"video": video_result,
|
|
||||||
"news": news_result
|
|
||||||
}
|
|
||||||
|
|
||||||
else:
|
if resource_type is None or resource_type != 'video':
|
||||||
video_result = await fetch(session, video_url, payload, limit)
|
text_task = asyncio.to_thread(_sync_fetch, {'q': query, 'format': 'json', 'categories': 'general'}, limit1, 'text')
|
||||||
combined_result = {
|
news_task = asyncio.to_thread(_sync_fetch, {'q': query, 'format': 'json', 'categories': 'news'}, limit2, 'news')
|
||||||
"video": video_result
|
video_task = asyncio.to_thread(_sync_fetch, {'q': query, 'format': 'json', 'categories': 'videos'}, limit3, 'video')
|
||||||
}
|
text_result, news_result, video_result = await asyncio.gather(text_task, news_task, video_task)
|
||||||
del limit1,limit2,limit3
|
combined_result = {
|
||||||
# elif resource_type == 'news':
|
"text": text_result,
|
||||||
# news_result = await fetch(session, news_url, payload)
|
"video": video_result,
|
||||||
# combined_result = {
|
"news": news_result,
|
||||||
# "news": news_result
|
}
|
||||||
# }
|
else:
|
||||||
|
video_result = await asyncio.to_thread(_sync_fetch, {'q': query, 'format': 'json', 'categories': 'videos'}, limit, 'video')
|
||||||
|
combined_result = {"video": video_result}
|
||||||
|
|
||||||
# else: # 其他类型
|
logger.info("searxng 请求已完成")
|
||||||
# text_result = await fetch(session, text_url, payload)
|
|
||||||
# combined_result = {
|
|
||||||
# "text": text_result
|
|
||||||
# }
|
|
||||||
|
|
||||||
logger.info("请求已完成")
|
res = []
|
||||||
res = []
|
source = []
|
||||||
source = []
|
info = utils.get_shared_variable(uuid)
|
||||||
info = utils.get_shared_variable(uuid)
|
index = info["num"]
|
||||||
index = info["num"]
|
if "text" in combined_result:
|
||||||
if "text" in combined_result:
|
for item in combined_result["text"]:
|
||||||
for item in combined_result["text"]:
|
index += 1
|
||||||
index += 1
|
res.append(f'资料[{index}] 资料标题{item["title"]}({item["href"]}) 资料内容为: {item["body"]}')
|
||||||
res.append(f'资料[{index}] 资料标题{item["title"]}({item["href"]}) 资料内容为: {item["body"]}')
|
source.append(f'资料[{index}] [{item["title"]}]({item["href"]})')
|
||||||
source.append(f'资料[{index}] [{item["title"]}]({item["href"]})')
|
if "video" in combined_result:
|
||||||
if "video" in combined_result:
|
for item in combined_result["video"]:
|
||||||
for item in combined_result["video"]:
|
index += 1
|
||||||
index += 1
|
res.append(f'资料[{index}] 视频标题[{item["title"]}]({item["content"]}) 视频内容为: {item["description"]}')
|
||||||
res.append(f'资料[{index}] 视频标题[{item["title"]}]({item["content"]}) 视频内容为: {item["description"]}')
|
source.append(f'视频资料[{index}] [{item["title"]}]({item["content"]})')
|
||||||
source.append(f'视频资料[{index}] [{item["title"]}]({item["content"]})')
|
if "news" in combined_result:
|
||||||
if "news" in combined_result:
|
for item in combined_result["news"]:
|
||||||
for item in combined_result["news"]:
|
index += 1
|
||||||
index += 1
|
res.append(f'资料[{index}] 新闻标题[{item["title"]}]({item["url"]}) 新闻内容为: {item["body"]}')
|
||||||
res.append(f'资料[{index}] 新闻标题[{item["title"]}]({item["url"]}) 新闻内容为: {item["body"]}')
|
source.append(f'资料[{index}] [{item["title"]}]({item["url"]})')
|
||||||
source.append(f'资料[{index}] [{item["title"]}]({item["url"]})')
|
info["source_docs"].extend(source)
|
||||||
info["source_docs"].extend(source)
|
utils.set_shared_variable(uuid, info)
|
||||||
utils.set_shared_variable(uuid, info)
|
return res, source
|
||||||
return res,source
|
|
||||||
|
|
||||||
|
|
||||||
def duckduckgo_search(query: str, time: str = "", resource_type: str = None):
|
def duckduckgo_search(query: str, time: str = "", resource_type: str = None):
|
||||||
logger.info(f"模型输入: {query}")
|
logger.info(f"模型输入: {query}")
|
||||||
# 对传入的 query 字段进行解析
|
|
||||||
# 判断 query 是否包含 "}{"
|
|
||||||
# if "}{" in query:
|
|
||||||
# # 将 query 分割为两个JSON字符串
|
|
||||||
# split_index = query.find("}{")
|
|
||||||
# json_part1 = query[:split_index+1]
|
|
||||||
# json_part2 = query[split_index+1:]
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# obj1 = json.loads(json_part1)
|
|
||||||
# obj2 = json.loads(json_part2)
|
|
||||||
|
|
||||||
# # 提取 query, resource_type, time, uuid
|
|
||||||
# parsed_query = obj1.get("query", "")
|
|
||||||
# parsed_resource_type = obj1.get("resource_type", None)
|
|
||||||
# parsed_time = obj1.get("time", time) # 如obj1未包含time则使用传入的默认值
|
|
||||||
# parsed_uuid = obj2.get("uuid", "")
|
|
||||||
matches = re.findall(r'\{.*?\}', query)
|
matches = re.findall(r'\{.*?\}', query)
|
||||||
if len(matches)>=2:
|
if len(matches) >= 2:
|
||||||
query = matches[0]
|
query = matches[0]
|
||||||
else:
|
else:
|
||||||
return "<关键指令>不需要再调用该工具了</关键指令>"
|
return "<关键指令>不需要再调用该工具了</关键指令>"
|
||||||
|
parsed_uuid = ""
|
||||||
|
parsed_limit = 3
|
||||||
try:
|
try:
|
||||||
obj1= json.loads(query)
|
obj1 = json.loads(query)
|
||||||
parsed_query = obj1.get("query", "")
|
parsed_query = obj1.get("query", "")
|
||||||
parsed_limit = obj1.get("limit", 3)
|
parsed_limit = obj1.get("limit", 3)
|
||||||
parsed_resource_type = obj1.get("resource_type", None)
|
parsed_resource_type = obj1.get("resource_type", None)
|
||||||
parsed_time = obj1.get("time", time) # 如obj1未包含time则使用传入的默认值
|
parsed_time = obj1.get("time", time)
|
||||||
parsed_uuid = json.loads(matches[1])["uuid"]
|
parsed_uuid = json.loads(matches[1])["uuid"]
|
||||||
# 将解析到的值覆盖原有的参数
|
|
||||||
query = parsed_query if parsed_query else query
|
query = parsed_query if parsed_query else query
|
||||||
resource_type = parsed_resource_type if parsed_resource_type else resource_type
|
resource_type = parsed_resource_type if parsed_resource_type else resource_type
|
||||||
time = parsed_time if parsed_time else time
|
time = parsed_time if parsed_time else time
|
||||||
|
|
||||||
logger.info(f"解析完成,query: {query}, uuid: {parsed_uuid}, time: {time}, resource_type: {resource_type}, parsed_limit: {parsed_limit}")
|
logger.info(f"解析完成,query: {query}, uuid: {parsed_uuid}, time: {time}, resource_type: {resource_type}, parsed_limit: {parsed_limit}")
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
logger.error(f"解析JSON出错: {e}")
|
logger.error(f"解析JSON出错: {e}")
|
||||||
|
|
||||||
# 在同步环境中运行异步函数
|
|
||||||
combined_result = asyncio.run(duckduckgo_search_iter(query, parsed_uuid, time, resource_type, parsed_limit))
|
combined_result = asyncio.run(duckduckgo_search_iter(query, parsed_uuid, time, resource_type, parsed_limit))
|
||||||
# 以标准json格式输出
|
|
||||||
logger.info("返回JSON格式的结果给到模型...")
|
logger.info("返回JSON格式的结果给到模型...")
|
||||||
return combined_result
|
return combined_result
|
||||||
|
|
||||||
|
|
||||||
class DuckduckgoInput(BaseModel):
|
class DuckduckgoInput(BaseModel):
|
||||||
location: str = Field(description="网络搜索查询")
|
location: str = Field(description="网络搜索查询")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 测试调用
|
result_other = duckduckgo_search('{"query":"粉末冶金","limit":3}{"uuid":"test-uuid"}', "m", "other")
|
||||||
# 1. 默认请求三个API
|
print("searxng输出(其他):\n", result_other)
|
||||||
# result_default = duckduckgo_search("粉末冶金", "m", "default")
|
|
||||||
# print("duckduckgo输出(默认):\n", result_default)
|
|
||||||
|
|
||||||
# # 2. 只请求视频
|
|
||||||
# result_video = duckduckgo_search("粉末冶金", "m", "video")
|
|
||||||
# print("duckduckgo输出(视频):\n", result_video)
|
|
||||||
|
|
||||||
# # 3. 只请求新闻
|
|
||||||
# result_news = duckduckgo_search("粉末冶金", "m", "news")
|
|
||||||
# print("duckduckgo输出(新闻):\n", result_news)
|
|
||||||
|
|
||||||
# 4. 其它类型只请求文本
|
|
||||||
result_other = duckduckgo_search("粉末冶金", "m", "other")
|
|
||||||
print("duckduckgo输出(其他):\n", result_other)
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class ZhipuSearchAPIWrapper:
|
|||||||
)
|
)
|
||||||
|
|
||||||
logging.info(f"Zhipu检索内容:{search_query}")
|
logging.info(f"Zhipu检索内容:{search_query}")
|
||||||
url = "http://ywk3hvt4d:01Jp2V1tR9PdTsYSz919779Rb9_@134.122.191.214/search"
|
url = "http://118.196.92.255/searxng/search"
|
||||||
engines = "duckduckgo,bing"
|
engines = "duckduckgo,bing"
|
||||||
data = {
|
data = {
|
||||||
"format":"json",
|
"format":"json",
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# mac设备上的grep命令可能不支持grep -P选项,请使用Homebrew安装;或使用ggrep命令
|
|
||||||
ps -eo pid,user,cmd|grep -P 'server/api.py|webui.py|fastchat.serve|langchain_chat'|grep -v grep|awk '{print $1}'|xargs kill -9
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 启动 Python 后端服务脚本(使用 nohup)
|
|
||||||
|
|
||||||
# 颜色定义
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# 检查是否已有进程在运行
|
|
||||||
EXISTING=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
if [ -n "$EXISTING" ]; then
|
|
||||||
echo -e "${YELLOW}警告: 检测到已有 Python 后端进程在运行 (PID: $EXISTING)${NC}"
|
|
||||||
read -p "是否先停止现有进程? (y/n): " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo -e "${YELLOW}正在停止现有进程...${NC}"
|
|
||||||
kill $EXISTING 2>/dev/null
|
|
||||||
sleep 2
|
|
||||||
# 如果还在运行,强制终止
|
|
||||||
if ps -p $EXISTING > /dev/null 2>&1; then
|
|
||||||
kill -9 $EXISTING 2>/dev/null
|
|
||||||
fi
|
|
||||||
echo -e "${GREEN}已停止现有进程${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}请先停止现有进程或使用 stop.sh${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 获取脚本所在目录
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
||||||
cd "$SCRIPT_DIR"
|
|
||||||
|
|
||||||
# 设置 PDF 转换服务环境变量(确保与 pdf-convert-service 一致)
|
|
||||||
export PDF_CONVERT_KB_ROOT="${PDF_CONVERT_KB_ROOT:-$SCRIPT_DIR/knowledge_base}"
|
|
||||||
|
|
||||||
# 检查 conda 环境
|
|
||||||
if ! command -v conda &> /dev/null; then
|
|
||||||
echo -e "${RED}错误: 未找到 conda 命令${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 激活 conda 环境并启动
|
|
||||||
echo -e "${YELLOW}正在启动 Python 后端...${NC}"
|
|
||||||
echo -e "${YELLOW}使用环境: gangyan${NC}"
|
|
||||||
echo -e "${YELLOW}日志文件: nohup.out${NC}"
|
|
||||||
|
|
||||||
# 使用 nohup 启动
|
|
||||||
nohup conda run -n gangyan python startup.py -a > nohup.out 2>&1 &
|
|
||||||
PID=$!
|
|
||||||
|
|
||||||
echo -e "${GREEN}后端已启动,PID: $PID${NC}"
|
|
||||||
echo -e "${YELLOW}查看日志: tail -f nohup.out${NC}"
|
|
||||||
echo -e "${YELLOW}停止服务: ./stop.sh${NC}"
|
|
||||||
|
|
||||||
# 等待几秒后显示日志
|
|
||||||
sleep 2
|
|
||||||
echo -e "\n${YELLOW}=== 最近日志 ===${NC}"
|
|
||||||
tail -20 nohup.out
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 停止 Python 后端服务脚本
|
|
||||||
|
|
||||||
# 默认端口(从 server_config.py 中获取)
|
|
||||||
DEFAULT_PORT=7861
|
|
||||||
|
|
||||||
# 颜色定义
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "${YELLOW}正在查找运行中的 Python 后端进程...${NC}"
|
|
||||||
|
|
||||||
# 方法1: 通过进程名查找
|
|
||||||
PIDS=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
|
|
||||||
# 方法2: 如果方法1没找到,通过端口查找
|
|
||||||
if [ -z "$PIDS" ]; then
|
|
||||||
echo -e "${YELLOW}未找到 startup.py 进程,尝试通过端口 ${DEFAULT_PORT} 查找...${NC}"
|
|
||||||
PIDS=$(lsof -ti:${DEFAULT_PORT} 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$PIDS" ]; then
|
|
||||||
echo -e "${RED}未找到运行中的 Python 后端进程${NC}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}找到以下进程:${NC}"
|
|
||||||
ps aux | grep "[p]ython.*startup.py -a" | grep -v grep
|
|
||||||
if [ -n "$PIDS" ]; then
|
|
||||||
echo -e "${YELLOW}进程 PID: $PIDS${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 询问是否确认停止
|
|
||||||
read -p "是否停止这些进程? (y/n): " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo -e "${YELLOW}已取消${NC}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 停止进程
|
|
||||||
for PID in $PIDS; do
|
|
||||||
if [ -n "$PID" ]; then
|
|
||||||
echo -e "${YELLOW}正在停止进程 $PID...${NC}"
|
|
||||||
kill $PID 2>/dev/null
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
echo -e "${GREEN}进程 $PID 已发送停止信号${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}无法停止进程 $PID${NC}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 等待进程结束
|
|
||||||
echo -e "${YELLOW}等待进程结束...${NC}"
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
# 检查是否还有进程在运行
|
|
||||||
REMAINING=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
if [ -n "$REMAINING" ]; then
|
|
||||||
echo -e "${YELLOW}仍有进程在运行,强制终止...${NC}"
|
|
||||||
for PID in $REMAINING; do
|
|
||||||
kill -9 $PID 2>/dev/null
|
|
||||||
echo -e "${GREEN}已强制终止进程 $PID${NC}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}所有进程已停止${NC}"
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 快速停止 Python 后端服务脚本(无需确认)
|
|
||||||
|
|
||||||
# 默认端口
|
|
||||||
DEFAULT_PORT=7861
|
|
||||||
|
|
||||||
# 颜色定义
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
RED='\033[0;31m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
echo -e "${YELLOW}正在查找并停止 Python 后端进程...${NC}"
|
|
||||||
|
|
||||||
# 方法1: 通过进程名查找
|
|
||||||
PIDS=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
|
|
||||||
# 方法2: 如果方法1没找到,通过端口查找
|
|
||||||
if [ -z "$PIDS" ]; then
|
|
||||||
PIDS=$(lsof -ti:${DEFAULT_PORT} 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$PIDS" ]; then
|
|
||||||
echo -e "${RED}未找到运行中的 Python 后端进程${NC}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 显示找到的进程
|
|
||||||
echo -e "${GREEN}找到以下进程:${NC}"
|
|
||||||
ps aux | grep "[p]ython.*startup.py -a" | grep -v grep
|
|
||||||
|
|
||||||
# 停止进程
|
|
||||||
for PID in $PIDS; do
|
|
||||||
if [ -n "$PID" ]; then
|
|
||||||
echo -e "${YELLOW}正在停止进程 $PID...${NC}"
|
|
||||||
kill $PID 2>/dev/null
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# 等待进程结束
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
# 检查是否还有进程在运行,如果有则强制终止
|
|
||||||
REMAINING=$(ps aux | grep "[p]ython.*startup.py -a" | awk '{print $2}')
|
|
||||||
if [ -n "$REMAINING" ]; then
|
|
||||||
echo -e "${YELLOW}强制终止剩余进程...${NC}"
|
|
||||||
for PID in $REMAINING; do
|
|
||||||
kill -9 $PID 2>/dev/null
|
|
||||||
echo -e "${GREEN}已强制终止进程 $PID${NC}"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ 所有进程已停止${NC}"
|
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||||
# 重启 Java 后端 chat_web_yj.jar(与 start_all.sh 一致)
|
# 重启 Java 后端 chat_web_backend.jar(源码 mvn 编译产物,profile=dev)
|
||||||
# 日志:gangyan/logs/backend.log
|
# 日志:gangyan/logs/backend.log
|
||||||
# 勿在此加 -Dspring.datasource*:与 application-local.yml 打架易连错库。
|
# 注:backend/chat_web_yj.jar(同一 jar 的改名副本)及其 application-local.yml 覆盖配置已于 2026-04-20 归档删除。
|
||||||
# 若 jar 未重打、内嵌 yml 仍是远程库,必须依赖 backend/application-local.yml(含完整 spring 数据源)。
|
|
||||||
set -u
|
set -u
|
||||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||||
# 默认 backend.log;若曾被 root 创建导致当前用户不可写,则改用同目录 backend-<用户>.log(仍在 gangyan/logs 下)
|
# 默认 backend.log;若曾被 root 创建导致当前用户不可写,则改用同目录 backend-<用户>.log
|
||||||
LOG_FILE="$LOG_DIR/backend.log"
|
LOG_FILE="$LOG_DIR/backend.log"
|
||||||
if ! ( umask 022; : >>"$LOG_FILE" ) 2>/dev/null; then
|
if ! ( umask 022; : >>"$LOG_FILE" ) 2>/dev/null; then
|
||||||
ALT="$LOG_DIR/backend-$(id -un).log"
|
ALT="$LOG_DIR/backend-$(id -un).log"
|
||||||
@@ -25,34 +24,41 @@ fi
|
|||||||
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
||||||
export PATH="$JAVA_HOME/bin:$PATH"
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
|
|
||||||
log_tee "======== 停止 chat_web_yj.jar ========"
|
BACKEND_DIR="$GANGYAN_ROOT/chat_web_backend"
|
||||||
pkill -f "chat_web_yj.jar" 2>/dev/null && log_tee "已发送停止信号" || log_tee "未找到运行中的进程"
|
JAR_REL="target/chat_web_backend.jar"
|
||||||
sleep 2
|
|
||||||
|
|
||||||
log_tee "======== 启动 chat_web_yj.jar ========"
|
if [ ! -f "$BACKEND_DIR/$JAR_REL" ]; then
|
||||||
cd "$GANGYAN_ROOT/backend"
|
log_tee "错误: 未找到 $BACKEND_DIR/$JAR_REL。先执行 chat_web_backend/compile.sh 编译。"
|
||||||
LOCAL_CFG="$GANGYAN_ROOT/backend/application-local.yml"
|
exit 1
|
||||||
EXTRA_JAVA_ARGS=()
|
|
||||||
if [ -f "$LOCAL_CFG" ]; then
|
|
||||||
log_tee "加载本地配置: $LOCAL_CFG"
|
|
||||||
EXTRA_JAVA_ARGS=(-Dspring.config.additional-location="file:${LOCAL_CFG}")
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log_tee "======== 停止 chat_web_backend.jar ========"
|
||||||
|
pkill -f "target/chat_web_backend.jar" 2>/dev/null && log_tee "已发送停止信号" || log_tee "未找到运行中的进程"
|
||||||
|
sleep 2
|
||||||
|
# 端口兜底(非 hawei 启的旧进程 lsof 可能看不到,用 ss 探测)
|
||||||
|
if ss -tln 2>/dev/null | grep -qE ':8099[[:space:]]'; then
|
||||||
|
log_tee "8099 仍被占用,再等 3 秒..."
|
||||||
|
sleep 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_tee "======== 启动 chat_web_backend.jar (profile=dev) ========"
|
||||||
|
cd "$BACKEND_DIR"
|
||||||
nohup java -jar \
|
nohup java -jar \
|
||||||
-Xms512m -Xmx2048m \
|
-Xms512m -Xmx2048m \
|
||||||
"${EXTRA_JAVA_ARGS[@]}" \
|
"$JAR_REL" \
|
||||||
-Dspring.profiles.active=yj \
|
--spring.profiles.active=dev >> "$LOG_FILE" 2>&1 &
|
||||||
chat_web_yj.jar >> "$LOG_FILE" 2>&1 &
|
|
||||||
STARTED_PID=$!
|
STARTED_PID=$!
|
||||||
log_tee "已后台启动,PID=$STARTED_PID"
|
log_tee "已后台启动,PID=$STARTED_PID"
|
||||||
log_tee "Java 标准输出/错误写入: $LOG_FILE"
|
log_tee "Java 标准输出/错误写入: $LOG_FILE"
|
||||||
sleep 3
|
sleep 3
|
||||||
if kill -0 "$STARTED_PID" 2>/dev/null; then
|
if kill -0 "$STARTED_PID" 2>/dev/null; then
|
||||||
if command -v ss >/dev/null 2>&1 && ss -tln 2>/dev/null | grep -q ':8099'; then
|
if ss -tln 2>/dev/null | grep -qE ':8099[[:space:]]'; then
|
||||||
log_tee "自检: 进程存活且 8099 已监听(后端已就绪或即将就绪)"
|
log_tee "自检: 进程存活且 8099 已监听"
|
||||||
else
|
else
|
||||||
log_tee "自检: 进程存活,但 8099 尚未监听(可能仍在启动;若 10 秒后仍无,请 tail 上面日志路径)"
|
log_tee "自检: 进程存活,但 8099 尚未监听(可能仍在启动;10 秒后若仍无请 tail $LOG_FILE)"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log_tee "自检失败: 进程已退出。请查看日志末尾:"
|
log_tee "自检失败: 进程已退出。最近日志:"
|
||||||
tail -n 40 "$LOG_FILE" 2>/dev/null | while IFS= read -r line || [ -n "$line" ]; do log_line "$line"; done
|
tail -n 40 "$LOG_FILE" 2>/dev/null | while IFS= read -r line || [ -n "$line" ]; do log_line "$line"; done
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ fi
|
|||||||
|
|
||||||
MAX_BYTES=$((MAX_MB * 1024 * 1024))
|
MAX_BYTES=$((MAX_MB * 1024 * 1024))
|
||||||
TMP="${FILE}.trimtmp.$$"
|
TMP="${FILE}.trimtmp.$$"
|
||||||
LOCK="${FILE}.trimlock"
|
# LOCK 放 /tmp 并按用户命名,避免不同用户启动时 .trimlock owner 错配导致 Permission denied
|
||||||
|
LOCK="/tmp/gangyan-trim-$(basename "$FILE").$(id -un).lock"
|
||||||
|
|
||||||
mkdir -p "$(dirname "$FILE")"
|
mkdir -p "$(dirname "$FILE")"
|
||||||
touch "$FILE" 2>/dev/null || true
|
touch "$FILE" 2>/dev/null || true
|
||||||
|
|||||||
83
scripts/start-all.sh
Executable file
83
scripts/start-all.sh
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||||
|
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||||
|
# 一键启动全部 gangyan 服务:基础设施 -> 后端 -> 前端。
|
||||||
|
# 每一步直接 source 已有的 *-restart.sh,保持单一事实来源。
|
||||||
|
# 日志:gangyan/logs/start-all.log
|
||||||
|
set -u
|
||||||
|
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||||
|
LOG_FILE="$LOG_DIR/start-all.log"
|
||||||
|
|
||||||
|
run_step() {
|
||||||
|
local label="$1" script="$2"
|
||||||
|
log_tee "━━━━━━━━ ${label} ━━━━━━━━"
|
||||||
|
if [ ! -x "$SCRIPT_DIR/$script" ]; then
|
||||||
|
log_tee "跳过: $script 不存在或不可执行"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
bash "$SCRIPT_DIR/$script" 2>&1 | tee -a "$LOG_FILE"
|
||||||
|
local rc=${PIPESTATUS[0]}
|
||||||
|
[ "$rc" -eq 0 ] || log_tee "警告: $script 返回 $rc"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
port_check() {
|
||||||
|
local port="$1" name="$2"
|
||||||
|
if ss -tln 2>/dev/null | grep -qE ":${port}[[:space:]]"; then
|
||||||
|
log_tee " [OK] ${name} :${port}"
|
||||||
|
else
|
||||||
|
log_tee " [!!] ${name} :${port} 未监听"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
log_tee "╔══════════════════════════════════════╗"
|
||||||
|
log_tee "║ gangyan 全量启动 $(date '+%F %H:%M:%S') ║"
|
||||||
|
log_tee "╚══════════════════════════════════════╝"
|
||||||
|
|
||||||
|
# 1) 基础设施(Docker 容器:MySQL / Redis / Milvus)
|
||||||
|
run_step "[1/5] MySQL" mysql-restart.sh
|
||||||
|
run_step "[2/5] Redis" redis-restart.sh
|
||||||
|
run_step "[3/5] Milvus" milvus-restart.sh
|
||||||
|
|
||||||
|
# 2) 应用层(langchain-chat 会顺带起 pdf-convert-service + log-trim daemon)
|
||||||
|
run_step "[4/6] langchain-chat + pdf-convert + log-trim" langchain-restart.sh
|
||||||
|
run_step "[5/6] Java 后端" backend-restart.sh
|
||||||
|
run_step "[6/6] 前端 vite" frontend-restart.sh
|
||||||
|
|
||||||
|
# 3) 辅助进程状态(excalidraw-ai / pptist-ai 当前以 screen -dmS 管理,非脚本化;本脚本仅做健康检查)
|
||||||
|
log_tee "━━━━━━━━ 辅助进程检查 ━━━━━━━━"
|
||||||
|
if pgrep -f 'excalidraw-ai-proxy\.py' >/dev/null; then
|
||||||
|
log_tee " [OK] excalidraw-ai-proxy.py (screen -dmS aiproxy)"
|
||||||
|
else
|
||||||
|
log_tee " [!!] excalidraw-ai-proxy.py 未运行。手动启: screen -dmS aiproxy bash -c 'cd $GANGYAN_ROOT/scripts && /opt/software/miniconda3/envs/langchain-chat/bin/python excalidraw-ai-proxy.py'"
|
||||||
|
fi
|
||||||
|
if pgrep -f 'pptist-ai-backend\.py' >/dev/null; then
|
||||||
|
log_tee " [OK] pptist-ai-backend.py (screen -dmS pptist-ai)"
|
||||||
|
else
|
||||||
|
log_tee " [!!] pptist-ai-backend.py 未运行。手动启: screen -dmS pptist-ai bash -c 'cd $GANGYAN_ROOT/scripts && /opt/software/miniconda3/envs/langchain-chat/bin/python pptist-ai-backend.py'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) 系统级 tools-nginx(systemd 管理,不在本脚本中重启)
|
||||||
|
if systemctl is-active --quiet nginx 2>/dev/null; then
|
||||||
|
log_tee " [OK] nginx (systemd, tools-nginx.conf -> :18000)"
|
||||||
|
else
|
||||||
|
log_tee " [!!] nginx 未运行。sudo systemctl start nginx"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5) 端口自检
|
||||||
|
log_tee "━━━━━━━━ 端口自检(等 5 秒) ━━━━━━━━"
|
||||||
|
sleep 5
|
||||||
|
port_check 3306 "MySQL (3306 映射)"
|
||||||
|
port_check 33306 "MySQL (33306 映射)"
|
||||||
|
port_check 6379 "Redis"
|
||||||
|
port_check 19530 "Milvus gRPC"
|
||||||
|
port_check 9091 "Milvus HTTP"
|
||||||
|
port_check 7861 "langchain-chat API"
|
||||||
|
port_check 6006 "pdf-convert-service"
|
||||||
|
port_check 8099 "Java 后端"
|
||||||
|
port_check 3000 "vite 前端"
|
||||||
|
port_check 18000 "tools-nginx (工具集合)"
|
||||||
|
|
||||||
|
log_tee ""
|
||||||
|
log_tee "完成。完整日志: $LOG_FILE"
|
||||||
|
log_tee "访问: http://<server-ip>:3000/metalinfo"
|
||||||
58
start_all.sh
58
start_all.sh
@@ -1,58 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# 启动 gangyan 项目所有服务(与 /opt/start_all.sh 同步维护时可覆盖过去)
|
|
||||||
|
|
||||||
echo "启动 gangyan 项目服务..."
|
|
||||||
|
|
||||||
# 1. 启动 Docker 服务
|
|
||||||
echo "[1/4] 启动 Docker 服务..."
|
|
||||||
cd /opt/download/oss_files/gangyan-deploy/gangyan/milvus && docker compose up -d
|
|
||||||
cd /opt/download/oss_files/gangyan-deploy/gangyan/mysql/mysql-8.4.4 && docker compose up -d
|
|
||||||
docker start redis-server 2>/dev/null || docker run -d --name redis-server -p 6379:6379 redis:7-alpine
|
|
||||||
|
|
||||||
# 2. 启动 Java 后端(MySQL 33306 / Redis 见 jar 内 application-yj.yml;勿在此加 -Dspring.datasource* 以免覆盖端口)
|
|
||||||
echo "[2/4] 启动 Java 后端..."
|
|
||||||
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
|
||||||
export PATH=$JAVA_HOME/bin:$PATH
|
|
||||||
pkill -f "chat_web_yj.jar" 2>/dev/null
|
|
||||||
sleep 2
|
|
||||||
cd /opt/download/oss_files/gangyan-deploy/gangyan/backend
|
|
||||||
LOCAL_CFG="/opt/download/oss_files/gangyan-deploy/gangyan/backend/application-local.yml"
|
|
||||||
EXTRA_JAVA=()
|
|
||||||
[ -f "$LOCAL_CFG" ] && EXTRA_JAVA=(-Dspring.config.additional-location="file:${LOCAL_CFG}")
|
|
||||||
nohup java -jar \
|
|
||||||
-Xms512m -Xmx2048m \
|
|
||||||
"${EXTRA_JAVA[@]}" \
|
|
||||||
-Dspring.profiles.active=yj \
|
|
||||||
chat_web_yj.jar > nohup.out 2>&1 &
|
|
||||||
|
|
||||||
# 3. 启动前端
|
|
||||||
echo "[3/4] 启动前端..."
|
|
||||||
if ! pgrep -f "vite" > /dev/null; then
|
|
||||||
cd /opt/download/oss_files/gangyan-deploy/gangyan/chat_web_front
|
|
||||||
nohup npm run dev > nohup.out 2>&1 &
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 4. 启动 langchain-chat(可选)
|
|
||||||
# --all-api:仅 API(7861)+依赖进程,不启 Streamlit WebUI;-a 需要 pip install streamlit
|
|
||||||
echo "[4/4] 启动 langchain-chat(可选)..."
|
|
||||||
read -p "是否启动 langchain-chat? (y/n) " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
source /opt/software/miniconda3/etc/profile.d/conda.sh
|
|
||||||
conda activate langchain-chat
|
|
||||||
cd /opt/download/oss_files/gangyan-deploy/gangyan/langchain-chat
|
|
||||||
export PYTHONPATH="/opt/download/oss_files/gangyan-deploy/gangyan/langchain-chat"
|
|
||||||
nohup python startup.py --all-api > langchain.log 2>&1 &
|
|
||||||
echo "langchain-chat 启动中(API :7861),查看日志: tail -f langchain.log"
|
|
||||||
# PDF 预览依赖的本地转换微服务(:6006,PyMuPDF 抽文本→Markdown)
|
|
||||||
bash /opt/download/oss_files/gangyan-deploy/gangyan/scripts/pdf-convert-service.sh
|
|
||||||
echo "pdf-convert-service 已尝试启动(:6006),日志: tail -f /opt/download/oss_files/gangyan-deploy/gangyan/logs/pdf-convert-service.log"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "服务启动完成!"
|
|
||||||
echo " 前端: http://localhost:3000/metalinfo"
|
|
||||||
echo " 后端: http://localhost:8099/chat_web_backend"
|
|
||||||
echo " MySQL: localhost:33306 (Docker 映射,勿用 3306 连宿主)"
|
|
||||||
echo " Redis: localhost:6379"
|
|
||||||
echo " Milvus: localhost:19530"
|
|
||||||
Reference in New Issue
Block a user