feat: add provider usage adapters for openai and placeholders for others

This commit is contained in:
zhi
2026-03-11 13:08:58 +00:00
parent c0ec70c64f
commit 5b8f84d87d

View File

@@ -1,6 +1,6 @@
import json
from datetime import datetime, timedelta, timezone
from typing import Any, Dict
from typing import Any, Dict, Tuple
import requests
from sqlalchemy.orm import Session
@@ -66,21 +66,69 @@ def test_provider_connection(provider: str, credential: str):
return False, str(e)
def _openai_usage(credential: str) -> Tuple[str, Dict[str, Any]]:
# Uses legacy billing endpoints; may be disabled in some orgs.
headers = _provider_headers('openai', credential)
today = _now().date()
start = (today - timedelta(days=7)).isoformat()
end = today.isoformat()
usage_url = f'https://api.openai.com/v1/dashboard/billing/usage?start_date={start}&end_date={end}'
sub_url = 'https://api.openai.com/v1/dashboard/billing/subscription'
u = requests.get(usage_url, headers=headers, timeout=12)
s = requests.get(sub_url, headers=headers, timeout=12)
if u.status_code != 200 or s.status_code != 200:
return 'error', {'error': f'usage:{u.status_code}, subscription:{s.status_code}'}
usage = u.json()
sub = s.json()
total_usage = usage.get('total_usage')
hard_limit = sub.get('hard_limit_usd')
reset_at = sub.get('billing_cycle_anchor')
if reset_at:
reset_at = datetime.fromtimestamp(reset_at, tz=timezone.utc).isoformat()
usage_pct = None
if total_usage is not None and hard_limit:
usage_pct = round(total_usage / hard_limit * 100, 2)
return 'ok', {
'window_label': '7d',
'used': total_usage,
'limit': hard_limit,
'usage_pct': usage_pct,
'reset_at': reset_at,
'raw': {'usage': usage, 'subscription': sub},
}
def _anthropic_usage(credential: str) -> Tuple[str, Dict[str, Any]]:
# Anthropic usage endpoints are enterprise-specific; keep placeholder.
# We return accepted status; detail will be filled once API confirmed.
return 'unsupported', {'error': 'anthropic usage API not configured'}
def refresh_provider_usage_once(db: Session):
accounts = db.query(ProviderAccount).filter(ProviderAccount.is_enabled == True).all()
now = _now()
for a in accounts:
ok, msg = test_provider_connection(a.provider, a.credential)
status = 'pending'
payload: Dict[str, Any] = {}
if a.provider == 'openai':
status, payload = _openai_usage(a.credential)
elif a.provider == 'anthropic':
status, payload = _anthropic_usage(a.credential)
else:
ok, msg = test_provider_connection(a.provider, a.credential)
status = 'ok' if ok else 'error'
payload = {'error': None if ok else msg}
snap = ProviderUsageSnapshot(
account_id=a.id,
window_label='provider-default',
used=None,
limit=None,
usage_pct=None,
reset_at=None,
status='ok' if ok else 'error',
error=None if ok else msg,
raw_payload=json.dumps({'message': msg}, ensure_ascii=False),
window_label=payload.get('window_label'),
used=payload.get('used'),
limit=payload.get('limit'),
usage_pct=payload.get('usage_pct'),
reset_at=payload.get('reset_at'),
status=status,
error=payload.get('error'),
raw_payload=json.dumps(payload.get('raw') or payload, ensure_ascii=False),
fetched_at=now,
)
db.add(snap)
@@ -100,7 +148,7 @@ def get_provider_usage_view(db: Session):
'usage_pct': snap.usage_pct if snap else None,
'used': snap.used if snap else None,
'limit': snap.limit if snap else None,
'reset_at': snap.reset_at.isoformat() if snap and snap.reset_at else None,
'reset_at': snap.reset_at if snap else None,
'status': snap.status if snap else 'pending',
'error': snap.error if snap else None,
'fetched_at': snap.fetched_at.isoformat() if snap and snap.fetched_at else None,