Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ A streaming chat function app demonstrating real-time AI conversations using Azu

![azd up completed](./docs/azd-up-result.png)

5. Copy and run the az command from the UI and run it in the terminal to get the func app key. Paste the key into the UI and start chatting.
5. Login the **Azure CLI**

```bash
az login --tenant $AZURE_TENANT_ID
```

6. Copy and run the az command from the UI and run it in the terminal to get the func app key. Paste the key into the UI and start chatting.

![UI](./docs/ui.png)

Expand Down
1 change: 0 additions & 1 deletion infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -355,5 +355,4 @@ output APPLICATIONINSIGHTS_CONNECTION_STRING string = monitoring.outputs.applica
output NG_API_URL string = 'https://${functionApp.outputs.defaultHostname}'
output NG_FUNCTION_APP_NAME string = functionApp.outputs.name
output NG_RG_NAME string = resourceGroup.name

output WEBAPP_URL string = webApp.outputs.defaultHostname
56 changes: 40 additions & 16 deletions infra/replace-placeholders.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ set -e # Exit on any error

# Function to display usage
usage() {
echo "Usage: $0 <template_file> <output_file> [env_prefix]"
echo " template_file: Path to the template file with placeholders"
echo "Usage: $0 <template_file> <output_file>"
echo " template_file: Path to the template file with placeholders (e.g., %KEY%)"
echo " output_file: Path where the processed file will be saved"
echo " env_prefix: Environment variable prefix to filter (default: NG_)"
exit 1
}

Expand All @@ -18,7 +17,6 @@ fi

TEMPLATE_FILE="$1"
OUTPUT_FILE="$2"
ENV_PREFIX="${3:-NG_}"

# Check if template file exists
if [ ! -f "$TEMPLATE_FILE" ]; then
Expand Down Expand Up @@ -47,24 +45,50 @@ if [ -z "$ENV_VARS" ]; then
echo "Make sure the environment has been provisioned with: azd provision"
fi

# Create a temporary file to store filtered environment variables
# Create a temporary file to store environment variables (all keys)
TEMP_ENV_FILE=$(mktemp)
echo "$ENV_VARS" | grep "^${ENV_PREFIX}" > "$TEMP_ENV_FILE" || true
# Keep only KEY=VALUE lines (ignore blanks/comments)
echo "$ENV_VARS" | grep -E '^[A-Za-z_][A-Za-z0-9_]*=' > "$TEMP_ENV_FILE" || true

# Read the template file
echo "Processing template file: $TEMPLATE_FILE"
CONTENT=$(cat "$TEMPLATE_FILE")

# Process each environment variable that starts with the prefix
while IFS='=' read -r key value; do
# Process each environment variable; replace only if %KEY% exists in the template
while IFS= read -r line; do
# Skip empty lines just in case
[ -z "$line" ] && continue

# Split into key and value at the first '=' only
key=${line%%=*}
value=${line#*=}

if [ -n "$key" ] && [ -n "$value" ]; then
# Remove quotes from value if present
clean_value=$(echo "$value" | sed 's/^["'\'']\|["'\'']$//g')

echo "Replacing %${key}% with: $clean_value"

# Replace all occurrences of %KEY% with the value
CONTENT=$(echo "$CONTENT" | sed "s|%${key}%|${clean_value}|g")
# Replace only if the placeholder exists
if printf '%s' "$CONTENT" | grep -q "%${key}%"; then
clean_value="$value"
# Strip matching surrounding quotes symmetrically ("..." or '...')
if [ "${clean_value#\"}" != "$clean_value" ] && [ "${clean_value%\"}" != "$clean_value" ]; then
clean_value=${clean_value:1:${#clean_value}-2}
elif [ "${clean_value#\'}" != "$clean_value" ] && [ "${clean_value%\'}" != "$clean_value" ]; then
clean_value=${clean_value:1:${#clean_value}-2}
else
# If there's a stray trailing quote with no leading one, drop it
if [ "${clean_value%\"}" != "$clean_value" ] && [ "${clean_value#\"}" = "$clean_value" ]; then
clean_value=${clean_value%\"}
fi
if [ "${clean_value%\'}" != "$clean_value" ] && [ "${clean_value#\'}" = "$clean_value" ]; then
clean_value=${clean_value%\'}
fi
fi

# Escape sed replacement specials: /, &, |
esc_value=$(printf '%s' "$clean_value" | sed -e 's/[\/&|]/\\&/g')

echo "Replacing %${key}%"
# Replace all occurrences of %KEY% with the escaped value
CONTENT=$(printf '%s' "$CONTENT" | sed "s|%${key}%|${esc_value}|g")
fi
fi
done < "$TEMP_ENV_FILE"

Expand All @@ -74,4 +98,4 @@ echo "$CONTENT" > "$OUTPUT_FILE"
# Clean up temporary file
rm -f "$TEMP_ENV_FILE"

echo "Successfully processed template and saved to: $OUTPUT_FILE"
echo "Successfully processed template and saved to: $OUTPUT_FILE"
10 changes: 10 additions & 0 deletions ng-web/src/app/api-key/api-key.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<mat-form-field
class="api-key__key-input mat-body-medium"
appearance="outline"
subscriptSizing="dynamic"
>
<input
[type]="keyInputType()"
Expand All @@ -19,6 +20,15 @@
<mat-hint
>If you are using the deployed API paste the function key here
(<strong>{{getKeyCommand}}</strong>)
<button
matIconButton
color="accent"
class="mat-body-title"
aria-label="copy the command to the clipboard"
[cdkCopyToClipboard]="getKeyCommand"
>
<mat-icon>content_copy</mat-icon>
</button>
</mat-hint>
</mat-form-field>
</mat-card>
5 changes: 4 additions & 1 deletion ng-web/src/app/api-key/api-key.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ClipboardModule } from '@angular/cdk/clipboard';
import { CommonModule } from '@angular/common';
import {
Component,
Expand All @@ -9,6 +10,7 @@ import {
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
Expand All @@ -19,11 +21,12 @@ import { environment } from '../../environments/environment';
selector: 'app-api-key',
imports: [
CommonModule,

ClipboardModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatButtonModule,
MatCardModule
],
templateUrl: './api-key.html',
Expand Down
2 changes: 1 addition & 1 deletion ng-web/src/environments/environment-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const environment = {
aiApi: {
uri: '%NG_API_URL%',
getKeyCommand:
'az functionapp function keys list --resource-group %NG_RG_NAME% --name %NG_FUNCTION_APP_NAME% --function-name chat',
'az login --tenant %AZURE_TENANT_ID% && az functionapp function keys list --resource-group %NG_RG_NAME% --name %NG_FUNCTION_APP_NAME% --function-name chat',
endpoints: {
chat: 'api/chat'
}
Expand Down
2 changes: 1 addition & 1 deletion ng-web/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export const environment = {
aiApi: {
uri: 'https://func-lxevwr7a4vipw.azurewebsites.net',
getKeyCommand:
'az functionapp function keys list --resource-group rg-skazd --name func-lxevwr7a4vipw --function-name chat',
'az login --tenant 8e8dee8b-d10c-4894-8d43-cae3f9ed549b && az functionapp function keys list --resource-group rg-skazd --name func-lxevwr7a4vipw --function-name chat',
endpoints: {
chat: 'api/chat'
}
Expand Down
11 changes: 11 additions & 0 deletions ng-web/src/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ html {
height: 100%;
font-family: Roboto, 'Helvetica Neue', sans-serif;
margin: 0;

mat-hint {
.mdc-icon-button {
@include mat.icon-button-overrides(
(
icon-size: 18px
)
);
}
}

app-root {
height: 100%;
}
Expand Down