mirror of
https://github.com/khoj-ai/khoj.git
synced 2024-11-23 23:48:56 +01:00
Render next run time in user timezone in config, chat UIs
- Pass timezone string from ipapi to khoj via clients - Pass this data from web, desktop and obsidian clients to server - Use user tz to render next run time of scheduled task in user tz
This commit is contained in:
parent
6736551ba3
commit
c17dbbeb92
5 changed files with 33 additions and 11 deletions
|
@ -80,6 +80,7 @@ dependencies = [
|
||||||
"psutil >= 5.8.0",
|
"psutil >= 5.8.0",
|
||||||
"huggingface-hub >= 0.22.2",
|
"huggingface-hub >= 0.22.2",
|
||||||
"apscheduler ~= 3.10.0",
|
"apscheduler ~= 3.10.0",
|
||||||
|
"pytz ~= 2024.1",
|
||||||
]
|
]
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
let region = null;
|
let region = null;
|
||||||
let city = null;
|
let city = null;
|
||||||
let countryName = null;
|
let countryName = null;
|
||||||
|
let timezone = null;
|
||||||
|
|
||||||
fetch("https://ipapi.co/json")
|
fetch("https://ipapi.co/json")
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
region = data.region;
|
region = data.region;
|
||||||
city = data.city;
|
city = data.city;
|
||||||
countryName = data.country_name;
|
countryName = data.country_name;
|
||||||
|
timezone = data.timezone;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -463,7 +465,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate backend API URL to execute query
|
// Generate backend API URL to execute query
|
||||||
let chatApi = `${hostURL}/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}`;
|
let chatApi = `${hostURL}/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}&timezone=${timezone}`;
|
||||||
|
|
||||||
let newResponseEl = document.createElement("div");
|
let newResponseEl = document.createElement("div");
|
||||||
newResponseEl.classList.add("chat-message", "khoj");
|
newResponseEl.classList.add("chat-message", "khoj");
|
||||||
|
|
|
@ -15,6 +15,7 @@ export class KhojChatModal extends Modal {
|
||||||
region: string;
|
region: string;
|
||||||
city: string;
|
city: string;
|
||||||
countryName: string;
|
countryName: string;
|
||||||
|
timezone: string;
|
||||||
|
|
||||||
constructor(app: App, setting: KhojSetting) {
|
constructor(app: App, setting: KhojSetting) {
|
||||||
super(app);
|
super(app);
|
||||||
|
@ -30,6 +31,7 @@ export class KhojChatModal extends Modal {
|
||||||
this.region = data.region;
|
this.region = data.region;
|
||||||
this.city = data.city;
|
this.city = data.city;
|
||||||
this.countryName = data.country_name;
|
this.countryName = data.country_name;
|
||||||
|
this.timezone = data.timezone;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -393,7 +395,7 @@ export class KhojChatModal extends Modal {
|
||||||
|
|
||||||
// Get chat response from Khoj backend
|
// Get chat response from Khoj backend
|
||||||
let encodedQuery = encodeURIComponent(query);
|
let encodedQuery = encodeURIComponent(query);
|
||||||
let chatUrl = `${this.setting.khojUrl}/api/chat?q=${encodedQuery}&n=${this.setting.resultsCount}&client=obsidian&stream=true®ion=${this.region}&city=${this.city}&country=${this.countryName}`;
|
let chatUrl = `${this.setting.khojUrl}/api/chat?q=${encodedQuery}&n=${this.setting.resultsCount}&client=obsidian&stream=true®ion=${this.region}&city=${this.city}&country=${this.countryName}&timezone=${this.timezone}`;
|
||||||
let responseElement = this.createKhojResponseDiv();
|
let responseElement = this.createKhojResponseDiv();
|
||||||
|
|
||||||
// Temporary status message to indicate that Khoj is thinking
|
// Temporary status message to indicate that Khoj is thinking
|
||||||
|
|
|
@ -58,6 +58,7 @@ To get started, just start typing below. You can also type / to see a list of co
|
||||||
let region = null;
|
let region = null;
|
||||||
let city = null;
|
let city = null;
|
||||||
let countryName = null;
|
let countryName = null;
|
||||||
|
let timezone = null;
|
||||||
let waitingForLocation = true;
|
let waitingForLocation = true;
|
||||||
|
|
||||||
let websocketState = {
|
let websocketState = {
|
||||||
|
@ -74,13 +75,14 @@ To get started, just start typing below. You can also type / to see a list of co
|
||||||
region = data.region;
|
region = data.region;
|
||||||
city = data.city;
|
city = data.city;
|
||||||
countryName = data.country_name;
|
countryName = data.country_name;
|
||||||
|
timezone = data.timezone;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
return;
|
return;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
console.debug("Region:", region, "City:", city, "Country:", countryName);
|
console.debug("Region:", region, "City:", city, "Country:", countryName, "Timezone:", timezone);
|
||||||
waitingForLocation = false;
|
waitingForLocation = false;
|
||||||
setupWebSocket();
|
setupWebSocket();
|
||||||
});
|
});
|
||||||
|
@ -511,7 +513,7 @@ To get started, just start typing below. You can also type / to see a list of co
|
||||||
chatInput.classList.remove("option-enabled");
|
chatInput.classList.remove("option-enabled");
|
||||||
|
|
||||||
// Generate backend API URL to execute query
|
// Generate backend API URL to execute query
|
||||||
let url = `/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}`;
|
let url = `/api/chat?q=${encodeURIComponent(query)}&n=${resultsCount}&client=web&stream=true&conversation_id=${conversationID}®ion=${region}&city=${city}&country=${countryName}&timezone=${timezone}`;
|
||||||
|
|
||||||
// Call specified Khoj API
|
// Call specified Khoj API
|
||||||
let response = await fetch(url);
|
let response = await fetch(url);
|
||||||
|
@ -906,7 +908,7 @@ To get started, just start typing below. You can also type / to see a list of co
|
||||||
|
|
||||||
if (chatBody.dataset.conversationId) {
|
if (chatBody.dataset.conversationId) {
|
||||||
webSocketUrl += `?conversation_id=${chatBody.dataset.conversationId}`;
|
webSocketUrl += `?conversation_id=${chatBody.dataset.conversationId}`;
|
||||||
webSocketUrl += (!!region && !!city && !!countryName) ? `®ion=${region}&city=${city}&country=${countryName}` : '';
|
webSocketUrl += (!!region && !!city && !!countryName) && !!timezone ? `®ion=${region}&city=${city}&country=${countryName}&timezone=${timezone}` : '';
|
||||||
|
|
||||||
websocket = new WebSocket(webSocketUrl);
|
websocket = new WebSocket(webSocketUrl);
|
||||||
websocket.onmessage = function(event) {
|
websocket.onmessage = function(event) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ from datetime import datetime
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
|
|
||||||
|
import pytz
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
from asgiref.sync import sync_to_async
|
from asgiref.sync import sync_to_async
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket
|
from fastapi import APIRouter, Depends, HTTPException, Request, WebSocket
|
||||||
|
@ -273,6 +274,7 @@ async def websocket_endpoint(
|
||||||
city: Optional[str] = None,
|
city: Optional[str] = None,
|
||||||
region: Optional[str] = None,
|
region: Optional[str] = None,
|
||||||
country: Optional[str] = None,
|
country: Optional[str] = None,
|
||||||
|
timezone: Optional[str] = None,
|
||||||
):
|
):
|
||||||
connection_alive = True
|
connection_alive = True
|
||||||
|
|
||||||
|
@ -426,13 +428,19 @@ async def websocket_endpoint(
|
||||||
f"Unable to schedule reminder. Ensure the reminder doesn't already exist."
|
f"Unable to schedule reminder. Ensure the reminder doesn't already exist."
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
# Display next run time in user timezone instead of UTC
|
||||||
|
user_timezone = pytz.timezone(timezone)
|
||||||
|
next_run_time_utc = job.next_run_time.replace(tzinfo=pytz.utc)
|
||||||
|
next_run_time_user_tz = next_run_time_utc.astimezone(user_timezone)
|
||||||
|
next_run_time = next_run_time_user_tz.strftime("%Y-%m-%d %H:%M %Z (%z)")
|
||||||
|
# Remove /task prefix from inferred_query
|
||||||
unprefixed_inferred_query = re.sub(r"^\/task\s*", "", inferred_query)
|
unprefixed_inferred_query = re.sub(r"^\/task\s*", "", inferred_query)
|
||||||
next_run_time = job.next_run_time.strftime("%Y-%m-%d %H:%M:%S")
|
# Create the scheduled task response
|
||||||
llm_response = f"""
|
llm_response = f"""
|
||||||
### 🕒 Scheduled Task
|
### 🕒 Scheduled Task
|
||||||
- Query: **"{unprefixed_inferred_query}"**
|
- Query: **"{unprefixed_inferred_query}"**
|
||||||
- Schedule: `{crontime}`
|
- Schedule: `{crontime}` UTC (+0000)
|
||||||
- Next Run At: **{next_run_time}** UTC.
|
- Next Run At: **{next_run_time}**.
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
await sync_to_async(save_to_conversation_log)(
|
await sync_to_async(save_to_conversation_log)(
|
||||||
|
@ -608,6 +616,7 @@ async def chat(
|
||||||
city: Optional[str] = None,
|
city: Optional[str] = None,
|
||||||
region: Optional[str] = None,
|
region: Optional[str] = None,
|
||||||
country: Optional[str] = None,
|
country: Optional[str] = None,
|
||||||
|
timezone: Optional[str] = None,
|
||||||
rate_limiter_per_minute=Depends(
|
rate_limiter_per_minute=Depends(
|
||||||
ApiUserRateLimiter(requests=5, subscribed_requests=60, window=60, slug="chat_minute")
|
ApiUserRateLimiter(requests=5, subscribed_requests=60, window=60, slug="chat_minute")
|
||||||
),
|
),
|
||||||
|
@ -691,13 +700,19 @@ async def chat(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Display next run time in user timezone instead of UTC
|
||||||
|
user_timezone = pytz.timezone(timezone)
|
||||||
|
next_run_time_utc = job.next_run_time.replace(tzinfo=pytz.utc)
|
||||||
|
next_run_time_user_tz = next_run_time_utc.astimezone(user_timezone)
|
||||||
|
next_run_time = next_run_time_user_tz.strftime("%Y-%m-%d %H:%M %Z (%z)")
|
||||||
|
# Remove /task prefix from inferred_query
|
||||||
unprefixed_inferred_query = re.sub(r"^\/task\s*", "", inferred_query)
|
unprefixed_inferred_query = re.sub(r"^\/task\s*", "", inferred_query)
|
||||||
next_run_time = job.next_run_time.strftime("%Y-%m-%d %H:%M:%S")
|
# Create the scheduled task response
|
||||||
llm_response = f"""
|
llm_response = f"""
|
||||||
### 🕒 Scheduled Task
|
### 🕒 Scheduled Task
|
||||||
- Query: **"{unprefixed_inferred_query}"**
|
- Query: **"{unprefixed_inferred_query}"**
|
||||||
- Schedule: `{crontime}`
|
- Schedule: `{crontime}` UTC (+0000)
|
||||||
- Next Run At: **{next_run_time}** UTC.'
|
- Next Run At: **{next_run_time}**.'
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
await sync_to_async(save_to_conversation_log)(
|
await sync_to_async(save_to_conversation_log)(
|
||||||
|
|
Loading…
Reference in a new issue