功能模块: - 仪表盘: 统计数据概览、快速操作入口 - 资料池管理: 查看、搜索、删除资料 - 文章历史: 查看历史文章列表和主题标签 - 工作流控制: 新建工作流、配置参数、启动流程 - 系统设置: LLM配置、文章类型、数据管理 技术栈: - Flask Web框架 - Tailwind CSS - RESTful API - 实时LLM连接测试
276 lines
6.7 KiB
Python
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) |