Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,054 changes: 178 additions & 876 deletions docs/index.html

Large diffs are not rendered by default.

702 changes: 10 additions & 692 deletions docs/openapi/ai-visibility-api.yaml

Large diffs are not rendered by default.

38 changes: 0 additions & 38 deletions docs/openapi/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -808,44 +808,6 @@ paths:
$ref: './tokens-api.yaml#/site-token-by-type'

# AI Visibility
/llmo/ai-visibility/brands/stats:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-stats'
/llmo/ai-visibility/brands/topics:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-topics'
/llmo/ai-visibility/brands/prompts:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-prompts'
/llmo/ai-visibility/brands/cited-pages:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-cited-pages'
/llmo/ai-visibility/brands/topic-opportunities:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-topic-opportunities'
/llmo/ai-visibility/brands/top-brands:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-top-brands'
/llmo/ai-visibility/brands/cited-sources:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-cited-sources'
/llmo/ai-visibility/brands/source-opportunities:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-source-opportunities'
/llmo/ai-visibility/brands/competitors:
$ref: './ai-visibility-api.yaml#/ai-visibility-brands-competitors'
/llmo/ai-visibility/competitors/metrics:
$ref: './ai-visibility-api.yaml#/ai-visibility-competitors-metrics'
/llmo/ai-visibility/meta:
$ref: './ai-visibility-api.yaml#/ai-visibility-meta'
/llmo/ai-visibility/prompts/responses/latest:
$ref: './ai-visibility-api.yaml#/ai-visibility-prompts-responses-latest'
/llmo/ai-visibility/prompts/responses:
$ref: './ai-visibility-api.yaml#/ai-visibility-prompts-responses'
/llmo/ai-visibility/topics/research/stats:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-research-stats'
/llmo/ai-visibility/topics/research:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-research'
/llmo/ai-visibility/topics/stats:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-stats'
/llmo/ai-visibility/topics/research/prompts:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-research-prompts'
/llmo/ai-visibility/topics/research/brands:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-research-brands'
/llmo/ai-visibility/topics/research/source-domains:
$ref: './ai-visibility-api.yaml#/ai-visibility-topics-research-source-domains'
/llmo/ai-visibility/v1/brand/stats-by-llm:
$ref: './ai-visibility-api.yaml#/ai-visibility-v1-brand-stats-by-llm'
/llmo/ai-visibility/v1/brand/stats-by-country:
Expand Down
227 changes: 0 additions & 227 deletions docs/openapi/schemas.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10006,57 +10006,6 @@ AiVisibilityServiceUnavailable:
example: Missing SEO_CLIENT_ID
required: [error, message]

AiVisibilityEngineBreakdown:
type: object
description: Per-LLM-engine numeric breakdown
properties:
all:
type: number
chatgpt:
type: number
gemini:
type: number
googleAiMode:
type: number
googleAiOverview:
type: number

AiVisibilityByDateEntry:
type: object
description: A single date-bucket in brand statistics
properties:
year:
type: integer
month:
type: integer
day:
type: integer
aiVisibility:
type: number
mentions:
$ref: '#/AiVisibilityEngineBreakdown'
citedPages:
$ref: '#/AiVisibilityEngineBreakdown'
visibilityByEngine:
$ref: '#/AiVisibilityEngineBreakdown'
ownedSources:
type: integer
audience:
type: integer

AiVisibilityByCountryEntry:
type: object
description: Per-country breakdown row in brand statistics
properties:
country:
type: string
mentions:
type: integer
audience:
type: integer
citedPages:
type: integer

AiVisibilitySrFilters:
type: object
description: Available filter dimensions extracted from the response
Expand All @@ -10078,52 +10027,6 @@ AiVisibilitySrFilters:
items:
type: string

AiVisibilityBrandStats:
type: object
description: Brand visibility statistics response
properties:
visibility:
type: number
visibilityByEngine:
$ref: '#/AiVisibilityEngineBreakdown'
audience:
type: integer
mentions:
$ref: '#/AiVisibilityEngineBreakdown'
citedPages:
$ref: '#/AiVisibilityEngineBreakdown'
byDate:
type: array
items:
$ref: '#/AiVisibilityByDateEntry'
byCountry:
type: array
items:
$ref: '#/AiVisibilityByCountryEntry'
srFilters:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilityPaginatedResponse:
type: object
description: Generic paginated response for AI Visibility list endpoints
properties:
data:
type: array
items:
type: object
additionalProperties: true
total:
type: integer
description: Total number of results matching the query
offset:
type: integer
limit:
type: integer
srFilters:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilitySemrushCountry:
type: string
description: COUNTRY enum from ai-seo-ts common/types_pb
Expand Down Expand Up @@ -11651,48 +11554,6 @@ AiVisibilityV1FtsExportResponse:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilityCompetitorsMetrics:
type: object
description: Competitor comparison time-series response
properties:
byBrand:
type: array
items:
type: object
properties:
brand:
type: object
properties:
domain:
type: string
name:
type: string
byDate:
type: array
items:
type: object
properties:
date:
type: object
properties:
year:
type: integer
month:
type: integer
day:
type: integer
visibility:
type: number
mentions:
type: number
audience:
type: number
ownedSources:
type: number
srFilters:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilityGapPromptRow:
type: object
description: A single gap prompt row
Expand Down Expand Up @@ -11738,94 +11599,6 @@ AiVisibilityGapPromptsResponse:
$ref: '#/AiVisibilitySrFilters'
required: [data, total, offset, limit]

AiVisibilityMeta:
type: object
description: AI Visibility metadata including supported countries
properties:
countries:
type: array
items:
type: object
properties:
countryCode:
type: string
description: ISO country code
daily:
type: array
items:
type: object
monthly:
type: array
items:
type: object
isComingSoon:
type: boolean
srFilters:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilityTopicsResearchStats:
type: object
description: Aggregate statistics for topic research
properties:
topicsTotal:
type: integer
description: Total number of distinct topics matching the query
brandsTotal:
type: integer
description: Total number of brands across matching topics
sourceDomainsTotal:
type: integer
description: Total number of source domains across matching topics
intentBreakdown:
type: array
items:
type: object
properties:
intent:
type: string
count:
type: integer
relatedTopicsAiVolume:
type: integer
description: Aggregated AI volume for related topics
srFilters:
$ref: '#/AiVisibilitySrFilters'
additionalProperties: true

AiVisibilitySourceDomainRow:
type: object
description: A source domain row in topic research
properties:
sourceDomain:
type: string
sourcesCount:
type: integer
mentions:
type: integer
organicTraffic:
type: integer
promptExample:
type: string

AiVisibilitySourceDomainsResponse:
type: object
description: Normalized source domains response
properties:
data:
type: array
items:
$ref: '#/AiVisibilitySourceDomainRow'
total:
type: integer
offset:
type: integer
limit:
type: integer
srFilters:
$ref: '#/AiVisibilitySrFilters'
required: [data, total, offset, limit]

# ── Semrush AIO proxy ─────────────────────────────────────────────────────────
# Schemas for /v2/orgs/{spaceCatId}/brands/{brandId}/serenity/*. See
# docs/openapi/serenity-api.yaml for the operations.
Expand Down
53 changes: 1 addition & 52 deletions src/controllers/ai-visibility.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,8 @@ import {
} from '@adobe/spacecat-shared-http-utils';
import { isNonEmptyObject } from '@adobe/spacecat-shared-utils';
import { getGrpcClients } from '../support/ai-visibility/grpc-transport.js';
import { normalizeVisibilityV1SuccessfulBody } from '../support/ai-visibility/visibility-normalize.js';
import { attachSrFiltersToSuccessfulBody } from '../support/ai-visibility/visibility-filters.js';

import {
handleBrandStats,
handleBrandTopics,
handleBrandPrompts,
handleBrandCitedPages,
handleBrandTopicOpportunities,
handleBrandTopBrands,
handleBrandCitedSources,
handleBrandSourceOpportunities,
handleBrandCompetitors,
} from '../support/ai-visibility/handlers/brands.js';
import {
handleCompetitorsMetrics,
} from '../support/ai-visibility/handlers/competitors.js';
import {
handlePromptsResponses,
handlePromptsResponsesLatest,
} from '../support/ai-visibility/handlers/prompts.js';
import {
handleTopicsResearchStats,
handleTopicsResearch,
handleTopicsStats,
handleTopicsResearchPrompts,
handleTopicsResearchBrands,
handleTopicsResearchSourceDomains,
} from '../support/ai-visibility/handlers/topics.js';
import { handleBrandTopics as handleBrandTopicsV1 } from '../support/ai-visibility/handlers/v1/topic/brand-topics.js';
import { handleBrandTopicsExport as handleBrandTopicsExportV1 } from '../support/ai-visibility/handlers/v1/topic/brand-topics-export.js';
import { handleBrandTopicsTotals as handleBrandTopicsTotalsV1 } from '../support/ai-visibility/handlers/v1/topic/brand-topics-totals.js';
Expand Down Expand Up @@ -92,28 +65,8 @@ import { handlePromptsResearchExport as handlePromptsResearchExportV1 } from '..
import { handleBrandsResearchExport as handleBrandsResearchExportV1 } from '../support/ai-visibility/handlers/v1/prompt-research/brands-export.js';
import { handleSourceDomainsResearchExport as handleSourceDomainsResearchExportV1 } from '../support/ai-visibility/handlers/v1/prompt-research/source-domains-export.js';
import { handleTopicsResearchExport as handleTopicsResearchExportV1 } from '../support/ai-visibility/handlers/v1/prompt-research/topics-export.js';
import { handleMeta } from '../support/ai-visibility/handlers/meta.js';

const ROUTE_MAP = [
['/brands/stats', handleBrandStats],
['/brands/topics', handleBrandTopics],
['/brands/prompts', handleBrandPrompts],
['/brands/cited-pages', handleBrandCitedPages],
['/brands/topic-opportunities', handleBrandTopicOpportunities],
['/brands/top-brands', handleBrandTopBrands],
['/brands/cited-sources', handleBrandCitedSources],
['/brands/source-opportunities', handleBrandSourceOpportunities],
['/brands/competitors', handleBrandCompetitors],
['/competitors/metrics', handleCompetitorsMetrics],
['/meta', handleMeta],
['/prompts/responses/latest', handlePromptsResponsesLatest],
['/prompts/responses', handlePromptsResponses],
['/topics/research/stats', handleTopicsResearchStats],
['/topics/research/prompts', handleTopicsResearchPrompts],
['/topics/research/brands', handleTopicsResearchBrands],
['/topics/research/source-domains', handleTopicsResearchSourceDomains],
['/topics/research', handleTopicsResearch],
['/topics/stats', handleTopicsStats],
['/v1/prompt-research/prompts-export', handlePromptsResearchExportV1],
['/v1/prompt-research/brands-export', handleBrandsResearchExportV1],
['/v1/prompt-research/source-domains-export', handleSourceDomainsResearchExportV1],
Expand Down Expand Up @@ -205,13 +158,9 @@ function wrapHandler(handlerFn, relPath, log) {
if (result.status !== 200) {
return createResponse(result.body, result.status);
}
const normalized = normalizeVisibilityV1SuccessfulBody(
relPath,
result.body,
);
const withFilters = attachSrFiltersToSuccessfulBody(
result.status,
normalized,
result.body,
sp,
);
return ok(withFilters);
Expand Down
Loading
Loading