GEO 智能内容优化平台

This commit is contained in:
刘国栋
2026-01-23 15:43:03 +08:00
commit cec0543064
13 changed files with 4087 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
# SQLite 数据库文件
*.db
*.sqlite
*.sqlite3
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
.venv
# Streamlit
.streamlit/secrets.toml
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# 数据目录(如果使用JSON方式)
data/
+10
View File
@@ -0,0 +1,10 @@
[theme]
base="light"
primaryColor="#2563EB"
backgroundColor="#FFFFFF"
secondaryBackgroundColor="#F7FAFC"
textColor="#1A202C"
borderColor="#E2E8F0"
baseRadius="10"
buttonRadius="10"
showSidebarBorder=true
+365
View File
@@ -0,0 +1,365 @@
# 🚀 GEO 工具高级功能建议
## 📋 功能分类
### 🧠 一、智能化增强(AI 驱动)
#### 1. **智能内容质量评分系统** ⭐⭐⭐⭐⭐
**价值**:自动评估内容是否符合 GEO 原则,提供改进建议
**功能点**
- 自动分析生成内容的结构化程度(标题、清单、FAQ 等)
- 品牌提及位置和频率评分
- 内容权威性评估(数据支撑、案例引用)
- 给出具体的优化建议(如"建议在开头增加结论摘要")
- 内容 GEO 分数(0-100分)
**实现思路**
- 使用 LLM 分析内容,输出结构化评分
- 建立评分标准(结构化、品牌提及、权威性、可引用性)
- 在内容生成后自动评分,并提供改进建议
**预期效果**:用户无需手动判断内容质量,系统自动优化
---
#### 2. **智能关键词挖掘与趋势分析** ⭐⭐⭐⭐⭐
**价值**:发现新的高价值关键词,预测关键词趋势
**功能点**
- 基于行业热点自动挖掘新关键词
- 分析关键词竞争度(在 AI 中的提及频率)
- 预测关键词趋势(上升/下降)
- 推荐高价值低竞争关键词
- 关键词组合建议(长尾词挖掘)
**实现思路**
- 使用 LLM 分析行业趋势和用户搜索意图
- 结合历史验证数据,分析关键词效果
- 提供关键词价值矩阵(高价值/低价值 × 高竞争/低竞争)
**预期效果**:帮助用户发现蓝海关键词,提升 ROI
---
#### 3. **A/B 测试与内容对比** ⭐⭐⭐⭐
**价值**:对比不同版本内容的效果,数据驱动优化
**功能点**
- 为同一关键词生成多个版本内容(不同风格、结构)
- 同时验证多个版本,对比提及率
- 自动推荐最优版本
- 记录 A/B 测试历史,建立最佳实践库
**实现思路**
- 在内容生成时支持"生成多个版本"
- 批量验证不同版本
- 对比分析提及率、位置等指标
- 建立内容模板库(基于效果最好的版本)
**预期效果**:通过数据找到最佳内容策略
---
### 📊 二、数据洞察增强
#### 4. **ROI 分析与成本优化** ⭐⭐⭐⭐⭐
**价值**:量化 GEO 投入产出比,优化成本结构
**功能点**
- 计算每次验证的 API 成本
- 统计内容生成成本(按平台、按关键词)
- 分析提及率提升带来的价值(估算)
- 成本效益分析(哪些关键词/平台 ROI 最高)
- 预算管理和成本预警
**实现思路**
- 记录每次 API 调用的成本(基于各平台定价)
- 计算总投入成本
- 分析提及率提升幅度,估算品牌曝光价值
- 提供 ROI 报表和优化建议
**预期效果**:让用户清楚知道投入产出,优化预算分配
---
#### 5. **竞品监控与预警** ⭐⭐⭐⭐
**价值**:自动监控竞品在 AI 中的表现,及时调整策略
**功能点**
- 定期自动验证竞品提及率
- 竞品提及率变化趋势
- 竞品内容策略分析(哪些关键词/平台效果好)
- 竞品超越预警(当竞品提及率超过自己时)
- 竞品对比报告(自动生成)
**实现思路**
- 定时任务自动验证竞品
- 对比分析竞品和自身的数据
- 识别竞品的优势策略
- 提供应对建议
**预期效果**:保持竞争优势,及时应对市场变化
---
#### 6. **内容效果预测模型** ⭐⭐⭐⭐
**价值**:预测内容发布后的效果,优化内容策略
**功能点**
- 基于历史数据训练预测模型
- 预测新内容的提及率
- 预测不同平台的效果差异
- 推荐最优发布策略(平台组合、发布时间等)
**实现思路**
- 收集历史数据(内容特征、平台、提及率)
- 使用机器学习模型预测效果
- 提供预测置信度
- 持续优化模型准确性
**预期效果**:在发布前就知道效果,避免无效投入
---
### 🔄 三、自动化增强
#### 7. **智能工作流自动化** ⭐⭐⭐⭐⭐
**价值**:一键完成从关键词到验证的完整流程
**功能点**
- 自定义工作流(关键词生成 → 内容创作 → 自动验证)
- 定时任务(每天/每周自动验证)
- 条件触发(当提及率低于阈值时自动优化)
- 批量处理(一次性处理多个关键词)
- 工作流模板(保存常用工作流)
**实现思路**
- 创建工作流配置界面
- 支持条件判断和循环
- 集成定时任务(使用 APScheduler
- 提供工作流执行日志
**预期效果**:大幅减少重复工作,提升效率
---
#### 8. **内容模板库与最佳实践** ⭐⭐⭐⭐
**价值**:积累成功经验,复用最佳内容模板
**功能点**
- 自动保存高效果内容为模板
- 模板分类(按平台、按行业、按效果)
- 模板搜索和推荐
- 基于模板快速生成内容
- 模板效果统计(使用次数、平均提及率)
**实现思路**
- 识别高效果内容(提及率 > 阈值)
- 提取内容结构作为模板
- 模板参数化(品牌、优势等可替换)
- 提供模板管理界面
**预期效果**:复用成功经验,提升内容质量
---
#### 9. **智能内容去重与相似度检测** ⭐⭐⭐
**价值**:避免重复内容,确保内容多样性
**功能点**
- 检测新生成内容与历史内容的相似度
- 自动去重(相似度 > 阈值时提示)
- 内容多样性分析(确保覆盖不同角度)
- 推荐内容角度(基于已有内容分析)
**实现思路**
- 使用文本相似度算法(如余弦相似度)
- 对比新内容与历史内容
- 提供相似度评分和建议
**预期效果**:确保内容多样性,避免重复投入
---
### 🌐 四、平台与集成增强
#### 10. **多语言支持** ⭐⭐⭐⭐
**价值**:扩展国际市场,提升品牌全球影响力
**功能点**
- 支持英文、日文等多语言内容生成
- 多语言关键词挖掘
- 多语言平台支持(Medium、Dev.to、Reddit 等)
- 多语言验证(使用海外 AI 平台)
**实现思路**
- 扩展 Prompt 模板支持多语言
- 添加多语言平台列表
- 集成海外 AI 平台(Claude、Gemini 等)
**预期效果**:拓展国际市场,提升全球品牌影响力
---
#### 11. **API 接口与集成** ⭐⭐⭐⭐
**价值**:与其他系统集成,支持自动化流程
**功能点**
- RESTful API 接口
- Webhook 支持(内容生成完成时通知)
- 与 CMS 系统集成
- 与营销自动化工具集成
- API 文档和示例代码
**实现思路**
- 使用 FastAPI 创建 API 服务
- 提供认证和限流
- 支持异步任务
- 提供 SDKPython/JavaScript
**预期效果**:支持企业级集成,提升工具价值
---
#### 12. **团队协作与权限管理** ⭐⭐⭐
**价值**:支持团队使用,提升协作效率
**功能点**
- 多用户支持(注册/登录)
- 角色权限管理(管理员、编辑、查看者)
- 内容审核流程
- 团队数据共享
- 操作日志和审计
**实现思路**
- 集成用户认证系统(如 Streamlit-Authenticator
- 数据库添加用户和权限表
- 实现基于角色的访问控制
**预期效果**:支持团队协作,适合企业使用
---
### 🎯 五、内容质量提升
#### 13. **内容个性化与定制** ⭐⭐⭐⭐
**价值**:根据目标受众定制内容风格和角度
**功能点**
- 目标受众画像(技术专家、业务人员、决策者等)
- 内容风格选择(专业、通俗、故事化等)
- 内容角度选择(功能对比、使用教程、案例分析等)
- 个性化内容生成
**实现思路**
- 在 Prompt 中加入受众和风格参数
- 提供预设的受众模板
- 根据受众调整内容深度和语言风格
**预期效果**:提升内容针对性和效果
---
#### 14. **内容结构化增强** ⭐⭐⭐
**价值**:确保内容符合 GEO 最佳实践
**功能点**
- 自动检查内容结构完整性(标题、摘要、清单、FAQ 等)
- 结构化建议(缺失部分自动补充)
- 内容层次优化(确保逻辑清晰)
- Markdown/HTML 格式优化
**实现思路**
- 使用 LLM 分析内容结构
- 识别缺失的结构元素
- 自动生成补充内容
**预期效果**:确保所有内容都符合 GEO 原则
---
### 📈 六、高级分析功能
#### 15. **预测性分析与趋势预测** ⭐⭐⭐⭐
**价值**:预测未来趋势,提前布局
**功能点**
- 提及率趋势预测(未来 30 天)
- 关键词热度预测
- 竞品趋势预测
- 最佳行动时机推荐
**实现思路**
- 使用时间序列分析(ARIMA、LSTM 等)
- 分析历史趋势
- 预测未来变化
- 提供置信区间
**预期效果**:提前布局,抢占先机
---
#### 16. **内容关联分析** ⭐⭐⭐
**价值**:发现内容之间的关联,优化内容策略
**功能点**
- 关键词关联分析(哪些关键词经常一起被提及)
- 平台关联分析(哪些平台组合效果好)
- 内容主题聚类
- 内容网络图可视化
**实现思路**
- 使用关联规则挖掘(Apriori 算法)
- 构建内容关联图
- 可视化展示
**预期效果**:发现隐藏的内容策略规律
---
## 🎯 推荐优先级(综合价值与实现难度)
### 🔥 第一优先级(高价值 + 中等难度)
1. **智能内容质量评分系统** - 直接提升内容质量
2. **ROI 分析与成本优化** - 量化价值,优化投入
3. **智能工作流自动化** - 大幅提升效率
4. **智能关键词挖掘** - 发现新机会
### 🟡 第二优先级(高价值 + 较高难度)
5. **A/B 测试与内容对比** - 数据驱动优化
6. **竞品监控与预警** - 保持竞争优势
7. **内容效果预测模型** - 提前优化策略
### 🟢 第三优先级(中等价值)
8. **内容模板库** - 复用最佳实践
9. **多语言支持** - 扩展市场
10. **API 接口** - 企业级集成
---
## 💡 实施建议
1. **分阶段实施**:先实现第一优先级功能,验证价值后再扩展
2. **数据积累**:先运行一段时间,积累足够数据后再做预测和分析
3. **用户反馈**:根据实际使用情况调整功能优先级
4. **技术选型**:考虑使用现有开源库(如 scikit-learn 用于预测模型)
---
## 🚀 快速开始建议
**第一步**:实现"智能内容质量评分系统"
- 价值高,实现相对简单
- 可以立即提升用户体验
- 为后续功能打下基础
**第二步**:实现"ROI 分析与成本优化"
- 帮助用户量化价值
- 提升工具的商业价值
- 为定价策略提供依据
**第三步**:实现"智能工作流自动化"
- 大幅提升效率
- 增强用户粘性
- 差异化竞争优势
+78
View File
@@ -0,0 +1,78 @@
# SQLite 持久化集成说明
## ✅ 已完成的功能
### 1. 数据自动保存
-**关键词生成**:自动保存到数据库
-**内容生成**:每生成一篇文章自动保存
-**文章优化**:优化记录自动保存
-**验证结果**:验证结果自动保存
### 2. 历史记录查看(新增 Tab5)
- ✅ 统计数据总览(关键词、文章、优化、验证数量)
- ✅ 历史文章列表和详情查看
- ✅ 历史优化记录和详情查看
- ✅ 历史验证结果和可视化
## 📁 数据库文件
- **位置**`geo_data.db`(项目根目录)
- **格式**SQLite 单文件数据库
- **已添加到**`.gitignore`(不会提交到版本控制)
## 🚀 使用方法
### 正常使用
所有数据会自动保存,无需额外操作。只需正常使用各个功能模块即可。
### 查看历史记录
1. 点击 **"5 历史记录"** Tab
2. 查看统计数据
3. 浏览历史文章、优化记录、验证结果
4. 点击选择框查看详情
## 🔧 技术细节
### 错误处理
- 所有数据库操作都包含 try-except 错误处理
- 即使数据库保存失败,也不会影响主要功能
- 会显示警告提示,但不会中断流程
### 数据存储结构
- **keywords 表**:关键词列表
- **articles 表**:生成的文章内容
- **optimizations 表**:优化记录
- **verify_results 表**:验证结果
## 📊 性能
- SQLite 是轻量级数据库,性能优秀
- 单文件存储,易于备份和迁移
- 支持复杂查询和统计分析
## 🔄 数据迁移
如果需要迁移数据:
1. 复制 `geo_data.db` 文件即可
2. 或使用 SQLite 工具导出/导入
## ⚠️ 注意事项
1. **首次运行**:会自动创建数据库文件
2. **数据持久化**:关闭应用后数据不会丢失
3. **多品牌支持**:数据按品牌分类存储
4. **清空功能**:侧边栏的"重置全部结果"只清空 Session State**不会删除数据库记录**
## 🐛 故障排除
如果遇到数据库相关错误:
1. 检查是否有写入权限
2. 检查 `geo_data.db` 文件是否被其他程序占用
3. 可以删除 `geo_data.db` 文件重新创建(会丢失所有历史数据)
## 📝 后续扩展建议
1. **数据导出**:可以添加导出功能,将数据导出为 CSV/Excel
2. **数据搜索**:可以添加搜索功能,按关键词搜索历史记录
3. **数据统计**:可以添加更详细的统计分析
4. **数据备份**:可以添加定期备份功能
+94
View File
@@ -0,0 +1,94 @@
# 平台扩展安装说明
## 已支持的平台
### 基础平台(已包含依赖)
- DeepSeek
- OpenAI (GPT)
- Tongyi (通义千问)
- Groq
- Moonshot (Kimi)
### 新增平台(需要额外安装)
#### 1. 豆包(字节跳动)
**安装命令:**
```bash
pip install 'volcengine-python-sdk[ark]'
```
**API Key 格式:**
```
access_key:secret_key:endpoint_id
```
用冒号分隔三个值:
- `access_key`: 火山引擎 Access Key
- `secret_key`: 火山引擎 Secret Key
- `endpoint_id`: 接入点名称(Endpoint ID
**获取方式:**
1. 访问 [火山引擎官网](https://www.volcengine.com/)
2. 注册账号并完成实名认证
3. 在控制台获取 Access Key 和 Secret Key
4. 创建模型接入点,获取 Endpoint ID
**使用示例:**
在侧边栏"生成&优化 LLM"或"验证用LLM"中选择"豆包(字节跳动)",输入格式化的 API Key。
---
#### 2. 文心一言(百度)
**安装命令:**
```bash
pip install qianfan
```
**API Key 格式:**
```
app_key:app_secret
```
用冒号分隔两个值:
- `app_key`: 百度智能云 App Key
- `app_secret`: 百度智能云 App Secret
**获取方式:**
1. 访问 [百度智能云千帆平台](https://cloud.baidu.com/product/qianfan.html)
2. 注册账号并完成认证
3. 创建应用,获取 App Key 和 App Secret
**使用示例:**
在侧边栏"生成&优化 LLM"或"验证用LLM"中选择"文心一言(百度)",输入格式化的 API Key。
---
## 快速安装所有平台
如果需要使用所有平台,可以运行:
```bash
pip install 'volcengine-python-sdk[ark]' qianfan
```
---
## 注意事项
1. **API Key 格式**:豆包和文心一言的 API Key 需要使用冒号分隔多个值
2. **依赖冲突**:某些包可能有版本冲突,如遇到问题请单独安装
3. **可选安装**:这些平台是可选的,如果不使用可以不安装,不影响其他功能
---
## 故障排除
### 豆包安装失败
- 确保 Python 版本 >= 3.7
- Windows 系统可能需要启用长路径支持
- 尝试:`pip install 'volcengine-python-sdk[ark]' -U`
### 文心一言初始化失败
- 确保已安装 `qianfan`
- 检查 API Key 格式是否正确(app_key:app_secret
- 确认环境变量或参数中的 AK/SK 是否正确
+285
View File
@@ -0,0 +1,285 @@
# 运行命令
`streamlit run geo_tool.py`
---
# 功能迭代计划
## ✅ 已完成功能
- [x] **数据持久化(SQLite** - 已完成
- 关键词、文章、优化记录、验证结果自动保存
- 历史记录查看功能(Tab5
- 详见 `INTEGRATION_NOTES.md`
- [x] **AI 蒸馏词 - 托词工具** - 已完成
- 支持三种生成模式:AI生成、托词工具、混合模式
- 词库管理(编辑、导入、导出)
- 组合算法(支持10种组合模式)
- LLM 润色功能(混合模式)
- 自动去重和相似度过滤
- [x] **收录平台扩展** - 已完成
- 新增豆包(字节跳动)支持
- 新增文心一言(百度)支持
- API Key 格式提示和验证
- 详见 `PLATFORM_SETUP.md`
- [x] **自媒体账号平台扩展** - 已完成
- 新增微信公众号(长文)支持
- 新增抖音图文(短内容)支持
- 新增百家号、网易号、企鹅号、简书支持
- 每个平台都有专门的 Prompt 模板
- 支持 Markdown 格式输出
- [x] **AI 数据报表** - 已完成
- 自动验证任务(使用历史关键词)
- 提及率趋势图(按日期展示)
- 平台贡献度分析(文章平台分布)
- 关键词效果排名(Top 20
- 竞品对比分析(多维度对比)
- 数据导出功能(CSV 格式)
---
## 📋 待实现功能(按优先级排序)
> **优先级说明**:优先级基于对 GEO 效果的直接影响、实现成本和用户价值综合评估。
> **调整原则**:优先实现能直接提升 GEO 效果的功能(平台扩展、内容渠道),延后实现辅助性功能(图库)。
### 🔥 高优先级(核心功能增强)
#### 1. 收录平台扩展
**当前支持:** DeepSeek, OpenAI, Tongyi, Groq, Moonshot
**待添加平台:**
- 豆包(字节跳动)- ⭐ 高优先级(用户量大)
- 文心一言(百度)- ⭐ 高优先级(用户量大)
- 腾讯元宝 - 需确认 API 可用性
- 纳米 - 需确认具体 API
**重要性分析:**
-**直接影响 GEO 效果**:更多平台 = 更全面的验证覆盖
-**提升验证准确性**:国内主流平台(豆包、文心一言)用户量大,验证结果更有参考价值
-**实现成本低**:主要是 API 接入,技术难度不高
**评估与优化建议:**
- ⚠️ **需要优化**
1. **API 接入优先级**:优先接入豆包、文心一言(用户量大)
2. **平台分类管理**:按平台类型分类(国内/国外、通用/专业)
3. **验证成本控制**:支持批量验证时的并发控制,避免 API 费用过高
**实现建议:**
-`build_llm` 函数中扩展新平台支持
- 在侧边栏配置中增加新平台选项
- 添加平台可用性检测
---
#### 2. 自媒体账号平台扩展
**当前支持:** 知乎、小红书、CSDN、B站、头条号、GitHub
**待添加平台:**
- 微信公众号 - ⭐ 高优先级(用户量大、影响力强)
- 抖音图文 - ⭐ 高优先级(流量大)
- 百家号 - 中优先级(百度生态)
- 网易号 - 中优先级
- 企鹅号 - 中优先级
- 简书 - 低优先级
**重要性分析:**
-**扩大内容投放渠道**:更多平台 = 更多曝光机会
-**提升品牌影响力**:微信公众号、抖音等平台用户量大
-**实现成本中等**:主要是 Prompt 模板和格式转换
**评估与优化建议:**
- ⚠️ **需要优化**
1. **平台特性差异**
- 微信公众号:需要特殊格式(富文本、排版)
- 抖音图文:图片为主,文字为辅
- 百家号/网易号/企鹅号:可能有字数限制、格式要求
2. **内容适配策略**
- 为每个平台创建专门的 Prompt 模板
- 支持平台特定的格式要求(如微信公众号的 Markdown 转 HTML
3. **发布功能(可选)**
- 初期只生成内容,后续可考虑接入各平台 API 实现自动发布
**实现建议:**
- 扩展 `platforms` 列表
- 为每个平台创建专门的 Prompt 模板
- 添加平台格式转换功能(如 Markdown → HTML
---
#### 3. 稿件记录(数据持久化)
**功能描述:**
- 保留所有的稿件记录
**状态:****已完成**
- 已实现 SQLite 数据持久化
- 支持关键词、文章、优化记录、验证结果的保存和查看
- 详见 `INTEGRATION_NOTES.md`
**后续扩展建议:**
- 数据导出功能(CSV/Excel
- 数据搜索功能(按关键词搜索历史记录)
- 更详细的统计分析
- 数据备份功能
---
### 🟡 中优先级(功能扩展)
#### 4. AI 数据报表
**功能描述:**
- 系统自动模拟用户提问
- 收录结果实时同步至 AI 数据报表
- 清晰展示哪些词已被引用、哪些平台贡献了曝光
**重要性分析:**
-**监控 GEO 效果**:自动化监控,数据可视化
-**指导优化方向**:通过数据反馈优化内容策略
- ⚠️ **实现成本较高**:需要定时任务、数据可视化等
**评估与优化建议:**
- ⚠️ **需要优化**
1. **模拟提问的策略**
- 定期自动验证(如每天/每周)
- 支持自定义验证频率
- 记录历史趋势(提及率变化)
2. **数据存储**
- 使用数据库(SQLite)存储历史数据
- 支持数据导出和分析
3. **报表功能**
- 提及率趋势图
- 平台贡献度分析
- 关键词效果排名
- 竞品对比分析
4. **实时同步**
- 后台任务 + 实时更新 UI
**实现建议:**
- 新增模块:AI 数据报表(可放在 Tab5 或独立 Tab)
- 自动验证任务(定时/手动触发)
- 数据可视化(趋势图、对比图、热力图)
- 数据导出功能
---
### 🟢 低优先级(高级功能 / 可选功能)
#### 5. 企业知识库 - 企业图库
**功能描述:**
- 分类上传产品图、场景图、资质证书等
- 这些素材会在后续内容生成中自动嵌入,确保品牌一致性
**重要性分析:**
- ⚠️ **对 GEO 直接贡献有限**:GEO 核心是文本内容,大模型主要从文本中提取信息
- ⚠️ **适用场景有限**:主要适用于小红书、抖音等图文平台,对知乎、CSDN 等文字平台作用不大
- ⚠️ **实现成本较高**:需要图片存储、管理、智能匹配等功能
-**替代方案**:可手动配图,或让 LLM 生成图片描述/建议
**评估与优化建议:**
-**优点**:提升品牌一致性,素材复用
- ⚠️ **需要优化**
1. **图片存储与管理**
- 使用本地文件系统或云存储(OSS/S3)
- 支持图片分类、标签、搜索
2. **图片在内容中的嵌入方式**
- 文本内容:生成图片描述,提示"可配图:xxx"
- Markdown:自动插入图片链接
- 小红书/抖音:生成图片使用建议
3. **图片与内容的智能匹配**
- 使用 LLM 分析内容主题,自动推荐匹配图片
4. **版权与合规**
- 增加图片版权信息记录
**实现建议:**
- 新增模块:企业图库管理(可放在侧边栏或独立 Tab)
- 图片上传(支持批量)
- 图片分类(产品图、场景图、资质证书等)
- 图片标签系统
- 内容生成时自动匹配图片
**建议:** 可延后实现,或先实现简化版(仅图片上传和描述生成)
---
#### 6. 数据报表高级分析
- 更详细的统计分析
- 预测性分析
- 竞品深度对比
#### 7. 自动发布功能
- 接入各平台 API
- 自动发布生成的内容
- 发布状态跟踪
---
## 📊 整体架构建议
### 优先级排序
1. **高优先级**(核心功能增强)
- 收录平台扩展(豆包、文心一言等)⭐ ✅ 已完成
- 自媒体平台扩展(微信公众号、抖音等)⭐ ✅ 已完成
- 稿件记录 ✅ 已完成
2. **中优先级**(功能扩展)
- AI 数据报表(基础版)✅ 已完成
3. **低优先级**(高级功能 / 可选功能)
- 企业图库(对 GEO 直接贡献有限,可延后)
- 数据报表高级分析
- 自动发布功能
### 技术架构建议
1. **数据持久化** ✅ 已完成
- 使用 SQLite(轻量)
- 存储:关键词、内容、优化记录、验证结果、图片元数据
2. **模块化重构**
- 将功能拆分为独立模块
- 便于维护和扩展
3. **配置管理**
- 使用配置文件管理平台模板、词库等
- 支持用户自定义
4. **性能优化**
- 批量操作使用并发/异步
- 缓存常用数据
---
## 📝 实现记录
### 已完成
- [x] SQLite 数据持久化(2024
- [x] 历史记录查看功能
- [x] 托词工具(AI 蒸馏词)- 2024
- [x] 收录平台扩展(豆包、文心一言)- 2024
- [x] 自媒体平台扩展(微信公众号、抖音等)- 2024
- [x] AI 数据报表 - 2024
### 待开始(按优先级)
- [ ] 企业图库 - 低优先级(可延后)
---
## 🔗 相关文档
- `INTEGRATION_NOTES.md` - SQLite 持久化集成说明
- `STORAGE_GUIDE.md` - 数据持久化方案对比
- `PLATFORM_SETUP.md` - 平台扩展安装说明(豆包、文心一言)
- `data_storage.py` - 数据存储模块实现
+194
View File
@@ -0,0 +1,194 @@
# 数据持久化方案对比
## 为什么不能用 IndexedDB
**IndexedDB 是浏览器 API**,只能在 JavaScript 前端使用。
**Streamlit 是 Python 后端应用**,运行在服务器端,无法使用 IndexedDB。
---
## 方案对比
### 方案1SQLite(⭐ 推荐)
**优点:**
- ✅ Python 内置支持(`sqlite3`),无需安装额外依赖
- ✅ 单文件数据库,易于备份和迁移
- ✅ 查询性能好,支持复杂查询
- ✅ 支持事务,数据安全
- ✅ 支持 SQL 查询,灵活强大
- ✅ 适合 MVP 到生产环境的平滑升级
**缺点:**
- ⚠️ 需要学习基本的 SQL(但很简单)
- ⚠️ 多进程写入需要处理锁(Streamlit 单进程,无此问题)
**代码复杂度:** ⭐⭐(非常简单)
**适用场景:** MVP 和生产环境都适用
---
### 方案2JSON 文件
**优点:**
- ✅ 最简单,无需学习 SQL
- ✅ 人类可读,易于调试
- ✅ 无需数据库知识
**缺点:**
- ❌ 查询性能差(需要加载整个文件)
- ❌ 数据量大时很慢
- ❌ 并发写入可能丢失数据
- ❌ 不支持复杂查询
**代码复杂度:** ⭐(极简单)
**适用场景:** 仅适合数据量很小(<1000条)的 MVP
---
## 推荐方案:SQLite
### 为什么推荐 SQLite
1. **其实很简单**:只需要几行代码
```python
import sqlite3
conn = sqlite3.connect('data.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO table VALUES (?)", (value,))
conn.commit()
conn.close()
```
2. **性能好**:即使数据量增长到几万条,依然很快
3. **功能强大**:支持统计、查询、分析,为后续功能扩展打好基础
4. **零依赖**:Python 内置,无需安装任何包
---
## 快速开始
### 1. 使用已封装好的 DataStorage 类
我已经为你创建了 `data_storage.py`,提供了统一的接口:
```python
from data_storage import DataStorage
# 初始化(SQLite方式)
storage = DataStorage(storage_type="sqlite", db_path="geo_data.db")
# 保存关键词
storage.save_keywords(["关键词1", "关键词2"], "品牌名")
# 获取关键词
keywords = storage.get_keywords("品牌名")
# 保存文章
storage.save_article("关键词", "平台", "内容", "文件名", "品牌名")
# 获取统计数据
stats = storage.get_stats("品牌名")
```
### 2. 最小改动集成
在 `geo_tool.py` 中,只需要在关键位置添加几行保存代码:
```python
# 文件顶部
from data_storage import DataStorage
storage = DataStorage(storage_type="sqlite", db_path="geo_data.db")
# 关键词生成后(约第533行)
if cleaned:
st.session_state.keywords = cleaned
storage.save_keywords(cleaned, brand) # 新增这一行
st.success(f"生成完成({len(cleaned)} 条)")
# 内容生成后(约第714行)
st.session_state.generated_contents = contents
storage.save_article(keyword, plat, content, filename, brand) # 在循环中添加
# 优化后(约第838行)
st.session_state.optimized_article = optimized_article
storage.save_optimization(
original_article, optimized_article, changes, target_platform, brand
) # 新增
# 验证后(约第932行)
st.session_state.verify_combined = combined
storage.save_verify_results(all_results) # 新增
```
### 3. 添加历史记录查看功能(可选)
可以新增一个 Tab 来查看历史数据:
```python
tab5 = st.tabs([..., "5 历史记录"])
with tab5:
st.header("历史记录")
# 统计数据
stats = storage.get_stats(brand)
col1, col2, col3, col4 = st.columns(4)
col1.metric("关键词", stats["keywords_count"])
col2.metric("文章", stats["articles_count"])
col3.metric("优化", stats["optimizations_count"])
col4.metric("验证", stats["verify_results_count"])
# 历史文章列表
articles = storage.get_articles(brand=brand)
if articles:
df = pd.DataFrame(articles)
st.dataframe(df[["keyword", "platform", "created_at"]])
```
---
## 数据库文件位置
- **SQLite 文件**`geo_data.db`(项目根目录)
- **JSON 文件**`data/` 目录(如果使用 JSON 方式)
**建议:** 将 `geo_data.db` 添加到 `.gitignore`,避免提交到版本控制。
---
## 性能对比(参考)
| 数据量 | SQLite | JSON文件 |
|--------|--------|----------|
| 100条 | <10ms | <10ms |
| 1000条 | <50ms | ~100ms |
| 10000条 | ~200ms | ~5秒 |
| 100000条 | ~1秒 | 很慢 |
---
## 总结
**对于 MVP 版本,强烈推荐使用 SQLite**
1. ✅ 简单:使用封装好的 `DataStorage` 类,只需几行代码
2. ✅ 高效:性能好,支持未来扩展
3. ✅ 可靠:数据安全,支持事务
4. ✅ 零依赖:Python 内置,无需安装
**如果数据量真的非常小(<100条),可以考虑 JSON 文件。**
---
## 下一步
1. 查看 `data_storage.py` 了解实现细节
2. 查看 `storage_example.py` 了解使用方法
3. 在 `geo_tool.py` 中集成(参考上面的最小改动示例)
需要我帮你直接集成到 `geo_tool.py` 吗?
+222
View File
@@ -0,0 +1,222 @@
"""
内容质量评分系统
自动评估内容是否符合 GEO 原则,提供改进建议
"""
from typing import Dict, List, Optional
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
import json
import re
class ContentScorer:
"""内容质量评分器"""
def __init__(self):
self.scoring_prompt_template = """
你是一名 GEO(生成式引擎优化)内容质量评估专家。请对以下内容进行全面评估,并给出详细的评分和改进建议。
【内容】
{content}
【品牌】{brand}
【优势】{advantages}
【平台】{platform}
【评估维度】
请从以下维度进行评估(每个维度 0-25 分,总分 100 分):
1. **结构化程度**25分)
- 是否有清晰的标题层级?
- 是否包含清单、列表、FAQ 等结构化元素?
- 内容层次是否清晰?
- 是否有结论摘要?
2. **品牌提及质量**25分)
- 品牌提及次数是否合适(2-4次)?
- 品牌提及位置是否靠前(前1/3优先)?
- 品牌提及是否自然(先通用标准,再品牌适用)?
- 品牌与内容的关联度如何?
3. **内容权威性**25分)
- 是否有数据支撑或案例引用?
- 是否有评估维度或选择标准?
- 是否避免编造数据(使用占位建议)?
- 内容是否专业可信?
4. **可引用性**25分)
- 信息密度是否高?
- 结论是否先行?
- 是否容易被 AI 提取和引用?
- 是否符合目标平台的格式要求?
【输出格式】
请严格按照以下 JSON 格式输出,不要添加任何其他内容:
{{
"scores": {{
"structure": <结构化得分 0-25>,
"brand_mention": <品牌提及得分 0-25>,
"authority": <权威性得分 0-25>,
"citations": <可引用性得分 0-25>,
"total": <总分 0-100>
}},
"details": {{
"structure": "<结构化评估详情>",
"brand_mention": "<品牌提及评估详情>",
"authority": "<权威性评估详情>",
"citations": "<可引用性评估详情>"
}},
"improvements": [
"<改进建议1>",
"<改进建议2>",
"<改进建议3>"
],
"strengths": [
"<优点1>",
"<优点2>"
]
}}
【开始评估】
"""
def score_content(self, content: str, brand: str, advantages: str,
platform: str, llm_chain) -> Dict:
"""
对内容进行质量评分
Args:
content: 要评分的内容
brand: 品牌名称
advantages: 品牌优势
platform: 发布平台
llm_chain: LangChain 链对象
Returns:
包含评分、详情和改进建议的字典
"""
try:
prompt = PromptTemplate.from_template(self.scoring_prompt_template)
chain = prompt | llm_chain | StrOutputParser()
result = chain.invoke({
"content": content,
"brand": brand,
"advantages": advantages,
"platform": platform
})
# 尝试解析 JSON
score_data = self._parse_score_result(result)
return score_data
except Exception as e:
# 如果评分失败,返回默认评分
return {
"scores": {
"structure": 0,
"brand_mention": 0,
"authority": 0,
"citations": 0,
"total": 0
},
"details": {
"structure": f"评分失败:{str(e)}",
"brand_mention": "",
"authority": "",
"citations": ""
},
"improvements": ["评分系统暂时无法评估此内容,请手动检查"],
"strengths": []
}
def _parse_score_result(self, result: str) -> Dict:
"""解析评分结果"""
# 尝试提取 JSON
json_match = re.search(r'\{.*\}', result, re.DOTALL)
if json_match:
try:
score_data = json.loads(json_match.group())
# 验证数据结构
if "scores" in score_data and "total" in score_data["scores"]:
return score_data
except json.JSONDecodeError:
pass
# 如果无法解析 JSON,尝试从文本中提取信息
return self._extract_scores_from_text(result)
def _extract_scores_from_text(self, text: str) -> Dict:
"""从文本中提取评分信息(备用方案)"""
# 尝试提取总分
total_match = re.search(r'总分[:]\s*(\d+)', text)
total_score = int(total_match.group(1)) if total_match else 0
# 简单分配分数(如果无法精确提取)
avg_score = total_score // 4 if total_score > 0 else 0
return {
"scores": {
"structure": avg_score,
"brand_mention": avg_score,
"authority": avg_score,
"citations": avg_score,
"total": total_score
},
"details": {
"structure": "无法解析详细评分",
"brand_mention": "无法解析详细评分",
"authority": "无法解析详细评分",
"citations": "无法解析详细评分"
},
"improvements": ["请检查内容是否符合 GEO 原则"],
"strengths": []
}
def get_score_level(self, total_score: int) -> tuple:
"""
根据总分返回等级和颜色
Returns:
(等级名称, 颜色代码)
"""
if total_score >= 90:
return ("优秀", "#10B981") # 绿色
elif total_score >= 75:
return ("良好", "#3B82F6") # 蓝色
elif total_score >= 60:
return ("中等", "#F59E0B") # 橙色
else:
return ("需改进", "#EF4444") # 红色
def get_quick_assessment(self, content: str, brand: str) -> Dict:
"""
快速评估(不调用 LLM,基于规则)
用于在 LLM 评分前提供初步评估
"""
assessment = {
"has_title": bool(re.search(r'^#+\s+|^标题|^##', content, re.MULTILINE)),
"has_list": bool(re.search(r'[-*•]\s+|^\d+[\.\)]\s+', content, re.MULTILINE)),
"has_faq": bool(re.search(r'FAQ|常见问题|Q[:]|问[:]', content, re.IGNORECASE)),
"brand_count": len(re.findall(re.escape(brand), content, re.IGNORECASE)),
"word_count": len(content)
}
# 计算初步分数
quick_score = 0
if assessment["has_title"]:
quick_score += 5
if assessment["has_list"]:
quick_score += 5
if assessment["has_faq"]:
quick_score += 5
if 2 <= assessment["brand_count"] <= 4:
quick_score += 10
elif assessment["brand_count"] > 4:
quick_score += 5
assessment["quick_score"] = min(quick_score, 30) # 最高30分(快速评估)
return assessment
+453
View File
@@ -0,0 +1,453 @@
"""
轻量级数据持久化模块 - MVP版本
支持 SQLite 和 JSON 两种存储方式
"""
import sqlite3
import json
import os
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Optional, Any
import pandas as pd
class DataStorage:
"""统一的数据存储接口,支持SQLite和JSON两种后端"""
def __init__(self, storage_type: str = "sqlite", db_path: str = "geo_data.db"):
"""
Args:
storage_type: "sqlite""json"
db_path: SQLite数据库路径,或JSON文件目录
"""
self.storage_type = storage_type
self.db_path = db_path
if storage_type == "sqlite":
self._init_sqlite()
else:
self._init_json()
def _init_sqlite(self):
"""初始化SQLite数据库"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# 关键词表
cursor.execute("""
CREATE TABLE IF NOT EXISTS keywords (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT NOT NULL,
brand TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 内容表(生成的文章)
cursor.execute("""
CREATE TABLE IF NOT EXISTS articles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT,
platform TEXT,
content TEXT,
filename TEXT,
brand TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 优化记录表
cursor.execute("""
CREATE TABLE IF NOT EXISTS optimizations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
original_content TEXT,
optimized_content TEXT,
changes TEXT,
platform TEXT,
brand TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# 验证结果表
cursor.execute("""
CREATE TABLE IF NOT EXISTS verify_results (
id INTEGER PRIMARY KEY AUTOINCREMENT,
query TEXT,
brand TEXT,
verify_model TEXT,
mention_count INTEGER,
mention_position TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
conn.close()
def _init_json(self):
"""初始化JSON存储目录"""
Path(self.db_path).mkdir(parents=True, exist_ok=True)
# ==================== 关键词相关 ====================
def save_keywords(self, keywords: List[str], brand: str):
"""保存关键词列表"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
for keyword in keywords:
cursor.execute(
"INSERT INTO keywords (keyword, brand) VALUES (?, ?)",
(keyword, brand)
)
conn.commit()
conn.close()
else:
# JSON方式:追加到文件
json_file = Path(self.db_path) / "keywords.json"
data = []
if json_file.exists():
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
for keyword in keywords:
data.append({
"keyword": keyword,
"brand": brand,
"created_at": datetime.now().isoformat()
})
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_keywords(self, brand: Optional[str] = None) -> List[str]:
"""获取关键词列表"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
if brand:
cursor.execute("SELECT keyword FROM keywords WHERE brand = ?", (brand,))
else:
cursor.execute("SELECT keyword FROM keywords")
keywords = [row[0] for row in cursor.fetchall()]
conn.close()
return keywords
else:
json_file = Path(self.db_path) / "keywords.json"
if not json_file.exists():
return []
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
if brand:
return [item["keyword"] for item in data if item.get("brand") == brand]
return [item["keyword"] for item in data]
# ==================== 文章内容相关 ====================
def save_article(self, keyword: str, platform: str, content: str,
filename: str, brand: str):
"""保存生成的文章"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("""
INSERT INTO articles (keyword, platform, content, filename, brand)
VALUES (?, ?, ?, ?, ?)
""", (keyword, platform, content, filename, brand))
conn.commit()
conn.close()
else:
json_file = Path(self.db_path) / "articles.json"
data = []
if json_file.exists():
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data.append({
"keyword": keyword,
"platform": platform,
"content": content,
"filename": filename,
"brand": brand,
"created_at": datetime.now().isoformat()
})
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_articles(self, brand: Optional[str] = None,
platform: Optional[str] = None) -> List[Dict]:
"""获取文章列表"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
if brand and platform:
df = pd.read_sql_query(
"SELECT * FROM articles WHERE brand = ? AND platform = ?",
conn, params=(brand, platform)
)
elif brand:
df = pd.read_sql_query(
"SELECT * FROM articles WHERE brand = ?",
conn, params=(brand,)
)
else:
df = pd.read_sql_query("SELECT * FROM articles", conn)
conn.close()
return df.to_dict('records')
else:
json_file = Path(self.db_path) / "articles.json"
if not json_file.exists():
return []
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
if brand and platform:
return [item for item in data
if item.get("brand") == brand and item.get("platform") == platform]
elif brand:
return [item for item in data if item.get("brand") == brand]
return data
# ==================== 优化记录相关 ====================
def save_optimization(self, original_content: str, optimized_content: str,
changes: str, platform: str, brand: str):
"""保存优化记录"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("""
INSERT INTO optimizations
(original_content, optimized_content, changes, platform, brand)
VALUES (?, ?, ?, ?, ?)
""", (original_content, optimized_content, changes, platform, brand))
conn.commit()
conn.close()
else:
json_file = Path(self.db_path) / "optimizations.json"
data = []
if json_file.exists():
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
data.append({
"original_content": original_content,
"optimized_content": optimized_content,
"changes": changes,
"platform": platform,
"brand": brand,
"created_at": datetime.now().isoformat()
})
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_optimizations(self, brand: Optional[str] = None) -> List[Dict]:
"""获取优化记录"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
if brand:
df = pd.read_sql_query(
"SELECT * FROM optimizations WHERE brand = ? ORDER BY created_at DESC",
conn, params=(brand,)
)
else:
df = pd.read_sql_query(
"SELECT * FROM optimizations ORDER BY created_at DESC",
conn
)
conn.close()
return df.to_dict('records')
else:
json_file = Path(self.db_path) / "optimizations.json"
if not json_file.exists():
return []
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
if brand:
return [item for item in data if item.get("brand") == brand]
return data
# ==================== 验证结果相关 ====================
def save_verify_results(self, results: List[Dict]):
"""批量保存验证结果"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
for result in results:
cursor.execute("""
INSERT INTO verify_results
(query, brand, verify_model, mention_count, mention_position)
VALUES (?, ?, ?, ?, ?)
""", (
result.get("问题"),
result.get("品牌"),
result.get("验证模型"),
result.get("提及次数"),
result.get("位置")
))
conn.commit()
conn.close()
else:
json_file = Path(self.db_path) / "verify_results.json"
data = []
if json_file.exists():
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
for result in results:
data.append({
"query": result.get("问题"),
"brand": result.get("品牌"),
"verify_model": result.get("验证模型"),
"mention_count": result.get("提及次数"),
"mention_position": result.get("位置"),
"created_at": datetime.now().isoformat()
})
with open(json_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def get_verify_results(self, brand: Optional[str] = None, include_timestamp: bool = False) -> pd.DataFrame:
"""获取验证结果(返回DataFrame
Args:
brand: 品牌名称,如果为None则返回所有品牌
include_timestamp: 是否包含时间戳字段
"""
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
if include_timestamp:
if brand:
df = pd.read_sql_query(
"""SELECT query as "问题", brand as "品牌", verify_model as "验证模型",
mention_count as "提及次数", mention_position as "位置",
created_at as "验证时间"
FROM verify_results WHERE brand = ? ORDER BY created_at DESC""",
conn, params=(brand,)
)
else:
df = pd.read_sql_query(
"""SELECT query as "问题", brand as "品牌", verify_model as "验证模型",
mention_count as "提及次数", mention_position as "位置",
created_at as "验证时间"
FROM verify_results ORDER BY created_at DESC""",
conn
)
else:
if brand:
df = pd.read_sql_query(
"""SELECT query as "问题", brand as "品牌", verify_model as "验证模型",
mention_count as "提及次数", mention_position as "位置"
FROM verify_results WHERE brand = ?""",
conn, params=(brand,)
)
else:
df = pd.read_sql_query(
"""SELECT query as "问题", brand as "品牌", verify_model as "验证模型",
mention_count as "提及次数", mention_position as "位置"
FROM verify_results""",
conn
)
conn.close()
if include_timestamp and not df.empty and "验证时间" in df.columns:
df["验证时间"] = pd.to_datetime(df["验证时间"])
return df
else:
json_file = Path(self.db_path) / "verify_results.json"
if not json_file.exists():
return pd.DataFrame()
with open(json_file, 'r', encoding='utf-8') as f:
data = json.load(f)
if brand:
data = [item for item in data if item.get("brand") == brand]
# 转换为DataFrame格式
records = []
for item in data:
record = {
"问题": item.get("query"),
"品牌": item.get("brand"),
"验证模型": item.get("verify_model"),
"提及次数": item.get("mention_count"),
"位置": item.get("mention_position")
}
if include_timestamp and "created_at" in item:
record["验证时间"] = pd.to_datetime(item.get("created_at"))
records.append(record)
df = pd.DataFrame(records)
if include_timestamp and not df.empty and "验证时间" in df.columns:
df = df.sort_values("验证时间", ascending=False)
return df
# ==================== 统计功能 ====================
def get_stats(self, brand: Optional[str] = None) -> Dict[str, Any]:
"""获取统计数据"""
stats = {}
if self.storage_type == "sqlite":
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# 关键词数量
if brand:
cursor.execute("SELECT COUNT(*) FROM keywords WHERE brand = ?", (brand,))
else:
cursor.execute("SELECT COUNT(*) FROM keywords")
stats["keywords_count"] = cursor.fetchone()[0]
# 文章数量
if brand:
cursor.execute("SELECT COUNT(*) FROM articles WHERE brand = ?", (brand,))
else:
cursor.execute("SELECT COUNT(*) FROM articles")
stats["articles_count"] = cursor.fetchone()[0]
# 优化记录数量
if brand:
cursor.execute("SELECT COUNT(*) FROM optimizations WHERE brand = ?", (brand,))
else:
cursor.execute("SELECT COUNT(*) FROM optimizations")
stats["optimizations_count"] = cursor.fetchone()[0]
# 验证结果数量
if brand:
cursor.execute("SELECT COUNT(*) FROM verify_results WHERE brand = ?", (brand,))
else:
cursor.execute("SELECT COUNT(*) FROM verify_results")
stats["verify_results_count"] = cursor.fetchone()[0]
conn.close()
else:
# JSON方式统计
keywords_file = Path(self.db_path) / "keywords.json"
articles_file = Path(self.db_path) / "articles.json"
optimizations_file = Path(self.db_path) / "optimizations.json"
verify_file = Path(self.db_path) / "verify_results.json"
def count_json(file_path, brand_filter=None):
if not file_path.exists():
return 0
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
if brand_filter:
return len([item for item in data if item.get("brand") == brand_filter])
return len(data)
stats["keywords_count"] = count_json(keywords_file, brand)
stats["articles_count"] = count_json(articles_file, brand)
stats["optimizations_count"] = count_json(optimizations_file, brand)
stats["verify_results_count"] = count_json(verify_file, brand)
return stats
+2016
View File
File diff suppressed because it is too large Load Diff
+234
View File
@@ -0,0 +1,234 @@
"""
托词工具模块 - AI 蒸馏词功能
支持词库组合生成关键词
"""
import json
import itertools
from typing import List, Dict, Set
from difflib import SequenceMatcher
class KeywordTool:
"""托词工具:通过词库组合生成关键词"""
def __init__(self):
"""初始化默认词库"""
self.default_wordbanks = {
"A前缀1": ["行业上", "市场上", "市面上", "目前", "国内", "市场"],
"B前缀2": ["口碑好的", "比较好的", "靠谱的", "有实力的", "可靠的", "诚信的", "正规的", "专业的", "热门的", "知名的"],
"C主词": ["外贸软件", "外贸ERP", "CRM管理系统"],
"D通义词": ["品牌", "公司", "工厂", "厂商", "生产厂家", "供应商"],
"E推荐词": ["推荐", "排行", "推荐榜", "排行榜", "推荐榜单", "推荐排行", "推荐排行榜", "口碑排行"],
"F疑问词": ["哪家好", "哪家强", "哪家靠谱", "哪家权威", "哪个好", "有哪些", "找哪家", "选哪家", "为什么"],
}
self.combination_patterns = [
["C", "D"],
["A", "C", "D"],
["B", "C", "D"],
["A", "B", "C", "D"],
["C", "D", "E"],
["C", "D", "F"],
["A", "C", "D", "E"],
["B", "C", "D", "E"],
["A", "B", "C", "D", "E"],
["A", "B", "C", "D", "F"],
]
def load_wordbanks(self, wordbanks: Dict[str, List[str]] = None) -> Dict[str, List[str]]:
"""加载词库,如果未提供则使用默认词库"""
if wordbanks is None:
return self.default_wordbanks.copy()
return wordbanks
def generate_combinations(
self,
wordbanks: Dict[str, List[str]],
patterns: List[List[str]] = None,
max_results: int = 100,
similarity_threshold: float = 0.8
) -> List[str]:
"""
根据组合模式生成关键词组合
Args:
wordbanks: 词库字典,格式如 {"A前缀1": ["词1", "词2"], ...}
patterns: 组合模式列表,如 [["C", "D"], ["A", "C", "D"]]
max_results: 最大生成数量
similarity_threshold: 相似度阈值,用于去重(0-1之间)
Returns:
生成的关键词列表
"""
if patterns is None:
patterns = self.combination_patterns
# 创建模式字母到词库key的映射
# 例如: "C" -> "C主词", "D" -> "D通义词"
pattern_to_bank = {}
for bank_key in wordbanks.keys():
# 提取第一个字母作为模式标识
if bank_key and len(bank_key) > 0:
pattern_letter = bank_key[0]
pattern_to_bank[pattern_letter] = bank_key
all_keywords = []
seen = set()
for pattern in patterns:
# 将模式字母转换为实际的词库key
required_banks = []
for pattern_letter in pattern:
if pattern_letter in pattern_to_bank:
bank_key = pattern_to_bank[pattern_letter]
if bank_key in wordbanks and wordbanks[bank_key]:
required_banks.append(bank_key)
if not required_banks:
continue
# 获取每个词库的词列表
word_lists = [wordbanks[bank] for bank in required_banks]
# 生成笛卡尔积组合
for combo in itertools.product(*word_lists):
keyword = "".join(combo) # 直接拼接
# 去重:检查是否已存在
keyword_lower = keyword.lower()
if keyword_lower in seen:
continue
# 相似度去重
is_similar = False
for existing in seen:
similarity = SequenceMatcher(None, keyword_lower, existing).ratio()
if similarity >= similarity_threshold:
is_similar = True
break
if not is_similar:
seen.add(keyword_lower)
all_keywords.append(keyword)
if len(all_keywords) >= max_results:
return all_keywords
return all_keywords[:max_results]
def get_pattern_descriptions(self) -> Dict[str, List[str]]:
"""获取组合模式的描述"""
return {
"C+D": ["C主词", "D通义词"],
"A+C+D": ["A前缀1", "C主词", "D通义词"],
"B+C+D": ["B前缀2", "C主词", "D通义词"],
"A+B+C+D": ["A前缀1", "B前缀2", "C主词", "D通义词"],
"C+D+E": ["C主词", "D通义词", "E推荐词"],
"C+D+F": ["C主词", "D通义词", "F疑问词"],
"A+C+D+E": ["A前缀1", "C主词", "D通义词", "E推荐词"],
"B+C+D+E": ["B前缀2", "C主词", "D通义词", "E推荐词"],
"A+B+C+D+E": ["A前缀1", "B前缀2", "C主词", "D通义词", "E推荐词"],
"A+B+C+D+F": ["A前缀1", "B前缀2", "C主词", "D通义词", "F疑问词"],
}
def polish_with_llm(
self,
keywords: List[str],
llm_chain,
brand: str = "",
max_polish: int = 50
) -> List[str]:
"""
使用 LLM 对关键词进行润色,使其更自然
Args:
keywords: 原始关键词列表
llm_chain: LangChain chain 对象(接受 {"input": str} 格式)
brand: 品牌名称(可选)
max_polish: 最多润色的关键词数量
Returns:
润色后的关键词列表
"""
if not keywords or not llm_chain:
return keywords
# 限制润色数量,避免 API 调用过多
keywords_to_polish = keywords[:max_polish]
polish_prompt = f"""你是关键词优化专家。请将以下关键词润色为更自然、更符合用户搜索习惯的表达。
{"品牌:" + brand if brand else ""}
原始关键词列表:
{json.dumps(keywords_to_polish, ensure_ascii=False, indent=2)}
要求:
1) 保持原意,但表达更自然、口语化
2) 长度控制在 12-28 字
3) 去除生硬拼接感
4) 输出 JSON 数组格式:["润色后的关键词1", "润色后的关键词2", ...]
只输出 JSON 数组,不要其他内容。
"""
try:
result = llm_chain.invoke({"input": polish_prompt})
if isinstance(result, str):
# 尝试解析 JSON
import re
m = re.search(r'\[[\s\S]*?\]', result)
if m:
polished = json.loads(m.group(0))
else:
# 如果解析失败,尝试按行分割
lines = [line.strip() for line in result.split('\n') if line.strip()]
polished = [line.strip('"\'[],') for line in lines if line.strip('"\'[],')]
elif isinstance(result, list):
polished = result
else:
polished = keywords_to_polish
except Exception as e:
polished = keywords_to_polish
# 确保返回的是列表
if not isinstance(polished, list):
polished = keywords_to_polish
# 合并润色后的和未润色的
return polished + keywords[len(keywords_to_polish):]
def export_wordbanks(self, wordbanks: Dict[str, List[str]], filepath: str):
"""导出词库到 JSON 文件"""
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(wordbanks, f, ensure_ascii=False, indent=2)
def import_wordbanks(self, filepath: str) -> Dict[str, List[str]]:
"""从 JSON 文件导入词库"""
with open(filepath, 'r', encoding='utf-8') as f:
return json.load(f)
def export_wordbanks_csv(self, wordbanks: Dict[str, List[str]], filepath: str):
"""导出词库到 CSV 文件"""
import csv
with open(filepath, 'w', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['词库类型', '词汇'])
for bank_type, words in wordbanks.items():
for word in words:
writer.writerow([bank_type, word])
def import_wordbanks_csv(self, filepath: str) -> Dict[str, List[str]]:
"""从 CSV 文件导入词库"""
import csv
wordbanks = {}
with open(filepath, 'r', encoding='utf-8-sig') as f:
reader = csv.DictReader(f)
for row in reader:
bank_type = row.get('词库类型', '').strip()
word = row.get('词汇', '').strip()
if bank_type and word:
if bank_type not in wordbanks:
wordbanks[bank_type] = []
wordbanks[bank_type].append(word)
return wordbanks
+18
View File
@@ -0,0 +1,18 @@
streamlit>=1.30,<2
pandas>=2.0,<3
plotly>=5.0,<6
langchain-core==1.2.7
langchain-community==0.4.1
langchain-openai==1.1.7
langchain-groq==1.1.1
langchain-deepseek==1.0.1
dashscope>=1.0,<2
# 豆包(字节跳动)- 可选,需要时安装
# pip install 'volcengine-python-sdk[ark]'
# 文心一言(百度)- 可选,需要时安装
# pip install qianfan
# 或使用 langchain-community 的 QianfanChatEndpoint(需要 qianfan 包)
+86
View File
@@ -0,0 +1,86 @@
"""
数据持久化集成示例
展示如何在 geo_tool.py 中集成 DataStorage
"""
# ==================== 方式1SQLite(推荐,简单高效) ====================
from data_storage import DataStorage
# 初始化存储(SQLite方式,单文件数据库)
storage = DataStorage(storage_type="sqlite", db_path="geo_data.db")
# 或者使用JSON方式(更简单,但查询性能差)
# storage = DataStorage(storage_type="json", db_path="data")
# ==================== 在关键词模块中使用 ====================
def save_keywords_example(keywords: list, brand: str):
"""保存关键词到数据库"""
storage.save_keywords(keywords, brand)
def load_keywords_example(brand: str) -> list:
"""从数据库加载关键词"""
return storage.get_keywords(brand)
# ==================== 在内容生成模块中使用 ====================
def save_article_example(keyword: str, platform: str, content: str,
filename: str, brand: str):
"""保存生成的文章"""
storage.save_article(keyword, platform, content, filename, brand)
def get_article_history_example(brand: str, platform: str = None):
"""获取历史文章"""
return storage.get_articles(brand=brand, platform=platform)
# ==================== 在优化模块中使用 ====================
def save_optimization_example(original: str, optimized: str,
changes: str, platform: str, brand: str):
"""保存优化记录"""
storage.save_optimization(original, optimized, changes, platform, brand)
# ==================== 在验证模块中使用 ====================
def save_verify_example(results: list):
"""保存验证结果"""
storage.save_verify_results(results)
def get_verify_history_example(brand: str):
"""获取历史验证结果"""
return storage.get_verify_results(brand=brand)
# ==================== 统计功能 ====================
def get_stats_example(brand: str):
"""获取统计数据"""
return storage.get_stats(brand=brand)
# ==================== 完整集成示例 ====================
"""
在 geo_tool.py 中的集成方式:
1. 在文件顶部添加:
from data_storage import DataStorage
storage = DataStorage(storage_type="sqlite", db_path="geo_data.db")
2. 在关键词生成后保存:
if cleaned:
st.session_state.keywords = cleaned
storage.save_keywords(cleaned, brand) # 新增:保存到数据库
st.success(f"生成完成({len(cleaned)} 条)")
3. 在内容生成后保存:
for keyword, plat in keywords_to_generate:
# ... 生成内容 ...
storage.save_article(keyword, plat, content, filename, brand) # 新增
4. 在优化后保存:
storage.save_optimization(
original_article,
optimized_article,
changes,
target_platform,
brand
) # 新增
5. 在验证后保存:
storage.save_verify_results(all_results) # 新增
6. 可选:添加"历史记录"Tab,查看已保存的数据
"""