188 lines
7.4 KiB
Python
188 lines
7.4 KiB
Python
from prisma import Prisma
|
|
import csv
|
|
import json
|
|
import asyncio
|
|
from datetime import datetime
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
import os
|
|
|
|
## VARIABLES
|
|
DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/litellm"
|
|
CSV_FILE_PATH = "./path_to_csv.csv"
|
|
|
|
os.environ["DATABASE_URL"] = DATABASE_URL
|
|
|
|
|
|
async def parse_csv_value(value: str, field_type: str) -> Any:
|
|
"""Parse CSV values according to their expected types"""
|
|
if value == "NULL" or value == "" or value is None:
|
|
return None
|
|
|
|
if field_type == "boolean":
|
|
return value.lower() == "true"
|
|
elif field_type == "float":
|
|
return float(value)
|
|
elif field_type == "int":
|
|
return int(value) if value.isdigit() else None
|
|
elif field_type == "bigint":
|
|
return int(value) if value.isdigit() else None
|
|
elif field_type == "datetime":
|
|
try:
|
|
return datetime.fromisoformat(value.replace("Z", "+00:00"))
|
|
except:
|
|
return None
|
|
elif field_type == "json":
|
|
try:
|
|
return value if value else json.dumps({})
|
|
except:
|
|
return json.dumps({})
|
|
elif field_type == "string_array":
|
|
# Handle string arrays like {default-models}
|
|
if value.startswith("{") and value.endswith("}"):
|
|
content = value[1:-1] # Remove braces
|
|
if content:
|
|
return [item.strip() for item in content.split(",")]
|
|
else:
|
|
return []
|
|
return []
|
|
else:
|
|
return value
|
|
|
|
|
|
async def migrate_verification_tokens():
|
|
"""Main migration function"""
|
|
prisma = Prisma()
|
|
await prisma.connect()
|
|
|
|
try:
|
|
# Read CSV file
|
|
csv_file_path = CSV_FILE_PATH
|
|
|
|
with open(csv_file_path, "r", encoding="utf-8") as file:
|
|
csv_reader = csv.DictReader(file)
|
|
|
|
processed_count = 0
|
|
error_count = 0
|
|
|
|
for row in csv_reader:
|
|
try:
|
|
# Replace 'default-team' with the specified UUID
|
|
team_id = row.get("team_id")
|
|
if team_id == "NULL" or team_id == "":
|
|
team_id = None
|
|
|
|
# Prepare data for insertion
|
|
verification_token_data = {
|
|
"token": row["token"],
|
|
"key_name": await parse_csv_value(row["key_name"], "string"),
|
|
"key_alias": await parse_csv_value(row["key_alias"], "string"),
|
|
"soft_budget_cooldown": await parse_csv_value(
|
|
row["soft_budget_cooldown"], "boolean"
|
|
),
|
|
"spend": await parse_csv_value(row["spend"], "float"),
|
|
"expires": await parse_csv_value(row["expires"], "datetime"),
|
|
"models": await parse_csv_value(row["models"], "string_array"),
|
|
"aliases": await parse_csv_value(row["aliases"], "json"),
|
|
"config": await parse_csv_value(row["config"], "json"),
|
|
"user_id": await parse_csv_value(row["user_id"], "string"),
|
|
"team_id": team_id,
|
|
"permissions": await parse_csv_value(
|
|
row["permissions"], "json"
|
|
),
|
|
"max_parallel_requests": await parse_csv_value(
|
|
row["max_parallel_requests"], "int"
|
|
),
|
|
"metadata": await parse_csv_value(row["metadata"], "json"),
|
|
"tpm_limit": await parse_csv_value(row["tpm_limit"], "bigint"),
|
|
"rpm_limit": await parse_csv_value(row["rpm_limit"], "bigint"),
|
|
"max_budget": await parse_csv_value(row["max_budget"], "float"),
|
|
"budget_duration": await parse_csv_value(
|
|
row["budget_duration"], "string"
|
|
),
|
|
"budget_reset_at": await parse_csv_value(
|
|
row["budget_reset_at"], "datetime"
|
|
),
|
|
"allowed_cache_controls": await parse_csv_value(
|
|
row["allowed_cache_controls"], "string_array"
|
|
),
|
|
"model_spend": await parse_csv_value(
|
|
row["model_spend"], "json"
|
|
),
|
|
"model_max_budget": await parse_csv_value(
|
|
row["model_max_budget"], "json"
|
|
),
|
|
"budget_id": await parse_csv_value(row["budget_id"], "string"),
|
|
"blocked": await parse_csv_value(row["blocked"], "boolean"),
|
|
"created_at": await parse_csv_value(
|
|
row["created_at"], "datetime"
|
|
),
|
|
"updated_at": await parse_csv_value(
|
|
row["updated_at"], "datetime"
|
|
),
|
|
"allowed_routes": await parse_csv_value(
|
|
row["allowed_routes"], "string_array"
|
|
),
|
|
"object_permission_id": await parse_csv_value(
|
|
row["object_permission_id"], "string"
|
|
),
|
|
"created_by": await parse_csv_value(
|
|
row["created_by"], "string"
|
|
),
|
|
"updated_by": await parse_csv_value(
|
|
row["updated_by"], "string"
|
|
),
|
|
"organization_id": await parse_csv_value(
|
|
row["organization_id"], "string"
|
|
),
|
|
}
|
|
|
|
# Remove None values to use database defaults
|
|
verification_token_data = {
|
|
k: v
|
|
for k, v in verification_token_data.items()
|
|
if v is not None
|
|
}
|
|
|
|
# Check if token already exists
|
|
existing_token = await prisma.litellm_verificationtoken.find_unique(
|
|
where={"token": verification_token_data["token"]}
|
|
)
|
|
|
|
if existing_token:
|
|
print(
|
|
f"Token {verification_token_data['token']} already exists, skipping..."
|
|
)
|
|
continue
|
|
|
|
# Insert the record
|
|
await prisma.litellm_verificationtoken.create(
|
|
data=verification_token_data
|
|
)
|
|
|
|
processed_count += 1
|
|
print(
|
|
f"Successfully migrated token: {verification_token_data['token']}"
|
|
)
|
|
|
|
except Exception as e:
|
|
error_count += 1
|
|
print(
|
|
f"Error processing row with token {row.get('token', 'unknown')}: {str(e)}"
|
|
)
|
|
continue
|
|
|
|
print(f"\nMigration completed!")
|
|
print(f"Successfully processed: {processed_count} records")
|
|
print(f"Errors encountered: {error_count} records")
|
|
|
|
except Exception as e:
|
|
print(f"Migration failed: {str(e)}")
|
|
|
|
finally:
|
|
await prisma.disconnect()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(migrate_verification_tokens())
|