diff --git a/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/.template.config/template.json b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/.template.config/template.json new file mode 100644 index 0000000..e895dc5 --- /dev/null +++ b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/src/ChatWithCustomData/.template.config/template.json @@ -0,0 +1,588 @@ +{ + "$schema": "http://json.schemastore.org/template", + "author": "Microsoft", + "classifications": [ "Common", "AI", "Web", "Blazor", ".NET Aspire" ], + "identity": "Microsoft.Extensions.AI.Templates.WebChat.CSharp", + "name": "AI Chat Web App", + "description": "A project template for creating an AI chat application, which uses retrieval-augmented generation (RAG) to chat with your own data.", + "shortName": "aichatweb", + "defaultName": "ChatApp", + "sourceName": "ChatWithCustomData-CSharp", + "preferNameDirectory": true, + "tags": { + "language": "C#", + "type": "project" + }, + "guids": [ + "d5681fae-b21b-4114-b781-48180f08c0c4", + "b2f4f5e9-1083-472c-8c3b-f055ac67ba54", + "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC", + "4DF52F58-4890-4A0A-BC25-5C3D167B3490", + "2222CF31-6E3A-42E7-AD3A-A56B14EAD9D0", + "A7D19173-F0AD-4A8D-B8EA-E12DE203E409" + ], + "primaryOutputs": [ + { + "path": "./README.md" + }, + { + "condition": "(!IsAspire)", + "path": "./ChatWithCustomData-CSharp.csproj" + }, + { + "condition": "(IsAspire && (HostIdentifier == \"dotnetcli\" || HostIdentifier == \"dotnetcli-preview\"))", + "path": "./ChatWithCustomData-CSharp.sln" + }, + { + "condition": "(IsAspire)", + "path": "./ChatWithCustomData-CSharp.AppHost/ChatWithCustomData-CSharp.AppHost.csproj" + }, + { + "condition": "(IsAspire)", + "path": "./ChatWithCustomData-CSharp.ServiceDefaults/ChatWithCustomData-CSharp.ServiceDefaults.csproj" + }, + { + "condition": "(IsAspire)", + "path": "./ChatWithCustomData-CSharp.Web/ChatWithCustomData-CSharp.Web.csproj" + } + ], + "sources": [{ + "source": "./", + "target": "./", + "modifiers": [ + { + "condition": "(!IsAspire)", + "rename": { + "ChatWithCustomData-CSharp.Web/ChatWithCustomData-CSharp.Web.csproj": "ChatWithCustomData-CSharp.csproj", + "ChatWithCustomData-CSharp.Web/": "./" + }, + "exclude": [ + "ChatWithCustomData-CSharp.AppHost/**", + "ChatWithCustomData-CSharp.ServiceDefaults/**", + "ChatWithCustomData-CSharp.Web/Program.Aspire.cs", + "README.Aspire.md", + "*.sln" + ] + }, + { + "condition": "(IsAspire)", + "exclude": [ + "ChatWithCustomData-CSharp.Web/Program.cs", + "ChatWithCustomData-CSharp.Web/README.md" + ], + "rename": { + "Program.Aspire.cs": "Program.cs", + "README.Aspire.md": "README.md" + } + }, + { + "condition": "(!UseLocalVectorStore)", + "exclude": [ + "ChatWithCustomData-CSharp.Web/Services/JsonVectorStore.cs" + ] + } + ] + }], + "symbols": { + "Framework": { + "type": "parameter", + "description": "The target framework for the project.", + "datatype": "choice", + "choices": [ + { + "choice": "net9.0", + "description": "Target net9.0" + } + ], + "replaces": "net9.0", + "defaultValue": "net9.0", + "displayName": "Framework" + }, + "hostIdentifier": { + "type": "bind", + "binding": "HostIdentifier" + }, + "AiServiceProvider": { + "type": "parameter", + "displayName": "_AI service provider", + "datatype": "choice", + "defaultValue": "githubmodels", + "choices": [ + { + "choice": "azureopenai", + "displayName": "Azure OpenAI", + "description": "Uses Azure OpenAI service" + }, + { + "choice": "githubmodels", + "displayName": "GitHub Models", + "description": "Uses GitHub Models" + }, + { + "choice": "ollama", + "displayName": "Ollama (for local development)", + "description": "Uses Ollama with the llama3.2 and all-minilm models" + }, + { + "choice": "openai", + "displayName": "OpenAI Platform", + "description": "Uses the OpenAI Platform" + } + // { + // "choice": "azureaifoundry", + // "displayName": "Azure AI Foundry (Preview)", + // "description": "Uses Azure AI Foundry (Preview)" + // } + ] + }, + "VectorStore": { + "type": "parameter", + "displayName": "_Vector store", + "datatype": "choice", + "defaultValue": "local", + "choices": [ + { + "choice": "local", + "displayName": "Local on-disk (for prototyping)", + "description": "Uses a JSON file on disk. You can change the implementation to a real vector database before publishing." + }, + { + "choice": "azureaisearch", + "displayName": "Azure AI Search", + "description": "Uses Azure AI Search. This also avoids the need to define a data ingestion pipeline, since it's managed by Azure AI Search." + }, + { + "choice": "qdrant", + "displayName": "Qdrant", + "description": "Uses Qdrant in a Docker container, orchestrated using Aspire." + } + ] + }, + "UseManagedIdentity": { + "type": "parameter", + "displayName": "Use keyless authentication for Azure services", + "datatype": "bool", + "defaultValue": "true", + "isEnabled": "(!UseAspire && VectorStore != \"qdrant\" && (AiServiceProvider == \"azureopenai\" || AiServiceProvider == \"azureaifoundry\" || VectorStore == \"azureaisearch\"))", + "description": "Use managed identity to access Azure services" + }, + "UseAspire": { + "type": "parameter", + "displayName": "Use Aspire orchestration", + "datatype": "bool", + "defaultValue": "false", + "description": "Create the project as a distributed application using .NET Aspire." + }, + "IsAspire": { + "type": "computed", + "value": "(UseAspire || VectorStore == \"qdrant\")" + }, + "IsAzureOpenAI": { + "type": "computed", + "value": "(AiServiceProvider == \"azureopenai\")" + }, + "IsOpenAI": { + "type": "computed", + "value": "(AiServiceProvider == \"openai\")" + }, + "IsGHModels": { + "type": "computed", + "value": "(AiServiceProvider == \"githubmodels\")" + }, + "IsOllama": { + "type": "computed", + "value": "(AiServiceProvider == \"ollama\")" + }, + "IsAzureAIFoundry": { + "type": "computed", + "value": "(AiServiceProvider == \"azureaifoundry\")" + }, + "UseAzureAISearch": { + "type": "computed", + "value": "(VectorStore == \"azureaisearch\")" + }, + "UseLocalVectorStore": { + "type": "computed", + "value": "(VectorStore == \"local\")" + }, + "UseQdrant": { + "type": "computed", + "value": "(VectorStore == \"qdrant\")" + }, + "UseAzure": { + "type": "computed", + "value": "(IsAzureOpenAI || IsAzureAiFoundry || UseAzureAISearch)" + }, + "ChatModel": { + "type": "parameter", + "displayName": "Model/deployment for chat completions. Example: gpt-4o-mini", + "description": "Model/deployment for chat completions. Example: gpt-4o-mini" + }, + "EmbeddingModel": { + "type": "parameter", + "displayName": "Model/deployment for embeddings. Example: text-embedding-3-small", + "description": "Model/deployment for embeddings. Example: text-embedding-3-small" + }, + "OpenAiChatModelDefault": { + "type": "generated", + "generator": "constant", + "parameters": { + "value": "gpt-4o-mini" + } + }, + "OpenAiEmbeddingModelDefault": { + "type": "generated", + "generator": "constant", + "parameters": { + "value": "text-embedding-3-small" + } + }, + "OpenAiChatModel": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "ChatModel", + "fallbackVariableName": "OpenAiChatModelDefault" + }, + "replaces": "gpt-4o-mini" + }, + "OpenAiEmbeddingModel": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "EmbeddingModel", + "fallbackVariableName": "OpenAiEmbeddingModelDefault" + }, + "replaces": "text-embedding-3-small" + }, + "OllamaChatModelDefault": { + "type": "generated", + "generator": "constant", + "parameters": { + "value": "llama3.2" + } + }, + "OllamaEmbeddingModelDefault": { + "type": "generated", + "generator": "constant", + "parameters": { + "value": "all-minilm" + } + }, + "OllamaChatModel": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "ChatModel", + "fallbackVariableName": "OllamaChatModelDefault" + }, + "replaces": "llama3.2" + }, + "OllamaEmbeddingModel": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "EmbeddingModel", + "fallbackVariableName": "OllamaEmbeddingModelDefault" + }, + "replaces": "all-minilm" + }, + "webHttpPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the HTTP endpoint in the launchSettings.json of the Web project." + }, + "webHttpPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 5000, + "high": 5300 + } + }, + "webHttpPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "webHttpPort", + "fallbackVariableName": "webHttpPortGenerated" + }, + "replaces": "5000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "webHttpsPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the HTTPS endpoint in the launchSettings.json of the Web project." + }, + "webHttpsPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 7000, + "high": 7300 + } + }, + "webHttpsPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "webHttpsPort", + "fallbackVariableName": "webHttpsPortGenerated" + }, + "replaces": "5001", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostHttpPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the HTTP endpoint in the launchSettings.json of the AppHost project." + }, + "appHostHttpPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 15000, + "high": 15300 + } + }, + "appHostHttpPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostHttpPort", + "fallbackVariableName": "appHostHttpPortGenerated" + }, + "replaces": "15000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostOtlpHttpPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the OTLP HTTP endpoint in launchSettings.json of the AppHost project." + }, + "appHostOtlpHttpPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 19000, + "high": 19300 + } + }, + "appHostOtlpHttpPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostOtlpHttpPort", + "fallbackVariableName": "appHostOtlpHttpPortGenerated" + }, + "replaces": "19000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostResourceHttpPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the resource service HTTP endpoint in launchSettings.json of the AppHost project." + }, + "appHostResourceHttpPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 20000, + "high": 20300 + } + }, + "appHostResourceHttpPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostResourceHttpPort", + "fallbackVariableName": "appHostResourceHttpPortGenerated" + }, + "replaces": "20000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostHttpsPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the HTTPS endpoint in launchSettings.json of the AppHost project." + }, + "appHostHttpsPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 17000, + "high": 17300 + } + }, + "appHostHttpsPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostHttpsPort", + "fallbackVariableName": "appHostHttpsPortGenerated" + }, + "replaces": "17000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostOtlpHttpsPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the OTLP HTTPS endpoint in launchSettings.json of the AppHost project." + }, + "appHostOtlpHttpsPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 21000, + "high": 21300 + } + }, + "appHostOtlpHttpsPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostOtlpHttpsPort", + "fallbackVariableName": "appHostOtlpHttpsPortGenerated" + }, + "replaces": "21000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "appHostResourceHttpsPort": { + "type": "parameter", + "datatype": "integer", + "description": "Port number to use for the resource service HTTPS endpoint in launchSettings.json of the AppHost project." + }, + "appHostResourceHttpsPortGenerated": { + "type": "generated", + "generator": "port", + "parameters": { + "low": 22000, + "high": 22300 + } + }, + "appHostResourceHttpsPortReplacer": { + "type": "generated", + "generator": "coalesce", + "parameters": { + "sourceVariableName": "appHostResourceHttpsPort", + "fallbackVariableName": "appHostResourceHttpsPortGenerated" + }, + "replaces": "22000", + "onlyIf": [{ + "after": "localhost:" + }] + }, + "vectorStoreIndexNameReplacer": { + "type": "derived", + "valueSource": "name", + "valueTransform": "vectorStoreIndexNameTransform", + "replaces": "data-ChatWithCustomData-CSharp.Web-ingestion" + }, + "webProjectNamespaceAdjuster": { + "type": "generated", + "generator": "switch", + "replaces": ".Web", + "onlyIf": [{ + "after": "ChatWithCustomData_CSharp" + }, { + "after": "ChatWithCustomData-CSharp" + }], + "parameters": { + "evaluator": "C++", + "cases": [ + { + "condition": "(IsAspire)", + "value": ".Web" + }, + { + "condition": "(!IsAspire)", + "value": "" + } + ] + } + } + }, + "forms": { + "vectorStoreIndexNameTransform": { + "identifier": "chain", + "steps": [ + "lowerCaseForm", + "vectorStoreIndexName_ReplaceIllegalCharacters", + "vectoreStoreIndexName_CollapseConsecutiveDashesUnderscores", + "vectorStoreIndexName_LengthLimit", + "vectorStoreIndexName_PrefixSuffix" + ], + "description": "See https://learn.microsoft.com/rest/api/searchservice/naming-rules" + }, + "lowerCaseForm": { + "identifier": "lowerCase" + }, + "vectorStoreIndexName_ReplaceIllegalCharacters": { + "identifier": "replace", + "pattern": "[^a-z0-9-_]", + "replacement": "_", + "description": "Only letters, numbers, dashes, and underscores are allowed" + }, + "vectoreStoreIndexName_CollapseConsecutiveDashesUnderscores": { + "identifier": "replace", + "pattern": "([-_])\\1+", + "replacement": "$1", + "description": "No consecutive dashes are underscores are allowed" + }, + "vectorStoreIndexName_LengthLimit": { + "identifier": "replace", + "pattern": "^(.{0,114}).*", + "replacement": "$1", + "description": "Length is limited to 128 characters, including the 14 characters of prefix and suffix to be added." + }, + "vectorStoreIndexName_PrefixSuffix": { + "identifier": "replace", + "pattern": "^(.*)$", + "replacement": "data-$1-ingested", + "description": "Produces a meaningful name parameterized by project name; ensures first, second, and last characters are valid" + } + }, + "postActions": [{ + "condition": "(hostIdentifier != \"dotnetcli\")", + "description": "Opens README file in the editor", + "manualInstructions": [ ], + "actionId": "84C0DA21-51C8-4541-9940-6CA19AF04EE6", + "args": { + "files": "0" + }, + "continueOnError": true + }], + "SpecialCustomOperations": { + "**/*.md": { + "operations": [ + { + "type": "conditional", + "configuration": { + "if": ["#### ---#if"], + "else": ["#### ---#else"], + "elseif": ["#### ---#elseif", "#### ---#elif"], + "endif": ["#### ---#endif"], + "trim" : "true", + "wholeLine": "true", + "evaluator": "C++" + } + } + ] + } + } +}