ai_marketplace_monitor package

Submodules

ai_marketplace_monitor.ai module

class ai_marketplace_monitor.ai.AIBackend(config: AIConfig, logger: Logger | None = None)[source]

Bases: Generic[TAIConfig]

connect() None[source]
evaluate(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig) AIResponse[source]
classmethod get_config(**kwargs: Any) TAIConfig[source]
get_prompt(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig) str[source]
class ai_marketplace_monitor.ai.AIConfig(name: str, enabled: bool | None = None, api_key: str | None = None, provider: str | None = None, model: str | None = None, base_url: str | None = None, max_retries: int = 10, timeout: int | None = None)[source]

Bases: BaseConfig

api_key: str | None = None
base_url: str | None = None
handle_api_key() None[source]
handle_max_retries() None[source]
handle_provider() None[source]
handle_timeout() None[source]
max_retries: int = 10
model: str | None = None
provider: str | None = None
timeout: int | None = None
class ai_marketplace_monitor.ai.AIResponse(score: int, comment: str, name: str = '')[source]

Bases: object

NOT_EVALUATED: ClassVar = 'Not evaluated by AI'
comment: str
property conclusion: str
classmethod from_cache(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig, local_cache: Cache | None = None) AIResponse | None[source]
name: str = ''
score: int
property stars: str
property style: str
to_cache(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig, local_cache: Cache | None = None) None[source]
class ai_marketplace_monitor.ai.AIServiceProvider(*values)[source]

Bases: Enum

ANTHROPIC = 'Anthropic'
DEEPSEEK = 'DeepSeek'
OLLAMA = 'Ollama'
OPENAI = 'OpenAI'
class ai_marketplace_monitor.ai.AnthropicBackend(config: AIConfig, logger: Logger | None = None)[source]

Bases: AIBackend

connect() None[source]
default_model = 'claude-sonnet-4-20250514'
evaluate(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig) AIResponse[source]
classmethod get_config(**kwargs: Any) AnthropicConfig[source]
class ai_marketplace_monitor.ai.AnthropicConfig(name: str, enabled: bool | None = None, api_key: str | None = None, provider: str | None = None, model: str | None = None, base_url: str | None = None, max_retries: int = 10, timeout: int | None = None)[source]

Bases: AIConfig

handle_api_key() None[source]
class ai_marketplace_monitor.ai.DeekSeekConfig(name: str, enabled: bool | None = None, api_key: str | None = None, provider: str | None = None, model: str | None = None, base_url: str | None = None, max_retries: int = 10, timeout: int | None = None)[source]

Bases: OpenAIConfig

class ai_marketplace_monitor.ai.DeepSeekBackend(config: AIConfig, logger: Logger | None = None)[source]

Bases: OpenAIBackend

base_url: str | None = 'https://api.deepseek.com'
default_model = 'deepseek-chat'
classmethod get_config(**kwargs: Any) DeekSeekConfig[source]
class ai_marketplace_monitor.ai.OllamaBackend(config: AIConfig, logger: Logger | None = None)[source]

Bases: OpenAIBackend

default_model = 'deepseek-r1:14b'
classmethod get_config(**kwargs: Any) OllamaConfig[source]
class ai_marketplace_monitor.ai.OllamaConfig(name: str, enabled: bool | None = None, api_key: str | None = 'ollama', provider: str | None = None, model: str | None = None, base_url: str | None = None, max_retries: int = 10, timeout: int | None = None)[source]

Bases: OpenAIConfig

api_key: str | None = 'ollama'
handle_base_url() None[source]
handle_model() None[source]
class ai_marketplace_monitor.ai.OpenAIBackend(config: AIConfig, logger: Logger | None = None)[source]

Bases: AIBackend

base_url: str | None = None
connect() None[source]
default_model = 'gpt-4o'
evaluate(listing: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig) AIResponse[source]
classmethod get_config(**kwargs: Any) OpenAIConfig[source]
class ai_marketplace_monitor.ai.OpenAIConfig(name: str, enabled: bool | None = None, api_key: str | None = None, provider: str | None = None, model: str | None = None, base_url: str | None = None, max_retries: int = 10, timeout: int | None = None)[source]

Bases: AIConfig

handle_api_key() None[source]

ai_marketplace_monitor.cli module

Console script for ai-marketplace-monitor.

ai_marketplace_monitor.cli.main(config_files: Path] | None, <typer.models.OptionInfo object at 0x7d8f0ac39b20>]=None, headless: Annotated[bool | None, <typer.models.OptionInfo object at 0x7d8f0ac39bb0>]=False, clear_cache: Annotated[str | None, <typer.models.OptionInfo object at 0x7d8f0ac39c40>]=None, verbose: Annotated[bool | None, <typer.models.OptionInfo object at 0x7d8f0ac39cd0>]=False, items: List[str] | None, <typer.models.OptionInfo object at 0x7d8f0ac39d60>]=None, for_item: Annotated[str | None, <typer.models.OptionInfo object at 0x7d8f0ac39df0>]=None, webui: Annotated[bool, <typer.models.OptionInfo object at 0x7d8f0ac39e80>]=True, webui_host: Annotated[str, <typer.models.OptionInfo object at 0x7d8f0ac39f10>]='127.0.0.1', webui_port: Annotated[int, <typer.models.OptionInfo object at 0x7d8f0ac39fa0>]=8467, webui_log_retention: Annotated[int, <typer.models.OptionInfo object at 0x7d8f0ac3a030>]=2000, version: Annotated[bool | None, <typer.models.OptionInfo object at 0x7d8f0ac3a0c0>]=None) None[source]

Console script for AI Marketplace Monitor.

ai_marketplace_monitor.cli.version_callback(value: bool) None[source]

Callback function for the –version option.

Parameters:

value (-) – The value provided for the –version option.

Raises:
  • - typer.Exit – Raises an Exit exception if the –version option is provided,

  • printing the Awesome CLI version and exiting the program.

ai_marketplace_monitor.config module

class ai_marketplace_monitor.config.Config(config_files: List[pathlib.Path], logger: logging.Logger | None = None)[source]

Bases: Generic[TAIConfig, TItemConfig, TMarketplaceConfig]

ai: Dict[str, TAIConfig]
expand_notifications(logger: Logger | None = None) None[source]
expand_regions() None[source]
get_ai_config(config: Dict[str, Any]) None[source]
get_item_config(config: Dict[str, Any]) None[source]
get_marketplace_config(config: Dict[str, Any]) None[source]
get_monitor_config(config: Dict[str, Any]) None[source]
get_notification_config(config: Dict[str, Any]) None[source]
get_region_config(config: Dict[str, Any]) None[source]
get_translator_config(config: Dict[str, Any]) None[source]
get_user_config(config: Dict[str, Any]) None[source]
item: Dict[str, TItemConfig]
marketplace: Dict[str, TMarketplaceConfig]
monitor: MonitorConfig
notification: Dict[str, NotificationConfig]
region: Dict[str, RegionConfig]
translator: Dict[str, Translator]
user: Dict[str, UserConfig]
validate_ais() None[source]
validate_items() None[source]
validate_sections(config: Dict[str, Any]) None[source]
validate_users() None[source]

Check if notified users exists

class ai_marketplace_monitor.config.ConfigItem(*values)[source]

Bases: Enum

AI = 'ai'
ITEM = 'item'
MARKETPLACE = 'marketplace'
MONITOR = 'monitor'
NOTIFICATION = 'notification'
REGION = 'region'
TRANSLATION = 'translation'
USER = 'user'

ai_marketplace_monitor.email_notify module

class ai_marketplace_monitor.email_notify.EmailNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, email: List[str] | None = None, smtp_server: str | None = None, smtp_port: int | None = None, smtp_username: str | None = None, smtp_password: str | None = None, smtp_from: str | None = None)[source]

Bases: NotificationConfig

email: List[str] | None = None
get_html_message(listings: List[Listing], ratings: List[AIResponse], notification_status: List[NotificationStatus], force: bool = False, logger: Logger | None = None) Tuple[str, list[Tuple[bytes, str, str]]][source]
get_text_message(listings: List[Listing], ratings: List[AIResponse], notification_status: List[NotificationStatus], force: bool = False, logger: Logger | None = None) str[source]
get_title(listings: List[Listing], notification_status: List[NotificationStatus], force: bool = False) str[source]
handle_email() None[source]
handle_smtp_from() None[source]
handle_smtp_password() None[source]
handle_smtp_port() None[source]
handle_smtp_server() None[source]
handle_smtp_username() None[source]
notify(listings: List[Listing], ratings: List[AIResponse], notification_status: List[NotificationStatus], force: bool = False, logger: Logger | None = None) bool[source]
notify_method = 'email'
required_fields: ClassVar[List[str]] = ['email', 'smtp_password']
send_email_message(title: str, message: str, html: str, images: List[Tuple[bytes, str, str]], logger: Logger | None = None) bool[source]
smtp_from: str | None = None
smtp_password: str | None = None
smtp_port: int | None = None
smtp_server: str | None = None
smtp_username: str | None = None

ai_marketplace_monitor.facebook module

class ai_marketplace_monitor.facebook.Availability(*values)[source]

Bases: Enum

ALL = 'all'
INSTOCK = 'in'
OUTSTOCK = 'out'
class ai_marketplace_monitor.facebook.Category(*values)[source]

Bases: Enum

APPAREL = 'apparel'
ELECTRONICS = 'electronics'
ENTERTAINMENT = 'entertainment'
FAMILY = 'family'
FREE = 'free'
FREE_STUFF = 'freestuff'
GARDEN = 'garden'
HOBBIES = 'hobbies'
HOME_GOODS = 'homegoods'
HOME_IMPROVEMENT = 'homeimprovement'
HOME_SALES = 'homesales'
MUSICAL_INSTRUMENTS = 'musicalinstruments'
OFFICE_SUPPLIES = 'officesupplies'
PET_SUPPLIES = 'petsupplies'
PROPERTY_RENTALS = 'propertyrentals'
SPORTING_GOODS = 'sportinggoods'
TICKETS = 'tickets'
TOYS = 'toys'
VEHICLES = 'vehicles'
VIDEO_GAMES = 'videogames'
class ai_marketplace_monitor.facebook.Condition(*values)[source]

Bases: Enum

NEW = 'new'
USED_FAIR = 'used_fair'
USED_GOOD = 'used_good'
USED_LIKE_NEW = 'used_like_new'
class ai_marketplace_monitor.facebook.DateListed(*values)[source]

Bases: Enum

ANYTIME = 0
PAST_24_HOURS = 1
PAST_MONTH = 30
PAST_WEEK = 7
class ai_marketplace_monitor.facebook.DeliveryMethod(*values)[source]

Bases: Enum

ALL = 'all'
LOCAL_PICK_UP = 'local_pick_up'
SHIPPING = 'shipping'
class ai_marketplace_monitor.facebook.FacebookAutoItemWithAboutAndDescriptionPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: FacebookRegularItemPage

get_condition() str[source]
get_description() str[source]
get_price() str[source]
verify_layout() bool[source]
class ai_marketplace_monitor.facebook.FacebookAutoItemWithDescriptionPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: FacebookAutoItemWithAboutAndDescriptionPage

get_condition() str[source]
get_description() str[source]
get_price() str[source]
verify_layout() bool[source]
class ai_marketplace_monitor.facebook.FacebookItemConfig(name: str, enabled: bool | None = None, seller_locations: List[str] | None = None, availability: List[str] | None = None, condition: List[str] | None = None, date_listed: List[int] | None = None, delivery_method: List[str] | None = None, category: str | None = None, ai: List[str] | None = None, exclude_sellers: List[str] | None = None, notify: List[str] | None = None, search_city: List[str] | None = None, city_name: List[str] | None = None, radius: List[int] | None = None, currency: List[str] | None = None, search_interval: int | None = None, max_search_interval: int | None = None, start_at: List[str] | None = None, search_region: List[str] | None = None, max_price: str | None = None, min_price: str | None = None, rating: List[int] | None = None, prompt: str | None = None, extra_prompt: str | None = None, rating_prompt: str | None = None, searched_count: int = 0, search_phrases: List[str] = <factory>, keywords: List[str] | None = None, antikeywords: List[str] | None = None, description: str | None = None, marketplace: str | None = None)[source]

Bases: ItemConfig, FacebookMarketItemCommonConfig

class ai_marketplace_monitor.facebook.FacebookItemPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: WebPage

get_condition() str[source]
get_description() str[source]
get_image_url() str[source]
get_location() str[source]
get_price() str[source]
get_seller() str[source]
get_title() str[source]
parse(post_url: str) Listing[source]
verify_layout() bool[source]
class ai_marketplace_monitor.facebook.FacebookMarketItemCommonConfig(name: str, enabled: bool | None = None, seller_locations: List[str] | None = None, availability: List[str] | None = None, condition: List[str] | None = None, date_listed: List[int] | None = None, delivery_method: List[str] | None = None, category: str | None = None)[source]

Bases: BaseConfig

Item options that can be defined in marketplace

This class defines and processes options that can be specified in both marketplace and item sections, specific to facebook marketplace

availability: List[str] | None = None
category: str | None = None
condition: List[str] | None = None
date_listed: List[int] | None = None
delivery_method: List[str] | None = None
handle_availability() None[source]
handle_category() None[source]
handle_condition() None[source]
handle_date_listed() None[source]
handle_delivery_method() None[source]
handle_seller_locations() None[source]
seller_locations: List[str] | None = None
class ai_marketplace_monitor.facebook.FacebookMarketplace(name: str, browser: Browser | None, keyboard_monitor: KeyboardMonitor | None = None, logger: Logger | None = None)[source]

Bases: Marketplace

check_listing(item: Listing, item_config: FacebookItemConfig, description_available: bool = True) bool[source]
classmethod get_config(**kwargs: Any) FacebookMarketplaceConfig[source]
classmethod get_item_config(**kwargs: Any) FacebookItemConfig[source]
get_listing_details(post_url: str, item_config: ItemConfig, price: str | None = None, title: str | None = None) Tuple[Listing, bool][source]
initial_url = 'https://www.facebook.com/login/device-based/regular/login/'
login() None[source]
name = 'facebook'
page: Page | None
search(item_config: FacebookItemConfig) Generator[Listing, None, None][source]
class ai_marketplace_monitor.facebook.FacebookMarketplaceConfig(name: str, enabled: bool | None = None, seller_locations: List[str] | None = None, availability: List[str] | None = None, condition: List[str] | None = None, date_listed: List[int] | None = None, delivery_method: List[str] | None = None, category: str | None = None, ai: List[str] | None = None, exclude_sellers: List[str] | None = None, notify: List[str] | None = None, search_city: List[str] | None = None, city_name: List[str] | None = None, radius: List[int] | None = None, currency: List[str] | None = None, search_interval: int | None = None, max_search_interval: int | None = None, start_at: List[str] | None = None, search_region: List[str] | None = None, max_price: str | None = None, min_price: str | None = None, rating: List[int] | None = None, prompt: str | None = None, extra_prompt: str | None = None, rating_prompt: str | None = None, market_type: str | None = 'facebook', language: str | None = None, monitor_config: MonitorConfig | None = None, login_wait_time: int | None = None, password: str | None = None, username: str | None = None)[source]

Bases: MarketplaceConfig, FacebookMarketItemCommonConfig

Options specific to facebook marketplace

This class defines and processes options that can be specified in the marketplace.facebook section only. None of the options are required.

handle_login_wait_time() None[source]
handle_password() None[source]
handle_username() None[source]
login_wait_time: int | None = None
password: str | None = None
username: str | None = None
class ai_marketplace_monitor.facebook.FacebookRegularItemPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: FacebookItemPage

get_condition() str[source]
get_description() str[source]
get_image_url() str[source]
get_location() str[source]
get_price() str[source]
get_seller() str[source]
get_title() str[source]
verify_layout() bool[source]
class ai_marketplace_monitor.facebook.FacebookRentalItemPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: FacebookRegularItemPage

get_condition() str[source]
get_description() str[source]
verify_layout() bool[source]
class ai_marketplace_monitor.facebook.FacebookSearchResultPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: WebPage

get_listings() List[Listing][source]
ai_marketplace_monitor.facebook.parse_listing(page: Page, post_url: str, translator: Translator | None = None, logger: Logger | None = None) Listing | None[source]

ai_marketplace_monitor.listing module

class ai_marketplace_monitor.listing.Listing(marketplace: str, name: str, id: str, title: str, image: str, price: str, post_url: str, location: str, seller: str, condition: str, description: str)[source]

Bases: object

condition: str
property content: Tuple[str, str, str]
description: str
classmethod from_cache(post_url: str, local_cache: Cache | None = None) Listing | None[source]
property hash: str
id: str
image: str
location: str
marketplace: str
name: str
post_url: str
price: str
seller: str
title: str
to_cache(post_url: str, local_cache: Cache | None = None) None[source]

ai_marketplace_monitor.marketplace module

class ai_marketplace_monitor.marketplace.ItemConfig(name: str, enabled: bool | None = None, ai: List[str] | None = None, exclude_sellers: List[str] | None = None, notify: List[str] | None = None, search_city: List[str] | None = None, city_name: List[str] | None = None, radius: List[int] | None = None, currency: List[str] | None = None, search_interval: int | None = None, max_search_interval: int | None = None, start_at: List[str] | None = None, search_region: List[str] | None = None, max_price: str | None = None, min_price: str | None = None, rating: List[int] | None = None, prompt: str | None = None, extra_prompt: str | None = None, rating_prompt: str | None = None, searched_count: int = 0, search_phrases: List[str] = <factory>, keywords: List[str] | None = None, antikeywords: List[str] | None = None, description: str | None = None, marketplace: str | None = None)[source]

Bases: MarketItemCommonConfig

This class defined options that can only be specified for items.

antikeywords: List[str] | None = None
description: str | None = None
handle_antikeywords() None[source]
handle_description() None[source]
handle_keywords() None[source]
handle_search_phrases() None[source]
keywords: List[str] | None = None
marketplace: str | None = None
search_phrases: List[str]
searched_count: int = 0
class ai_marketplace_monitor.marketplace.MarketItemCommonConfig(name: str, enabled: bool | None = None, ai: List[str] | None = None, exclude_sellers: List[str] | None = None, notify: List[str] | None = None, search_city: List[str] | None = None, city_name: List[str] | None = None, radius: List[int] | None = None, currency: List[str] | None = None, search_interval: int | None = None, max_search_interval: int | None = None, start_at: List[str] | None = None, search_region: List[str] | None = None, max_price: str | None = None, min_price: str | None = None, rating: List[int] | None = None, prompt: str | None = None, extra_prompt: str | None = None, rating_prompt: str | None = None)[source]

Bases: BaseConfig

Item options that can be specified in market (non-marketplace specifc)

This class defines and processes options that can be specified in both marketplace and item sections, generic to all marketplaces

ai: List[str] | None = None
city_name: List[str] | None = None
currency: List[str] | None = None
exclude_sellers: List[str] | None = None
extra_prompt: str | None = None
handle_ai() None[source]
handle_city_name() None[source]
handle_currency() None[source]
handle_exclude_sellers() None[source]
handle_extra_prompt() None[source]
handle_max_price() None[source]
handle_max_search_interval() None[source]
handle_min_price() None[source]
handle_notify() None[source]
handle_prompt() None[source]
handle_radius() None[source]
handle_rating() None[source]
handle_rating_prompt() None[source]
handle_search_city() None[source]
handle_search_interval() None[source]
handle_search_region() None[source]
handle_start_at() None[source]
max_price: str | None = None
max_search_interval: int | None = None
min_price: str | None = None
notify: List[str] | None = None
prompt: str | None = None
radius: List[int] | None = None
rating: List[int] | None = None
rating_prompt: str | None = None
search_city: List[str] | None = None
search_interval: int | None = None
search_region: List[str] | None = None
start_at: List[str] | None = None
class ai_marketplace_monitor.marketplace.MarketPlace(*values)[source]

Bases: Enum

FACEBOOK = 'facebook'
class ai_marketplace_monitor.marketplace.Marketplace(name: str, browser: Browser | None, keyboard_monitor: KeyboardMonitor | None = None, logger: Logger | None = None)[source]

Bases: Generic[TMarketplaceConfig, TItemConfig]

configure(config: TMarketplaceConfig, translator: Translator | None = None) None[source]
create_page(swap_proxy: bool = False) Page[source]
classmethod get_config(**kwargs: Any) TMarketplaceConfig[source]
classmethod get_item_config(**kwargs: Any) TItemConfig[source]
goto_url(url: str, attempt: int = 0) None[source]
page: Page | None
search(item: TItemConfig) Generator[Listing, None, None][source]
set_browser(browser: Browser | None = None) None[source]
stop() None[source]
class ai_marketplace_monitor.marketplace.MarketplaceConfig(name: str, enabled: bool | None = None, ai: List[str] | None = None, exclude_sellers: List[str] | None = None, notify: List[str] | None = None, search_city: List[str] | None = None, city_name: List[str] | None = None, radius: List[int] | None = None, currency: List[str] | None = None, search_interval: int | None = None, max_search_interval: int | None = None, start_at: List[str] | None = None, search_region: List[str] | None = None, max_price: str | None = None, min_price: str | None = None, rating: List[int] | None = None, prompt: str | None = None, extra_prompt: str | None = None, rating_prompt: str | None = None, market_type: str | None = 'facebook', language: str | None = None, monitor_config: MonitorConfig | None = None)[source]

Bases: MarketItemCommonConfig

Generic marketplace config

handle_language() None[source]
handle_market_type() None[source]
language: str | None = None
market_type: str | None = 'facebook'
monitor_config: MonitorConfig | None = None
class ai_marketplace_monitor.marketplace.WebPage(page: Page, translator: Translator | None = None, logger: Logger | None = None)[source]

Bases: object

translator: Translator

ai_marketplace_monitor.monitor module

class ai_marketplace_monitor.monitor.MarketplaceMonitor(config_files: List[Path] | None, headless: bool | None, logger: Logger | None)[source]

Bases: object

active_marketplaces: ClassVar = {}
check_items(items: List[str] | None = None, for_item: str | None = None) None[source]

Main function to monitor the marketplace.

evaluate_by_ai(item: Listing, item_config: TItemConfig, marketplace_config: TMarketplaceConfig) AIResponse[source]
handle_pause() None[source]

Handle interruption signal.

load_ai_agents() None[source]

Load the AI agent.

load_config_file() Config[source]

Load the configuration file.

schedule_jobs() None[source]

Schedule jobs to run periodically.

search_item(marketplace_config: TMarketplaceConfig, marketplace: Marketplace, item_config: TItemConfig) None[source]

Search for an item on the marketplace.

start_monitor() None[source]

Main function to monitor the marketplace.

stop_monitor() None[source]

Stop the monitor.

ai_marketplace_monitor.notification module

class ai_marketplace_monitor.notification.NotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None)[source]

Bases: BaseConfig

classmethod get_config(**kwargs: Any) NotificationConfig | None[source]

Get the specific subclass name from the specified keys, for validation purposes

global_rate_limit: int = 10
handle_max_retries() None[source]
handle_retry_delay() None[source]
instance_rate_limit: float = 1.0
max_retries: int = 5
classmethod notify_all(config: NotificationConfig, *args, **kwargs: Any) bool[source]

Call the notify method of all subclasses

rate_limit_enabled: bool = False
required_fields: ClassVar[List[str]] = []
retry_delay: int = 60
send_message(title: str, message: str, logger: Logger | None = None) bool[source]
send_message_with_retry(title: str, message: str, logger: Logger | None = None) bool[source]

Enhanced retry method with rate limiting support.

Subclasses that set _handles_own_rate_limiting = True (e.g. Telegram, which applies async rate limiting inside its own send_message) will NOT get sync rate limiting here — avoiding a double-wait.

class ai_marketplace_monitor.notification.NotificationStatus(*values)[source]

Bases: Enum

EXPIRED = 1
LISTING_CHANGED = 3
LISTING_DISCOUNTED = 4
NOTIFIED = 2
NOT_NOTIFIED = 0
class ai_marketplace_monitor.notification.PushNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None)[source]

Bases: NotificationConfig

handle_message_format() None[source]
handle_with_description() None[source]
message_format: str | None = None
notify(listings: List[Listing], ratings: List[AIResponse], notification_status: List[NotificationStatus], force: bool = False, logger: Logger | None = None) bool[source]
notify_method = 'push_notification'
with_description: int | None = None

ai_marketplace_monitor.ntfy module

class ai_marketplace_monitor.ntfy.NtfyNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None, ntfy_server: str | None = None, ntfy_topic: str | None = None)[source]

Bases: PushNotificationConfig

handle_ntfy_server() None[source]
handle_ntfy_topic() None[source]
message_format: str | None = None
notify_method = 'ntfy'
ntfy_server: str | None = None
ntfy_topic: str | None = None
required_fields: ClassVar[List[str]] = ['ntfy_server', 'ntfy_topic']
send_message(title: str, message: str, logger: Logger | None = None) bool[source]

ai_marketplace_monitor.pushbullet module

class ai_marketplace_monitor.pushbullet.PushbulletNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None, pushbullet_token: str | None = None, pushbullet_proxy_type: str | None = None, pushbullet_proxy_server: str | None = None)[source]

Bases: PushNotificationConfig

handle_message_format() None[source]
handle_pushbullet_proxy_server() None[source]
handle_pushbullet_proxy_type() None[source]
handle_pushbullet_token() None[source]
notify_method = 'pushbullet'
pushbullet_proxy_server: str | None = None
pushbullet_proxy_type: str | None = None
pushbullet_token: str | None = None
required_fields: ClassVar[List[str]] = ['pushbullet_token']
send_message(title: str, message: str, logger: Logger | None = None) bool[source]

ai_marketplace_monitor.pushover module

class ai_marketplace_monitor.pushover.PushoverNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None, pushover_user_key: str | None = None, pushover_api_token: str | None = None)[source]

Bases: PushNotificationConfig

handle_message_format() None[source]
handle_pushover_api_token() None[source]
handle_pushover_user_key() None[source]
notify_method = 'pushover'
pushover_api_token: str | None = None
pushover_user_key: str | None = None
required_fields: ClassVar[List[str]] = ['pushover_user_key', 'pushover_api_token']
send_message(title: str, message: str, logger: Logger | None = None) bool[source]

ai_marketplace_monitor.region module

class ai_marketplace_monitor.region.RegionConfig(name: str, enabled: bool | None = None, search_city: List[str] = <factory>, full_name: str = '', radius: List[int] = <factory>, city_name: List[str] = <factory>, currency: List[str] = <factory>)[source]

Bases: BaseConfig

city_name: List[str]
currency: List[str]
full_name: str = ''
handle_city_name() None[source]
handle_currency() None[source]
handle_radius() None[source]
handle_search_city() None[source]
radius: List[int]
search_city: List[str]

ai_marketplace_monitor.telegram module

class ai_marketplace_monitor.telegram.TelegramNotificationConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = True, instance_rate_limit: float = 1.0, global_rate_limit: int = 30, _handles_own_rate_limiting: bool = True, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None, telegram_token: str | None = None, telegram_chat_id: str | None = None)[source]

Bases: PushNotificationConfig

global_rate_limit: int = 30
handle_telegram_chat_id() None[source]
handle_telegram_token() None[source]
notify_method = 'telegram'
rate_limit_enabled: bool = True
required_fields: ClassVar[List[str]] = ['telegram_token', 'telegram_chat_id']
send_message(title: str, message: str, logger: Logger | None = None) bool[source]

Send message using asyncio.run to call async Telegram operations.

telegram_chat_id: str | None = None
telegram_token: str | None = None

ai_marketplace_monitor.user module

class ai_marketplace_monitor.user.User(config: UserConfig, logger: Logger | None = None)[source]

Bases: object

classmethod get_config(**kwargs: Any) UserConfig[source]
notification_status(listing: Listing, local_cache: Cache | None = None) NotificationStatus[source]
notified_key(listing: Listing) Tuple[str, str, str, str][source]
notify(listings: List[Listing], ratings: List[AIResponse], item_config: TItemConfig, local_cache: Cache | None = None, force: bool = False) None[source]
time_since_notification(listing: Listing, local_cache: Cache | None = None) int[source]
to_cache(listing: Listing, local_cache: Cache | None = None) None[source]
class ai_marketplace_monitor.user.UserConfig(name: str, enabled: bool | None = None, max_retries: int = 5, retry_delay: int = 60, rate_limit_enabled: bool = False, instance_rate_limit: float = 1.0, global_rate_limit: int = 10, _handles_own_rate_limiting: bool = False, _last_send_time: float | None = None, message_format: str | None = None, with_description: int | None = None, telegram_token: str | None = None, telegram_chat_id: str | None = None, ntfy_server: str | None = None, ntfy_topic: str | None = None, pushover_user_key: str | None = None, pushover_api_token: str | None = None, pushbullet_token: str | None = None, pushbullet_proxy_type: str | None = None, pushbullet_proxy_server: str | None = None, email: List[str] | None = None, smtp_server: str | None = None, smtp_port: int | None = None, smtp_username: str | None = None, smtp_password: str | None = None, smtp_from: str | None = None, notify_with: List[str] | None = None, remind: int | None = None)[source]

Bases: EmailNotificationConfig, PushbulletNotificationConfig, PushoverNotificationConfig, NtfyNotificationConfig, TelegramNotificationConfig

UserConfiguration

Derive from EmailNotificationConfig, PushbulletNotificationConfig allows the user config class to use settings from both classes.

It is possible to dynamically added these classes as parent class of UserConfig, but it is troublesome to make sure that these classes are imported.

handle_notify_with() None[source]
handle_remind() None[source]
notify_with: List[str] | None = None
remind: int | None = None

ai_marketplace_monitor.utils module

class ai_marketplace_monitor.utils.BaseConfig(name: str, enabled: bool | None = None)[source]

Bases: object

enabled: bool | None = None
handle_enabled() None[source]
property hash: str
name: str
class ai_marketplace_monitor.utils.CacheType(*values)[source]

Bases: Enum

AI_INQUIRY = 'ai-inquiries'
COUNTERS = 'counters'
LISTING_DETAILS = 'listing-details'
USER_NOTIFIED = 'user-notifications'
class ai_marketplace_monitor.utils.ChangeHandler(files: List[str])[source]

Bases: FileSystemEventHandler

on_created(event: FileSystemEvent) None[source]

Called when a file or directory is created.

Parameters:

event (DirCreatedEvent or FileCreatedEvent) – Event representing file/directory creation.

on_deleted(event: FileSystemEvent) None[source]

Called when a file or directory is deleted.

Parameters:

event (DirDeletedEvent or FileDeletedEvent) – Event representing file/directory deletion.

on_modified(event: FileSystemEvent) None[source]

Called when a file or directory is modified.

Parameters:

event (DirModifiedEvent or FileModifiedEvent) – Event representing file/directory modification.

on_moved(event: FileSystemEvent) None[source]

Called when a file or a directory is moved or renamed.

Parameters:

event (DirMovedEvent or FileMovedEvent) – Event representing file/directory movement.

class ai_marketplace_monitor.utils.Counter[source]

Bases: object

increment(counter_key: CounterItem, item_name: str, by: int = 1) None[source]
class ai_marketplace_monitor.utils.CounterItem(*values)[source]

Bases: Enum

AI_QUERY = 'Total AI Queries'
EXCLUDED_LISTING = 'Listing excluded'
FAILED_AI_QUERY = 'Failed AI Queries)'
LISTING_EXAMINED = 'Total listing examined'
LISTING_QUERY = 'New listing fetched'
NEW_AI_QUERY = 'New AI Queries'
NEW_VALIDATED_LISTING = 'New validated listing'
NOTIFICATIONS_SENT = 'Notifications sent'
REMINDERS_SENT = 'Reminders sent'
SEARCH_PERFORMED = 'Search performed'
class ai_marketplace_monitor.utils.Currency(*values)[source]

Bases: Enum

ARS_unsupported = 'ARS'
AUD = 'AUD'
BGN = 'BGN'
BRL = 'BRL'
CAD = 'CAD'
CHF = 'CHF'
CNY = 'CNY'
CYP = 'CYP'
CZK = 'CZK'
DKK = 'DKK'
EEK = 'EEK'
EUR = 'EUR'
GBP = 'GBP'
HKD = 'HKD'
HRK = 'HRK'
HUF = 'HUF'
IDR = 'IDR'
ILS = 'ILS'
INR = 'INR'
ISK = 'ISK'
JPY = 'JPY'
KRW = 'KRW'
LTL = 'LTL'
LVL = 'LVL'
MTL = 'MTL'
MXN = 'MXN'
MYR = 'MYR'
NOK = 'NOK'
NZD = 'NZD'
PHP = 'PHP'
PLN = 'PLN'
ROL = 'ROL'
RON = 'RON'
RUB = 'RUB'
SEK = 'SEK'
SGD = 'SGD'
SIT = 'SIT'
SKK = 'SKK'
THB = 'THB'
TRL = 'TRL'
TRY = 'TRY'
USD = 'USD'
ZAR = 'ZAR'
class ai_marketplace_monitor.utils.KeyboardMonitor[source]

Bases: object

confirm(msg: str | None = None) bool[source]
confirm_character = 'c'
is_confirmed() bool[source]
is_paused() bool[source]
is_sleeping() bool[source]
set_paused(paused: bool = True) None[source]
start() None[source]
start_sleeping() None[source]
stop() None[source]
class ai_marketplace_monitor.utils.MonitorConfig(name: str, enabled: bool | None = None, proxy_server: List[str] | None = None, proxy_bypass: str | None = None, proxy_username: str | None = None, proxy_password: str | None = None)[source]

Bases: BaseConfig

get_proxy_options() ProxySettings | None[source]
handle_proxy_bypass() None[source]
handle_proxy_password() None[source]
handle_proxy_server() None[source]
handle_proxy_username() None[source]
proxy_bypass: str | None = None
proxy_password: str | None = None
proxy_server: List[str] | None = None
proxy_username: str | None = None
class ai_marketplace_monitor.utils.SleepStatus(*values)[source]

Bases: Enum

BY_FILE_CHANGE = 2
BY_KEYBOARD = 1
NOT_DISRUPTED = 0
class ai_marketplace_monitor.utils.Translator(locale: str | None = None, dictionary: Dict[str, str] | None = None)[source]

Bases: object

ai_marketplace_monitor.utils.aimm_event(kind: str, **fields: Any) Dict[str, Any][source]

Build a structured-event payload for a log call.

Usage:

logger.info(message, extra=aimm_event(“ai_eval”, score=5, …))

The web UI surfaces these structured fields in its filter dropdowns (kind / item / score) and in the expand-row detail pane.

ai_marketplace_monitor.utils.calculate_file_hash(file_paths: List[Path]) str[source]

Calculate the SHA-256 hash of the file content.

ai_marketplace_monitor.utils.convert_to_seconds(time_str: str) int[source]
ai_marketplace_monitor.utils.doze(duration: int, files: List[Path] | None = None, keyboard_monitor: KeyboardMonitor | None = None) SleepStatus[source]

Sleep for a specified duration while monitoring the change of files.

Returns:

if doze was done naturally. 1: if doze was disrupted by keyboard 2: if doze was disrupted by file change

Return type:

0

ai_marketplace_monitor.utils.extract_price(price: str) str[source]
ai_marketplace_monitor.utils.fetch_with_retry(url: str, timeout: int = 10, max_retries: int = 3, backoff_factor: float = 1.5, logger: Logger | None = None) Tuple[bytes, str] | None[source]

Fetch URL content with retry logic

Parameters:
  • url – URL to fetch

  • timeout – Timeout in seconds

  • max_retries – Maximum number of retry attempts

  • backoff_factor – Multiplier for exponential backoff

  • logger – logger object

Returns:

Tuple of (content, content_type) if successful, None if failed

ai_marketplace_monitor.utils.hash_dict(obj: Dict[str, Any]) str[source]

Hash a dictionary to a string.

ai_marketplace_monitor.utils.hilight(text: str, style: str = 'name') str[source]

Highlight the keywords in the text with the specified color.

ai_marketplace_monitor.utils.is_substring(var1: str | List[str], var2: str | List[str], logger: Logger | None = None) bool[source]

Check if var1 is a substring of var2, after normalizing both strings. One of them can be a list of strings.

var1: can be a single string, or a list of string, for which a condition of OR is assumed.

this program will parse var11 for “AND”, “OR” and “NOT”, and return the results of the logical expression.

var2: one or more strings for testing if strings in “var1” is a substring.

ai_marketplace_monitor.utils.merge_dicts(dicts: list) dict[source]

Merge a list of dictionaries into a single dictionary, including nested dictionaries.

Parameters:

dicts – A list of dictionaries to merge.

Returns:

A single merged dictionary.

ai_marketplace_monitor.utils.normalize_string(string: str) str[source]

Normalize a string by replacing multiple spaces (including space, tab, and newline) with a single space.

ai_marketplace_monitor.utils.resize_image_data(image_data: bytes, max_width: int = 800, max_height: int = 600) bytes[source]

Module contents

Top-level package for ai-marketplace-monitor.