Files
article-workflow/admin/app.py
hubian 45b8c70cb9 新增后台管理系统
功能模块:
- 仪表盘: 统计数据概览、快速操作入口
- 资料池管理: 查看、搜索、删除资料
- 文章历史: 查看历史文章列表和主题标签
- 工作流控制: 新建工作流、配置参数、启动流程
- 系统设置: LLM配置、文章类型、数据管理

技术栈:
- Flask Web框架
- Tailwind CSS
- RESTful API
- 实时LLM连接测试
2026-04-08 11:48:39 +08:00

276 lines
6.7 KiB
Python

"""
文章撰写工作流系统 - 后台管理API
"""
from flask import Flask, render_template, jsonify, request, send_file
from flask_cors import CORS
import json
import os
import sys
from pathlib import Path
from datetime import datetime
# 添加父目录到路径
sys.path.insert(0, str(Path(__file__).parent.parent))
from config.settings import LLM_CONFIG, ARTICLE_TYPES, RESOURCE_POOL_CONFIG
from src.resource_pool import ResourcePool
from src.llm_client import LLMClient
app = Flask(__name__)
CORS(app)
# 初始化资料池
pool = ResourcePool(RESOURCE_POOL_CONFIG)
# ============ 页面路由 ============
@app.route('/')
def index():
"""首页 - 仪表盘"""
return render_template('index.html')
@app.route('/resources')
def resources_page():
"""资料池页面"""
return render_template('resources.html')
@app.route('/articles')
def articles_page():
"""文章历史页面"""
return render_template('articles.html')
@app.route('/workflow')
def workflow_page():
"""工作流控制页面"""
return render_template('workflow.html')
@app.route('/settings')
def settings_page():
"""系统设置页面"""
return render_template('settings.html')
# ============ API路由 ============
@app.route('/api/stats')
def api_stats():
"""获取统计数据"""
stats = pool.get_stats()
# 添加更多统计
articles = pool.get_article_history(limit=100)
# 按日期统计文章
date_stats = {}
for article in articles:
date = article.get('date', '')[:10]
date_stats[date] = date_stats.get(date, 0) + 1
stats['articles_by_date'] = date_stats
stats['recent_articles'] = articles[:5]
return jsonify(stats)
@app.route('/api/resources')
def api_resources():
"""获取资料列表"""
analyzed_only = request.args.get('analyzed') == 'true'
keyword = request.args.get('keyword', '')
resources = pool.list_resources(analyzed_only=analyzed_only)
# 关键词过滤
if keyword:
resources = [r for r in resources if
keyword.lower() in r.get('title', '').lower() or
keyword.lower() in r.get('url', '').lower()]
return jsonify(resources)
@app.route('/api/resources/<resource_id>')
def api_resource_detail(resource_id):
"""获取资料详情"""
resource = pool.get_resource(resource_id)
if not resource:
return jsonify({'error': 'Resource not found'}), 404
# 获取分析摘要
summary = pool.get_summary(resource_id)
if summary:
resource['summary'] = summary
return jsonify(resource)
@app.route('/api/resources/<resource_id>', methods=['DELETE'])
def api_delete_resource(resource_id):
"""删除资料"""
# TODO: 实现删除逻辑
return jsonify({'success': True})
@app.route('/api/summaries')
def api_summaries():
"""获取所有摘要"""
summaries = pool.get_all_summaries()
return jsonify(summaries)
@app.route('/api/articles')
def api_articles():
"""获取文章历史"""
limit = request.args.get('limit', 20, type=int)
articles = pool.get_article_history(limit=limit)
return jsonify(articles)
@app.route('/api/topics')
def api_topics():
"""获取历史主题"""
topics = pool.get_past_topics()
return jsonify(topics)
@app.route('/api/article-types')
def api_article_types():
"""获取文章类型"""
return jsonify(ARTICLE_TYPES)
@app.route('/api/keywords')
def api_keywords():
"""获取关键词索引"""
keywords = pool.index.get('keywords_index', {})
return jsonify(keywords)
@app.route('/api/config')
def api_config():
"""获取当前配置"""
# 隐藏敏感信息
safe_config = {
'base_url': LLM_CONFIG.get('base_url', ''),
'model': LLM_CONFIG.get('model', ''),
'max_tokens': LLM_CONFIG.get('max_tokens', 4096),
'temperature': LLM_CONFIG.get('temperature', 0.7),
}
return jsonify(safe_config)
@app.route('/api/config', methods=['POST'])
def api_update_config():
"""更新配置"""
data = request.json
# 这里只更新内存中的配置,实际应该保存到文件
# TODO: 实现配置持久化
return jsonify({'success': True, 'message': '配置已更新'})
@app.route('/api/workflow/start', methods=['POST'])
def api_start_workflow():
"""启动工作流"""
data = request.json
topic = data.get('topic')
article_type = data.get('type', '技术解析')
mode = data.get('mode', 'full')
if not topic:
return jsonify({'error': '请提供文章主题'}), 400
# TODO: 实际启动工作流(可以用线程或队列)
# 这里返回模拟响应
result = {
'status': 'started',
'topic': topic,
'type': article_type,
'mode': mode,
'message': '工作流已启动,请稍后查看结果'
}
return jsonify(result)
@app.route('/api/workflow/status')
def api_workflow_status():
"""获取工作流状态"""
# TODO: 实现实际的工作流状态追踪
return jsonify({
'running': False,
'current_step': None,
'progress': 0
})
@app.route('/api/test-llm', methods=['POST'])
def api_test_llm():
"""测试LLM连接"""
try:
client = LLMClient(LLM_CONFIG)
result = client.generate("你好,请回复'连接成功'")
if result:
return jsonify({'success': True, 'response': result})
else:
return jsonify({'success': False, 'error': '模型无响应'}), 500
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/articles/<path:filename>')
def api_article_file(filename):
"""获取文章文件内容"""
output_dir = Path(__file__).parent.parent / 'output' / 'articles'
filepath = output_dir / filename
if filepath.exists():
return send_file(filepath)
else:
return jsonify({'error': 'File not found'}), 404
@app.route('/api/export/resources')
def api_export_resources():
"""导出资料数据"""
resources = pool.list_resources()
export_data = {
'exported_at': datetime.now().isoformat(),
'count': len(resources),
'resources': resources
}
return jsonify(export_data)
# ============ 错误处理 ============
@app.errorhandler(404)
def not_found(error):
return jsonify({'error': 'Not found'}), 404
@app.errorhandler(500)
def server_error(error):
return jsonify({'error': 'Internal server error'}), 500
if __name__ == '__main__':
print("=" * 50)
print("文章撰写工作流系统 - 后台管理")
print("=" * 50)
print(f"访问地址: http://localhost:5001")
print("=" * 50)
app.run(host='0.0.0.0', port=5001, debug=True)