✨ 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 |
]
|