diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/CHANGELOG.md b/ERP/Commerce/AI-Search-for-Dynamics-365/CHANGELOG.md new file mode 100644 index 00000000..34b3c342 --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog + +All notable changes to this project are documented here. + +## [V7-20260815] – 2026-08-15 + +### Changed +- **D365 X++ (`CCAIProductSearchExportData`)** now extracts only the blob **endpoint URL** from + the storage connection string (retrieved from Key Vault) and sends that non-secret URL to the + Function App. The storage **account key is no longer transmitted**. A helper, + `getBlobEndpointFromConnectionString`, performs the parsing; the existing method/field/JSON + naming (`retrieveProductSearchStorageConnectionString`, `DestinationConnectionString`) is kept. +- **Function App (`ProductListStorageWriter`)** now authenticates to the destination storage + account using its **managed identity** (`DefaultAzureCredential`) and treats the incoming + `DestinationConnectionString` value as the blob endpoint URL. Added the `Azure.Identity` package. + +### Security +- The storage **account key is never sent** from D365 to the Function App and is **not stored** on + the function, removing the risk of the secret leaking via request bodies, logs, or telemetry. + The full connection string remains only in Key Vault (still used by the Azure AI Search data + source). + +### Fixed +- Corrected CLR exception handling in `exportInitialProductData` and `copyData` (proper + `System.Exception.get_Message()` retrieval and CLR object cleanup). +- Aligned DMF refresh type with the sync mode (`FullPush` for initial sync, + `IncrementalPush` otherwise) and added error logging in the generic catch blocks. + +### Upgrade notes +- Enable a **system-assigned managed identity** on the Function App and grant it **Storage Blob + Data Contributor** on the destination storage account. No storage app setting is required. + See [`docs/azure-setup.md`](docs/azure-setup.md). + +## [7.0] – 2025-11-21 + +### Changed +- `CCAIProductSearch.createOrderLines`: removed `_fds.research(true)`. +- `CCAIProductSearch.canClose()`: added `RetailInventTable` to the entity (custom tables can be + added); removed the code in `defaultCTQuery()`. + +### Resources +- `CCAISearchProductSearchDataSourceSchema` +- `CCAISearchProductSearchIndexSchema` +- `FTA.en-US.label` + +> Version 7 corresponds to the D365 F&O deployable package `FTA_CCAISearch_V7.axpp`, distributed +> separately from this repository. diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/LICENSE b/ERP/Commerce/AI-Search-for-Dynamics-365/LICENSE new file mode 100644 index 00000000..916de9a1 --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Microsoft FastTrack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/README.md b/ERP/Commerce/AI-Search-for-Dynamics-365/README.md new file mode 100644 index 00000000..30218f5c --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/README.md @@ -0,0 +1,133 @@ +# CCAISearch – Azure AI Search for Item Search in Dynamics 365 F&O + +Enhance item retrieval in **Dynamics 365 Finance & Operations** sales order creation by +replacing the standard SQL-based lookup with **Azure AI Search** and its *Semantic Ranker*. +This delivers faster, more accurate, natural-language product search while reducing load on +the ERP database. + +> Developed by the **Microsoft FastTrack** team. See the [Disclaimer](#disclaimer). + +> [!IMPORTANT] +> This README always describes the **latest release** (currently **V7-20260815**). +> If you are running an **older deployment package**, check out the matching Git tag on the +> [Releases][releases] page to view the documentation as it was for that version, or read +> [`CHANGELOG.md`](CHANGELOG.md) to see what has changed since your version. + +--- + +## Table of contents + +- [Overview](#overview) +- [Architecture](#architecture) +- [Get started](#get-started) +- [Downloads](#downloads) +- [Repository structure](#repository-structure) +- [Disclaimer](#disclaimer) +- [License](#license) + +--- + +## Overview + +**Next-Generation Product Search Powered by Azure AI** + +![AI Product Search Demo](docs/images/ai-product-search-demo.gif) + +The standard item search in Dynamics 365 Finance & Operations is SQL-based keyword matching. +With large product catalogs, this degrades search performance and user experience. + +This solution replaces **SQL-based product search in Dynamics 365** with **Azure AI Search's semantic ranking**, delivering: + +- **Faster discovery** — employees find products in seconds, even in large catalogs +- **Intelligent matching** — understands natural language, handles typos, synonyms and + conceptual matches +- **Reduced ERP load** — search no longer burdens the database; all queries hit Azure AI Search +- **Enterprise-grade** — fully managed, secure, scalable, with document-level access control + +## Architecture + +![Deployment components](docs/images/deployment-components.svg) + +### How it works + +1. **Data Export** – Dynamics 365 product master data is exported as CSV (via DMF) to Azure Blob + Storage. +2. **Data Transformation** – The **Function App** (`ProductListStorageWriter`) is triggered, + downloads the CSV, parses it into records, and uploads them as JSON chunks to a destination + blob container. It receives only the storage **endpoint URL** from D365 and authenticates to + storage with its own **managed identity** — no storage key or connection string is sent or + stored on the function. +3. **Indexing** – **Azure AI Search** discovers and indexes the JSON chunks in near-real-time, + building a searchable product index with semantic ranking enabled. +4. **Search** – Users search on the D365 Sales Order form; the X++ form extension queries the + Azure AI Search index directly (no SQL on the ERP), retrieves ranked results, and displays them. +5. **Security** – Secrets (AI Search key, Storage connection string, Function key) are stored in + **Azure Key Vault** and referenced via D365 Key Vault parameters. D365 extracts only the blob + **endpoint URL** from the storage connection string and passes that non-secret value to the + Function App, which writes to storage using its **managed identity** (Storage Blob Data + Contributor). The storage account key is never transmitted between components. + +### Technology stack + +| Component | Technology | Purpose | +|---|---|---| +| **Cloud indexing** | Azure AI Search (Semantic Ranker) | Semantic search, re-ranking, NLP | +| **Data storage** | Azure Blob Storage | CSV source + JSON index data | +| **Transformation** | .NET 8 Azure Function (isolated) | CSV ▸ JSON chunking + upload | +| **Secrets mgmt** | Azure Key Vault | Secure credential storage | +| **UI Integration** | Dynamics 365 X++ (FTA model) | Sales Order search form extension | + +## Repository structure + +| Component | Location | Type | Deploy method | +|---|---|---|---| +| **Function App code & deployment** | `src/CCAISearch-Deploy/` | .NET 8 C# | See [Azure setup](docs/azure-setup.md) Step 4 | +| **D365 X++ source & deployment** | `src/Dynamics365/` | X++/XML | See [Dynamics 365 Model Deployment](docs/fno-model-deployment.md) | +| **Azure resources** | n/a | Azure | See [Azure setup](docs/azure-setup.md) Steps 1–3, 5–7 | +| **Configuration** | n/a | D365 forms | See [F&O configuration](docs/fno-configuration.md) | + +## Get started + +Follow these guides **in order** to deploy the solution: + +1. **[Azure setup](docs/azure-setup.md)** – Provision Resource Group, Azure AI Search, Storage, + Function App, Key Vault. Takes ~15 min. +2. **[Dynamics 365 Model Deployment](docs/fno-model-deployment.md)** – Import and deploy the X++ model package. + Takes ~5 min. +3. **[F&O configuration](docs/fno-configuration.md)** – Configure Key Vault parameters, AI Search + index, and Sales Order form extension. Takes ~10 min. + +--- + +## Downloads + +All deployment packages are available on the [GitHub Releases][releases] page: + +- **Function App deployment package** – `CCAISearch-Deploy-v1.0.zip` (.NET 8 source code) +- **Dynamics 365 model package** – `FTA_CCAISearch_V7_20260815.axpp` (pre-built X++ model) + +> Each release includes **both** artifacts. Always deploy the Function App package and the +> D365 model package from the **same release** to keep the two sides in sync. + +See the deployment guides for instructions on how to use each package. + +--- + +## Disclaimer + +This solution is developed by the **Microsoft FastTrack** team. It is **not** covered under +product warranty and is **outside the scope of D365 support services**. + +- Test thoroughly before deploying to production. If issues occur in production, disable the + feature from the **Azure AI Search parameters** form. +- Use **separate** Azure AI Search instances for Production and UAT — the environments may + hold different data. +- The same approach can be extended to customer or order search. +- Index only the fields you need; too many fields slows response times. + +## License + +Released under the [MIT License](LICENSE). + + +[releases]: https://github.com/fechiram_microsoft/AI-Search-for-Dynamics365/releases diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/azure-setup.md b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/azure-setup.md new file mode 100644 index 00000000..3f9a9b67 --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/azure-setup.md @@ -0,0 +1,201 @@ +# Azure setup + +Step-by-step provisioning of the Azure resources required by the CCAISearch solution. Perform +these steps once **per environment** (e.g. UAT and Production should have separate services to +avoid data corruption). + +## Assumptions and working methodology + +- Product search uses **Item ID** as the key. Keys may contain letters, digits, underscores + (`_`), dashes (`-`) or equals (`=`), but **no spaces**. +- **Index strategy**: Create a separate index per legal entity (recommended). You can optionally + reuse a single index across legal entities, but ensure the combined dataset size fits your + AI Search tier. +- Provision a **separate Azure AI Search service per environment** (Production and UAT must not + share data). +- Choose the AI Search pricing tier based on the number of indexes and the volume of exported + data. + +Throughout this guide, values you must copy for later are marked like `#SecretName`. + +--- + +## Step 1 – Resource Group + +1. Sign in to the [Azure portal](https://portal.azure.com). +2. Create a new **Resource Group**: choose your subscription, a meaningful name and the + appropriate region, then **Review + create**. + +## Step 2 – Azure AI Search + +Azure AI Search loads and indexes the exported data and returns ranked results. + +1. In the Resource Group, **Create a resource** ▸ **Azure AI Search**. +2. Select the Resource Group created in Step 1. +3. **Change Pricing Tier** to a tier that supports your index count / data volume. + > The **Semantic Ranker** must be enabled (available from the Standard tier). It uses + > neural networks for relevance and handles typos, synonyms and conceptual matches. +4. Configure Scale and other options, then **Review + create** ▸ **Create**. +5. Copy the service endpoint from **Overview ▸ Essentials ▸ URL** as `#AISearchServiceEndpoint` + (e.g., `https://.search.windows.net/`). +6. Copy the admin key from **Settings ▸ Keys ▸ primary admin key** as `#AzureAISearchAccessKey`. + +## Step 3 – Storage Account + +Cloud storage holds the master data that AI Search indexes, enabling independent, incremental, +periodic updates from the ERP. + +1. **Create a resource** ▸ search **Storage account** ▸ **Create**. +2. Select the same Resource Group, enter a meaningful name, complete required fields, then + **Review + create**. +3. Copy the connection string from **Security + networking ▸ Access keys ▸ key1 ▸ Connection + string** as `#StorageAccountConnectionString` + (format: `DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net`). + +## Step 4 – Deploy the Function App + +The Function App (.NET 8 isolated-worker) transforms CSV product data into JSON chunks indexed by Azure AI Search. + +### Prerequisites + +- [Visual Studio Code](https://code.visualstudio.com/) with the + [Azure Functions extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) +- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) +- An active Azure subscription with **Contributor** or **Owner** permissions on the + Resource Group from Step 1 + +### Step 4a – Create the Function App in Azure Portal + +Creating the Function App in the portal first ensures your permissions are correct and avoids naming conflicts. + +1. Sign in to the [Azure portal](https://portal.azure.com). +2. Click **Create a resource** ▸ search for **Function App** ▸ **Create**. +3. Fill in the details: + - **Subscription**: Select your subscription + - **Resource Group**: Select the group from Step 1 + - **Function App name**: Enter a globally unique name (e.g., `ccaisearch-prod-001`) + > Naming rules: lowercase, digits, hyphens only; 3–24 characters; must be unique across Azure + - **Runtime stack**: **.NET** (Isolated) + - **Runtime version**: **8.0** + - **Region**: Same as your Resource Group + - **Storage Account**: Select the account from Step 3 + > Azure Function Apps require a storage account for runtime infrastructure (logs, metadata, state). + > We reuse the one from Step 3, which also holds your CSV source data and JSON chunks. +4. Click **Review + create** ▸ **Create**. Wait ~2 minutes for provisioning to complete. + +**If naming fails:** The portal will show you the exact reason (e.g., name taken, permissions). Fix it and retry. + +### Step 4b – Deploy Code via VS Code + +Now deploy the Function App code to the resource you just created. + +1. **Prepare the code folder:** + - If cloned: Open `src/CCAISearch-Deploy` in VS Code + - If downloaded zip: Extract `CCAISearch-Deploy-v1.0.zip` and open the extracted folder in VS Code + +2. In VS Code, press `Ctrl+Shift+P` ▸ **Azure Functions: Deploy to Function App…** + +3. Follow the prompts: + - Sign in to Azure if prompted + - Select your subscription + - Select the Function App you created in Step 4a + - Confirm the deployment + +4. Deployment takes ~30 seconds. When complete, you'll see a success message. + +### Retrieve the endpoint and key + +After successful deployment: + +5. In the Azure portal, open the deployed Function App ▸ **Functions ▸ ProductListStorageWriter + ▸ Get function URL**. + Copy the **base URL only** (without any `?code=…` query string) as `#DataUploadAzureFunctionEndpoint` + (e.g., `https://.azurewebsites.net/api/ProductListStorageWriter`). + +6. To get the access key, go to **Functions ▸ ProductListStorageWriter ▸ Function Keys** tab. + Copy the **default** key value as `#DataUploadAzureFunctionAccessKey`. + + ![Function Keys tab — copy the default key value](images/function-keys.png) + + > **Note:** The key in the "Get function URL" dialog is the same `default` key, but copying + > it from the **Function Keys** tab is clearer and avoids confusing the endpoint URL with + > the key parameter. + +### Function contract reference + +The function accepts HTTP POST requests (function-level auth) with this body: + +```json +{ + "sourceBlobUrl": "https://.blob.core.windows.net//products.csv?", + "destinationConnectionString": "https://.blob.core.windows.net", + "destinationContainer": "products-index", + "separator": "|", + "recordsPerFile": 1000, + "baseFileName": "s", + "resetContainer": "true" +} +``` + +| Field | Required | Default | Description | +| --- | --- | --- | --- | +| `sourceBlobUrl` | ✅ | – | URL (with SAS if private) of the source CSV | +| `destinationConnectionString` | ✅ | – | Blob **endpoint URL** of the destination storage account (e.g. `https://.blob.core.windows.net`). **Not** a secret — D365 parses it out of the stored connection string; the account key is never sent | +| `destinationContainer` | ✅ | – | Blob container that AI Search indexes | +| `separator` | ❌ | `,` | CSV column separator (use `\|` for VerticalBarSeparated) | +| `recordsPerFile` | ❌ | `1000` | Records per JSON chunk | +| `baseFileName` | ❌ | `s` | Prefix for generated JSON files | +| `resetContainer` | ❌ | `false` | `"true"` deletes existing blobs before upload | + +Response: `200 OK` with message `Successfully processed and uploaded JSON files.` + +> **Security — storage credential.** The storage **account key is never transmitted**. D365 reads +> the connection string from Key Vault, extracts only the blob **endpoint URL**, and sends that +> (non-secret) URL in the `destinationConnectionString` field. The Function App then authenticates +> to storage using its own **managed identity** — no key or connection string is stored on the +> function or carried in logs/telemetry. + +### Configure managed-identity access to the destination storage + +> **New in V7-20260815.** As of release **V7-20260815**, the Function App writes to storage using +> its **managed identity** (no storage key is sent from D365). Complete the steps below as part of +> deploying V7-20260815. + +1. In the Function App, enable a **system-assigned managed identity** + (**Settings ▸ Identity ▸ System assigned ▸ Status = On**). +2. On the **destination Storage account ▸ Access control (IAM) ▸ Add role assignment**, assign + **Storage Blob Data Contributor** to the Function App's managed identity, then **Review + assign**. + > This requires **Owner** or **User Access Administrator** on the storage account (or its + > resource group). If **Add role assignment** is greyed out, ask your Azure administrator to + > make this one assignment. +3. No storage app setting is required on the Function App — the endpoint arrives in each request + and the managed identity provides access. + +## Step 5 – App Registration (for Key Vault access) + +1. Azure portal ▸ **App registrations** ▸ **New registration**. Give it a name and register. +2. Open the app ▸ **Manage ▸ Certificates & secrets ▸ New client secret**. +3. Record the secret **Value** and, from **Overview**, the **Application (client) ID**. + +## Step 6 – Key Vault + +1. Azure portal ▸ **Key Vault** ▸ **Create**, in the same Resource Group. Complete details, + configure the security options, then **Review + create**. +2. **Go to resource ▸ Access control (IAM) ▸ Add ▸ Add role assignment**. +3. Role: **Key Vault Secrets User** ▸ **Next**. +4. **Select members** ▸ add the App Registration from Step 5 ▸ **Next ▸ Review + assign**. + +## Step 7 – Store the secrets in Key Vault + +Create four secrets in the Key Vault: + +| Secret | Source | +| --- | --- | +| `#AISearchServiceEndpoint` | Step 2 | +| `#AzureAISearchAccessKey` | Step 2 | +| `#StorageAccountConnectionString` | Step 3 | +| `#DataUploadAzureFunctionAccessKey` | Step 4 | + +--- + +Continue with **[Dynamics 365 Model Deployment](fno-model-deployment.md)** to deploy the model package. diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-configuration.md b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-configuration.md new file mode 100644 index 00000000..20c6f681 --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-configuration.md @@ -0,0 +1,74 @@ +# Dynamics 365 Finance & Operations configuration + +Complete the [Azure setup](azure-setup.md) first and have the `#…` values ready. + +## Step 1 – Key Vault parameters + +In D365 F&O, search for **Key Vault parameters** and create a new parameter: + +1. Enter the **Key Vault URL** of the vault you created. +2. Provide the **client ID** and **client secret** from the App Registration (Step 5). +3. Add the three secrets created in Key Vault: + - `#AzureAISearchAccessKey` + - `#StorageAccountConnectionString` + - `#DataUploadAzureFunctionAccessKey` +4. **Validate** each entry after inputting it. + +![Key Vault Secrets table](images/keyvault-secrets.png) + +## Step 2 – Azure AI Search integration setup + +Go to **Sales and marketing ▸ Setup ▸ Azure AI Search ▸ Azure AI search parameters**. + +### Integration Parameters tab + +1. Enter the **AI Search endpoint** (copy the URI from the Azure AI Search resource) and select + `AzureAISearchKey` from the dropdown. +2. Click **Validate endpoint** — it should verify successfully. +3. In the configuration section, select the **storage connection string** from the dropdown + (one of the three secrets). +4. In **Data Upload Function Endpoint**, enter `#DataUploadAzureFunctionEndpoint`. +5. Select the **access key** for the data upload function (`#DataUploadAzureFunctionAccessKey`). +6. Choose the data export **source separator** — e.g. **VerticalBarSeparated** (`|`) used as the + CSV column separator generated from DMF. +7. Click **Save**. + +### Product Search tab + +On the **Product Search** tab, configure the search index: + +1. Enable **Enable Product Search** toggle — the feature only works when enabled. +2. Enter the **Search index name** (e.g., `fta-ccaisearch-products`) — this is the name of the + AI Search index created during initialization (Step 3 below). +3. Set **Number of Records Retrieved** to control how many results are shown per search. + - **⚠️ Important:** For best semantic search quality, keep this **≤ 50 records**. Higher values + (e.g., 100+) may degrade relevance ranking as semantic similarity becomes less meaningful + with large result sets. Start with 20–50 and adjust based on your use case. +4. Enter the **Storage container name** (e.g., `usrt-productdatastore`) — this is where the + CSV product data is exported from D365. +5. Select the **Category Hierarchy** from the dropdown (e.g., **Retail Product Category**) — AI + Search will only export products defined in this hierarchy. + +![Number of Records Retrieved caveat (recommended ≤ 50)](images/records-retrieved-caveat.png) + +## Step 3 – Initialize & update index + +On the **Product Search** tab, click **Initialize index** to start the index creation process: + +1. This creates a batch job that exports all product data from the selected **Category Hierarchy** + and builds the AI Search index. +2. Monitor the job status — when complete, check **Integration logs** for any errors. +3. Once the index is successfully created (status shows **Completed**), schedule the recurring + **Update Index** batch job to keep products in sync. This runs periodically to export + incremental changes and reindex. + +## Step 4 – Use product search on a Sales Order + +1. Open a **Sales Order** and click the new **AI Product Search** button. +2. Enter search text and click **Search**. +3. Select a product and click **Add**. Repeat as needed; once items are selected and dimensions + entered, click **OK** to add the products to the sales order lines. + +--- + +See the [Disclaimer](../README.md#disclaimer) before using in production. diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-model-deployment.md b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-model-deployment.md new file mode 100644 index 00000000..4e6216f2 --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/fno-model-deployment.md @@ -0,0 +1,49 @@ +# Dynamics 365 F&O – X++ source (FTA_CCAISearch) + +This folder contains the extracted X++ source of the **AI Product Search** D365 Finance & +Operations model, as shipped in `FTA_CCAISearch_V7.axpp`. + +## Structure + +| Path | Contents | +| --- | --- | +| `Model/` | Model descriptor (`FTA.xml`) | +| `Project/` | Visual Studio project (`FTA_CCAISearch.rnrproj`) | +| `ProjectItem/` | All model objects, grouped by type | + +Key objects under `ProjectItem/`: + +- **Forms** – `CCAIProductSearch`, `CCAISearchServiceParameters`, `CCAISearchServiceIntegrationLog` +- **Classes** – service/API managers, export data, batch jobs (initialize / update / reindex) +- **Tables** – service parameters, integration log, staging, product list/search temp tables +- **Data entity** – `CCAISearchEcoResProductsEntity` +- **Resources** – AI Search index / indexer / data source schemas and request bodies (JSON under + `AxResource/ResourceContent/Data/`) +- **Extensions** – `SalesTable`, `InventTable`, menu and form extensions +- **Security** – privileges for maintain/view +- **Labels** – `FTA.en-US.label.txt` + +## How to build / deploy + +You normally deploy using the packaged **`FTA_CCAISearch_V7.axpp`** from the +[GitHub Releases][releases] page rather than these loose files: + +1. On a D365 F&O development VM, open Visual Studio. +2. **Dynamics 365 ▸ Import Project** and select the `.axpp` file. +3. Build the model, then **Dynamics 365 ▸ Deploy** (or create a deployable package for a + sandbox/production environment). + +For detailed deployment instructions, see **[Dynamics 365 Model Deployment](../fno-model-deployment.md)** guide. + +To work from this source directly, place the `FTA` model under your +`PackagesLocalDirectory` / metadata folder and open `Project/FTA_CCAISearch.rnrproj`. + +> This source is provided for transparency and version control. See the repository +> [Disclaimer](../../README.md#disclaimer). + +--- + +Continue with **[F&O configuration](fno-configuration.md)** to configure the imported model and enable the search feature. + + +[releases]: https://github.com/fechiram_microsoft/AI-Search-for-Dynamics365/releases diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/ai-product-search-demo.gif b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/ai-product-search-demo.gif new file mode 100644 index 00000000..72dc0254 Binary files /dev/null and b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/ai-product-search-demo.gif differ diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/deployment-components.svg b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/deployment-components.svg new file mode 100644 index 00000000..8a8871af --- /dev/null +++ b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/deployment-components.svg @@ -0,0 +1,112 @@ + + + + + + + + + + AI Product Search – Deployment Components + + + + Microsoft Azure (per environment: UAT / Prod) + + + + + Dynamics 365 F&O + Sales Order ▸ "AI Product Search" + FTA_CCAISearch model (X++) + + + + + + Function App + ProductListStorageWriter + .NET 8 isolated · v4 + CSV ▸ chunked JSON + + + + + + Blob Storage + Source CSV + (DMF export) + + + + + + Blob Storage + JSON chunks + (index container) + + + + + + Azure AI Search + Index + Indexer + Semantic Ranker + + + + + + Azure Key Vault + AI Search key · Storage conn · Fn key + + + + + + 1 · DMF export (CSV) + + + + 2 · HTTP trigger + + + + 3 · upload + + + + 4 · indexes + + + + 5 · query / ranked results + + + + invoke + + + + secrets referenced by F&O Key Vault params + + + + + + Legend: + + data / request flow + + secret reference / invoke + Deployables: Function App (src/CCAISearch-Deploy) · X++ package (src/Dynamics365) + + diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/function-keys.png b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/function-keys.png new file mode 100644 index 00000000..adfa0500 Binary files /dev/null and b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/function-keys.png differ diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/keyvault-secrets.png b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/keyvault-secrets.png new file mode 100644 index 00000000..a91de624 Binary files /dev/null and b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/keyvault-secrets.png differ diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/product-search-tab.png b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/product-search-tab.png new file mode 100644 index 00000000..f7f8ca6d Binary files /dev/null and b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/product-search-tab.png differ diff --git a/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/records-retrieved-caveat.png b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/records-retrieved-caveat.png new file mode 100644 index 00000000..64865992 Binary files /dev/null and b/ERP/Commerce/AI-Search-for-Dynamics-365/docs/images/records-retrieved-caveat.png differ