From bbd05b870c2c4f91856e04ba5ed15032e6db233d Mon Sep 17 00:00:00 2001 From: Islem Maboud Date: Mon, 5 Jan 2026 12:40:34 +0100 Subject: [PATCH 1/2] feat: add new exclusion fields for the articles endpoint --- perigon/api/v1_api.py | 73 +++++++++++++++++++++++++++++++-- perigon/models/summary_body.py | 5 ++- tests/integration/test_v1api.py | 4 +- 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/perigon/api/v1_api.py b/perigon/api/v1_api.py index 6ae6c66..dc63331 100644 --- a/perigon/api/v1_api.py +++ b/perigon/api/v1_api.py @@ -747,9 +747,13 @@ def search_articles( lon: Optional[float] = None, max_distance: Optional[float] = None, source_city: Optional[List[str]] = None, + exclude_source_city: Optional[List[str]] = None, source_county: Optional[List[str]] = None, + exclude_source_county: Optional[List[str]] = None, source_country: Optional[List[str]] = None, + exclude_source_country: Optional[List[str]] = None, source_state: Optional[List[str]] = None, + exclude_source_state: Optional[List[str]] = None, source_lat: Optional[float] = None, source_lon: Optional[float] = None, source_max_distance: Optional[float] = None, @@ -841,9 +845,13 @@ def search_articles( lon (Optional[float]): Float. Longitude of the center point to search places max_distance (Optional[float]): Float. Maximum distance (in km) from starting point to search articles by tagged places source_city (Optional[List[str]]): String Array. Find articles published by sources that are located within a given city. + exclude_source_city (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified cities. source_county (Optional[List[str]]): String Array. Find articles published by sources that are located within a given county. + exclude_source_county (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified counties. source_country (Optional[List[str]]): String Array. Find articles published by sources that are located within a given country. Must be 2 character country code (i.e. us, gb, etc). + exclude_source_country (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified countries. Must be 2 character country codes (e.g., us, gb). source_state (Optional[List[str]]): String Array. Find articles published by sources that are located within a given state. + exclude_source_state (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified states. source_lat (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_lon (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_max_distance (Optional[float]): Float. Maximum distance from starting point to search articles created by local publications. @@ -996,12 +1004,20 @@ def search_articles( params["maxDistance"] = max_distance if source_city is not None: params["sourceCity"] = source_city + if exclude_source_city is not None: + params["excludeSourceCity"] = exclude_source_city if source_county is not None: params["sourceCounty"] = source_county + if exclude_source_county is not None: + params["excludeSourceCounty"] = exclude_source_county if source_country is not None: params["sourceCountry"] = source_country + if exclude_source_country is not None: + params["excludeSourceCountry"] = exclude_source_country if source_state is not None: params["sourceState"] = source_state + if exclude_source_state is not None: + params["excludeSourceState"] = exclude_source_state if source_lat is not None: params["sourceLat"] = source_lat if source_lon is not None: @@ -1126,9 +1142,13 @@ async def search_articles_async( lon: Optional[float] = None, max_distance: Optional[float] = None, source_city: Optional[List[str]] = None, + exclude_source_city: Optional[List[str]] = None, source_county: Optional[List[str]] = None, + exclude_source_county: Optional[List[str]] = None, source_country: Optional[List[str]] = None, + exclude_source_country: Optional[List[str]] = None, source_state: Optional[List[str]] = None, + exclude_source_state: Optional[List[str]] = None, source_lat: Optional[float] = None, source_lon: Optional[float] = None, source_max_distance: Optional[float] = None, @@ -1220,9 +1240,13 @@ async def search_articles_async( lon (Optional[float]): Float. Longitude of the center point to search places max_distance (Optional[float]): Float. Maximum distance (in km) from starting point to search articles by tagged places source_city (Optional[List[str]]): String Array. Find articles published by sources that are located within a given city. + exclude_source_city (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified cities. source_county (Optional[List[str]]): String Array. Find articles published by sources that are located within a given county. + exclude_source_county (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified counties. source_country (Optional[List[str]]): String Array. Find articles published by sources that are located within a given country. Must be 2 character country code (i.e. us, gb, etc). + exclude_source_country (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified countries. Must be 2 character country codes (e.g., us, gb). source_state (Optional[List[str]]): String Array. Find articles published by sources that are located within a given state. + exclude_source_state (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified states. source_lat (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_lon (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_max_distance (Optional[float]): Float. Maximum distance from starting point to search articles created by local publications. @@ -1374,12 +1398,20 @@ async def search_articles_async( params["maxDistance"] = max_distance if source_city is not None: params["sourceCity"] = source_city + if exclude_source_city is not None: + params["excludeSourceCity"] = exclude_source_city if source_county is not None: params["sourceCounty"] = source_county + if exclude_source_county is not None: + params["excludeSourceCounty"] = exclude_source_county if source_country is not None: params["sourceCountry"] = source_country + if exclude_source_country is not None: + params["excludeSourceCountry"] = exclude_source_country if source_state is not None: params["sourceState"] = source_state + if exclude_source_state is not None: + params["excludeSourceState"] = exclude_source_state if source_lat is not None: params["sourceLat"] = source_lat if source_lon is not None: @@ -1904,7 +1936,7 @@ def search_sources( show_num_results: Optional[bool] = None, ) -> SourceSearchResult: """ - Search and filter the 142,000+ media sources available via the Perigon API. The result includes a list of individual media sources that were matched to your specific criteria. + Search and filter the 200,000+ media sources available via the Perigon API. The result includes a list of individual media sources that were matched to your specific criteria. Args: domain (Optional[List[str]]): String Array. Filter by specific publisher domains or subdomains. Supports wildcards (* and ?) for pattern matching (e.g., *.cnn.com, us?.nytimes.com). Multiple values create an OR filter. @@ -2023,7 +2055,7 @@ async def search_sources_async( show_num_results: Optional[bool] = None, ) -> SourceSearchResult: """ - Async variant of search_sources. Search and filter the 142,000+ media sources available via the Perigon API. The result includes a list of individual media sources that were matched to your specific criteria. + Async variant of search_sources. Search and filter the 200,000+ media sources available via the Perigon API. The result includes a list of individual media sources that were matched to your specific criteria. Args: domain (Optional[List[str]]): String Array. Filter by specific publisher domains or subdomains. Supports wildcards (* and ?) for pattern matching (e.g., *.cnn.com, us?.nytimes.com). Multiple values create an OR filter. @@ -2602,9 +2634,13 @@ def search_summarizer( lon: Optional[float] = None, max_distance: Optional[float] = None, source_city: Optional[List[str]] = None, + exclude_source_city: Optional[List[str]] = None, source_county: Optional[List[str]] = None, + exclude_source_county: Optional[List[str]] = None, source_country: Optional[List[str]] = None, + exclude_source_country: Optional[List[str]] = None, source_state: Optional[List[str]] = None, + exclude_source_state: Optional[List[str]] = None, source_lat: Optional[float] = None, source_lon: Optional[float] = None, source_max_distance: Optional[float] = None, @@ -2697,9 +2733,13 @@ def search_summarizer( lon (Optional[float]): Float. Longitude of the center point to search places max_distance (Optional[float]): Float. Maximum distance (in km) from starting point to search articles by tagged places source_city (Optional[List[str]]): String Array. Find articles published by sources that are located within a given city. + exclude_source_city (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified cities. source_county (Optional[List[str]]): String Array. Find articles published by sources that are located within a given county. + exclude_source_county (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified counties. source_country (Optional[List[str]]): String Array. Find articles published by sources that are located within a given country. Must be 2 character country code (i.e. us, gb, etc). + exclude_source_country (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified countries. Must be 2 character country codes (e.g., us, gb). source_state (Optional[List[str]]): String Array. Find articles published by sources that are located within a given state. + exclude_source_state (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified states. source_lat (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_lon (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_max_distance (Optional[float]): Float. Maximum distance from starting point to search articles created by local publications. @@ -2852,12 +2892,20 @@ def search_summarizer( params["maxDistance"] = max_distance if source_city is not None: params["sourceCity"] = source_city + if exclude_source_city is not None: + params["excludeSourceCity"] = exclude_source_city if source_county is not None: params["sourceCounty"] = source_county + if exclude_source_county is not None: + params["excludeSourceCounty"] = exclude_source_county if source_country is not None: params["sourceCountry"] = source_country + if exclude_source_country is not None: + params["excludeSourceCountry"] = exclude_source_country if source_state is not None: params["sourceState"] = source_state + if exclude_source_state is not None: + params["excludeSourceState"] = exclude_source_state if source_lat is not None: params["sourceLat"] = source_lat if source_lon is not None: @@ -2988,9 +3036,13 @@ async def search_summarizer_async( lon: Optional[float] = None, max_distance: Optional[float] = None, source_city: Optional[List[str]] = None, + exclude_source_city: Optional[List[str]] = None, source_county: Optional[List[str]] = None, + exclude_source_county: Optional[List[str]] = None, source_country: Optional[List[str]] = None, + exclude_source_country: Optional[List[str]] = None, source_state: Optional[List[str]] = None, + exclude_source_state: Optional[List[str]] = None, source_lat: Optional[float] = None, source_lon: Optional[float] = None, source_max_distance: Optional[float] = None, @@ -3083,9 +3135,13 @@ async def search_summarizer_async( lon (Optional[float]): Float. Longitude of the center point to search places max_distance (Optional[float]): Float. Maximum distance (in km) from starting point to search articles by tagged places source_city (Optional[List[str]]): String Array. Find articles published by sources that are located within a given city. + exclude_source_city (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified cities. source_county (Optional[List[str]]): String Array. Find articles published by sources that are located within a given county. + exclude_source_county (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified counties. source_country (Optional[List[str]]): String Array. Find articles published by sources that are located within a given country. Must be 2 character country code (i.e. us, gb, etc). + exclude_source_country (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified countries. Must be 2 character country codes (e.g., us, gb). source_state (Optional[List[str]]): String Array. Find articles published by sources that are located within a given state. + exclude_source_state (Optional[List[str]]): String Array. Excludes articles published by sources that are located within the specified states. source_lat (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_lon (Optional[float]): Float. Latitude of the center point to search articles created by local publications. source_max_distance (Optional[float]): Float. Maximum distance from starting point to search articles created by local publications. @@ -3237,12 +3293,20 @@ async def search_summarizer_async( params["maxDistance"] = max_distance if source_city is not None: params["sourceCity"] = source_city + if exclude_source_city is not None: + params["excludeSourceCity"] = exclude_source_city if source_county is not None: params["sourceCounty"] = source_county + if exclude_source_county is not None: + params["excludeSourceCounty"] = exclude_source_county if source_country is not None: params["sourceCountry"] = source_country + if exclude_source_country is not None: + params["excludeSourceCountry"] = exclude_source_country if source_state is not None: params["sourceState"] = source_state + if exclude_source_state is not None: + params["excludeSourceState"] = exclude_source_state if source_lat is not None: params["sourceLat"] = source_lat if source_lon is not None: @@ -3304,7 +3368,10 @@ async def search_summarizer_async( params = _normalise_query(params) resp = await self.api_client.request_async( - "POST", path, params=params, json=summary_body.model_dump(by_alias=True) + "POST", + path, + params=params, + json=summary_body.model_dump(by_alias=True, exclude_none=True), ) resp.raise_for_status() return SummarySearchResult.model_validate(resp.json()) diff --git a/perigon/models/summary_body.py b/perigon/models/summary_body.py index 2874007..5ef7403 100644 --- a/perigon/models/summary_body.py +++ b/perigon/models/summary_body.py @@ -57,7 +57,8 @@ class SummaryBody(BaseModel): description="Method for selecting articles: ARTICLES (include all matches) or CLUSTERS (one per cluster).", ) model: Optional[StrictStr] = Field( - default="gpt-4.1", description="The underlying LLM model to use for generation." + default="gpt-4o-mini", + description="The underlying LLM model to use for generation.", ) temperature: Optional[ Union[ @@ -264,7 +265,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: obj.get("method") if obj.get("method") is not None else "ARTICLES" ), "model": ( - obj.get("model") if obj.get("model") is not None else "gpt-4.1" + obj.get("model") if obj.get("model") is not None else "gpt-4o-mini" ), "temperature": ( obj.get("temperature") diff --git a/tests/integration/test_v1api.py b/tests/integration/test_v1api.py index 54068d2..8691827 100644 --- a/tests/integration/test_v1api.py +++ b/tests/integration/test_v1api.py @@ -145,8 +145,8 @@ def test_vector_search(api: V1Api): def test_summarizer(api: V1Api): - # Use gpt-4o-mini which is more stable and widely supported - summary_body = SummaryBody() + # Uses gpt-4o-mini by default which is more stable and widely supported + summary_body = SummaryBody(model="gpt-4o-mini") result = api.search_summarizer( summary_body=summary_body, q="AI", From a2749710a6f59fb1e4c9f639c752fa5a23c9ce7c Mon Sep 17 00:00:00 2001 From: Islem Maboud Date: Mon, 5 Jan 2026 12:46:53 +0100 Subject: [PATCH 2/2] fix: the api.mustache template to always include exclude_none=True for the client.request --- perigon/api/v1_api.py | 8 ++++---- perigon/models/summary_body.py | 5 ++--- templates/api.mustache | 6 ++++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/perigon/api/v1_api.py b/perigon/api/v1_api.py index dc63331..0469d70 100644 --- a/perigon/api/v1_api.py +++ b/perigon/api/v1_api.py @@ -3740,7 +3740,7 @@ def vector_search_articles( "POST", path, params=params, - json=article_search_params.model_dump(by_alias=True), + json=article_search_params.model_dump(by_alias=True, exclude_none=True), ) resp.raise_for_status() return ArticlesVectorSearchResult.model_validate(resp.json()) @@ -3768,7 +3768,7 @@ async def vector_search_articles_async( "POST", path, params=params, - json=article_search_params.model_dump(by_alias=True), + json=article_search_params.model_dump(by_alias=True, exclude_none=True), ) resp.raise_for_status() return ArticlesVectorSearchResult.model_validate(resp.json()) @@ -3797,7 +3797,7 @@ def vector_search_wikipedia( "POST", path, params=params, - json=wikipedia_search_params.model_dump(by_alias=True), + json=wikipedia_search_params.model_dump(by_alias=True, exclude_none=True), ) resp.raise_for_status() return WikipediaVectorSearchResult.model_validate(resp.json()) @@ -3825,7 +3825,7 @@ async def vector_search_wikipedia_async( "POST", path, params=params, - json=wikipedia_search_params.model_dump(by_alias=True), + json=wikipedia_search_params.model_dump(by_alias=True, exclude_none=True), ) resp.raise_for_status() return WikipediaVectorSearchResult.model_validate(resp.json()) diff --git a/perigon/models/summary_body.py b/perigon/models/summary_body.py index 5ef7403..2874007 100644 --- a/perigon/models/summary_body.py +++ b/perigon/models/summary_body.py @@ -57,8 +57,7 @@ class SummaryBody(BaseModel): description="Method for selecting articles: ARTICLES (include all matches) or CLUSTERS (one per cluster).", ) model: Optional[StrictStr] = Field( - default="gpt-4o-mini", - description="The underlying LLM model to use for generation.", + default="gpt-4.1", description="The underlying LLM model to use for generation." ) temperature: Optional[ Union[ @@ -265,7 +264,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: obj.get("method") if obj.get("method") is not None else "ARTICLES" ), "model": ( - obj.get("model") if obj.get("model") is not None else "gpt-4o-mini" + obj.get("model") if obj.get("model") is not None else "gpt-4.1" ), "temperature": ( obj.get("temperature") diff --git a/templates/api.mustache b/templates/api.mustache index c6f7898..b84a60c 100644 --- a/templates/api.mustache +++ b/templates/api.mustache @@ -109,7 +109,8 @@ class {{classname}}: resp = self.api_client.request( "{{httpMethod}}", path, - params=params{{#bodyParam}}, json={{paramName}}.model_dump(by_alias=True){{/bodyParam}} + params=params{{#bodyParam}}, + json={{paramName}}.model_dump(by_alias=True, exclude_none=True),{{/bodyParam}} ) resp.raise_for_status() {{#returnType}} @@ -157,7 +158,8 @@ class {{classname}}: resp = await self.api_client.request_async( "{{httpMethod}}", path, - params=params{{#bodyParam}}, json={{paramName}}.model_dump(by_alias=True){{/bodyParam}} + params=params{{#bodyParam}}, + json={{paramName}}.model_dump(by_alias=True, exclude_none=True),{{/bodyParam}} ) resp.raise_for_status() {{#returnType}}