mirror of
https://github.com/deepset-ai/haystack.git
synced 2025-08-19 14:08:19 +00:00
Fix bug on REST API for queries on empty document stores (#2161)
* Handle no answers and no documents scenarios in '_process_request' * Fix tests * Change return type in '_process_request' * Return to use dicts Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
00795bd71e
commit
13a9bc6a99
@ -755,8 +755,7 @@
|
|||||||
"QueryResponse": {
|
"QueryResponse": {
|
||||||
"title": "QueryResponse",
|
"title": "QueryResponse",
|
||||||
"required": [
|
"required": [
|
||||||
"query",
|
"query"
|
||||||
"answers"
|
|
||||||
],
|
],
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -769,14 +768,16 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/AnswerSerialized"
|
"$ref": "#/components/schemas/AnswerSerialized"
|
||||||
}
|
},
|
||||||
|
"default": []
|
||||||
},
|
},
|
||||||
"documents": {
|
"documents": {
|
||||||
"title": "Documents",
|
"title": "Documents",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/components/schemas/DocumentSerialized"
|
"$ref": "#/components/schemas/DocumentSerialized"
|
||||||
}
|
},
|
||||||
|
"default": []
|
||||||
},
|
},
|
||||||
"_debug": {
|
"_debug": {
|
||||||
"title": " Debug",
|
"title": " Debug",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
from typing import Dict, Any
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
@ -65,7 +67,7 @@ def query(request: QueryRequest):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _process_request(pipeline, request) -> QueryResponse:
|
def _process_request(pipeline, request) -> Dict[str, Any]:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
params = request.params or {}
|
params = request.params or {}
|
||||||
@ -75,22 +77,26 @@ def _process_request(pipeline, request) -> QueryResponse:
|
|||||||
params["filters"] = _format_filters(params["filters"])
|
params["filters"] = _format_filters(params["filters"])
|
||||||
|
|
||||||
# format targeted node filters (e.g. "params": {"Retriever": {"filters": {"value"}}})
|
# format targeted node filters (e.g. "params": {"Retriever": {"filters": {"value"}}})
|
||||||
for key, value in params.items():
|
for key in params.keys():
|
||||||
if "filters" in params[key].keys():
|
if "filters" in params[key].keys():
|
||||||
params[key]["filters"] = _format_filters(params[key]["filters"])
|
params[key]["filters"] = _format_filters(params[key]["filters"])
|
||||||
|
|
||||||
result = pipeline.run(query=request.query, params=params, debug=request.debug)
|
result = pipeline.run(query=request.query, params=params, debug=request.debug)
|
||||||
|
|
||||||
|
# Ensure answers and documents exist, even if they're empty lists
|
||||||
|
if not "documents" in result:
|
||||||
|
result["documents"] = []
|
||||||
|
if not "answers" in result:
|
||||||
|
result["answers"] = []
|
||||||
|
|
||||||
# if any of the documents contains an embedding as an ndarray the latter needs to be converted to list of float
|
# if any of the documents contains an embedding as an ndarray the latter needs to be converted to list of float
|
||||||
for document in result["documents"] or []:
|
for document in result["documents"]:
|
||||||
if isinstance(document.embedding, ndarray):
|
if isinstance(document.embedding, ndarray):
|
||||||
document.embedding = document.embedding.tolist()
|
document.embedding = document.embedding.tolist()
|
||||||
|
|
||||||
end_time = time.time()
|
|
||||||
logger.info(
|
logger.info(
|
||||||
json.dumps({"request": request, "response": result, "time": f"{(end_time - start_time):.2f}"}, default=str)
|
json.dumps({"request": request, "response": result, "time": f"{(time.time() - start_time):.2f}"}, default=str)
|
||||||
)
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,6 +66,6 @@ class CreateLabelSerialized(BaseModel):
|
|||||||
|
|
||||||
class QueryResponse(BaseModel):
|
class QueryResponse(BaseModel):
|
||||||
query: str
|
query: str
|
||||||
answers: List[AnswerSerialized]
|
answers: List[AnswerSerialized] = []
|
||||||
documents: Optional[List[DocumentSerialized]]
|
documents: List[DocumentSerialized] = []
|
||||||
debug: Optional[Dict] = Field(None, alias="_debug")
|
debug: Optional[Dict] = Field(None, alias="_debug")
|
||||||
|
@ -225,6 +225,23 @@ def test_query_with_invalid_filter(populated_client: TestClient):
|
|||||||
assert len(response_json["answers"]) == 0
|
assert len(response_json["answers"]) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_with_no_documents_and_no_answers():
|
||||||
|
os.environ["PIPELINE_YAML_PATH"] = str(
|
||||||
|
(Path(__file__).parent / "samples" / "pipeline" / "test_pipeline.yaml").absolute()
|
||||||
|
)
|
||||||
|
os.environ["INDEXING_PIPELINE_NAME"] = "indexing_text_pipeline"
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
# Clean up to make sure the docstore is empty
|
||||||
|
client.post(url="/documents/delete_by_filters", data='{"filters": {}}')
|
||||||
|
query = {"query": "Who made the PDF specification?"}
|
||||||
|
response = client.post(url="/query", json=query)
|
||||||
|
assert 200 == response.status_code
|
||||||
|
response_json = response.json()
|
||||||
|
assert response_json["documents"] == []
|
||||||
|
assert response_json["answers"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_write_feedback(populated_client: TestClient):
|
def test_write_feedback(populated_client: TestClient):
|
||||||
response = populated_client.post(url="/feedback", json=FEEDBACK)
|
response = populated_client.post(url="/feedback", json=FEEDBACK)
|
||||||
assert 200 == response.status_code
|
assert 200 == response.status_code
|
||||||
|
Loading…
x
Reference in New Issue
Block a user