Skip to content

Commit e4a3361

Browse files
feat: quota check script and guide (#1854)
1 parent 8cbb2cb commit e4a3361

File tree

5 files changed

+357
-0
lines changed

5 files changed

+357
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ To review Cosmos DB configuration overview and steps, follow the link [here](doc
182182
![Solution Architecture - Chat with your data CosmosDB](/docs/images/architecture_cdb.png)
183183

184184
### Deploy instructions
185+
<br/>
186+
187+
> ⚠️ **Important: Check Azure OpenAI Quota Availability**
188+
<br/>To ensure sufficient quota is available in your subscription, please follow [quota check instructions guide](./docs/QuotaCheck.md) before you deploy the solution.
189+
190+
<br/>
185191
The "Deploy to Azure" button offers a one-click deployment where you don’t have to clone the code. If you would like a developer experience instead, follow the [local deployment instructions](./docs/LOCAL_DEPLOYMENT.md).
186192

187193
Once you deploy to Azure, you will have the option to select PostgreSQL or Cosmos DB, see screenshot below.

docs/QuotaCheck.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
## Check Quota Availability Before Deployment
2+
3+
Before deploying the accelerator, **ensure sufficient quota availability** for the required model.
4+
5+
> **For Global Standard |GPT-4.1- the capacity to at least 150k tokens post-deployment for optimal performance.**
6+
7+
### Login if you have not done so already
8+
```
9+
azd auth login
10+
```
11+
12+
13+
### 📌 Default Models & Capacities:
14+
```
15+
gpt4.1:30, text-embedding-ada-002:30
16+
```
17+
### 📌 Default Regions:
18+
```
19+
francecentral, australiaeast, uksouth, eastus2, northcentralus, swedencentral, westus, westus2, southcentralus
20+
```
21+
### Usage Scenarios:
22+
- No parameters passed → Default models and capacities will be checked in default regions.
23+
- Only model(s) provided → The script will check for those models in the default regions.
24+
- Only region(s) provided → The script will check default models in the specified regions.
25+
- Both models and regions provided → The script will check those models in the specified regions.
26+
- `--verbose` passed → Enables detailed logging output for debugging and traceability.
27+
28+
### **Input Formats**
29+
> Use the --models, --regions, and --verbose options for parameter handling:
30+
31+
✔️ Run without parameters to check default models & regions without verbose logging:
32+
```
33+
./quota_check_params.sh
34+
```
35+
✔️ Enable verbose logging:
36+
```
37+
./quota_check_params.sh --verbose
38+
```
39+
✔️ Check specific model(s) in default regions:
40+
```
41+
./quota_check_params.sh --models gpt4.1:30,text-embedding-ada-002:30
42+
```
43+
✔️ Check default models in specific region(s):
44+
```
45+
./quota_check_params.sh --regions eastus2,westus
46+
```
47+
✔️ Passing Both models and regions:
48+
```
49+
./quota_check_params.sh --models gpt4.1:30 --regions eastus2,westus
50+
```
51+
✔️ All parameters combined:
52+
```
53+
./quota_check_params.sh --models gpt4.1:30,text-embedding-ada-002:30 --regions eastus2,westus --verbose
54+
```
55+
56+
### **Sample Output**
57+
The final table lists regions with available quota. You can select any of these regions for deployment.
58+
59+
![quota-check-ouput](images/quota-check-output.png)
60+
61+
---
62+
### **If using Azure Portal and Cloud Shell**
63+
64+
1. Navigate to the [Azure Portal](https://portal.azure.com).
65+
2. Click on **Azure Cloud Shell** in the top right navigation menu.
66+
3. Run the appropriate command based on your requirement:
67+
68+
**To check quota for the deployment**
69+
70+
```sh
71+
curl -L -o quota_check_params.sh "https://raw.githubusercontent.com/Azure-Samples/chat-with-your-data-solution-accelerator/main/scripts/quota_check_params.sh"
72+
chmod +x quota_check_params.sh
73+
./quota_check_params.sh
74+
```
75+
- Refer to [Input Formats](#input-formats) for detailed commands.
76+
77+
### **If using VS Code or Codespaces**
78+
1. Open the terminal in VS Code or Codespaces.
79+
2. If you're using VS Code, click the dropdown on the right side of the terminal window, and select `Git Bash`.
80+
![git_bash](images/git_bash.png)
81+
3. Navigate to the `scripts` folder where the script files are located and make the script as executable:
82+
```sh
83+
cd scripts
84+
chmod +x quota_check_params.sh
85+
```
86+
4. Run the appropriate script based on your requirement:
87+
88+
**To check quota for the deployment**
89+
90+
```sh
91+
./quota_check_params.sh
92+
```
93+
- Refer to [Input Formats](#input-formats) for detailed commands.
94+
95+
5. If you see the error `_bash: az: command not found_`, install Azure CLI:
96+
97+
```sh
98+
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
99+
az login
100+
```
101+
6. Rerun the script after installing Azure CLI.

docs/images/git_bash.png

29.3 KB
Loading

docs/images/quota-check-output.png

12.6 KB
Loading

scripts/quota_check_params.sh

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
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

Comments
 (0)