cuery.seo.geo#

Tools to apply SEO to LLM responses.

Attributes#

Classes#

Brands

Base class for all response models.

GeoConfig

Configuration for GEO analysis (LLM brand mentions and ranks).

Functions#

normalize_brand(url)

Extract the brand name (domain) from a URL.

find_competitors([brands, sector, market, max_count, ...])

Find a list of competitor brands using LLM with live search.

generate_prompts(n[, intents, language, sector, ...])

Generate N realistic commercial/consumer search queries using an LLM meta-instruction.

query_ais(prompts, models[, use_search, ...])

Run a list of prompts through a list of models and return a combined DataFrame.

token_rank_in_text(text, tokens[, whole_word])

Find mention of first(!) token in text, returning list of (token, rank) tuples.

token_pos_in_list(items, tokens[, key, whole_word, ...])

Find mention of first token in list of strings, returning list of (token, position) tuples.

add_brand_ranks(search_result, brands)

Add brand rank columns to a search result DataFrame.

in_strings(values, lst)

Check if any of values is among list items.

pos_in_strings(values, lst)

Find first position of any of values among list items. To Do: optimize.

in_dicts(values, lst, key)

Check if any of values is in any dict under the specified key.

pos_in_dicts(values, lst, key)

Find first position of any of values in any dict under the specified key

summarize_ranks(df, own, competitors, models)

Summarize brand ranks in a results DataFrame.

analyse(cfg[, progress_callback])

Run a list of prompts through a list of models and return a combined DataFrame.

Module Contents#

cuery.seo.geo.DEFAULT_MODELS = ['openai/gpt-4.1-mini', 'google/gemini-2.5-flash']#
class cuery.seo.geo.Brands(/, **data)#

Bases: cuery.Response

Base class for all response models.

Adds functionality to cache the raw response from the API call, calculate token usage, and to create a fallback instance, which by default is an empty model with all fields set to None.

Also implements rich’s console protocol for pretty printing of the model’s fields, and allows inspection of the model’s fields to determine if it has a single multivalued field (a list) or not (which can be used to automatically “explode” items into DataFrame rows e.g.).

Parameters:

data (Any)

names: list[str]#

List of brand names.

cuery.seo.geo.normalize_brand(url)#

Extract the brand name (domain) from a URL.

Parameters:

url (str)

Return type:

str

async cuery.seo.geo.find_competitors(brands=None, sector=None, market=None, max_count=5, model='openai/gpt-4.1', known=None)#

Find a list of competitor brands using LLM with live search.

Parameters:
  • brands (list[str] | None)

  • sector (str | None)

  • market (str | None)

  • max_count (int)

  • model (str)

  • known (list[str] | None)

Return type:

list[str]

async cuery.seo.geo.generate_prompts(n, intents=None, language='English', sector=None, market=None, brands=None, include_brands='sometimes', seed_prompts=None)#

Generate N realistic commercial/consumer search queries using an LLM meta-instruction.

Parameters:
  • n (int)

  • intents (list[str] | None)

  • language (str)

  • sector (str | None)

  • market (str | None)

  • brands (list[str] | None)

  • include_brands (Literal['never', 'sometimes', 'always'])

  • seed_prompts (list[str] | None)

Return type:

list[str]

async cuery.seo.geo.query_ais(prompts, models, use_search=True, search_country=None, progress_callback=None, to_pandas=True)#

Run a list of prompts through a list of models and return a combined DataFrame.

Gathers all model and prompt comnbinations concurrently.

Parameters:
  • prompts (list[str])

  • models (list[str])

  • use_search (bool)

  • search_country (str | None)

  • progress_callback (collections.abc.Coroutine | None)

  • to_pandas (bool)

Return type:

pandas.DataFrame | cuery.ResponseSet

cuery.seo.geo.token_rank_in_text(text, tokens, whole_word=True)#

Find mention of first(!) token in text, returning list of (token, rank) tuples.

Parameters:
  • text (str)

  • tokens (list[str])

  • whole_word (bool)

Return type:

list[str] or None

cuery.seo.geo.token_pos_in_list(items, tokens, key='url', whole_word=True, include_none=False)#

Find mention of first token in list of strings, returning list of (token, position) tuples.

Parameters:
  • items (list[dict])

  • tokens (list[str])

  • key (str)

  • whole_word (bool)

  • include_none (bool)

Return type:

list[dict] | None

cuery.seo.geo.add_brand_ranks(search_result, brands)#

Add brand rank columns to a search result DataFrame.

Parameters:
  • search_result (pandas.DataFrame)

  • brands (list[str])

Return type:

pandas.DataFrame

cuery.seo.geo.in_strings(values, lst)#

Check if any of values is among list items.

Parameters:
  • values (list[str])

  • lst (list[str] | None)

Return type:

bool

cuery.seo.geo.pos_in_strings(values, lst)#

Find first position of any of values among list items. To Do: optimize.

Parameters:
  • values (list[str])

  • lst (list[str] | None)

Return type:

int | None

cuery.seo.geo.in_dicts(values, lst, key)#

Check if any of values is in any dict under the specified key.

Parameters:
  • values (list)

  • lst (list[dict] | None)

  • key (str)

Return type:

bool

cuery.seo.geo.pos_in_dicts(values, lst, key)#

Find first position of any of values in any dict under the specified key

Parameters:
  • values (list)

  • lst (list[dict] | None)

  • key (str)

Return type:

int | None

cuery.seo.geo.summarize_ranks(df, own, competitors, models)#

Summarize brand ranks in a results DataFrame.

Parameters:
  • df (pandas.DataFrame)

  • own (list[str])

  • competitors (list[str])

  • models (list[str])

Return type:

pandas.DataFrame

class cuery.seo.geo.GeoConfig(/, **data)#

Bases: cuery.utils.Configurable

Configuration for GEO analysis (LLM brand mentions and ranks).

Parameters:

data (Any)

brands: list[str] | None = None#

List of own(!) brand names or URLs.

models: list[str] | None = None#

List of LLM models to evaluate.

prompts: list[str] | None = None#

List of seed prompts.

prompts_max: int = 20#

Maximum number of prompts to generate using LLM.

prompt_intents: list[str] | None = None#

List of user intents to focus on in generated prompts.

prompt_language: str = 'English'#

Language for generated prompts.

brands_in_prompt: Literal['never', 'sometimes', 'always'] = 'never'#

Whether to include brand names in generated prompts.

competitors: list[str] | None = None#

List of seed brand names or URLs.

competitors_max: int = 10#

Maximum number of competitor brands to identify using LLM.

competitors_model: str = 'openai/gpt-4.1'#

LLM model to use for competitor brand identification.

sector: str | None = None#

Sector to focus on.

market: str | None = None#

Market to focus on.

Whether to enable web/live search when evaluating LLMs.

search_country: str | None = None#

Country code for search localisation, e.g. ‘us’, ‘uk’, ‘de ‘.

check_params()#
async cuery.seo.geo.analyse(cfg, progress_callback=None)#

Run a list of prompts through a list of models and return a combined DataFrame.

Parameters:
  • cfg (GeoConfig)

  • progress_callback (collections.abc.Coroutine | None)

Return type:

pandas.DataFrame | Any