mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-03 13:19:16 +00:00
Make Online Search Location Aware (#929)
## Overview Add user country code as context for doing online search with serper.dev API. This should find more user relevant results from online searches by Khoj ## Details ### Major - Default to using system clock to infer user timezone on js clients - Infer country from timezone when only timezone received by chat API - Localize online search results to user country when location available ### Minor - Add `__str__` func to `LocationData` class to deduplicate location string generation
This commit is contained in:
@@ -60,7 +60,8 @@
|
||||
let region = null;
|
||||
let city = null;
|
||||
let countryName = null;
|
||||
let timezone = null;
|
||||
let countryCode = null;
|
||||
let timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
let chatMessageState = {
|
||||
newResponseTextEl: null,
|
||||
newResponseEl: null,
|
||||
@@ -76,6 +77,7 @@
|
||||
region = data.region;
|
||||
city = data.city;
|
||||
countryName = data.country_name;
|
||||
countryCode = data.country_code;
|
||||
timezone = data.timezone;
|
||||
})
|
||||
.catch(err => {
|
||||
@@ -157,6 +159,7 @@
|
||||
...(!!city && { city: city }),
|
||||
...(!!region && { region: region }),
|
||||
...(!!countryName && { country: countryName }),
|
||||
...(!!countryCode && { country_code: countryCode }),
|
||||
...(!!timezone && { timezone: timezone }),
|
||||
};
|
||||
|
||||
|
||||
@@ -308,18 +308,19 @@
|
||||
<script src="./utils.js"></script>
|
||||
<script src="./chatutils.js"></script>
|
||||
<script>
|
||||
|
||||
let region = null;
|
||||
let city = null;
|
||||
let countryName = null;
|
||||
let timezone = null;
|
||||
let countryCode = null;
|
||||
let timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
fetch("https://ipapi.co/json")
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
region = data.region;
|
||||
city = data.city;
|
||||
region = data.region;
|
||||
countryName = data.country_name;
|
||||
countryCode = data.country_code;
|
||||
timezone = data.timezone;
|
||||
})
|
||||
.catch(err => {
|
||||
@@ -410,6 +411,7 @@
|
||||
...(!!city && { city: city }),
|
||||
...(!!region && { region: region }),
|
||||
...(!!countryName && { country: countryName }),
|
||||
...(!!countryCode && { country_code: countryCode }),
|
||||
...(!!timezone && { timezone: timezone }),
|
||||
};
|
||||
|
||||
|
||||
@@ -33,9 +33,10 @@ interface ChatMessageState {
|
||||
}
|
||||
|
||||
interface Location {
|
||||
region: string;
|
||||
city: string;
|
||||
countryName: string;
|
||||
region?: string;
|
||||
city?: string;
|
||||
countryName?: string;
|
||||
countryCode?: string;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
@@ -43,7 +44,7 @@ export class KhojChatView extends KhojPaneView {
|
||||
result: string;
|
||||
setting: KhojSetting;
|
||||
waitingForLocation: boolean;
|
||||
location: Location;
|
||||
location: Location = { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone };
|
||||
keyPressTimeout: NodeJS.Timeout | null = null;
|
||||
userMessages: string[] = []; // Store user sent messages for input history cycling
|
||||
currentMessageIndex: number = -1; // Track current message index in userMessages array
|
||||
@@ -70,6 +71,7 @@ export class KhojChatView extends KhojPaneView {
|
||||
region: data.region,
|
||||
city: data.city,
|
||||
countryName: data.country_name,
|
||||
countryCode: data.country_code,
|
||||
timezone: data.timezone,
|
||||
};
|
||||
})
|
||||
@@ -1056,12 +1058,11 @@ export class KhojChatView extends KhojPaneView {
|
||||
n: this.setting.resultsCount,
|
||||
stream: true,
|
||||
...(!!conversationId && { conversation_id: conversationId }),
|
||||
...(!!this.location && {
|
||||
city: this.location.city,
|
||||
region: this.location.region,
|
||||
country: this.location.countryName,
|
||||
timezone: this.location.timezone,
|
||||
}),
|
||||
...(!!this.location && this.location.city && { city: this.location.city }),
|
||||
...(!!this.location && this.location.region && { region: this.location.region }),
|
||||
...(!!this.location && this.location.countryName && { country: this.location.countryName }),
|
||||
...(!!this.location && this.location.countryCode && { country_code: this.location.countryCode }),
|
||||
...(!!this.location && this.location.timezone && { timezone: this.location.timezone }),
|
||||
};
|
||||
|
||||
let newResponseEl = this.createKhojResponseDiv();
|
||||
|
||||
@@ -518,12 +518,14 @@ function EditCard(props: EditCardProps) {
|
||||
updateQueryUrl += `&subject=${encodeURIComponent(values.subject)}`;
|
||||
}
|
||||
updateQueryUrl += `&crontime=${encodeURIComponent(cronFrequency)}`;
|
||||
if (props.locationData) {
|
||||
if (props.locationData && props.locationData.city)
|
||||
updateQueryUrl += `&city=${encodeURIComponent(props.locationData.city)}`;
|
||||
if (props.locationData && props.locationData.region)
|
||||
updateQueryUrl += `®ion=${encodeURIComponent(props.locationData.region)}`;
|
||||
if (props.locationData && props.locationData.country)
|
||||
updateQueryUrl += `&country=${encodeURIComponent(props.locationData.country)}`;
|
||||
if (props.locationData && props.locationData.timezone)
|
||||
updateQueryUrl += `&timezone=${encodeURIComponent(props.locationData.timezone)}`;
|
||||
}
|
||||
|
||||
let method = props.createNew ? "POST" : "PUT";
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ export default function Chat() {
|
||||
const [uploadedFiles, setUploadedFiles] = useState<string[]>([]);
|
||||
const [image64, setImage64] = useState<string>("");
|
||||
|
||||
const locationData = useIPLocationData();
|
||||
const locationData = useIPLocationData() || {
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
};
|
||||
const authenticatedData = useAuthenticatedData();
|
||||
const isMobileWidth = useIsMobileWidth();
|
||||
|
||||
@@ -241,9 +243,10 @@ export default function Chat() {
|
||||
conversation_id: conversationId,
|
||||
stream: true,
|
||||
...(locationData && {
|
||||
city: locationData.city,
|
||||
region: locationData.region,
|
||||
country: locationData.country,
|
||||
city: locationData.city,
|
||||
country_code: locationData.countryCode,
|
||||
timezone: locationData.timezone,
|
||||
}),
|
||||
...(image64 && { image: image64 }),
|
||||
|
||||
@@ -2,13 +2,10 @@ import { useEffect, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
export interface LocationData {
|
||||
ip: string;
|
||||
city: string;
|
||||
region: string;
|
||||
country: string;
|
||||
postal: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
city?: string;
|
||||
region?: string;
|
||||
country?: string;
|
||||
countryCode?: string;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
@@ -50,9 +47,7 @@ export function useIPLocationData() {
|
||||
{ revalidateOnFocus: false },
|
||||
);
|
||||
|
||||
if (locationDataError) return null;
|
||||
if (!locationData) return null;
|
||||
|
||||
if (locationDataError || !locationData) return;
|
||||
return locationData;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,9 @@ export default function SharedChat() {
|
||||
const [paramSlug, setParamSlug] = useState<string | undefined>(undefined);
|
||||
const [image64, setImage64] = useState<string>("");
|
||||
|
||||
const locationData = useIPLocationData();
|
||||
const locationData = useIPLocationData() || {
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
};
|
||||
const authenticatedData = useAuthenticatedData();
|
||||
const isMobileWidth = useIsMobileWidth();
|
||||
|
||||
@@ -231,6 +233,7 @@ export default function SharedChat() {
|
||||
region: locationData.region,
|
||||
country: locationData.country,
|
||||
city: locationData.city,
|
||||
country_code: locationData.countryCode,
|
||||
timezone: locationData.timezone,
|
||||
}),
|
||||
...(image64 && { image: image64 }),
|
||||
|
||||
Reference in New Issue
Block a user