Spaces:
Running
Running
| from fastapi.testclient import TestClient | |
| from app.main import create_app | |
| def test_places_search_endpoint() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/places/search", | |
| json={ | |
| "query": "lugares tranquilos para cenar", | |
| "city": "Tuxtla Gutierrez", | |
| "filters": {"is_active": True}, | |
| "limit": 3, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["query"] == "lugares tranquilos para cenar" | |
| assert payload["places"] | |
| assert payload["metrics"]["engine"] == "fasttext_mean_embeddings" | |
| assert payload["metrics"]["candidate_retrieval"] == "mock_embeddings" | |
| assert payload["metrics"]["score_metric"] == "cosine_similarity" | |
| assert payload["metrics"]["ranking_parameters"] == {"dimension": 16.0} | |
| assert payload["metrics"]["field_weights"] == { | |
| "tags": 6, | |
| "category": 4, | |
| "description": 3, | |
| "name": 1, | |
| } | |
| assert payload["metrics"]["returned_count"] == len(payload["places"]) | |
| assert payload["metrics"]["max_score"] >= payload["metrics"]["mean_score"] | |
| def test_places_search_metrics_endpoint() -> None: | |
| client = TestClient(create_app()) | |
| response = client.get("/places/search/metrics?k=3") | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["engine"] == "bm25" | |
| assert payload["benchmark"] == "built_in_places_v3_bm25" | |
| assert payload["qrels_source"] == "predefined_graded_qrels" | |
| assert payload["query_count"] == 10 | |
| assert payload["metric_definitions"]["precision_at_k"]["label"] == "Precision@3" | |
| assert payload["metric_definitions"]["recall_at_k"]["label"] == "Recall@3" | |
| assert payload["metric_definitions"]["mrr"]["label"] == "MRR" | |
| assert payload["metric_definitions"]["map"]["label"] == "MAP" | |
| assert payload["metric_definitions"]["ndcg_at_k"]["label"] == "nDCG@3" | |
| assert payload["recommended_metric"]["key"] == "ndcg_at_k" | |
| assert payload["recommended_metric"]["label"] == "nDCG@3" | |
| assert payload["recommended_metric"]["value"] == payload["aggregate"]["ndcg_at_k"] | |
| assert all( | |
| 0.0 <= payload["aggregate"][metric] <= 1.0 | |
| for metric in ["precision_at_k", "recall_at_k", "mrr", "map", "ndcg_at_k"] | |
| ) | |
| def test_places_search_metrics_post_requires_no_body() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post("/places/search/metrics?k=2") | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["k"] == 2 | |
| assert payload["query_count"] == 10 | |
| def test_places_chat_endpoint_returns_trace_and_structured_places() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/places/chat", | |
| json={ | |
| "message": "quiero una cena tranquila con mi pareja", | |
| "city": "Tuxtla Gutierrez", | |
| "filters": {"occasion": "pareja", "is_active": True}, | |
| "limit": 3, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["response_id"].startswith("resp_") | |
| assert payload["nlp_trace_id"].startswith("trace_") | |
| assert payload["message"] | |
| assert payload["places"] | |
| assert payload["metadata"]["places_used_as_context"] | |
| def test_places_recommendations_returns_llm_message_and_semantic_metadata() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/places/recommendations", | |
| json={ | |
| "query": "quiero ver el atardecer y tomar fotos", | |
| "city": "Tuxtla Gutierrez", | |
| "filters": {"is_active": True}, | |
| "limit": 3, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["message"] | |
| assert payload["places"] | |
| assert payload["metrics"]["engine"] == "fasttext_mean_embeddings" | |
| assert payload["metrics"]["score_metric"] == "cosine_similarity" | |
| assert payload["metrics"]["returned_count"] == len(payload["places"]) | |
| assert payload["metrics"]["candidate_retrieval"] == "mock_embeddings" | |
| assert payload["metrics"]["query_token_count"] > 0 | |
| assert payload["metrics"]["matched_query_token_count"] > 0 | |
| assert payload["metrics"]["scope"] == "current_query" | |
| assert payload["metrics"]["ground_truth_available"] is False | |
| assert "evaluation_metrics" not in payload | |
| assert payload["metadata"]["ranking"] == "fasttext_mean_embeddings" | |
| assert payload["metadata"]["response_mode"] == "confident" | |
| assert payload["metadata"]["used_llm"] is True | |
| def test_places_recommendations_returns_no_places_without_candidates() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/places/recommendations", | |
| json={ | |
| "query": "xqzv blorf 998zz", | |
| "city": "Ciudad inexistente", | |
| "filters": {"is_active": True}, | |
| "limit": 3, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["places"] == [] | |
| assert payload["metrics"]["max_score"] == 0.0 | |
| assert payload["metrics"]["returned_count"] == 0 | |
| assert payload["metrics"]["match_quality"] == "no_match" | |
| assert payload["metadata"]["response_mode"] == "no_match" | |
| assert payload["message"] | |
| def test_places_search_rejects_incomplete_coordinates() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/places/search", | |
| json={ | |
| "query": "parque cercano", | |
| "lat": 16.7531, | |
| "limit": 5, | |
| }, | |
| ) | |
| assert response.status_code == 422 | |
| def test_posts_recommendations_endpoint() -> None: | |
| client = TestClient(create_app()) | |
| response = client.post( | |
| "/posts/recommendations", | |
| json={ | |
| "query": "ideas para fotos con amigos", | |
| "city": "Tuxtla Gutierrez", | |
| "limit": 3, | |
| }, | |
| ) | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["posts"] | |
| assert payload["metadata"]["computed_clusters_during_request"] is False | |
| def test_posts_clusters_endpoint() -> None: | |
| client = TestClient(create_app()) | |
| response = client.get("/posts/clusters") | |
| assert response.status_code == 200 | |
| payload = response.json() | |
| assert payload["clusters"] | |
| assert payload["metadata"]["computed_during_request"] is False | |