✨ Feature: Add feature: The /stats endpoint supports passing an 'hours' parameter to specify the number of hours of historical statistics data to return
Browse files
main.py
CHANGED
|
@@ -902,12 +902,20 @@ def generate_api_key():
|
|
| 902 |
return JSONResponse(content={"api_key": api_key})
|
| 903 |
|
| 904 |
# 在 /stats 路由中返回成功和失败百分比
|
| 905 |
-
from
|
| 906 |
from sqlalchemy import func, desc, case
|
|
|
|
| 907 |
|
| 908 |
@app.get("/stats", dependencies=[Depends(rate_limit_dependency)])
|
| 909 |
-
async def get_stats(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
async with async_session() as session:
|
|
|
|
|
|
|
|
|
|
| 911 |
# 1. 每个渠道下面每个模型的成功率
|
| 912 |
channel_model_stats = await session.execute(
|
| 913 |
select(
|
|
@@ -915,7 +923,9 @@ async def get_stats(request: Request, token: str = Depends(verify_admin_api_key)
|
|
| 915 |
ChannelStat.model,
|
| 916 |
func.count().label('total'),
|
| 917 |
func.sum(case((ChannelStat.success == True, 1), else_=0)).label('success_count')
|
| 918 |
-
)
|
|
|
|
|
|
|
| 919 |
)
|
| 920 |
channel_model_stats = channel_model_stats.fetchall()
|
| 921 |
|
|
@@ -925,14 +935,17 @@ async def get_stats(request: Request, token: str = Depends(verify_admin_api_key)
|
|
| 925 |
ChannelStat.provider,
|
| 926 |
func.count().label('total'),
|
| 927 |
func.sum(case((ChannelStat.success == True, 1), else_=0)).label('success_count')
|
| 928 |
-
)
|
|
|
|
|
|
|
| 929 |
)
|
| 930 |
channel_stats = channel_stats.fetchall()
|
| 931 |
|
| 932 |
# 3. 每个模型在所有渠道总的请求次数
|
| 933 |
model_stats = await session.execute(
|
| 934 |
-
select(
|
| 935 |
-
.
|
|
|
|
| 936 |
.order_by(desc('count'))
|
| 937 |
)
|
| 938 |
model_stats = model_stats.fetchall()
|
|
@@ -940,6 +953,7 @@ async def get_stats(request: Request, token: str = Depends(verify_admin_api_key)
|
|
| 940 |
# 4. 每个端点的请求次数
|
| 941 |
endpoint_stats = await session.execute(
|
| 942 |
select(RequestStat.endpoint, func.count().label('count'))
|
|
|
|
| 943 |
.group_by(RequestStat.endpoint)
|
| 944 |
.order_by(desc('count'))
|
| 945 |
)
|
|
@@ -947,25 +961,29 @@ async def get_stats(request: Request, token: str = Depends(verify_admin_api_key)
|
|
| 947 |
|
| 948 |
# 5. 每个ip请求的次数
|
| 949 |
ip_stats = await session.execute(
|
| 950 |
-
select(RequestStat.
|
| 951 |
-
.
|
|
|
|
| 952 |
.order_by(desc('count'))
|
| 953 |
)
|
| 954 |
ip_stats = ip_stats.fetchall()
|
| 955 |
|
| 956 |
# 处理统计数据并返回
|
| 957 |
stats = {
|
|
|
|
| 958 |
"channel_model_success_rates": [
|
| 959 |
{
|
| 960 |
"provider": stat.provider,
|
| 961 |
"model": stat.model,
|
| 962 |
-
"success_rate": stat.success_count / stat.total if stat.total > 0 else 0
|
|
|
|
| 963 |
} for stat in sorted(channel_model_stats, key=lambda x: x.success_count / x.total if x.total > 0 else 0, reverse=True)
|
| 964 |
],
|
| 965 |
"channel_success_rates": [
|
| 966 |
{
|
| 967 |
"provider": stat.provider,
|
| 968 |
-
"success_rate": stat.success_count / stat.total if stat.total > 0 else 0
|
|
|
|
| 969 |
} for stat in sorted(channel_stats, key=lambda x: x.success_count / x.total if x.total > 0 else 0, reverse=True)
|
| 970 |
],
|
| 971 |
"model_request_counts": [
|
|
@@ -982,7 +1000,7 @@ async def get_stats(request: Request, token: str = Depends(verify_admin_api_key)
|
|
| 982 |
],
|
| 983 |
"ip_request_counts": [
|
| 984 |
{
|
| 985 |
-
"ip": stat.
|
| 986 |
"count": stat.count
|
| 987 |
} for stat in ip_stats
|
| 988 |
]
|
|
|
|
| 902 |
return JSONResponse(content={"api_key": api_key})
|
| 903 |
|
| 904 |
# 在 /stats 路由中返回成功和失败百分比
|
| 905 |
+
from datetime import datetime, timedelta, timezone
|
| 906 |
from sqlalchemy import func, desc, case
|
| 907 |
+
from fastapi import Query
|
| 908 |
|
| 909 |
@app.get("/stats", dependencies=[Depends(rate_limit_dependency)])
|
| 910 |
+
async def get_stats(
|
| 911 |
+
request: Request,
|
| 912 |
+
token: str = Depends(verify_admin_api_key),
|
| 913 |
+
hours: int = Query(default=24, ge=1, le=720, description="Number of hours to look back for stats (1-720)")
|
| 914 |
+
):
|
| 915 |
async with async_session() as session:
|
| 916 |
+
# 计算指定时间范围的开始时间
|
| 917 |
+
start_time = datetime.now(timezone.utc) - timedelta(hours=hours)
|
| 918 |
+
|
| 919 |
# 1. 每个渠道下面每个模型的成功率
|
| 920 |
channel_model_stats = await session.execute(
|
| 921 |
select(
|
|
|
|
| 923 |
ChannelStat.model,
|
| 924 |
func.count().label('total'),
|
| 925 |
func.sum(case((ChannelStat.success == True, 1), else_=0)).label('success_count')
|
| 926 |
+
)
|
| 927 |
+
.where(ChannelStat.timestamp >= start_time)
|
| 928 |
+
.group_by(ChannelStat.provider, ChannelStat.model)
|
| 929 |
)
|
| 930 |
channel_model_stats = channel_model_stats.fetchall()
|
| 931 |
|
|
|
|
| 935 |
ChannelStat.provider,
|
| 936 |
func.count().label('total'),
|
| 937 |
func.sum(case((ChannelStat.success == True, 1), else_=0)).label('success_count')
|
| 938 |
+
)
|
| 939 |
+
.where(ChannelStat.timestamp >= start_time)
|
| 940 |
+
.group_by(ChannelStat.provider)
|
| 941 |
)
|
| 942 |
channel_stats = channel_stats.fetchall()
|
| 943 |
|
| 944 |
# 3. 每个模型在所有渠道总的请求次数
|
| 945 |
model_stats = await session.execute(
|
| 946 |
+
select(RequestStat.model, func.count().label('count'))
|
| 947 |
+
.where(RequestStat.timestamp >= start_time)
|
| 948 |
+
.group_by(RequestStat.model)
|
| 949 |
.order_by(desc('count'))
|
| 950 |
)
|
| 951 |
model_stats = model_stats.fetchall()
|
|
|
|
| 953 |
# 4. 每个端点的请求次数
|
| 954 |
endpoint_stats = await session.execute(
|
| 955 |
select(RequestStat.endpoint, func.count().label('count'))
|
| 956 |
+
.where(RequestStat.timestamp >= start_time)
|
| 957 |
.group_by(RequestStat.endpoint)
|
| 958 |
.order_by(desc('count'))
|
| 959 |
)
|
|
|
|
| 961 |
|
| 962 |
# 5. 每个ip请求的次数
|
| 963 |
ip_stats = await session.execute(
|
| 964 |
+
select(RequestStat.client_ip, func.count().label('count'))
|
| 965 |
+
.where(RequestStat.timestamp >= start_time)
|
| 966 |
+
.group_by(RequestStat.client_ip)
|
| 967 |
.order_by(desc('count'))
|
| 968 |
)
|
| 969 |
ip_stats = ip_stats.fetchall()
|
| 970 |
|
| 971 |
# 处理统计数据并返回
|
| 972 |
stats = {
|
| 973 |
+
"time_range": f"Last {hours} hours",
|
| 974 |
"channel_model_success_rates": [
|
| 975 |
{
|
| 976 |
"provider": stat.provider,
|
| 977 |
"model": stat.model,
|
| 978 |
+
"success_rate": stat.success_count / stat.total if stat.total > 0 else 0,
|
| 979 |
+
"total_requests": stat.total
|
| 980 |
} for stat in sorted(channel_model_stats, key=lambda x: x.success_count / x.total if x.total > 0 else 0, reverse=True)
|
| 981 |
],
|
| 982 |
"channel_success_rates": [
|
| 983 |
{
|
| 984 |
"provider": stat.provider,
|
| 985 |
+
"success_rate": stat.success_count / stat.total if stat.total > 0 else 0,
|
| 986 |
+
"total_requests": stat.total
|
| 987 |
} for stat in sorted(channel_stats, key=lambda x: x.success_count / x.total if x.total > 0 else 0, reverse=True)
|
| 988 |
],
|
| 989 |
"model_request_counts": [
|
|
|
|
| 1000 |
],
|
| 1001 |
"ip_request_counts": [
|
| 1002 |
{
|
| 1003 |
+
"ip": stat.client_ip,
|
| 1004 |
"count": stat.count
|
| 1005 |
} for stat in ip_stats
|
| 1006 |
]
|