""" 文章撰写工作流系统 - 后台管理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/') 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/', 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/') 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:19001") print("=" * 50) app.run(host='0.0.0.0', port=19001, debug=True)