|
| 1 | +#!/bin/bash |
| 2 | +# VERBOSE=false |
| 3 | + |
| 4 | +MODELS="" |
| 5 | +REGIONS="" |
| 6 | +VERBOSE=false |
| 7 | + |
| 8 | +while [[ $# -gt 0 ]]; do |
| 9 | + case "$1" in |
| 10 | + --models) |
| 11 | + MODELS="$2" |
| 12 | + shift 2 |
| 13 | + ;; |
| 14 | + --regions) |
| 15 | + REGIONS="$2" |
| 16 | + shift 2 |
| 17 | + ;; |
| 18 | + --verbose) |
| 19 | + VERBOSE=true |
| 20 | + shift |
| 21 | + ;; |
| 22 | + *) |
| 23 | + echo "Unknown option: $1" |
| 24 | + exit 1 |
| 25 | + ;; |
| 26 | + esac |
| 27 | +done |
| 28 | + |
| 29 | +# Fallback to defaults if not provided |
| 30 | +[[ -z "$MODELS" ]] |
| 31 | +[[ -z "$REGIONS" ]] |
| 32 | + |
| 33 | +echo "Models: $MODELS" |
| 34 | +echo "Regions: $REGIONS" |
| 35 | +echo "Verbose: $VERBOSE" |
| 36 | + |
| 37 | +for arg in "$@"; do |
| 38 | + if [ "$arg" = "--verbose" ]; then |
| 39 | + VERBOSE=true |
| 40 | + fi |
| 41 | +done |
| 42 | + |
| 43 | +log_verbose() { |
| 44 | + if [ "$VERBOSE" = true ]; then |
| 45 | + echo "$1" |
| 46 | + fi |
| 47 | +} |
| 48 | + |
| 49 | +# Default Models and Capacities (Comma-separated in "model:capacity" format) |
| 50 | +DEFAULT_MODEL_CAPACITY="gpt4.1:30,text-embedding-ada-002:30" |
| 51 | + |
| 52 | +# Convert the comma-separated string into an array |
| 53 | +IFS=',' read -r -a MODEL_CAPACITY_PAIRS <<< "$DEFAULT_MODEL_CAPACITY" |
| 54 | + |
| 55 | +echo "🔄 Fetching available Azure subscriptions..." |
| 56 | +SUBSCRIPTIONS=$(az account list --query "[?state=='Enabled'].{Name:name, ID:id}" --output tsv) |
| 57 | +SUB_COUNT=$(echo "$SUBSCRIPTIONS" | wc -l) |
| 58 | + |
| 59 | +if [ "$SUB_COUNT" -eq 0 ]; then |
| 60 | + echo "❌ ERROR: No active Azure subscriptions found. Please log in using 'az login' and ensure you have an active subscription." |
| 61 | + exit 1 |
| 62 | +elif [ "$SUB_COUNT" -eq 1 ]; then |
| 63 | + # If only one subscription, automatically select it |
| 64 | + AZURE_SUBSCRIPTION_ID=$(echo "$SUBSCRIPTIONS" | awk '{print $2}') |
| 65 | + if [ -z "$AZURE_SUBSCRIPTION_ID" ]; then |
| 66 | + echo "❌ ERROR: No active Azure subscriptions found. Please log in using 'az login' and ensure you have an active subscription." |
| 67 | + exit 1 |
| 68 | + fi |
| 69 | + echo "✅ Using the only available subscription: $AZURE_SUBSCRIPTION_ID" |
| 70 | +else |
| 71 | + # If multiple subscriptions exist, prompt the user to choose one |
| 72 | + echo "Multiple subscriptions found:" |
| 73 | + echo "$SUBSCRIPTIONS" | awk '{print NR")", $1, "-", $2}' |
| 74 | + |
| 75 | + while true; do |
| 76 | + echo "Enter the number of the subscription to use:" |
| 77 | + read SUB_INDEX |
| 78 | + |
| 79 | + # Validate user input |
| 80 | + if [[ "$SUB_INDEX" =~ ^[0-9]+$ ]] && [ "$SUB_INDEX" -ge 1 ] && [ "$SUB_INDEX" -le "$SUB_COUNT" ]; then |
| 81 | + AZURE_SUBSCRIPTION_ID=$(echo "$SUBSCRIPTIONS" | awk -v idx="$SUB_INDEX" 'NR==idx {print $2}') |
| 82 | + echo "✅ Selected Subscription: $AZURE_SUBSCRIPTION_ID" |
| 83 | + break |
| 84 | + else |
| 85 | + echo "❌ Invalid selection. Please enter a valid number from the list." |
| 86 | + fi |
| 87 | + done |
| 88 | +fi |
| 89 | + |
| 90 | + |
| 91 | +# Set the selected subscription |
| 92 | +az account set --subscription "$AZURE_SUBSCRIPTION_ID" |
| 93 | +echo "🎯 Active Subscription: $(az account show --query '[name, id]' --output tsv)" |
| 94 | + |
| 95 | +# Default Regions to check (Comma-separated, now configurable) |
| 96 | +DEFAULT_REGIONS="francecentral,australiaeast,uksouth,eastus2,northcentralus,swedencentral,westus,westus2,southcentralus" |
| 97 | +IFS=',' read -r -a DEFAULT_REGION_ARRAY <<< "$DEFAULT_REGIONS" |
| 98 | + |
| 99 | +# Read parameters (if any) |
| 100 | +IFS=',' read -r -a USER_PROVIDED_PAIRS <<< "$MODELS" |
| 101 | +USER_REGION="$REGIONS" |
| 102 | + |
| 103 | +IS_USER_PROVIDED_PAIRS=false |
| 104 | + |
| 105 | +if [ ${#USER_PROVIDED_PAIRS[@]} -lt 1 ]; then |
| 106 | + echo "No parameters provided, using default model-capacity pairs: ${MODEL_CAPACITY_PAIRS[*]}" |
| 107 | +else |
| 108 | + echo "Using provided model and capacity pairs: ${USER_PROVIDED_PAIRS[*]}" |
| 109 | + IS_USER_PROVIDED_PAIRS=true |
| 110 | + MODEL_CAPACITY_PAIRS=("${USER_PROVIDED_PAIRS[@]}") |
| 111 | +fi |
| 112 | + |
| 113 | +declare -a FINAL_MODEL_NAMES |
| 114 | +declare -a FINAL_CAPACITIES |
| 115 | +declare -a TABLE_ROWS |
| 116 | + |
| 117 | +for PAIR in "${MODEL_CAPACITY_PAIRS[@]}"; do |
| 118 | + MODEL_NAME=$(echo "$PAIR" | cut -d':' -f1 | tr '[:upper:]' '[:lower:]') |
| 119 | + CAPACITY=$(echo "$PAIR" | cut -d':' -f2) |
| 120 | + |
| 121 | + if [ -z "$MODEL_NAME" ] || [ -z "$CAPACITY" ]; then |
| 122 | + echo "❌ ERROR: Invalid model and capacity pair '$PAIR'. Both model and capacity must be specified." |
| 123 | + exit 1 |
| 124 | + fi |
| 125 | + |
| 126 | + FINAL_MODEL_NAMES+=("$MODEL_NAME") |
| 127 | + FINAL_CAPACITIES+=("$CAPACITY") |
| 128 | + |
| 129 | +done |
| 130 | + |
| 131 | +echo "🔄 Using Models: ${FINAL_MODEL_NAMES[*]} with respective Capacities: ${FINAL_CAPACITIES[*]}" |
| 132 | +echo "----------------------------------------" |
| 133 | + |
| 134 | +# Check if the user provided a region, if not, use the default regions |
| 135 | +if [ -n "$USER_REGION" ]; then |
| 136 | + echo "🔍 User provided region: $USER_REGION" |
| 137 | + IFS=',' read -r -a REGIONS <<< "$USER_REGION" |
| 138 | +else |
| 139 | + echo "No region specified, using default regions: ${DEFAULT_REGION_ARRAY[*]}" |
| 140 | + REGIONS=("${DEFAULT_REGION_ARRAY[@]}") |
| 141 | + APPLY_OR_CONDITION=true |
| 142 | +fi |
| 143 | + |
| 144 | +echo "✅ Retrieved Azure regions. Checking availability..." |
| 145 | +INDEX=1 |
| 146 | + |
| 147 | +VALID_REGIONS=() |
| 148 | +for REGION in "${REGIONS[@]}"; do |
| 149 | + log_verbose "----------------------------------------" |
| 150 | + log_verbose "🔍 Checking region: $REGION" |
| 151 | + |
| 152 | + QUOTA_INFO=$(az cognitiveservices usage list --location "$REGION" --output json | tr '[:upper:]' '[:lower:]') |
| 153 | + if [ -z "$QUOTA_INFO" ]; then |
| 154 | + log_verbose "⚠️ WARNING: Failed to retrieve quota for region $REGION. Skipping." |
| 155 | + continue |
| 156 | + fi |
| 157 | + |
| 158 | + TEXT_EMBEDDING_AVAILABLE=false |
| 159 | + AT_LEAST_ONE_MODEL_AVAILABLE=false |
| 160 | + TEMP_TABLE_ROWS=() |
| 161 | + |
| 162 | + for index in "${!FINAL_MODEL_NAMES[@]}"; do |
| 163 | + MODEL_NAME="${FINAL_MODEL_NAMES[$index]}" |
| 164 | + REQUIRED_CAPACITY="${FINAL_CAPACITIES[$index]}" |
| 165 | + FOUND=false |
| 166 | + INSUFFICIENT_QUOTA=false |
| 167 | + |
| 168 | + if [ "$MODEL_NAME" = "text-embedding-ada-002" ]; then |
| 169 | + MODEL_TYPES=("openai.standard.$MODEL_NAME") |
| 170 | + else |
| 171 | + MODEL_TYPES=("openai.standard.$MODEL_NAME" "openai.globalstandard.$MODEL_NAME") |
| 172 | + fi |
| 173 | + |
| 174 | + for MODEL_TYPE in "${MODEL_TYPES[@]}"; do |
| 175 | + FOUND=false |
| 176 | + INSUFFICIENT_QUOTA=false |
| 177 | + log_verbose "🔍 Checking model: $MODEL_NAME with required capacity: $REQUIRED_CAPACITY ($MODEL_TYPE)" |
| 178 | + |
| 179 | + MODEL_INFO=$(echo "$QUOTA_INFO" | awk -v model="\"value\": \"$MODEL_TYPE\"" ' |
| 180 | + BEGIN { RS="},"; FS="," } |
| 181 | + $0 ~ model { print $0 } |
| 182 | + ') |
| 183 | + |
| 184 | + if [ -z "$MODEL_INFO" ]; then |
| 185 | + FOUND=false |
| 186 | + log_verbose "⚠️ WARNING: No quota information found for model: $MODEL_NAME in region: $REGION for model type: $MODEL_TYPE." |
| 187 | + continue |
| 188 | + fi |
| 189 | + |
| 190 | + if [ -n "$MODEL_INFO" ]; then |
| 191 | + FOUND=true |
| 192 | + CURRENT_VALUE=$(echo "$MODEL_INFO" | awk -F': ' '/"currentvalue"/ {print $2}' | tr -d ',' | tr -d ' ') |
| 193 | + LIMIT=$(echo "$MODEL_INFO" | awk -F': ' '/"limit"/ {print $2}' | tr -d ',' | tr -d ' ') |
| 194 | + |
| 195 | + CURRENT_VALUE=${CURRENT_VALUE:-0} |
| 196 | + LIMIT=${LIMIT:-0} |
| 197 | + |
| 198 | + CURRENT_VALUE=$(echo "$CURRENT_VALUE" | cut -d'.' -f1) |
| 199 | + LIMIT=$(echo "$LIMIT" | cut -d'.' -f1) |
| 200 | + |
| 201 | + AVAILABLE=$((LIMIT - CURRENT_VALUE)) |
| 202 | + log_verbose "✅ Model: $MODEL_TYPE | Used: $CURRENT_VALUE | Limit: $LIMIT | Available: $AVAILABLE" |
| 203 | + |
| 204 | + if [ "$AVAILABLE" -ge "$REQUIRED_CAPACITY" ]; then |
| 205 | + FOUND=true |
| 206 | + if [ "$MODEL_NAME" = "text-embedding-ada-002" ]; then |
| 207 | + TEXT_EMBEDDING_AVAILABLE=true |
| 208 | + fi |
| 209 | + AT_LEAST_ONE_MODEL_AVAILABLE=true |
| 210 | + TEMP_TABLE_ROWS+=("$(printf "| %-4s | %-20s | %-43s | %-10s | %-10s | %-10s |" "$INDEX" "$REGION" "$MODEL_TYPE" "$LIMIT" "$CURRENT_VALUE" "$AVAILABLE")") |
| 211 | + else |
| 212 | + INSUFFICIENT_QUOTA=true |
| 213 | + fi |
| 214 | + fi |
| 215 | + |
| 216 | + if [ "$FOUND" = false ]; then |
| 217 | + log_verbose "❌ No models found for model: $MODEL_NAME in region: $REGION (${MODEL_TYPES[*]})" |
| 218 | + |
| 219 | + elif [ "$INSUFFICIENT_QUOTA" = true ]; then |
| 220 | + log_verbose "⚠️ Model $MODEL_NAME in region: $REGION has insufficient quota (${MODEL_TYPES[*]})." |
| 221 | + fi |
| 222 | + done |
| 223 | + done |
| 224 | + |
| 225 | +if { [ "$IS_USER_PROVIDED_PAIRS" = true ] && [ "$INSUFFICIENT_QUOTA" = false ] && [ "$FOUND" = true ]; } || { [ "$TEXT_EMBEDDING_AVAILABLE" = true ] && { [ "$APPLY_OR_CONDITION" != true ] || [ "$AT_LEAST_ONE_MODEL_AVAILABLE" = true ]; }; }; then |
| 226 | + VALID_REGIONS+=("$REGION") |
| 227 | + TABLE_ROWS+=("${TEMP_TABLE_ROWS[@]}") |
| 228 | + INDEX=$((INDEX + 1)) |
| 229 | + elif [ ${#USER_PROVIDED_PAIRS[@]} -eq 0 ]; then |
| 230 | + echo "🚫 Skipping $REGION as it does not meet quota requirements." |
| 231 | + fi |
| 232 | + |
| 233 | +done |
| 234 | + |
| 235 | +if [ ${#TABLE_ROWS[@]} -eq 0 ]; then |
| 236 | + echo "--------------------------------------------------------------------------------------------------------------------" |
| 237 | + |
| 238 | + echo "❌ No regions have sufficient quota for all required models. Please request a quota increase: https://aka.ms/oai/stuquotarequest" |
| 239 | +else |
| 240 | + echo "---------------------------------------------------------------------------------------------------------------------" |
| 241 | + printf "| %-4s | %-20s | %-43s | %-10s | %-10s | %-10s |\n" "No." "Region" "Model Name" "Limit" "Used" "Available" |
| 242 | + echo "---------------------------------------------------------------------------------------------------------------------" |
| 243 | + for ROW in "${TABLE_ROWS[@]}"; do |
| 244 | + echo "$ROW" |
| 245 | + done |
| 246 | + echo "---------------------------------------------------------------------------------------------------------------------" |
| 247 | + echo "➡️ To request a quota increase, visit: https://aka.ms/oai/stuquotarequest" |
| 248 | +fi |
| 249 | + |
| 250 | +echo "✅ Script completed." |
0 commit comments