codex-lb 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. app/__init__.py +5 -0
  2. app/cli.py +24 -0
  3. app/core/__init__.py +0 -0
  4. app/core/auth/__init__.py +96 -0
  5. app/core/auth/models.py +49 -0
  6. app/core/auth/refresh.py +144 -0
  7. app/core/balancer/__init__.py +19 -0
  8. app/core/balancer/logic.py +140 -0
  9. app/core/balancer/types.py +9 -0
  10. app/core/clients/__init__.py +0 -0
  11. app/core/clients/http.py +39 -0
  12. app/core/clients/oauth.py +340 -0
  13. app/core/clients/proxy.py +265 -0
  14. app/core/clients/usage.py +143 -0
  15. app/core/config/__init__.py +0 -0
  16. app/core/config/settings.py +69 -0
  17. app/core/crypto.py +37 -0
  18. app/core/errors.py +73 -0
  19. app/core/openai/__init__.py +0 -0
  20. app/core/openai/models.py +122 -0
  21. app/core/openai/parsing.py +55 -0
  22. app/core/openai/requests.py +59 -0
  23. app/core/types.py +4 -0
  24. app/core/usage/__init__.py +185 -0
  25. app/core/usage/logs.py +57 -0
  26. app/core/usage/models.py +35 -0
  27. app/core/usage/pricing.py +172 -0
  28. app/core/usage/types.py +95 -0
  29. app/core/utils/__init__.py +0 -0
  30. app/core/utils/request_id.py +30 -0
  31. app/core/utils/retry.py +16 -0
  32. app/core/utils/sse.py +13 -0
  33. app/core/utils/time.py +19 -0
  34. app/db/__init__.py +0 -0
  35. app/db/models.py +82 -0
  36. app/db/session.py +44 -0
  37. app/dependencies.py +123 -0
  38. app/main.py +124 -0
  39. app/modules/__init__.py +0 -0
  40. app/modules/accounts/__init__.py +0 -0
  41. app/modules/accounts/api.py +81 -0
  42. app/modules/accounts/repository.py +80 -0
  43. app/modules/accounts/schemas.py +66 -0
  44. app/modules/accounts/service.py +211 -0
  45. app/modules/health/__init__.py +0 -0
  46. app/modules/health/api.py +10 -0
  47. app/modules/oauth/__init__.py +0 -0
  48. app/modules/oauth/api.py +57 -0
  49. app/modules/oauth/schemas.py +32 -0
  50. app/modules/oauth/service.py +356 -0
  51. app/modules/oauth/templates/oauth_success.html +122 -0
  52. app/modules/proxy/__init__.py +0 -0
  53. app/modules/proxy/api.py +76 -0
  54. app/modules/proxy/auth_manager.py +51 -0
  55. app/modules/proxy/load_balancer.py +208 -0
  56. app/modules/proxy/schemas.py +85 -0
  57. app/modules/proxy/service.py +707 -0
  58. app/modules/proxy/types.py +37 -0
  59. app/modules/proxy/usage_updater.py +147 -0
  60. app/modules/request_logs/__init__.py +0 -0
  61. app/modules/request_logs/api.py +31 -0
  62. app/modules/request_logs/repository.py +86 -0
  63. app/modules/request_logs/schemas.py +25 -0
  64. app/modules/request_logs/service.py +77 -0
  65. app/modules/shared/__init__.py +0 -0
  66. app/modules/shared/schemas.py +8 -0
  67. app/modules/usage/__init__.py +0 -0
  68. app/modules/usage/api.py +31 -0
  69. app/modules/usage/repository.py +113 -0
  70. app/modules/usage/schemas.py +62 -0
  71. app/modules/usage/service.py +246 -0
  72. app/static/7.css +1336 -0
  73. app/static/index.css +543 -0
  74. app/static/index.html +457 -0
  75. app/static/index.js +1898 -0
  76. codex_lb-0.1.2.dist-info/METADATA +108 -0
  77. codex_lb-0.1.2.dist-info/RECORD +80 -0
  78. codex_lb-0.1.2.dist-info/WHEEL +4 -0
  79. codex_lb-0.1.2.dist-info/entry_points.txt +2 -0
  80. codex_lb-0.1.2.dist-info/licenses/LICENSE +21 -0
app/static/index.css ADDED
@@ -0,0 +1,543 @@
1
+ .dialog-backdrop.auth-dialog-backdrop {
2
+ z-index: 1000;
3
+ }
4
+
5
+ .window.auth-dialog[role="dialog"] {
6
+ position: absolute;
7
+ top: 50%;
8
+ left: 50%;
9
+ width: min(560px, calc(100% - 40px));
10
+ transform: translate(-50%, -50%) scale(0.98);
11
+ opacity: 0;
12
+ visibility: hidden;
13
+ pointer-events: none;
14
+ transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
15
+ box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45), 0 6px 16px rgba(0, 0, 0, 0.25);
16
+ z-index: 1001;
17
+ }
18
+
19
+ .window.auth-dialog[role="dialog"].is-open {
20
+ opacity: 1;
21
+ visibility: visible;
22
+ pointer-events: auto;
23
+ transform: translate(-50%, -50%) scale(1);
24
+ transition: opacity 0.2s ease, transform 0.2s ease;
25
+ }
26
+
27
+ .window.auth-dialog .auth-dialog__body {
28
+ padding: 18px 22px;
29
+ }
30
+
31
+ .auth-dialog__intro,
32
+ .auth-dialog__panel {
33
+ display: grid;
34
+ gap: 12px;
35
+ }
36
+
37
+ .auth-dialog__lead {
38
+ margin: 0;
39
+ line-height: 1.4;
40
+ color: #1a1a1a;
41
+ }
42
+
43
+ .auth-dialog__methods {
44
+ margin: 0;
45
+ gap: 12px;
46
+ }
47
+
48
+ .auth-dialog__option {
49
+ display: grid;
50
+ gap: 4px;
51
+ align-items: start;
52
+ }
53
+
54
+ .auth-dialog__option label {
55
+ font-weight: 600;
56
+ }
57
+
58
+ .auth-dialog__option-meta {
59
+ margin-left: var(--w7-rd-left);
60
+ }
61
+
62
+
63
+ .auth-dialog__detail {
64
+ display: grid;
65
+ gap: 4px;
66
+ }
67
+
68
+ .auth-dialog__label {
69
+ font-size: 12px;
70
+ color: #555;
71
+ }
72
+
73
+ .auth-dialog__value {
74
+ font-size: 12px;
75
+ color: #1a1a1a;
76
+ word-break: break-all;
77
+ }
78
+
79
+ .auth-dialog__link {
80
+ color: #2b579a;
81
+ text-decoration: underline;
82
+ }
83
+
84
+ .auth-dialog__device-grid {
85
+ display: grid;
86
+ gap: 12px;
87
+ }
88
+
89
+ .auth-dialog__device-grid > div {
90
+ display: grid;
91
+ gap: 4px;
92
+ }
93
+
94
+ .auth-dialog__steps {
95
+ margin: 0;
96
+ padding-left: 18px;
97
+ color: #333;
98
+ font-size: 12px;
99
+ line-height: 1.4;
100
+ }
101
+
102
+ .auth-dialog__steps li {
103
+ margin-bottom: 4px;
104
+ }
105
+
106
+ .auth-dialog__code-value {
107
+ display: inline-block;
108
+ padding: 6px 10px;
109
+ border: 1px solid #c2c2c2;
110
+ background: #fff;
111
+ border-radius: 3px;
112
+ font-weight: 700;
113
+ letter-spacing: 1px;
114
+ font-size: 13px;
115
+ }
116
+
117
+ .auth-dialog__device-meta {
118
+ font-size: 12px;
119
+ }
120
+
121
+ .auth-dialog__status {
122
+ display: flex;
123
+ align-items: center;
124
+ gap: 6px;
125
+ font-size: 12px;
126
+ color: #444;
127
+ }
128
+
129
+ .auth-dialog__actions {
130
+ display: flex;
131
+ justify-content: flex-end;
132
+ gap: 8px;
133
+ flex-wrap: wrap;
134
+ }
135
+
136
+ .auth-dialog__actions-row {
137
+ display: flex;
138
+ gap: 8px;
139
+ flex-wrap: wrap;
140
+ }
141
+
142
+ :root {
143
+ color-scheme: light;
144
+ --shell-max-width: 1180px;
145
+ --shell-gap: 16px;
146
+ --panel-bg: #f6f8fc;
147
+ --panel-border: #b7c0d6;
148
+ --panel-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8);
149
+ --accent-blue: #2b579a;
150
+ --accent-green: #2f7d32;
151
+ --accent-orange: #b86a00;
152
+ --accent-red: #a32a2a;
153
+ --accent-gray: #5f5f5f;
154
+ }
155
+
156
+ * {
157
+ box-sizing: border-box;
158
+ }
159
+
160
+ [x-cloak] {
161
+ display: none !important;
162
+ }
163
+
164
+ body {
165
+ margin: 0;
166
+ min-height: 100vh;
167
+ padding: 20px;
168
+ background:
169
+ radial-gradient(circle at 12% 18%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0) 45%),
170
+ linear-gradient(135deg, #b9cce8 0%, #cadcf2 40%, #e8f0fb 100%);
171
+ }
172
+
173
+ .app-shell {
174
+ max-width: var(--shell-max-width);
175
+ margin: 0 auto;
176
+ display: flex;
177
+ flex-direction: column;
178
+ gap: var(--shell-gap);
179
+ }
180
+
181
+ .window > .window-body {
182
+ position: relative;
183
+ }
184
+
185
+ .loading-overlay {
186
+ position: absolute;
187
+ inset: 0;
188
+ display: flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ background: rgba(248, 250, 255, 0.88);
192
+ z-index: 10;
193
+ }
194
+
195
+ .loading-panel {
196
+ display: flex;
197
+ align-items: center;
198
+ gap: 10px;
199
+ padding: 10px 14px;
200
+ border: 1px solid var(--panel-border);
201
+ border-radius: 4px;
202
+ background: #fff;
203
+ box-shadow: 0 10px 24px rgba(0, 0, 0, 0.2);
204
+ font-weight: 600;
205
+ color: #222;
206
+ }
207
+
208
+ .loading-panel .spinner {
209
+ width: 22px;
210
+ height: 22px;
211
+ }
212
+
213
+
214
+ .section-grid {
215
+ display: grid;
216
+ gap: 12px;
217
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
218
+ }
219
+
220
+ .two-column {
221
+ display: grid;
222
+ gap: 16px;
223
+ grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr);
224
+ }
225
+
226
+ .two-column--equal {
227
+ grid-template-columns: repeat(2, minmax(0, 1fr));
228
+ }
229
+
230
+ @media (max-width: 900px) {
231
+ .two-column {
232
+ grid-template-columns: 1fr;
233
+ }
234
+ }
235
+
236
+ .panel {
237
+ border: 1px solid var(--panel-border);
238
+ background: var(--panel-bg);
239
+ padding: 12px;
240
+ border-radius: 4px;
241
+ box-shadow: var(--panel-shadow);
242
+ }
243
+
244
+ .panel h3 {
245
+ margin: 0 0 6px;
246
+ font-size: 14px;
247
+ }
248
+
249
+
250
+ .stat-value {
251
+ margin-top: 4px;
252
+ font-size: 22px;
253
+ font-weight: 600;
254
+ }
255
+
256
+ .stat-meta {
257
+ color: #555;
258
+ font-size: 12px;
259
+ }
260
+
261
+ .donut-wrap {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: 16px;
265
+ flex-wrap: wrap;
266
+ margin-top: 10px;
267
+ }
268
+
269
+ .donut {
270
+ width: 140px;
271
+ height: 140px;
272
+ border-radius: 50%;
273
+ background: var(--donut-data, #d3d3d3);
274
+ position: relative;
275
+ }
276
+
277
+ .donut::after {
278
+ content: "";
279
+ position: absolute;
280
+ inset: 18px;
281
+ background: #fdfdfd;
282
+ border-radius: 50%;
283
+ box-shadow: inset 0 0 0 1px #c7c7c7;
284
+ }
285
+
286
+ .donut-center {
287
+ position: absolute;
288
+ top: 50%;
289
+ left: 50%;
290
+ transform: translate(-50%, -50%);
291
+ text-align: center;
292
+ font-size: 12px;
293
+ color: #333;
294
+ z-index: 1;
295
+ }
296
+
297
+ .legend {
298
+ display: grid;
299
+ gap: 6px;
300
+ padding: 0;
301
+ list-style: none;
302
+ flex: 1;
303
+ min-width: 0;
304
+ }
305
+
306
+ .legend li {
307
+ display: flex;
308
+ justify-content: space-between;
309
+ gap: 8px;
310
+ font-size: 12px;
311
+ width: 100%;
312
+ }
313
+
314
+ .legend span {
315
+ display: inline-flex;
316
+ align-items: center;
317
+ gap: 6px;
318
+ }
319
+
320
+
321
+ .legend i {
322
+ width: 10px;
323
+ height: 10px;
324
+ border-radius: 2px;
325
+ display: inline-block;
326
+ background: var(--legend-color, #999);
327
+ }
328
+
329
+
330
+ .account-grid {
331
+ display: grid;
332
+ gap: 12px;
333
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
334
+ }
335
+
336
+ .account-card {
337
+ border: 1px solid var(--panel-border);
338
+ background: #fff;
339
+ padding: 10px;
340
+ border-radius: 4px;
341
+ }
342
+
343
+ .account-card header {
344
+ display: flex;
345
+ justify-content: space-between;
346
+ align-items: center;
347
+ gap: 10px;
348
+ margin-bottom: 8px;
349
+ }
350
+
351
+ .account-card header > div {
352
+ flex: 1 1 auto;
353
+ min-width: 0;
354
+ }
355
+
356
+ .account-card header > div > div {
357
+ overflow: hidden;
358
+ text-overflow: ellipsis;
359
+ white-space: nowrap;
360
+ }
361
+
362
+ .account-card .account-id {
363
+ font-size: 12px;
364
+ color: #666;
365
+ }
366
+
367
+ .account-card .account-actions {
368
+ display: flex;
369
+ gap: 6px;
370
+ flex-wrap: wrap;
371
+ margin-top: 8px;
372
+ }
373
+
374
+ .status-pill {
375
+ display: inline-flex;
376
+ align-items: center;
377
+ gap: 4px;
378
+ padding: 0 9px;
379
+ min-height: 18px;
380
+ border-radius: 999px;
381
+ border: 1px solid var(--w7-el-bd);
382
+ box-shadow: var(--w7-el-sd);
383
+ font-size: 11px;
384
+ line-height: 16px;
385
+ white-space: nowrap;
386
+ flex-shrink: 0;
387
+ color: #222;
388
+ background: var(--w7-el-grad);
389
+ text-shadow: 0 1px 0 #fff;
390
+ }
391
+
392
+ .status-pill.active {
393
+ background: linear-gradient(#f4fff6 45%, #dff3e4 45%, #c7e6d0);
394
+ border-color: #7fab86;
395
+ color: #1f5b2c;
396
+ }
397
+
398
+ .status-pill.limited {
399
+ background: linear-gradient(#fff8e7 45%, #f9e3b9 45%, #e5c981);
400
+ border-color: #c4973b;
401
+ color: #7c4f13;
402
+ }
403
+
404
+ .status-pill.paused {
405
+ background: linear-gradient(#f0f7ff 45%, #d6e6fb 45%, #bdd7f6);
406
+ border-color: #6f92c9;
407
+ color: #2b4a7a;
408
+ }
409
+
410
+ .status-pill.exceeded {
411
+ background: linear-gradient(#ffefed 45%, #f5d0cb 45%, #e2a59c);
412
+ border-color: #b45d58;
413
+ color: #7a2f2c;
414
+ }
415
+
416
+ .status-pill.deactivated {
417
+ background: linear-gradient(#f7f7f7 45%, #e7e7e7 45%, #d2d2d2);
418
+ border-color: #9b9b9b;
419
+ color: #5a5a5a;
420
+ }
421
+
422
+ .progress-row {
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 2px;
426
+ }
427
+
428
+ .progress-row label {
429
+ min-width: 60px;
430
+ font-size: 12px;
431
+ margin-right: 10px;
432
+ }
433
+
434
+ .progress-row [role="progressbar"] {
435
+ flex: 1;
436
+ }
437
+
438
+ .progress-row .text-muted {
439
+ flex: 0 0 36px;
440
+ text-align: right;
441
+ }
442
+
443
+ #tab-accounts .account-list-panel {
444
+ display: flex;
445
+ flex-direction: column;
446
+ }
447
+
448
+ #tab-accounts .account-list-panel .table-wrap {
449
+ flex: 1;
450
+ min-height: 0;
451
+ }
452
+
453
+ #tab-accounts .account-list-panel .table-wrap--column-lines {
454
+ --w7-table-cols: 6;
455
+ }
456
+
457
+ .table-wrap--requests {
458
+ --w7-table-cols: 7;
459
+ height: 220px;
460
+ }
461
+
462
+ table {
463
+ width: 100%;
464
+ }
465
+
466
+ .inline-actions {
467
+ display: flex;
468
+ gap: 8px;
469
+ flex-wrap: wrap;
470
+ }
471
+
472
+ .badge-row {
473
+ display: flex;
474
+ gap: 8px;
475
+ flex-wrap: wrap;
476
+ }
477
+
478
+ .text-muted {
479
+ color: #666;
480
+ font-size: 12px;
481
+ }
482
+
483
+ .split-stack {
484
+ display: grid;
485
+ gap: 12px;
486
+ }
487
+
488
+ .list-actions {
489
+ display: flex;
490
+ gap: 8px;
491
+ align-items: center;
492
+ flex-wrap: wrap;
493
+ margin-bottom: 8px;
494
+ }
495
+
496
+ .list-actions label[role="button"] {
497
+ position: relative;
498
+ overflow: hidden;
499
+ }
500
+
501
+ .list-actions label[role="button"].is-disabled {
502
+ opacity: 0.6;
503
+ pointer-events: none;
504
+ }
505
+
506
+ .list-actions label[role="button"] > input[type="file"].file-input {
507
+ position: absolute;
508
+ inset: 0;
509
+ display: block;
510
+ border: 0;
511
+ margin: 0;
512
+ padding: 0;
513
+ width: 100%;
514
+ height: 100%;
515
+ opacity: 0;
516
+ cursor: pointer;
517
+ }
518
+
519
+ .hero-banner {
520
+ display: grid;
521
+ gap: 8px;
522
+ border: 1px solid var(--panel-border);
523
+ background: rgba(255, 255, 255, 0.65);
524
+ padding: 12px;
525
+ border-radius: 4px;
526
+ }
527
+
528
+ .hero-banner h2 {
529
+ margin: 0;
530
+ font-size: 18px;
531
+ }
532
+
533
+ .summary-list {
534
+ display: grid;
535
+ gap: 6px;
536
+ font-size: 12px;
537
+ }
538
+
539
+ .summary-list div {
540
+ display: flex;
541
+ justify-content: space-between;
542
+ gap: 8px;
543
+ }