Skip to content

Commit 9c53782

Browse files
committed
feature: add searches per user
1 parent e883c78 commit 9c53782

12 files changed

Lines changed: 231 additions & 8 deletions

File tree

clients/trieve-shopify-extension/app/components/analytics/GraphComponent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ export const GraphComponent = <T,>({
5252
<Text as="span" variant="heading3xl" fontWeight="bold">
5353
{dataType === "percentage"
5454
? `${((topLevelMetric ?? 0) * 100).toFixed(2)}%`
55-
: topLevelMetric}
55+
: topLevelMetric?.toLocaleString("en-US", {
56+
maximumFractionDigits: 2,
57+
})}
5658
</Text>
5759
)}
5860
</div>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
import { useTrieve } from "app/context/trieveContext";
3+
import { RAGAnalyticsFilter, TopicAnalyticsFilter } from "trieve-ts-sdk";
4+
import { Granularity } from "trieve-ts-sdk";
5+
import { GraphComponent } from "../GraphComponent";
6+
import { searchesPerUserQuery } from "app/queries/analytics/search";
7+
8+
export const SearchesPerUser = ({
9+
filters,
10+
granularity,
11+
}: {
12+
filters: TopicAnalyticsFilter;
13+
granularity: Granularity;
14+
}) => {
15+
const { trieve } = useTrieve();
16+
const { data, isLoading } = useQuery(
17+
searchesPerUserQuery(trieve, filters, granularity),
18+
);
19+
20+
return (
21+
<GraphComponent
22+
loading={isLoading}
23+
topLevelMetric={data?.avg_searches_per_user}
24+
graphData={data?.points}
25+
granularity={granularity}
26+
date_range={filters.date_range}
27+
xAxis={"time_stamp"}
28+
yAxis={"point"}
29+
label="Searches Per User"
30+
tooltipContent="The average number of searches a user performs in one session."
31+
/>
32+
);
33+
};

clients/trieve-shopify-extension/app/queries/analytics/search.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
TrieveSDK,
1111
CTRMetricsOverTimeResponse,
1212
SearchConversionRateResponse,
13+
SearchesPerUserResponse,
1314
} from "trieve-ts-sdk";
1415
import { subDays } from "date-fns";
1516
import { formatDateForApi } from "../../utils/formatting";
@@ -133,3 +134,21 @@ export const searchConversionRateQuery = (
133134
},
134135
} satisfies QueryOptions;
135136
};
137+
138+
export const searchesPerUserQuery = (
139+
trieve: TrieveSDK,
140+
filters: SearchAnalyticsFilter,
141+
granularity: Granularity,
142+
) => {
143+
return {
144+
queryKey: ["searches_per_user", filters, granularity],
145+
queryFn: async () => {
146+
const result = await trieve.getSearchAnalytics({
147+
filter: filters,
148+
type: "searches_per_user",
149+
granularity,
150+
});
151+
return result as SearchesPerUserResponse;
152+
},
153+
} satisfies QueryOptions;
154+
};

clients/trieve-shopify-extension/app/routes/app._dashboard.search.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useState } from "react";
99
import { Granularity } from "trieve-ts-sdk";
1010
import { AllSearchesTable } from "app/components/analytics/search/AllSearchesTable";
1111
import { SearchCTRChart } from "app/components/analytics/search/SearchCTR";
12-
12+
import { SearchesPerUser } from "app/components/analytics/search/SearchesPerUser";
1313
export default function SearchAnalyticsPage() {
1414
const [filters, setFilters] = useState(defaultSearchAnalyticsFilter);
1515
const [granularity, setGranularity] = useState<Granularity>("day");
@@ -55,6 +55,11 @@ export default function SearchAnalyticsPage() {
5555
<Grid.Cell columnSpan={{ xs: 6, sm: 6, md: 6, lg: 6, xl: 6 }}>
5656
<SearchCTRChart filters={filters} granularity={granularity} />
5757
<div className="py-3"></div>
58+
<SearchesPerUser
59+
filters={filters}
60+
granularity={granularity}
61+
/>
62+
<div className="py-3"></div>
5863
<HeadQueriesTable filters={filters} />
5964
</Grid.Cell>
6065
</Grid>

clients/trieve-shopify-extension/app/utils/formatting.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,4 @@ export const fillDate = <T>({
260260
export const toTitleCase = (str: string) => {
261261
return str.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
262262
};
263+

clients/trieve-shopify-extension/yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8198,7 +8198,7 @@ tr46@~0.0.3:
81988198
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
81998199

82008200
trieve-ts-sdk@../ts-sdk:
8201-
version "0.0.62"
8201+
version "0.0.64"
82028202

82038203
trim-lines@^3.0.0:
82048204
version "3.0.1"

clients/ts-sdk/openapi.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16317,6 +16317,37 @@
1631716317
]
1631816318
}
1631916319
}
16320+
},
16321+
{
16322+
"type": "object",
16323+
"title": "SearchesPerUser",
16324+
"required": [
16325+
"type"
16326+
],
16327+
"properties": {
16328+
"filter": {
16329+
"allOf": [
16330+
{
16331+
"$ref": "#/components/schemas/SearchAnalyticsFilter"
16332+
}
16333+
],
16334+
"nullable": true
16335+
},
16336+
"granularity": {
16337+
"allOf": [
16338+
{
16339+
"$ref": "#/components/schemas/Granularity"
16340+
}
16341+
],
16342+
"nullable": true
16343+
},
16344+
"type": {
16345+
"type": "string",
16346+
"enum": [
16347+
"searches_per_user"
16348+
]
16349+
}
16350+
}
1632016351
}
1632116352
],
1632216353
"discriminator": {
@@ -16413,6 +16444,9 @@
1641316444
},
1641416445
{
1641516446
"$ref": "#/components/schemas/SearchConversionRateResponse"
16447+
},
16448+
{
16449+
"$ref": "#/components/schemas/SearchesPerUserResponse"
1641616450
}
1641716451
]
1641816452
},
@@ -17335,6 +17369,25 @@
1733517369
}
1733617370
}
1733717371
},
17372+
"SearchesPerUserResponse": {
17373+
"type": "object",
17374+
"required": [
17375+
"avg_searches_per_user",
17376+
"points"
17377+
],
17378+
"properties": {
17379+
"avg_searches_per_user": {
17380+
"type": "number",
17381+
"format": "double"
17382+
},
17383+
"points": {
17384+
"type": "array",
17385+
"items": {
17386+
"$ref": "#/components/schemas/FloatTimePoint"
17387+
}
17388+
}
17389+
}
17390+
},
1733817391
"SemanticBoost": {
1733917392
"type": "object",
1734017393
"description": "Semantic boosting moves the dense vector of the chunk in the direction of the distance phrase for semantic search. I.e. you can force a cluster by moving every chunk for a PDF closer to its title or push a chunk with a chunk_html of \"iphone\" 25% closer to the term \"flagship\" by using the distance phrase \"flagship\" and a distance factor of 0.25. Conceptually it's drawing a line (euclidean/L2 distance) between the vector for the innerText of the chunk_html and distance_phrase then moving the vector of the chunk_html distance_factor*L2Distance closer to or away from the distance_phrase point along the line between the two points.",

clients/ts-sdk/src/types.gen.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3027,6 +3027,10 @@ export type SearchAnalytics = {
30273027
filter?: ((SearchAnalyticsFilter) | null);
30283028
granularity?: ((Granularity) | null);
30293029
type: 'search_conversion_rate';
3030+
} | {
3031+
filter?: ((SearchAnalyticsFilter) | null);
3032+
granularity?: ((Granularity) | null);
3033+
type: 'searches_per_user';
30303034
};
30313035

30323036
export type type7 = 'latency_graph';
@@ -3041,7 +3045,7 @@ export type SearchAnalyticsFilter = {
30413045
top_score?: ((FloatRange) | null);
30423046
};
30433047

3044-
export type SearchAnalyticsResponse = LatencyGraphResponse | SearchUsageGraphResponse | DatasetAnalytics | HeadQueryResponse | SearchQueryResponse | QueryCountResponse | SearchQueryEvent | PopularFiltersResponse | CTRMetricsOverTimeResponse | SearchConversionRateResponse;
3048+
export type SearchAnalyticsResponse = LatencyGraphResponse | SearchUsageGraphResponse | DatasetAnalytics | HeadQueryResponse | SearchQueryResponse | QueryCountResponse | SearchQueryEvent | PopularFiltersResponse | CTRMetricsOverTimeResponse | SearchConversionRateResponse | SearchesPerUserResponse;
30453049

30463050
export type SearchCTRMetrics = {
30473051
avg_position_of_click: number;
@@ -3336,6 +3340,11 @@ export type SearchWithinGroupResults = {
33363340
total_pages: number;
33373341
};
33383342

3343+
export type SearchesPerUserResponse = {
3344+
avg_searches_per_user: number;
3345+
points: Array<FloatTimePoint>;
3346+
};
3347+
33393348
/**
33403349
* Semantic boosting moves the dense vector of the chunk in the direction of the distance phrase for semantic search. I.e. you can force a cluster by moving every chunk for a PDF closer to its title or push a chunk with a chunk_html of "iphone" 25% closer to the term "flagship" by using the distance phrase "flagship" and a distance factor of 0.25. Conceptually it's drawing a line (euclidean/L2 distance) between the vector for the innerText of the chunk_html and distance_phrase then moving the vector of the chunk_html distance_factor*L2Distance closer to or away from the distance_phrase point along the line between the two points.
33413350
*/

server/src/data/models.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7208,6 +7208,11 @@ pub enum SearchAnalytics {
72087208
filter: Option<SearchAnalyticsFilter>,
72097209
granularity: Option<Granularity>,
72107210
},
7211+
#[schema(title = "SearchesPerUser")]
7212+
SearchesPerUser {
7213+
filter: Option<SearchAnalyticsFilter>,
7214+
granularity: Option<Granularity>,
7215+
},
72117216
}
72127217

72137218
#[derive(Debug, Serialize, Deserialize, ToSchema)]
@@ -7450,6 +7455,12 @@ pub struct SearchConversionRateResponse {
74507455
pub points: Vec<FloatTimePoint>,
74517456
}
74527457

7458+
#[derive(Debug, Row, Serialize, Deserialize, ToSchema)]
7459+
pub struct SearchesPerUserResponse {
7460+
pub avg_searches_per_user: f64,
7461+
pub points: Vec<FloatTimePoint>,
7462+
}
7463+
74537464
#[derive(Debug, Row, Serialize, Deserialize, ToSchema)]
74547465
pub struct TopicQueriesResponse {
74557466
pub topics: Vec<TopicAnalyticsSummary>,
@@ -7542,6 +7553,8 @@ pub enum SearchAnalyticsResponse {
75427553
CTRMetricsOverTime(CTRMetricsOverTimeResponse),
75437554
#[schema(title = "SearchConversionRate")]
75447555
SearchConversionRate(SearchConversionRateResponse),
7556+
#[schema(title = "SearchesPerUser")]
7557+
SearchesPerUser(SearchesPerUserResponse),
75457558
}
75467559

75477560
#[derive(Debug, Serialize, Deserialize, ToSchema)]

server/src/handlers/analytics_handler.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,19 @@ pub async fn get_search_analytics(
331331

332332
SearchAnalyticsResponse::SearchConversionRate(search_conversion_rate)
333333
}
334+
SearchAnalytics::SearchesPerUser {
335+
filter,
336+
granularity,
337+
} => {
338+
let searches_per_user = get_searches_per_user_query(
339+
dataset_org_plan_sub.dataset.id,
340+
filter,
341+
granularity,
342+
clickhouse_client.get_ref(),
343+
)
344+
.await?;
345+
SearchAnalyticsResponse::SearchesPerUser(searches_per_user)
346+
}
334347
};
335348

336349
Ok(HttpResponse::Ok().json(response))

0 commit comments

Comments
 (0)