临时保存1

This commit is contained in:
rjb
2025-09-09 07:45:51 +08:00
parent 733a0487ff
commit 0c7420d17c
8 changed files with 403 additions and 42 deletions

View File

@@ -11,6 +11,7 @@ from datetime import datetime, timedelta
import plotly.graph_objs as go
import plotly.utils
import json
from src.flask_prompt_master.utils.performance_monitor import monitor_performance
class AnalyticsAdminView(BaseView):
"""数据分析管理视图"""
@@ -39,50 +40,53 @@ class AnalyticsAdminView(BaseView):
return self.render('admin/analytics_charts.html', charts_data=charts_data)
@monitor_performance
def _get_analytics_data(self):
"""获取分析数据"""
"""获取分析数据 - 优化版本"""
try:
# 用户统计
total_users = User.query.count()
active_users = User.query.filter_by(status=1).count()
new_users_today = User.query.filter(
User.created_time >= datetime.now().date()
).count()
new_users_week = User.query.filter(
User.created_time >= datetime.now() - timedelta(days=7)
).count()
today = datetime.now().date()
week_ago = datetime.now() - timedelta(days=7)
# 提示词统计
total_prompts = Prompt.query.count()
today_prompts = Prompt.query.filter(
Prompt.created_at >= datetime.now().date()
).count()
week_prompts = Prompt.query.filter(
Prompt.created_at >= datetime.now() - timedelta(days=7)
).count()
# 使用单个查询获取所有用户统计
user_stats = db.session.query(
func.count(User.uid).label('total_users'),
func.sum(func.case([(User.status == 1, 1)], else_=0)).label('active_users'),
func.sum(func.case([(User.created_time >= today, 1)], else_=0)).label('new_users_today'),
func.sum(func.case([(User.created_time >= week_ago, 1)], else_=0)).label('new_users_week')
).first()
# 使用单个查询获取所有提示词统计
prompt_stats = db.session.query(
func.count(Prompt.id).label('total_prompts'),
func.sum(func.case([(Prompt.created_at >= today, 1)], else_=0)).label('today_prompts'),
func.sum(func.case([(Prompt.created_at >= week_ago, 1)], else_=0)).label('week_prompts')
).first()
# 模板统计
total_templates = PromptTemplate.query.count()
default_templates = PromptTemplate.query.filter_by(is_default=True).count()
template_stats = db.session.query(
func.count(PromptTemplate.id).label('total_templates'),
func.sum(func.case([(PromptTemplate.is_default == True, 1)], else_=0)).label('default_templates')
).first()
# 用户活跃度
active_users_week = db.session.query(func.count(func.distinct(Prompt.user_id))).filter(
Prompt.created_at >= datetime.now() - timedelta(days=7)
).scalar()
# 用户活跃度 - 优化查询
active_users_week = db.session.query(
func.count(func.distinct(Prompt.user_id))
).filter(Prompt.created_at >= week_ago).scalar() or 0
return {
'total_users': total_users,
'active_users': active_users,
'new_users_today': new_users_today,
'new_users_week': new_users_week,
'total_prompts': total_prompts,
'today_prompts': today_prompts,
'week_prompts': week_prompts,
'total_templates': total_templates,
'default_templates': default_templates,
'active_users_week': active_users_week or 0
'total_users': user_stats.total_users or 0,
'active_users': user_stats.active_users or 0,
'new_users_today': user_stats.new_users_today or 0,
'new_users_week': user_stats.new_users_week or 0,
'total_prompts': prompt_stats.total_prompts or 0,
'today_prompts': prompt_stats.today_prompts or 0,
'week_prompts': prompt_stats.week_prompts or 0,
'total_templates': template_stats.total_templates or 0,
'default_templates': template_stats.default_templates or 0,
'active_users_week': active_users_week
}
except Exception as e:
print(f"获取分析数据失败: {str(e)}")
return {
'total_users': 0,
'active_users': 0,

View File

@@ -110,18 +110,26 @@ class ApiAdminView(BaseView):
# 成功率(模拟数据)
success_rate = 98.5 # 百分比
# 最近7天的调用趋势
# 最近7天的调用趋势 - 优化版本
week_ago = datetime.now() - timedelta(days=7)
daily_calls_data = db.session.query(
func.date(Prompt.created_at).label('date'),
func.count(Prompt.id).label('count')
).filter(
Prompt.created_at >= week_ago
).group_by(
func.date(Prompt.created_at)
).order_by(func.date(Prompt.created_at)).all()
# 构建完整的7天数据
daily_calls = []
for i in range(7):
date = datetime.now() - timedelta(days=i)
count = Prompt.query.filter(
func.date(Prompt.created_at) == date.date()
).count()
date = (datetime.now() - timedelta(days=6-i)).date()
count = next((item.count for item in daily_calls_data if item.date == date), 0)
daily_calls.append({
'date': date.strftime('%Y-%m-%d'),
'count': count
})
daily_calls.reverse()
return {
'today_calls': today_calls,

View File

@@ -269,8 +269,11 @@
<script>
document.addEventListener('DOMContentLoaded', function() {
// 初始化图表
initCharts();
// 延迟初始化,避免阻塞页面渲染
setTimeout(function() {
// 初始化图表
initCharts();
}, 100);
// 数字动画
const statsNumbers = document.querySelectorAll('.stats-number');

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
"""
缓存工具类
用于缓存频繁查询的数据,提升页面加载性能
"""
import json
import hashlib
from datetime import datetime, timedelta
from functools import wraps
from flask import current_app
# 简单的内存缓存实现
_cache = {}
_cache_expiry = {}
def cache_key(*args, **kwargs):
"""生成缓存键"""
key_str = json.dumps({'args': args, 'kwargs': kwargs}, sort_keys=True)
return hashlib.md5(key_str.encode()).hexdigest()
def cached(expiry_seconds=300):
"""
缓存装饰器
:param expiry_seconds: 缓存过期时间(秒)
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
key = f"{func.__name__}:{cache_key(*args, **kwargs)}"
# 检查缓存是否有效
if key in _cache and key in _cache_expiry:
if datetime.now() < _cache_expiry[key]:
return _cache[key]
# 执行函数并缓存结果
result = func(*args, **kwargs)
_cache[key] = result
_cache_expiry[key] = datetime.now() + timedelta(seconds=expiry_seconds)
return result
return wrapper
return decorator
def clear_cache(pattern=None):
"""
清除缓存
:param pattern: 缓存键模式如果为None则清除所有缓存
"""
global _cache, _cache_expiry
if pattern is None:
_cache.clear()
_cache_expiry.clear()
else:
keys_to_remove = [key for key in _cache.keys() if pattern in key]
for key in keys_to_remove:
_cache.pop(key, None)
_cache_expiry.pop(key, None)
def get_cache_stats():
"""获取缓存统计信息"""
return {
'total_keys': len(_cache),
'expired_keys': len([k for k, v in _cache_expiry.items() if datetime.now() > v]),
'cache_size': sum(len(str(v)) for v in _cache.values())
}

View File

@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
"""
性能监控工具
用于监控页面加载时间和数据库查询性能
"""
import time
import functools
from flask import request, g
from sqlalchemy import event
from sqlalchemy.engine import Engine
import logging
logger = logging.getLogger(__name__)
# 查询时间统计
query_times = []
@event.listens_for(Engine, "before_cursor_execute")
def receive_before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"""记录SQL查询开始时间"""
context._query_start_time = time.time()
@event.listens_for(Engine, "after_cursor_execute")
def receive_after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
"""记录SQL查询结束时间"""
total = time.time() - context._query_start_time
query_times.append({
'statement': statement,
'duration': total,
'timestamp': time.time()
})
# 记录慢查询
if total > 1.0: # 超过1秒的查询
logger.warning(f"慢查询检测: {total:.2f}s - {statement[:100]}...")
def monitor_performance(func):
"""性能监控装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
# 清空查询时间记录
global query_times
query_times.clear()
try:
result = func(*args, **kwargs)
return result
finally:
end_time = time.time()
duration = end_time - start_time
# 记录性能数据
performance_data = {
'function': func.__name__,
'duration': duration,
'query_count': len(query_times),
'total_query_time': sum(q['duration'] for q in query_times),
'slow_queries': [q for q in query_times if q['duration'] > 0.5]
}
# 记录到日志
logger.info(f"性能监控 - {func.__name__}: {duration:.2f}s, 查询数: {len(query_times)}")
# 如果性能较差,记录详细信息
if duration > 2.0 or len(query_times) > 10:
logger.warning(f"性能警告 - {func.__name__}: {performance_data}")
return wrapper
def get_performance_stats():
"""获取性能统计信息"""
if not query_times:
return {'message': '暂无查询数据'}
total_queries = len(query_times)
total_time = sum(q['duration'] for q in query_times)
avg_time = total_time / total_queries if total_queries > 0 else 0
slow_queries = [q for q in query_times if q['duration'] > 0.5]
return {
'total_queries': total_queries,
'total_time': round(total_time, 2),
'average_time': round(avg_time, 2),
'slow_queries_count': len(slow_queries),
'slow_queries': slow_queries[:5] # 只返回前5个慢查询
}