fix: match Turkish search accents
This commit is contained in:
@@ -8,7 +8,7 @@ import { Card } from "@/components/ui/card";
|
|||||||
import { AdCreativeMedia } from "@/components/ad-creative-media";
|
import { AdCreativeMedia } from "@/components/ad-creative-media";
|
||||||
import { ApifyEmptySearch } from "@/components/ads/apify-empty-search";
|
import { ApifyEmptySearch } from "@/components/ads/apify-empty-search";
|
||||||
import { AD_COUNTRIES } from "@/lib/countries";
|
import { AD_COUNTRIES } from "@/lib/countries";
|
||||||
import { AdSearchMatchMode, adSearchRelevance, adSearchTokens } from "@/lib/ad-search";
|
import { AdSearchMatchMode, adSearchDatabaseTerms, adSearchRelevance } from "@/lib/ad-search";
|
||||||
|
|
||||||
export default async function AdsPage({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {
|
export default async function AdsPage({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {
|
||||||
const user = await requireUser();
|
const user = await requireUser();
|
||||||
@@ -26,13 +26,13 @@ export default async function AdsPage({ searchParams }: { searchParams: Promise<
|
|||||||
const displayableCreativeWhere: Prisma.AdCreativeWhereInput = { url: { not: "" } };
|
const displayableCreativeWhere: Prisma.AdCreativeWhereInput = { url: { not: "" } };
|
||||||
const where: Prisma.AdWhereInput = { creatives: { some: displayableCreativeWhere } };
|
const where: Prisma.AdWhereInput = { creatives: { some: displayableCreativeWhere } };
|
||||||
if (q) {
|
if (q) {
|
||||||
const terms = matchMode === "EXACT_PHRASE" ? [q] : adSearchTokens(q);
|
const terms = adSearchDatabaseTerms(q, matchMode);
|
||||||
where.AND = terms.map((term) => ({ OR: [
|
where.AND = terms.map((variants) => ({ OR: variants.flatMap((term) => [
|
||||||
{ primaryText: { contains: term, mode: "insensitive" } },
|
{ primaryText: { contains: term, mode: "insensitive" as const } },
|
||||||
{ headline: { contains: term, mode: "insensitive" } },
|
{ headline: { contains: term, mode: "insensitive" as const } },
|
||||||
{ description: { contains: term, mode: "insensitive" } },
|
{ description: { contains: term, mode: "insensitive" as const } },
|
||||||
{ brandPage: { name: { contains: term, mode: "insensitive" } } }
|
{ brandPage: { name: { contains: term, mode: "insensitive" as const } } }
|
||||||
] }));
|
]) }));
|
||||||
}
|
}
|
||||||
if (niche) where.niche = { contains: niche, mode: "insensitive" };
|
if (niche) where.niche = { contains: niche, mode: "insensitive" };
|
||||||
if (mediaType) where.mediaType = mediaType as any;
|
if (mediaType) where.mediaType = mediaType as any;
|
||||||
|
|||||||
@@ -22,6 +22,25 @@ export function adSearchTokens(query: string) {
|
|||||||
return [...new Set(normalizeAdSearchText(query).split(" ").filter(Boolean))];
|
return [...new Set(normalizeAdSearchText(query).split(" ").filter(Boolean))];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function preserveAdSearchText(value: string | null | undefined) {
|
||||||
|
return (value || "")
|
||||||
|
.normalize("NFKC")
|
||||||
|
.toLocaleLowerCase("tr-TR")
|
||||||
|
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function adSearchDatabaseTerms(query: string, mode: AdSearchMatchMode) {
|
||||||
|
const preserved = preserveAdSearchText(query);
|
||||||
|
const ascii = normalizeAdSearchText(query);
|
||||||
|
if (mode === "EXACT_PHRASE") return [[...new Set([preserved, ascii].filter(Boolean))]];
|
||||||
|
|
||||||
|
const preservedTokens = preserved.split(" ").filter(Boolean);
|
||||||
|
const asciiTokens = ascii.split(" ").filter(Boolean);
|
||||||
|
return asciiTokens.map((token, index) => [...new Set([preservedTokens[index], token].filter(Boolean))]);
|
||||||
|
}
|
||||||
|
|
||||||
function containsPhrase(text: string, phrase: string) {
|
function containsPhrase(text: string, phrase: string) {
|
||||||
return Boolean(text && phrase && ` ${text} `.includes(` ${phrase} `));
|
return Boolean(text && phrase && ` ${text} `.includes(` ${phrase} `));
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -2,7 +2,7 @@ import assert from "node:assert/strict";
|
|||||||
import test from "node:test";
|
import test from "node:test";
|
||||||
import { MediaType } from "@prisma/client";
|
import { MediaType } from "@prisma/client";
|
||||||
import { actorInput, normalizeApifyAd, selectMediaRecordsForSearch } from "../src/lib/apify";
|
import { actorInput, normalizeApifyAd, selectMediaRecordsForSearch } from "../src/lib/apify";
|
||||||
import { adSearchRelevance, filterRelevantAds } from "../src/lib/ad-search";
|
import { adSearchDatabaseTerms, adSearchRelevance, filterRelevantAds } from "../src/lib/ad-search";
|
||||||
import { getFeatureLimit } from "../src/lib/plans";
|
import { getFeatureLimit } from "../src/lib/plans";
|
||||||
import { istemciIp, hizSiniriAsimi } from "../src/lib/rate-limit";
|
import { istemciIp, hizSiniriAsimi } from "../src/lib/rate-limit";
|
||||||
import { stripePriceFor } from "../src/lib/stripe";
|
import { stripePriceFor } from "../src/lib/stripe";
|
||||||
@@ -155,6 +155,11 @@ test("reklam araması tam kelimeyi eşleştirir ve alakasız alt dizeleri dışa
|
|||||||
assert.equal(adSearchRelevance({ primaryText: "Unrelated summer sale" }, "translate", "ALL_WORDS"), 0);
|
assert.equal(adSearchRelevance({ primaryText: "Unrelated summer sale" }, "translate", "ALL_WORDS"), 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("veritabanı araması Türkçe karakterli ve ASCII yazımları birlikte tarar", () => {
|
||||||
|
assert.deepEqual(adSearchDatabaseTerms("çeviri", "ALL_WORDS"), [["çeviri", "ceviri"]]);
|
||||||
|
assert.deepEqual(adSearchDatabaseTerms("hızlı çeviri", "EXACT_PHRASE"), [["hızlı çeviri", "hızlı ceviri"]]);
|
||||||
|
});
|
||||||
|
|
||||||
test("arama sonuçları ilgililiğe göre sıralanıp istenen sayıda kesilir", () => {
|
test("arama sonuçları ilgililiğe göre sıralanıp istenen sayıda kesilir", () => {
|
||||||
const ads = [
|
const ads = [
|
||||||
{ headline: null, primaryText: "Use translate today", brandName: "Other" },
|
{ headline: null, primaryText: "Use translate today", brandName: "Other" },
|
||||||
|
|||||||
Reference in New Issue
Block a user