Skip to content

Commit 43aa766

Browse files
authored
Allow semantic ranker with vector search (#1701)
* Allow semantic ranker with vector search * Change variable names * Remove en-us
1 parent c21aac3 commit 43aa766

File tree

65 files changed

+963
-162
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+963
-162
lines changed

app/backend/approaches/approach.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,34 @@ async def search(
133133
query_text: Optional[str],
134134
filter: Optional[str],
135135
vectors: List[VectorQuery],
136+
use_text_search: bool,
137+
use_vector_search: bool,
136138
use_semantic_ranker: bool,
137139
use_semantic_captions: bool,
138140
minimum_search_score: Optional[float],
139141
minimum_reranker_score: Optional[float],
140142
) -> List[Document]:
141-
# Use semantic ranker if requested and if retrieval mode is text or hybrid (vectors + text)
142-
if use_semantic_ranker and query_text:
143+
search_text = query_text if use_text_search else ""
144+
search_vectors = vectors if use_vector_search else []
145+
if use_semantic_ranker:
143146
results = await self.search_client.search(
144-
search_text=query_text,
147+
search_text=search_text,
145148
filter=filter,
149+
top=top,
150+
query_caption="extractive|highlight-false" if use_semantic_captions else None,
151+
vector_queries=search_vectors,
146152
query_type=QueryType.SEMANTIC,
147153
query_language=self.query_language,
148154
query_speller=self.query_speller,
149155
semantic_configuration_name="default",
150-
top=top,
151-
query_caption="extractive|highlight-false" if use_semantic_captions else None,
152-
vector_queries=vectors,
156+
semantic_query=query_text,
153157
)
154158
else:
155159
results = await self.search_client.search(
156-
search_text=query_text or "", filter=filter, top=top, vector_queries=vectors
160+
search_text=search_text,
161+
filter=filter,
162+
top=top,
163+
vector_queries=search_vectors,
157164
)
158165

159166
documents = []

app/backend/approaches/chatreadretrieveread.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ async def run_until_final_call(
8888
auth_claims: dict[str, Any],
8989
should_stream: bool = False,
9090
) -> tuple[dict[str, Any], Coroutine[Any, Any, Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]]]:
91-
has_text = overrides.get("retrieval_mode") in ["text", "hybrid", None]
92-
has_vector = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
93-
use_semantic_captions = True if overrides.get("semantic_captions") and has_text else False
91+
use_text_search = overrides.get("retrieval_mode") in ["text", "hybrid", None]
92+
use_vector_search = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
93+
use_semantic_ranker = True if overrides.get("semantic_ranker") else False
94+
use_semantic_captions = True if overrides.get("semantic_captions") else False
9495
top = overrides.get("top", 3)
9596
minimum_search_score = overrides.get("minimum_search_score", 0.0)
9697
minimum_reranker_score = overrides.get("minimum_reranker_score", 0.0)
97-
9898
filter = self.build_filter(overrides, auth_claims)
99-
use_semantic_ranker = True if overrides.get("semantic_ranker") and has_text else False
10099

101100
original_user_query = messages[-1]["content"]
102101
if not isinstance(original_user_query, str):
@@ -151,18 +150,16 @@ async def run_until_final_call(
151150

152151
# If retrieval mode includes vectors, compute an embedding for the query
153152
vectors: list[VectorQuery] = []
154-
if has_vector:
153+
if use_vector_search:
155154
vectors.append(await self.compute_text_embedding(query_text))
156155

157-
# Only keep the text query if the retrieval mode uses text, otherwise drop it
158-
if not has_text:
159-
query_text = None
160-
161156
results = await self.search(
162157
top,
163158
query_text,
164159
filter,
165160
vectors,
161+
use_text_search,
162+
use_vector_search,
166163
use_semantic_ranker,
167164
use_semantic_captions,
168165
minimum_search_score,
@@ -212,7 +209,8 @@ async def run_until_final_call(
212209
"use_semantic_ranker": use_semantic_ranker,
213210
"top": top,
214211
"filter": filter,
215-
"has_vector": has_vector,
212+
"use_vector_search": use_vector_search,
213+
"use_text_search": use_text_search,
216214
},
217215
),
218216
ThoughtStep(

app/backend/approaches/chatreadretrievereadvision.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,18 @@ async def run_until_final_call(
8989
auth_claims: dict[str, Any],
9090
should_stream: bool = False,
9191
) -> tuple[dict[str, Any], Coroutine[Any, Any, Union[ChatCompletion, AsyncStream[ChatCompletionChunk]]]]:
92-
has_text = overrides.get("retrieval_mode") in ["text", "hybrid", None]
93-
has_vector = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
94-
vector_fields = overrides.get("vector_fields", ["embedding"])
95-
use_semantic_captions = True if overrides.get("semantic_captions") and has_text else False
92+
use_text_search = overrides.get("retrieval_mode") in ["text", "hybrid", None]
93+
use_vector_search = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
94+
use_semantic_ranker = True if overrides.get("semantic_ranker") else False
95+
use_semantic_captions = True if overrides.get("semantic_captions") else False
9696
top = overrides.get("top", 3)
9797
minimum_search_score = overrides.get("minimum_search_score", 0.0)
9898
minimum_reranker_score = overrides.get("minimum_reranker_score", 0.0)
9999
filter = self.build_filter(overrides, auth_claims)
100-
use_semantic_ranker = True if overrides.get("semantic_ranker") and has_text else False
101100

102-
include_gtpV_text = overrides.get("gpt4v_input") in ["textAndImages", "texts", None]
103-
include_gtpV_images = overrides.get("gpt4v_input") in ["textAndImages", "images", None]
101+
vector_fields = overrides.get("vector_fields", ["embedding"])
102+
send_text_to_gptvision = overrides.get("gpt4v_input") in ["textAndImages", "texts", None]
103+
send_images_to_gptvision = overrides.get("gpt4v_input") in ["textAndImages", "images", None]
104104

105105
original_user_query = messages[-1]["content"]
106106
if not isinstance(original_user_query, str):
@@ -136,7 +136,7 @@ async def run_until_final_call(
136136

137137
# If retrieval mode includes vectors, compute an embedding for the query
138138
vectors = []
139-
if has_vector:
139+
if use_vector_search:
140140
for field in vector_fields:
141141
vector = (
142142
await self.compute_text_embedding(query_text)
@@ -145,15 +145,13 @@ async def run_until_final_call(
145145
)
146146
vectors.append(vector)
147147

148-
# Only keep the text query if the retrieval mode uses text, otherwise drop it
149-
if not has_text:
150-
query_text = None
151-
152148
results = await self.search(
153149
top,
154150
query_text,
155151
filter,
156152
vectors,
153+
use_text_search,
154+
use_vector_search,
157155
use_semantic_ranker,
158156
use_semantic_captions,
159157
minimum_search_score,
@@ -173,9 +171,9 @@ async def run_until_final_call(
173171
user_content: list[ChatCompletionContentPartParam] = [{"text": original_user_query, "type": "text"}]
174172
image_list: list[ChatCompletionContentPartImageParam] = []
175173

176-
if include_gtpV_text:
174+
if send_text_to_gptvision:
177175
user_content.append({"text": "\n\nSources:\n" + content, "type": "text"})
178-
if include_gtpV_images:
176+
if send_images_to_gptvision:
179177
for result in results:
180178
url = await fetch_image(self.blob_container_client, result)
181179
if url:
@@ -217,6 +215,7 @@ async def run_until_final_call(
217215
"top": top,
218216
"filter": filter,
219217
"vector_fields": vector_fields,
218+
"use_text_search": use_text_search,
220219
},
221220
),
222221
ThoughtStep(

app/backend/approaches/retrievethenread.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,27 @@ async def run(
8080
raise ValueError("The most recent message content must be a string.")
8181
overrides = context.get("overrides", {})
8282
auth_claims = context.get("auth_claims", {})
83-
has_text = overrides.get("retrieval_mode") in ["text", "hybrid", None]
84-
has_vector = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
85-
use_semantic_ranker = overrides.get("semantic_ranker") and has_text
86-
87-
use_semantic_captions = True if overrides.get("semantic_captions") and has_text else False
83+
use_text_search = overrides.get("retrieval_mode") in ["text", "hybrid", None]
84+
use_vector_search = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
85+
use_semantic_ranker = True if overrides.get("semantic_ranker") else False
86+
use_semantic_captions = True if overrides.get("semantic_captions") else False
8887
top = overrides.get("top", 3)
8988
minimum_search_score = overrides.get("minimum_search_score", 0.0)
9089
minimum_reranker_score = overrides.get("minimum_reranker_score", 0.0)
9190
filter = self.build_filter(overrides, auth_claims)
91+
9292
# If retrieval mode includes vectors, compute an embedding for the query
9393
vectors: list[VectorQuery] = []
94-
if has_vector:
94+
if use_vector_search:
9595
vectors.append(await self.compute_text_embedding(q))
9696

97-
# Only keep the text query if the retrieval mode uses text, otherwise drop it
98-
query_text = q if has_text else None
99-
10097
results = await self.search(
10198
top,
102-
query_text,
99+
q,
103100
filter,
104101
vectors,
102+
use_text_search,
103+
use_vector_search,
105104
use_semantic_ranker,
106105
use_semantic_captions,
107106
minimum_search_score,
@@ -141,13 +140,14 @@ async def run(
141140
"thoughts": [
142141
ThoughtStep(
143142
"Search using user query",
144-
query_text,
143+
q,
145144
{
146145
"use_semantic_captions": use_semantic_captions,
147146
"use_semantic_ranker": use_semantic_ranker,
148147
"top": top,
149148
"filter": filter,
150-
"has_vector": has_vector,
149+
"use_vector_search": use_vector_search,
150+
"use_text_search": use_text_search,
151151
},
152152
),
153153
ThoughtStep(

app/backend/approaches/retrievethenreadvision.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,22 @@ async def run(
8181

8282
overrides = context.get("overrides", {})
8383
auth_claims = context.get("auth_claims", {})
84-
has_text = overrides.get("retrieval_mode") in ["text", "hybrid", None]
85-
has_vector = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
86-
vector_fields = overrides.get("vector_fields", ["embedding"])
87-
88-
include_gtpV_text = overrides.get("gpt4v_input") in ["textAndImages", "texts", None]
89-
include_gtpV_images = overrides.get("gpt4v_input") in ["textAndImages", "images", None]
90-
91-
use_semantic_captions = True if overrides.get("semantic_captions") and has_text else False
84+
use_text_search = overrides.get("retrieval_mode") in ["text", "hybrid", None]
85+
use_vector_search = overrides.get("retrieval_mode") in ["vectors", "hybrid", None]
86+
use_semantic_ranker = True if overrides.get("semantic_ranker") else False
87+
use_semantic_captions = True if overrides.get("semantic_captions") else False
9288
top = overrides.get("top", 3)
9389
minimum_search_score = overrides.get("minimum_search_score", 0.0)
9490
minimum_reranker_score = overrides.get("minimum_reranker_score", 0.0)
9591
filter = self.build_filter(overrides, auth_claims)
96-
use_semantic_ranker = overrides.get("semantic_ranker") and has_text
9792

98-
# If retrieval mode includes vectors, compute an embedding for the query
93+
vector_fields = overrides.get("vector_fields", ["embedding"])
94+
send_text_to_gptvision = overrides.get("gpt4v_input") in ["textAndImages", "texts", None]
95+
send_images_to_gptvision = overrides.get("gpt4v_input") in ["textAndImages", "images", None]
9996

97+
# If retrieval mode includes vectors, compute an embedding for the query
10098
vectors = []
101-
if has_vector:
99+
if use_vector_search:
102100
for field in vector_fields:
103101
vector = (
104102
await self.compute_text_embedding(q)
@@ -107,14 +105,13 @@ async def run(
107105
)
108106
vectors.append(vector)
109107

110-
# Only keep the text query if the retrieval mode uses text, otherwise drop it
111-
query_text = q if has_text else None
112-
113108
results = await self.search(
114109
top,
115-
query_text,
110+
q,
116111
filter,
117112
vectors,
113+
use_text_search,
114+
use_vector_search,
118115
use_semantic_ranker,
119116
use_semantic_captions,
120117
minimum_search_score,
@@ -127,10 +124,10 @@ async def run(
127124
# Process results
128125
sources_content = self.get_sources_content(results, use_semantic_captions, use_image_citation=True)
129126

130-
if include_gtpV_text:
127+
if send_text_to_gptvision:
131128
content = "\n".join(sources_content)
132129
user_content.append({"text": content, "type": "text"})
133-
if include_gtpV_images:
130+
if send_images_to_gptvision:
134131
for result in results:
135132
url = await fetch_image(self.blob_container_client, result)
136133
if url:
@@ -164,13 +161,15 @@ async def run(
164161
"thoughts": [
165162
ThoughtStep(
166163
"Search using user query",
167-
query_text,
164+
q,
168165
{
169166
"use_semantic_captions": use_semantic_captions,
170167
"use_semantic_ranker": use_semantic_ranker,
171168
"top": top,
172169
"filter": filter,
173170
"vector_fields": vector_fields,
171+
"use_vector_search": use_vector_search,
172+
"use_text_search": use_text_search,
174173
},
175174
),
176175
ThoughtStep(

docs/gpt4v.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,33 @@
1-
# Using GPT-4 Turbo with Vision
1+
# Using GPT vision model with RAG approach
22

3-
This repository now includes an example of integrating GPT-4 Turbo with Vision with Azure AI Search. This feature enables indexing and searching images and graphs, such as financial documents, in addition to text-based content.
3+
This repository now includes an example of integrating a GPT Vision model with Azure AI Search. This feature enables indexing and searching images and graphs, such as financial documents, in addition to text-based content, and then sending the retrieved content to the GPT model for response generation.
44

55
## Feature Overview
66

77
- **Document Handling:** Source documents are split into pages and saved as PNG files in blob storage. Each file's name and page number are embedded for reference.
88
- **Data Extraction:** Text data is extracted using OCR.
99
- **Data Indexing:** Text and image embeddings, generated using Azure AI Vision ([Azure AI Vision Embeddings](https://learn.microsoft.com/azure/ai-services/computer-vision/how-to/image-retrieval)), are indexed in Azure AI Search along with the raw text.
10-
- **Search and Response:** Searches can be conducted using vectors or hybrid methods. Responses are generated by GPT-4 Turbo with Vision based on the retrieved content.
10+
- **Search and Response:** Searches can be conducted using vectors or hybrid methods. Responses are generated by GPT vision model based on the retrieved content.
1111

1212
## Getting Started
1313

1414
### Prerequisites
1515

1616
- Create a [Computer Vision account in Azure Portal first](https://ms.portal.azure.com/#create/Microsoft.CognitiveServicesComputerVision), so that you can agree to the Responsible AI terms for that resource. You can delete that account after agreeing.
17-
- The ability to deploy a GPT-4 Turbo with Vision model in the [supported regions](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#gpt-4-and-gpt-4-turbo-preview-model-availability). If you're not sure, try to create a deployment from your Azure OpenAI deployments page. You should be able to select:
18-
19-
| Model | Version |
20-
|--|--|
21-
|`gpt-4`|`vision-preview`|
22-
17+
- The ability to deploy a gpt-4o model in the [supported regions](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability). If you're not sure, try to create a gpt-4o deployment from your Azure OpenAI deployments page.
2318
- Ensure that you can deploy the Azure OpenAI resource group in [a region where all required components are available](https://learn.microsoft.com/azure/cognitive-services/openai/concepts/models#model-summary-table-and-region-availability):
2419
- Azure OpenAI models
2520
- gpt-35-turbo
2621
- text-embedding-ada-002
27-
- gpt-4v
22+
- gpt-4o
2823
- [Azure AI Vision](https://learn.microsoft.com/azure/ai-services/computer-vision/)
2924

3025
### Setup and Usage
3126

3227
1. **Update repository:**
3328
Pull the latest changes.
3429

35-
2. **Enable GPT-4 Turbo with Vision:**
30+
2. **Enable GPT vision approach:**
3631

3732
First, make sure you do *not* have integrated vectorization enabled, since that is currently incompatible:
3833

tests/snapshots/test_app/test_ask_rtr_hybrid/client0/result.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
"description": "What is the capital of France?",
1111
"props": {
1212
"filter": null,
13-
"has_vector": true,
1413
"top": 3,
1514
"use_semantic_captions": false,
16-
"use_semantic_ranker": null
15+
"use_semantic_ranker": false,
16+
"use_text_search": true,
17+
"use_vector_search": true
1718
},
1819
"title": "Search using user query"
1920
},

tests/snapshots/test_app/test_ask_rtr_hybrid/client1/result.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
"description": "What is the capital of France?",
1111
"props": {
1212
"filter": null,
13-
"has_vector": true,
1413
"top": 3,
1514
"use_semantic_captions": false,
16-
"use_semantic_ranker": null
15+
"use_semantic_ranker": false,
16+
"use_text_search": true,
17+
"use_vector_search": true
1718
},
1819
"title": "Search using user query"
1920
},

tests/snapshots/test_app/test_ask_rtr_text/client0/result.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
"description": "What is the capital of France?",
1111
"props": {
1212
"filter": null,
13-
"has_vector": false,
1413
"top": 3,
1514
"use_semantic_captions": false,
16-
"use_semantic_ranker": null
15+
"use_semantic_ranker": false,
16+
"use_text_search": true,
17+
"use_vector_search": false
1718
},
1819
"title": "Search using user query"
1920
},

0 commit comments

Comments
 (0)