Skip to content

Display filteredPool when AI search query is absent#4791

Open
ellenmuller wants to merge 10 commits into
mainfrom
em-handle-ai-only-filters
Open

Display filteredPool when AI search query is absent#4791
ellenmuller wants to merge 10 commits into
mainfrom
em-handle-ai-only-filters

Conversation

@ellenmuller

@ellenmuller ellenmuller commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What does this change?

When AI search mode has no ranking query, the UI previously showed two different empty states — one for "no query at all" and one for "filters but no query". This unifies them into a single state that tells the user how many images are in the pool a query would rank over.

  • Backend: The no-query AI case (with or without filters) now returns filterPoolCounts.filteredPool (the size of the pool a query would rank over) instead of erroring or returning an empty response. Consolidated onto the existing countMatchingFilterWithExtraCounts,
  • Frontend: Combined the two empty states into one message: "N images match your filters. Add a query to see the best 200." The results count below the search bar now also shows the pool size (N matches) in this state.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

@ellenmuller ellenmuller added the feature Departmental tracking: work on a new feature label Jul 2, 2026
@ellenmuller ellenmuller changed the title vibe coded mock up of displaying effect of filters on ai search Display filteredPool when AI search query is absent Jul 8, 2026
@ellenmuller ellenmuller marked this pull request as ready for review July 9, 2026 13:51
@ellenmuller ellenmuller requested a review from a team as a code owner July 9, 2026 13:51

@joelochlann joelochlann left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Functionality looks great 👌

Only UI thing that surprised me was: I did actually expect the badges (GNM-owned, agency picks) even in the filters-only mode, so that it's literally just the "Best 200 of" popping in when you add a query, i.e.

1,178,998 matches [4,705 GNM-owned] [5,960 agency picks]

to

Best 200 of 1,178,998 matches [4,705 GNM-owned] [5,960 agency picks]

But it doesn't matter much so it's only worth changing if it simplifies code or if someone else agrees with me.

On the code side, no blockers to this PR, but I'd definitely suggest having a go at simplifying the logic for distinguishing "normal AI search" from "filters-only AI search" from "an actual error", starting with #4752 (comment) which I think you'll find satisfying and will simplify some boilerplate in the tests. If anything's unclear about that let me know and we could do a quick half an hour's pairing to align

image-results-count">
<span ng-if="ctrl.isAiSearch">Best {{ctrl.aiResultsShown | toLocaleString}} of {{ctrl.totalResults | toLocaleString}} matches</span>
<span ng-if="! ctrl.isAiSearch">{{ctrl.totalResults | toLocaleString}} matches</span>
<span ng-if="ctrl.isAiSearch && !ctrl.filtersOnlyAiSearch">Best {{ctrl.aiResultsShown | toLocaleString}} of {{ctrl.totalResults | toLocaleString}} matches</span>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be clearer to wrap in a <span ng-if="ctrl.isAiSearch> since they both contain ctrl.isAiSearch condition?

// prompt the user to add a query.
case _ =>
emptyAiSearchResponse
filtersOnlyAiSearchResponse(_searchParams)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but I'm pretty sure there's an opportunity to simplify this, especially if you start by implementing this suggestion: #4752 (comment)

Basically if you make AiQueryParts.from do all the parsing and error handling, it will either give you a Left containing the reason why it can't do the search, or a Right with the parsed stuff ready to do a query. Then you should be able to call filtersOnlyAiSearchResponse in just one place, instead of three.

You could also make the Left be a union type (a sealed trait with some case objects) so you could pattern match on it to distinguish the expected cases you want to handle with your filters-only search, from the ones that are genuine error conditions.

case Left(_) =>
if (params.aiQueryParts.hasFilterConditions) {
logger.info(logMarker, s"AI search with only filters and no query to rank by; returning filter pool counts: ${params.aiQueryParts.filterConditions}")
filtersOnlyAiSearchResponse(params)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both these if/else branches contain filtersOnlyAiSearchResponse, maybe best to pull out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Departmental tracking: work on a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants