File size: 9,194 Bytes
3e35e18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
from datetime import datetime, timedelta
from app.utils.logging import log

def clean_expired_stats(api_call_stats):
    """清理过期统计数据的函数"""
    now = datetime.now()
    
    # 清理24小时前的数据
    # 清理总调用次数
    for hour_key in list(api_call_stats['last_24h']['total'].keys()):
        try:
            hour_time = datetime.strptime(hour_key, '%Y-%m-%d %H:00')
            if (now - hour_time).total_seconds() > 24 * 3600:  # 超过24小时
                del api_call_stats['last_24h']['total'][hour_key]
        except ValueError:
            # 如果键格式不正确,直接删除
            del api_call_stats['last_24h']['total'][hour_key]
    
    # 清理按端点和模型分类的数据
    for endpoint in list(api_call_stats['last_24h']['by_endpoint'].keys()):
        if not isinstance(api_call_stats['last_24h']['by_endpoint'][endpoint], dict):
            del api_call_stats['last_24h']['by_endpoint'][endpoint]
            continue
            
        for model in list(api_call_stats['last_24h']['by_endpoint'][endpoint].keys()):
            if not isinstance(api_call_stats['last_24h']['by_endpoint'][endpoint][model], dict):
                del api_call_stats['last_24h']['by_endpoint'][endpoint][model]
                continue
                
            for hour_key in list(api_call_stats['last_24h']['by_endpoint'][endpoint][model].keys()):
                try:
                    hour_time = datetime.strptime(hour_key, '%Y-%m-%d %H:00')
                    if (now - hour_time).total_seconds() > 24 * 3600:  # 超过24小时
                        del api_call_stats['last_24h']['by_endpoint'][endpoint][model][hour_key]
                except ValueError:
                    # 如果键格式不正确,直接删除
                    del api_call_stats['last_24h']['by_endpoint'][endpoint][model][hour_key]
    
    # 清理一小时前的小时统计数据
    one_hour_ago = now - timedelta(hours=1)
    # 清理总调用次数
    for hour_key in list(api_call_stats['hourly']['total'].keys()):
        try:
            hour_time = datetime.strptime(hour_key, '%Y-%m-%d %H:00')
            if hour_time < one_hour_ago:
                del api_call_stats['hourly']['total'][hour_key]
        except ValueError:
            # 如果键格式不正确,直接删除
            del api_call_stats['hourly']['total'][hour_key]
    
    # 清理按端点和模型分类的数据
    for endpoint in list(api_call_stats['hourly']['by_endpoint'].keys()):
        if not isinstance(api_call_stats['hourly']['by_endpoint'][endpoint], dict):
            del api_call_stats['hourly']['by_endpoint'][endpoint]
            continue
            
        for model in list(api_call_stats['hourly']['by_endpoint'][endpoint].keys()):
            if not isinstance(api_call_stats['hourly']['by_endpoint'][endpoint][model], dict):
                del api_call_stats['hourly']['by_endpoint'][endpoint][model]
                continue
                
            for hour_key in list(api_call_stats['hourly']['by_endpoint'][endpoint][model].keys()):
                try:
                    hour_time = datetime.strptime(hour_key, '%Y-%m-%d %H:00')
                    if hour_time < one_hour_ago:
                        del api_call_stats['hourly']['by_endpoint'][endpoint][model][hour_key]
                except ValueError:
                    # 如果键格式不正确,直接删除
                    del api_call_stats['hourly']['by_endpoint'][endpoint][model][hour_key]
    
    # 清理一分钟前的分钟统计数据
    one_minute_ago = now - timedelta(minutes=1)
    # 清理总调用次数
    for minute_key in list(api_call_stats['minute']['total'].keys()):
        try:
            minute_time = datetime.strptime(minute_key, '%Y-%m-%d %H:%M')
            if minute_time < one_minute_ago:
                del api_call_stats['minute']['total'][minute_key]
        except ValueError:
            # 如果键格式不正确,直接删除
            del api_call_stats['minute']['total'][minute_key]
    
    # 清理按端点和模型分类的数据
    for endpoint in list(api_call_stats['minute']['by_endpoint'].keys()):
        if not isinstance(api_call_stats['minute']['by_endpoint'][endpoint], dict):
            del api_call_stats['minute']['by_endpoint'][endpoint]
            continue
            
        for model in list(api_call_stats['minute']['by_endpoint'][endpoint].keys()):
            if not isinstance(api_call_stats['minute']['by_endpoint'][endpoint][model], dict):
                del api_call_stats['minute']['by_endpoint'][endpoint][model]
                continue
                
            for minute_key in list(api_call_stats['minute']['by_endpoint'][endpoint][model].keys()):
                try:
                    minute_time = datetime.strptime(minute_key, '%Y-%m-%d %H:%M')
                    if minute_time < one_minute_ago:
                        del api_call_stats['minute']['by_endpoint'][endpoint][model][minute_key]
                except ValueError:
                    # 如果键格式不正确,直接删除
                    del api_call_stats['minute']['by_endpoint'][endpoint][model][minute_key]

def update_api_call_stats(api_call_stats, endpoint=None, model=None):
    """
    更新API调用统计的函数
    
    参数:
    - api_call_stats: 统计数据字典
    - endpoint: API端点,为None则只更新总调用次数
    - model: 模型名称,与endpoint一起使用来分类统计数据
    """
    now = datetime.now()
    hour_key = now.strftime('%Y-%m-%d %H:00')
    minute_key = now.strftime('%Y-%m-%d %H:%M')
    
    # 检查并清理过期统计
    clean_expired_stats(api_call_stats)
    
    # 初始化总调用次数键(如果不存在)
    if hour_key not in api_call_stats['last_24h']['total']:
        api_call_stats['last_24h']['total'][hour_key] = 0
    if hour_key not in api_call_stats['hourly']['total']:
        api_call_stats['hourly']['total'][hour_key] = 0
    if minute_key not in api_call_stats['minute']['total']:
        api_call_stats['minute']['total'][minute_key] = 0
    
    # 更新总调用次数统计
    api_call_stats['last_24h']['total'][hour_key] += 1
    api_call_stats['hourly']['total'][hour_key] += 1
    api_call_stats['minute']['total'][minute_key] += 1
    
    # 如果提供了端点,更新按端点分类的统计
    if endpoint and model:
        # 确保端点字典存在
        for period in ['last_24h', 'hourly', 'minute']:
            if endpoint not in api_call_stats[period]['by_endpoint']:
                api_call_stats[period]['by_endpoint'][endpoint] = {}
            
            if model not in api_call_stats[period]['by_endpoint'][endpoint]:
                api_call_stats[period]['by_endpoint'][endpoint][model] = {}
        
        # 初始化端点和模型特定的时间键(如果不存在)
        if hour_key not in api_call_stats['last_24h']['by_endpoint'][endpoint][model]:
            api_call_stats['last_24h']['by_endpoint'][endpoint][model][hour_key] = 0
            
        if hour_key not in api_call_stats['hourly']['by_endpoint'][endpoint][model]:
            api_call_stats['hourly']['by_endpoint'][endpoint][model][hour_key] = 0
            
        if minute_key not in api_call_stats['minute']['by_endpoint'][endpoint][model]:
            api_call_stats['minute']['by_endpoint'][endpoint][model][minute_key] = 0
        
        # 更新端点特定的统计
        if model is not None:
            api_call_stats['last_24h']['by_endpoint'][endpoint][model][hour_key] += 1
            api_call_stats['hourly']['by_endpoint'][endpoint][model][hour_key] += 1
            api_call_stats['minute']['by_endpoint'][endpoint][model][minute_key] += 1
    
    # 计算总调用次数
    total_24h = sum(api_call_stats['last_24h']['total'].values())
    total_hourly = sum(api_call_stats['hourly']['total'].values())
    total_minute = sum(api_call_stats['minute']['total'].values())
    
    log_message = "API调用统计已更新: 24小时=%s, 1小时=%s, 1分钟=%s" % (
        total_24h, total_hourly, total_minute
    )
    
    # 如果提供了端点和模型,添加端点特定的统计信息
    if endpoint and model is not None:
        try:
            endpoint_24h = sum(api_call_stats['last_24h']['by_endpoint'][endpoint][model].values())
            endpoint_hourly = sum(api_call_stats['hourly']['by_endpoint'][endpoint][model].values())
            endpoint_minute = sum(api_call_stats['minute']['by_endpoint'][endpoint][model].values())
            
            log_message += " | 端点 '%s' 模型 '%s': 24小时=%s, 1小时=%s, 1分钟=%s" % (
                endpoint[:8], model[:8], endpoint_24h, endpoint_hourly, endpoint_minute
            )
        except (KeyError, TypeError):
            # 如果统计数据结构中缺少某些键,记录基本信息
            log_message += " | 端点 '%s' 模型 '%s': 统计数据不完整" % (
                endpoint[:8], model[:8]
            )
    else:
        log_message += " | 端点 '%s' 模型 '%s': 统计数据不完整" 
    
    log('info', log_message)