1
+ // This is a RAG (Retrieval Augmented Generation) implementation that:
2
+ // 1. Takes a user query about hotels
3
+ // 2. Searches a hotel database using Azure AI Search
4
+ // 3. Formats the search results for the LLM
5
+ // 4. Sends the query and formatted results to Azure OpenAI
6
+ // 5. Returns a grounded response based only on the retrieved information
7
+
8
+ import { SearchClient , SearchDocumentsResult } from "@azure/search-documents" ;
9
+ import { AzureOpenAI } from "openai" ;
10
+ import { DefaultAzureCredential , getBearerTokenProvider } from "@azure/identity" ;
11
+
12
+ function getClients ( ) : { openaiClient : AzureOpenAI ; searchClient : SearchClient < { HotelName : string ; Description : string ; Tags : string [ ] | string ; Address : string ; Rooms : string } > ; modelName : string } {
13
+
14
+ const credential = new DefaultAzureCredential ( ) ;
15
+
16
+ // Search
17
+ const azureSearchEndpoint = process . env . AZURE_SEARCH_ENDPOINT ! ;
18
+ const azureSearchIndexName = process . env . AZURE_SEARCH_INDEX_NAME ! ;
19
+ const searchClient = new SearchClient < { HotelName : string ; Description : string ; Tags : string [ ] | string ; Address : string ; Rooms : string } > (
20
+ azureSearchEndpoint ,
21
+ azureSearchIndexName ,
22
+ credential
23
+ ) ;
24
+
25
+ // OpenAI
26
+ const azureOpenAiEndpoint = process . env . AZURE_OPENAI_ENDPOINT ! ;
27
+ const azureOpenAiApiVersion = process . env . AZURE_OPENAI_VERSION ! ;
28
+ const azureOpenAiDeploymentName = process . env . AZURE_DEPLOYMENT_MODEL ! ;
29
+
30
+ const scope = "https://cognitiveservices.azure.com/.default" ;
31
+ const azureADTokenProvider = getBearerTokenProvider ( credential , scope ) ;
32
+ const options = { azureADTokenProvider, deployment : azureOpenAiDeploymentName , apiVersion : azureOpenAiApiVersion , endpoint : azureOpenAiEndpoint }
33
+ const openaiClient = new AzureOpenAI ( options ) ;
34
+
35
+ return { openaiClient, searchClient, modelName : azureOpenAiDeploymentName } ;
36
+ }
37
+
38
+
39
+ async function queryAISearchForSources (
40
+ searchClient : SearchClient < { HotelName : string ; Description : string ; Tags : string [ ] | string ; Address : string ; Rooms : string } > ,
41
+ query : string
42
+ ) : Promise < SearchDocumentsResult < { HotelName : string ; Description : string ; Tags : string [ ] | string ; Address : string ; Rooms : string } > > {
43
+ console . log ( `Searching for: "${ query } "\n` ) ;
44
+
45
+ const selectedFields : readonly [ "HotelName" , "Description" , "Address" , "Rooms" , "Tags" ] = [ "HotelName" , "Description" , "Address" , "Rooms" , "Tags" ] ;
46
+ const searchResults = await searchClient . search ( query , {
47
+ top : 5 ,
48
+ select : selectedFields ,
49
+ queryType : "semantic" ,
50
+ semanticSearchOptions : { } ,
51
+ } ) ;
52
+
53
+ return searchResults ;
54
+ }
55
+ async function queryOpenAIForResponse (
56
+ openaiClient : AzureOpenAI ,
57
+ query : string ,
58
+ sourcesFormatted : string ,
59
+ modelName : string
60
+ ) : Promise < { choices : { message : { content : string | null } } [ ] } > {
61
+
62
+ const GROUNDED_PROMPT = `
63
+ You are a friendly assistant that recommends hotels based on activities and amenities.
64
+ Answer the query using only the sources provided below in a friendly and concise bulleted manner.
65
+ Answer ONLY with the facts listed in the list of sources below.
66
+ If there isn't enough information below, say you don't know.
67
+ Do not generate answers that don't use the sources below.
68
+
69
+ Query: {query}
70
+ Sources: {sources}
71
+ ` ;
72
+
73
+ return openaiClient . chat . completions . create ( {
74
+ model : modelName ,
75
+ messages : [
76
+ {
77
+ role : "user" ,
78
+ content : GROUNDED_PROMPT . replace ( "{query}" , query ) . replace ( "{sources}" , sourcesFormatted ) ,
79
+ }
80
+ ] ,
81
+ temperature : 0.7 ,
82
+ max_tokens : 800 ,
83
+ } ) ;
84
+ }
85
+
86
+ async function main ( ) : Promise < void > {
87
+
88
+ const { openaiClient, searchClient, modelName } = getClients ( ) ;
89
+
90
+ const query = `
91
+ Can you recommend a few hotels that offer complimentary breakfast?
92
+ Tell me their description, address, tags, and the rate for one room that sleeps 4 people.
93
+ ` ;
94
+
95
+ const sourcesResult = await queryAISearchForSources ( searchClient , query ) ;
96
+ let sourcesFormatted = "" ;
97
+
98
+ for await ( const result of sourcesResult . results ) {
99
+ // Explicitly typing result to ensure compatibility
100
+ sourcesFormatted += JSON . stringify ( result . document ) + "\n" ;
101
+ }
102
+
103
+ const response = await queryOpenAIForResponse ( openaiClient , query , sourcesFormatted . trim ( ) , modelName ) ;
104
+
105
+ // Print the response from the chat model
106
+ const content = response . choices [ 0 ] . message . content ;
107
+ if ( content ) {
108
+ console . log ( content ) ;
109
+ } else {
110
+ console . log ( "No content available in the response." ) ;
111
+ }
112
+ }
113
+
114
+ main ( ) . catch ( ( error ) => {
115
+ console . error ( "An error occurred:" , error ) ;
116
+ process . exit ( 1 ) ;
117
+ } ) ;
0 commit comments