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
199 changes: 199 additions & 0 deletions client/client.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions infra/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,43 @@ resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2025-02-01' = {
}
}

// explanations and the votes on them, read by the prompt tuning skill. Table storage: one
// entity per explanation, a few thousand a month, no server to run.
resource feedbackStorage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'stoptimizerfeedback'
location: location
kind: 'StorageV2'
sku: {
name: 'Standard_LRS'
}
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
supportsHttpsTrafficOnly: true
}
}

resource feedbackTables 'Microsoft.Storage/storageAccounts/tableServices@2023-05-01' = {
parent: feedbackStorage
name: 'default'
}

resource feedbackTable 'Microsoft.Storage/storageAccounts/tableServices/tables@2023-05-01' = {
parent: feedbackTables
name: 'explanations'
}

// Storage Table Data Contributor for the container app's managed identity
resource feedbackWriter 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(feedbackStorage.id, containerApp.id, 'table-data-contributor')
scope: feedbackStorage
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aebd')
principalId: containerApp.identity.principalId
principalType: 'ServicePrincipal'
}
}

@description('Custom hostname served by the container app')
param customHostname string = 'optimizer.evcc.io'

Expand Down Expand Up @@ -127,6 +164,8 @@ resource containerApp 'Microsoft.App/containerApps@2025-01-01' = {
// plan explanations, /optimize/explain
{ name: 'OPTIMIZER_AZURE_OPENAI_ENDPOINT', value: 'https://evcc-ai-resource.cognitiveservices.azure.com/' }
{ name: 'OPTIMIZER_AZURE_OPENAI_KEY', secretRef: 'azure-openai-key' }
// explanations and votes, /optimize/explain/feedback, written with the managed identity
{ name: 'OPTIMIZER_FEEDBACK_TABLE_ENDPOINT', value: feedbackStorage.properties.primaryEndpoints.table }
]
probes: [
{
Expand Down
57 changes: 57 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,44 @@ paths:
schema:
$ref: "#/components/schemas/Error"

/optimize/explain/feedback:
post:
tags:
- optimization
summary: Vote on an explanation
description: |
Stores a thumbs up or down and an optional comment together with the plan and the explanation
/optimize/explain gave for it, to improve the prompt. Nothing is stored until a user votes.

The endpoint is only available where the service is configured with a feedback store.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ExplainFeedback"
responses:
"200":
description: The vote was stored
"400":
description: Bad request - plan, explanation or vote missing or malformed
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"502":
description: The feedback store could not be reached
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
"503":
description: Feedback is not configured on this service
content:
application/json:
schema:
$ref: "#/components/schemas/Error"

/optimize/health:
get:
tags:
Expand Down Expand Up @@ -566,6 +604,25 @@ components:
type: string
description: Explanation of the plan, markdown

ExplainFeedback:
allOf:
- $ref: "#/components/schemas/ExplainInput"
- type: object
required:
- explanation
- vote
properties:
explanation:
type: string
description: The explanation as returned by /optimize/explain
vote:
type: string
enum: [up, down]
description: Whether the explanation helped
comment:
type: string
description: What was wrong or missing, optional

Error:
type: object
properties:
Expand Down
Loading