`
+
+**优化**:
+- 🎯 新闻搜索使用专用关键词(优先级高于网站名称)
+- 🎯 严格匹配策略(双引号包裹关键词)
+- 🎯 所有search_site_news调用传递news_keywords参数
+
+**修复**:
+- 🐛 解决网站名称相似导致的新闻混淆问题
+- 🐛 提高新闻相关性和准确性
+
+---
+
+**部署文档版本**: v1.0
+**最后更新**: 2025-12-31
+**维护者**: ZJPB开发团队
diff --git a/DEPLOY_v2.3_QUICK.md b/DEPLOY_v2.3_QUICK.md
new file mode 100644
index 0000000..cafd601
--- /dev/null
+++ b/DEPLOY_v2.3_QUICK.md
@@ -0,0 +1,175 @@
+# ZJPB v2.3.0 快速部署指南
+
+> 3步完成部署,5分钟上线
+
+---
+
+## 📦 版本信息
+
+- **版本**: v2.3.0
+- **日期**: 2025-12-31
+- **核心**: 新闻准确性优化
+
+---
+
+## ⚡ 快速部署(3步)
+
+### 第1步:拉取代码
+
+```bash
+cd /opt/1panel/apps/zjpb
+./manage.sh stop
+git pull origin master
+```
+
+### 第2步:数据库迁移
+
+```bash
+source venv/bin/activate
+python migrate_news_keywords.py
+```
+
+### 第3步:重启应用
+
+```bash
+./manage.sh restart
+./manage.sh status
+```
+
+✅ **部署完成!**
+
+---
+
+## ✅ 快速验证
+
+### 1. 后台验证(1分钟)
+
+```
+1. 访问:http://your-domain.com/admin/login
+2. 进入:网站管理 → 编辑任意网站
+3. 检查:是否有"新闻关键词"字段
+```
+
+### 2. 前台验证(1分钟)
+
+```
+1. 访问:http://your-domain.com/site/xxxxxxxx
+2. 滚动:到"相关新闻"模块
+3. 检查:是否有"获取最新资讯"按钮
+```
+
+---
+
+## 🎯 核心功能
+
+### 1. 新闻关键词设置
+
+**后台操作**:
+```
+网站管理 → 编辑 → 新闻关键词 → 输入"ChatGPT" → 保存
+```
+
+**效果**:
+- 搜索更精准
+- 避免名称混淆
+- 提高相关性
+
+### 2. 前台手动刷新
+
+**用户操作**:
+```
+详情页 → 相关新闻 → 点击"获取最新资讯" → 等待刷新
+```
+
+**效果**:
+- 获取最新5条新闻
+- 自动去重
+- 1-2秒完成
+
+---
+
+## 🔧 关键词设置技巧
+
+### 推荐设置
+
+| 网站名称 | 推荐关键词 | 说明 |
+|---------|-----------|------|
+| ChatGPT | `ChatGPT` | 官方品牌名 |
+| GitHub Copilot | `GitHub Copilot` | 完整产品名 |
+| Claude | `Claude AI` | 添加AI避免混淆 |
+| 文心一言 | `文心一言` | 中文全称 |
+
+### 避免设置
+
+❌ `AI`、`工具`、`助手` - 过于宽泛
+❌ `聊天机器人` - 不够精准
+❌ `GPT` - 会匹配所有GPT相关
+
+---
+
+## 🐛 问题速查
+
+### 问题1:后台没有新字段
+
+```bash
+# 检查代码
+grep "news_keywords" app.py
+
+# 清缓存重启
+./manage.sh restart
+```
+
+### 问题2:刷新按钮不显示
+
+```bash
+# 检查模板
+grep "refresh-news-btn" templates/detail_new.html
+
+# 强制刷新浏览器(Ctrl + F5)
+```
+
+### 问题3:刷新失败
+
+```bash
+# 检查API配置
+grep "BOCHA_API_KEY" .env
+
+# 如未配置,添加:
+echo "BOCHA_API_KEY=sk-your-key" >> .env
+./manage.sh restart
+```
+
+---
+
+## 📊 变更文件
+
+| 文件 | 说明 |
+|------|------|
+| `models.py` | 添加字段 |
+| `migrate_news_keywords.py` | 迁移脚本 |
+| `app.py` | 后台+API |
+| `utils/news_searcher.py` | 搜索逻辑 |
+| `templates/detail_new.html` | 刷新按钮 |
+
+---
+
+## 🔄 回滚(如需要)
+
+```bash
+cd /opt/1panel/apps/zjpb
+./manage.sh stop
+git reset --hard HEAD~1 # 回到上一版本
+./manage.sh start
+```
+
+---
+
+## 📚 完整文档
+
+详细信息请查看:`DEPLOY_v2.3.0.md`
+
+---
+
+**快速指南版本**: v1.0
+**部署时间**: 约5分钟
+**难度**: ⭐ 简单
diff --git a/app.py b/app.py
index 2160534..05d4f80 100644
--- a/app.py
+++ b/app.py
@@ -146,6 +146,7 @@ def create_app(config_name='default'):
news_items = searcher.search_site_news(
site_name=site.name,
site_url=site.url,
+ news_keywords=site.news_keywords, # v2.3新增:使用专用关键词
count=3,
freshness='oneWeek'
)
@@ -547,6 +548,7 @@ def create_app(config_name='default'):
news_items = searcher.search_site_news(
site_name=site.name,
site_url=site.url,
+ news_keywords=site.news_keywords, # v2.3新增:使用专用关键词
count=count,
freshness=freshness
)
@@ -642,6 +644,7 @@ def create_app(config_name='default'):
news_items = searcher.search_site_news(
site_name=site.name,
site_url=site.url,
+ news_keywords=site.news_keywords, # v2.3新增:使用专用关键词
count=count_per_site,
freshness=freshness
)
@@ -706,6 +709,85 @@ def create_app(config_name='default'):
'message': f'批量获取失败: {str(e)}'
}), 500
+ @app.route('/api/refresh-site-news/', methods=['POST'])
+ def refresh_site_news(site_code):
+ """手动刷新指定网站的新闻(前台用户可访问)- v2.3新增"""
+ try:
+ # 根据code查找网站
+ site = Site.query.filter_by(code=site_code).first()
+ if not site:
+ return jsonify({
+ 'success': False,
+ 'message': '网站不存在'
+ }), 404
+
+ # 检查博查API配置
+ api_key = app.config.get('BOCHA_API_KEY')
+ if not api_key:
+ return jsonify({
+ 'success': False,
+ 'message': '新闻功能未启用'
+ }), 500
+
+ # 创建新闻搜索器
+ searcher = NewsSearcher(api_key)
+
+ # 搜索新闻(获取最新5条)
+ news_items = searcher.search_site_news(
+ site_name=site.name,
+ site_url=site.url,
+ news_keywords=site.news_keywords, # 使用专用关键词
+ count=5,
+ freshness='oneWeek' # 一周内的新闻
+ )
+
+ if not news_items:
+ return jsonify({
+ 'success': False,
+ 'message': '未找到相关新闻'
+ }), 404
+
+ # 保存新闻到数据库
+ saved_count = 0
+ for item in news_items:
+ # 检查新闻是否已存在(根据URL判断)
+ existing_news = News.query.filter_by(
+ site_id=site.id,
+ url=item['url']
+ ).first()
+
+ if not existing_news:
+ news = News(
+ site_id=site.id,
+ title=item['title'],
+ content=item.get('summary') or item.get('snippet', ''),
+ url=item['url'],
+ source_name=item.get('site_name', ''),
+ source_icon=item.get('site_icon', ''),
+ published_at=item.get('published_at'),
+ news_type='Search Result',
+ is_active=True
+ )
+ db.session.add(news)
+ saved_count += 1
+
+ # 提交事务
+ db.session.commit()
+
+ return jsonify({
+ 'success': True,
+ 'message': f'成功获取 {saved_count} 条新资讯',
+ 'total_found': len(news_items),
+ 'saved_count': saved_count
+ })
+
+ except Exception as e:
+ db.session.rollback()
+ return jsonify({
+ 'success': False,
+ 'message': f'获取失败: {str(e)}'
+ }), 500
+
# ========== 批量导入路由 ==========
@app.route('/admin/batch-import', methods=['GET', 'POST'])
@login_required
@@ -1004,6 +1086,7 @@ def create_app(config_name='default'):
'short_desc': '简短描述',
'description': '详细介绍',
'features': '主要功能',
+ 'news_keywords': '新闻关键词',
'is_active': '是否启用',
'view_count': '浏览次数',
'sort_order': '排序权重',
@@ -1011,7 +1094,7 @@ def create_app(config_name='default'):
'created_at': '创建时间',
'updated_at': '更新时间'
}
- form_columns = ['name', 'url', 'slug', 'logo', 'short_desc', 'description', 'features', 'tags', 'is_active', 'sort_order']
+ form_columns = ['name', 'url', 'slug', 'logo', 'short_desc', 'description', 'features', 'news_keywords', 'tags', 'is_active', 'sort_order']
# 自定义编辑/删除文字
column_extra_row_actions = None
diff --git a/migrate_news_keywords.py b/migrate_news_keywords.py
new file mode 100644
index 0000000..8d759c7
--- /dev/null
+++ b/migrate_news_keywords.py
@@ -0,0 +1,107 @@
+"""
+数据库迁移脚本 - 为Sites表添加news_keywords字段
+版本:v2.3.0
+日期:2025-12-31
+"""
+import pymysql
+import os
+from dotenv import load_dotenv
+
+# 加载环境变量
+load_dotenv()
+
+def migrate():
+ """执行数据库迁移"""
+ # 数据库配置
+ db_config = {
+ 'host': os.environ.get('DB_HOST', 'localhost'),
+ 'port': int(os.environ.get('DB_PORT', 3306)),
+ 'user': os.environ.get('DB_USER', 'root'),
+ 'password': os.environ.get('DB_PASSWORD', ''),
+ 'database': os.environ.get('DB_NAME', 'ai_nav'),
+ 'charset': 'utf8mb4'
+ }
+
+ try:
+ # 连接数据库
+ connection = pymysql.connect(**db_config)
+ cursor = connection.cursor()
+
+ print("=" * 60)
+ print("开始执行数据库迁移 v2.3.0")
+ print("=" * 60)
+
+ # 检查字段是否已存在
+ cursor.execute("""
+ SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_SCHEMA = %s
+ AND TABLE_NAME = 'sites'
+ AND COLUMN_NAME = 'news_keywords'
+ """, (db_config['database'],))
+
+ existing_columns = [row[0] for row in cursor.fetchall()]
+
+ # 添加 news_keywords 字段
+ if 'news_keywords' not in existing_columns:
+ print("\n1. 添加 news_keywords 字段...")
+ cursor.execute("""
+ ALTER TABLE sites
+ ADD COLUMN news_keywords VARCHAR(200)
+ COMMENT '新闻获取关键词(用于精准匹配相关新闻)'
+ AFTER features
+ """)
+ print(">>> news_keywords 字段添加成功")
+ else:
+ print("\n1. news_keywords 字段已存在,跳过")
+
+ # 可选:为现有网站设置默认关键词(使用网站名称)
+ if 'news_keywords' not in existing_columns:
+ print("\n2. 为现有网站设置默认关键词(使用网站名称)...")
+ cursor.execute("""
+ UPDATE sites
+ SET news_keywords = name
+ WHERE news_keywords IS NULL OR news_keywords = ''
+ """)
+ affected_rows = cursor.rowcount
+ print(f">>> 已更新 {affected_rows} 个网站的默认关键词")
+
+ # 提交事务
+ connection.commit()
+
+ print("\n" + "=" * 60)
+ print(">>> 数据库迁移完成!")
+ print("=" * 60)
+
+ # 显示表结构
+ print("\n当前 sites 表结构:")
+ cursor.execute("DESCRIBE sites")
+ for row in cursor.fetchall():
+ print(f" - {row[0]}: {row[1]} {row[2]}")
+
+ # 显示示例数据
+ print("\n示例数据(前5条):")
+ cursor.execute("""
+ SELECT id, name, news_keywords
+ FROM sites
+ LIMIT 5
+ """)
+ for row in cursor.fetchall():
+ print(f" ID: {row[0]}, 名称: {row[1]}, 关键词: {row[2] or '(空)'}")
+
+ except Exception as e:
+ print(f"\n>>> 迁移失败:{str(e)}")
+ if 'connection' in locals():
+ connection.rollback()
+ raise
+
+ finally:
+ if 'cursor' in locals():
+ cursor.close()
+ if 'connection' in locals():
+ connection.close()
+ print("\n数据库连接已关闭")
+
+
+if __name__ == '__main__':
+ migrate()
diff --git a/models.py b/models.py
index 6de887f..6bbda50 100644
--- a/models.py
+++ b/models.py
@@ -24,6 +24,7 @@ class Site(db.Model):
short_desc = db.Column(db.String(200), comment='简短描述')
description = db.Column(db.Text, comment='详细介绍')
features = db.Column(db.Text, comment='主要功能')
+ news_keywords = db.Column(db.String(200), comment='新闻获取关键词(用于精准匹配相关新闻)')
is_active = db.Column(db.Boolean, default=True, comment='是否启用')
view_count = db.Column(db.Integer, default=0, comment='浏览次数')
sort_order = db.Column(db.Integer, default=0, comment='排序权重')
@@ -49,6 +50,7 @@ class Site(db.Model):
'short_desc': self.short_desc,
'description': self.description,
'features': self.features,
+ 'news_keywords': self.news_keywords,
'is_active': self.is_active,
'view_count': self.view_count,
'tags': [tag.name for tag in self.tags],
diff --git a/templates/detail_new.html b/templates/detail_new.html
index b6ac54b..c67586e 100644
--- a/templates/detail_new.html
+++ b/templates/detail_new.html
@@ -622,10 +622,16 @@
{% if news_list %}
-
- 📰
- 相关新闻
-
+
+
+ 📰
+ 相关新闻
+
+
+
+
{% for news in news_list %}
@@ -667,6 +673,7 @@
{% endfor %}
+
{% endif %}
@@ -698,4 +705,127 @@
+
+
+
+
+
{% endblock %}
diff --git a/utils/news_searcher.py b/utils/news_searcher.py
index cfced90..9fe1dad 100644
--- a/utils/news_searcher.py
+++ b/utils/news_searcher.py
@@ -121,6 +121,7 @@ class NewsSearcher:
self,
site_name: str,
site_url: Optional[str] = None,
+ news_keywords: Optional[str] = None,
count: int = 10,
freshness: str = 'oneMonth'
) -> List[Dict]:
@@ -128,16 +129,23 @@ class NewsSearcher:
搜索特定网站的相关新闻
Args:
- site_name: 网站名称(用于搜索关键词)
+ site_name: 网站名称(用于搜索关键词,如果没有news_keywords)
site_url: 网站URL(可选,用于排除网站自身)
+ news_keywords: 新闻专用关键词(优先使用,支持精准匹配)
count: 返回结果数量
freshness: 时间范围
Returns:
新闻列表
"""
- # 构建搜索关键词:网站名称 + "最新" + "新闻"
- query = f'"{site_name}" 新闻'
+ # 构建搜索关键词
+ # 优先使用news_keywords(如果提供)- v2.3新增
+ if news_keywords and news_keywords.strip():
+ # 使用双引号包裹关键词,确保严格匹配
+ query = f'"{news_keywords.strip()}" 新闻'
+ else:
+ # 降级使用网站名称(向后兼容)
+ query = f'"{site_name}" 新闻'
# 如果提供了网站URL,排除网站自身的结果
exclude = None