Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: demo ai search #893

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
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 change: 1 addition & 0 deletions .github/workflows/deploy-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
security-events: write
secrets: inherit
with:
NAIS_RESOURCE: .nais/nais.yml
SKIP_DRAFT_RELEASE: ${{ github.ref_name != 'master' }}
deploy-redis:
name: Deploy redis
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ screenshots

# Sentry auth token
.sentryclirc

.aiapikey
3 changes: 3 additions & 0 deletions .nais/nais.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ spec:
- name: {{@key}}
value: "{{this}}"
{{/each}}
envFrom:
- secret: pam-ai
accessPolicy:
inbound:
rules:
Expand All @@ -73,6 +75,7 @@ spec:
- host: {{ arbeidsplassen_domain }}
- host: amplitude.nav.no
- host: sentry.gc.nav.no
- host: ai-stillingsok-poc.search.windows.net
redis:
- instance: {{ redis.instance }}
access: readwrite
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ services:

pam-aduser:
platform: linux/amd64
image: europe-north1-docker.pkg.dev/nais-management-233d/teampam/pam-aduser:24.291.135500
image: europe-north1-docker.pkg.dev/nais-management-233d/teampam/pam-aduser:24.310.120237
restart: unless-stopped
ports:
- "9017:9017"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"next": "npm run dev",
"build": "next build",
"dev": "next dev -p 3003",
"dev": "AZURE_SEARCH_KEY=$(if [ -f .aiapikey ]; then cat .aiapikey; fi) next dev -p 3003",
"test": "vitest run",
"test:watch": "vitest watch",
"start:dependencies": "./start-docker-compose.sh",
Expand Down
14 changes: 12 additions & 2 deletions src/app/(sok)/_components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,24 @@ import { SearchResult as SearchResultType } from "@/app/(sok)/_types/SearchResul
import { SearchLocation } from "@/app/(sok)/page";

interface SearchProps {
// eslint-disable-next-line
aiSearchData: any;
searchResult: SearchResultType;
aggregations: FilterAggregations;
locations: SearchLocation[];
postcodes: Postcode[];
resultsPerPage: number;
errors: FetchError[];
}
const Search = ({ searchResult, aggregations, locations, postcodes, resultsPerPage, errors }: SearchProps) => {
const Search = ({
aiSearchData,
searchResult,
aggregations,
locations,
postcodes,
resultsPerPage,
errors,
}: SearchProps) => {
const [isFiltersVisible, setIsFiltersVisible] = useState(false);
const failedToSearchForPostcodes =
errors.length > 0 && errors.find((error) => error.type === FETCH_SEARCH_WITHIN_DISTANCE_ERROR);
Expand Down Expand Up @@ -78,7 +88,7 @@ const Search = ({ searchResult, aggregations, locations, postcodes, resultsPerPa
</Alert>
)}

<SearchResult searchResult={searchResult} />
<SearchResult aiSearchData={aiSearchData} searchResult={searchResult} />
<MaxResultsBox resultsPerPage={resultsPerPage} />
<SearchPagination searchResult={searchResult} resultsPerPage={resultsPerPage} />
<DoYouWantToSaveSearch totalAds={searchResult.totalAds} />
Expand Down
4 changes: 4 additions & 0 deletions src/app/(sok)/_components/SearchWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { FetchError } from "@/app/(sok)/_utils/fetchTypes";
import { SearchLocation } from "@/app/(sok)/page";

type SearchWrapperProps = {
// eslint-disable-next-line
aiSearchData: any;
searchResult: SearchResult;
aggregations: FilterAggregations;
locations: SearchLocation[];
Expand All @@ -18,6 +20,7 @@ type SearchWrapperProps = {
errors: FetchError[];
};
const SearchWrapper = ({
aiSearchData,
searchResult,
aggregations,
locations,
Expand All @@ -28,6 +31,7 @@ const SearchWrapper = ({
return (
<QueryProvider>
<Search
aiSearchData={aiSearchData}
searchResult={searchResult}
locations={locations}
aggregations={aggregations}
Expand Down
52 changes: 52 additions & 0 deletions src/app/(sok)/_components/searchBox/SearchAi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"use client";

import { Search } from "@navikt/ds-react";
import React, { useEffect, useState } from "react";
import useQuery from "@/app/(sok)/_components/QueryProvider";
import { QueryNames } from "@/app/(sok)/_utils/QueryNames";

function SearchAi() {
// eslint-disable-next-line
const [windowWidth, setWindowWidth] = useState<number>(0);

const [searchTerm, setSearchTerm] = useState<string>("");

const query = useQuery();
const inputQuery = query.get("q") || "";

useEffect(() => {
function handleResize() {
setWindowWidth(window.innerWidth);
}

window.addEventListener("resize", handleResize);
handleResize();

return () => window.removeEventListener("resize", handleResize);
}, []);

// eslint-disable-next-line
const submitForm = (e: any) => {
e.preventDefault();
query.remove(QueryNames.SEARCH_STRING);
query.append(QueryNames.SEARCH_STRING, searchTerm);
};

return (
<>
<form onSubmit={submitForm}>
<Search
defaultValue={inputQuery}
label="(a)I robot"
hideLabel={false}
onChange={(e) => {
setSearchTerm(e);
}}
variant="primary"
/>
</form>
</>
);
}

export default SearchAi;
4 changes: 3 additions & 1 deletion src/app/(sok)/_components/searchBox/SearchBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import LoggedInButtons from "@/app/(sok)/_components/loggedInButtons/LoggedInBut
import FilterAggregations from "@/app/(sok)/_types/FilterAggregations";
import { Postcode } from "@/app/(sok)/_utils/fetchPostcodes";
import { SearchLocation } from "@/app/(sok)/page";
import SearchAi from "./SearchAi";

interface SearchBoxProps {
aggregations: FilterAggregations;
Expand All @@ -19,6 +20,7 @@ interface SearchBoxProps {

export default function SearchBox({ aggregations, locations, postcodes }: SearchBoxProps): ReactElement {
const query = useQuery();
const showSearchAi = query.has("ai");

const drivingDistanceFilterActive =
query.has(QueryNames.POSTCODE) &&
Expand Down Expand Up @@ -68,7 +70,7 @@ export default function SearchBox({ aggregations, locations, postcodes }: Search
</BodyShort>

<VStack gap="3">
<SearchCombobox aggregations={aggregations} locations={locations} />
{showSearchAi ? <SearchAi /> : <SearchCombobox aggregations={aggregations} locations={locations} />}

{drivingDistanceFilterActive && (
<HStack align="center" wrap={false} gap="1">
Expand Down
77 changes: 53 additions & 24 deletions src/app/(sok)/_components/searchResult/SearchResult.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@ import Divider from "@/app/(sok)/_components/searchResult/Divider";
import { SortByValues } from "@/app/(sok)/_components/searchResult/Sorting";
import { SEARCH_CHUNK_SIZE } from "../../_utils/query";
import SearchResultItem from "./SearchResultItem";
import SearchResultItemAi from "./SearchResultItemAi";
import useIsDebug from "@/app/(sok)/_components/IsDebugProvider";
import { SearchResult as SearchResultType } from "@/app/(sok)/_types/SearchResult";

interface SearchResultProps {
// eslint-disable-next-line
aiSearchData: any;
searchResult: SearchResultType;
}

export default function SearchResult({ searchResult }: SearchResultProps): ReactElement | null {
export default function SearchResult({ aiSearchData, searchResult }: SearchResultProps): ReactElement | null {
const query = useQuery();
const showSearchAi = query.has("ai");
const { isDebug } = useIsDebug();

const resultsPerPage: number = query.has(QueryNames.FROM)
Expand All @@ -35,6 +39,10 @@ export default function SearchResult({ searchResult }: SearchResultProps): React
(ad) => ad.score && ad.score < SCORE_THRESHOLD,
);

if (showSearchAi) {
console.log("AI HITS", aiSearchData);
}

/**
* Set focus to top of result list when user paginate to next search result section
*/
Expand All @@ -46,7 +54,7 @@ export default function SearchResult({ searchResult }: SearchResultProps): React
}
}, [query.paginate]);

if (!searchResult.ads || searchResult.ads.length === 0) {
if (!searchResult.ads || (searchResult.ads.length === 0 && !showSearchAi)) {
return null;
}

Expand All @@ -59,28 +67,49 @@ export default function SearchResult({ searchResult }: SearchResultProps): React
aria-label={`Søketreff, side ${page} av ${totalPages}`}
className="no-focus-outline"
>
{searchResult.ads.map((ad, index) => (
<React.Fragment key={ad.uuid}>
{isDebug &&
(!query.has(QueryNames.SORT) || query.get(QueryNames.SORT) === SortByValues.RELEVANT) &&
indexOfLastWithScoreAboveThreshold === index && <Divider />}
<SearchResultItem
ad={ad}
favouriteButton={
<FavouritesButton
useShortText
className="SearchResultsItem__favourite-button"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
stilling={ad as any}
id={ad.uuid}
hideText
variant="tertiary"
/>
}
isDebug={isDebug}
/>
</React.Fragment>
))}
{showSearchAi
? // eslint-disable-next-line
aiSearchData?.value.map((ad: any, index: any) => (
<React.Fragment key={index + ad.uuid}>
<SearchResultItemAi
ad={ad}
favouriteButton={
<FavouritesButton
useShortText
className="SearchResultsItem__favourite-button"
// eslint-disable-next-line
stilling={ad as any}
id={ad.uuid}
hideText
variant="tertiary"
/>
}
isDebug={isDebug}
/>
</React.Fragment>
))
: searchResult.ads.map((ad, index) => (
<React.Fragment key={ad.uuid}>
{isDebug &&
(!query.has(QueryNames.SORT) || query.get(QueryNames.SORT) === SortByValues.RELEVANT) &&
indexOfLastWithScoreAboveThreshold === index && <Divider />}
<SearchResultItem
ad={ad}
favouriteButton={
<FavouritesButton
useShortText
className="SearchResultsItem__favourite-button"
// eslint-disable-next-line
stilling={ad as any}
id={ad.uuid}
hideText
variant="tertiary"
/>
}
isDebug={isDebug}
/>
</React.Fragment>
))}
</VStack>
);
}
Loading
Loading