diff --git a/pyproject.toml b/pyproject.toml index e446a2a1..c8858365 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,6 +94,7 @@ prod = [ "stripe == 7.3.0", "twilio == 8.11", "boto3 >= 1.34.57", + "resend >= 0.8.0", ] dev = [ "khoj-assistant[prod]", diff --git a/src/khoj/app/settings.py b/src/khoj/app/settings.py index 8c17ec23..c8840f1f 100644 --- a/src/khoj/app/settings.py +++ b/src/khoj/app/settings.py @@ -151,7 +151,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_ROOT = BASE_DIR / "static" -STATICFILES_DIRS = [BASE_DIR / "interface/web"] +STATICFILES_DIRS = [BASE_DIR / "interface/web", BASE_DIR / "interface/email"] STATIC_URL = "/static/" # Default primary key field type diff --git a/src/khoj/configure.py b/src/khoj/configure.py index 554de35c..60aaf658 100644 --- a/src/khoj/configure.py +++ b/src/khoj/configure.py @@ -231,7 +231,10 @@ def configure_server( state.SearchType = configure_search_types() state.search_models = configure_search(state.search_models, state.config.search_type) setup_default_agent() - initialize_content(regenerate, search_type, init, user) + + if not init: + initialize_content(regenerate, search_type, user) + except Exception as e: raise e @@ -240,23 +243,20 @@ def setup_default_agent(): AgentAdapters.create_default_agent() -def initialize_content(regenerate: bool, search_type: Optional[SearchType] = None, init=False, user: KhojUser = None): +def initialize_content(regenerate: bool, search_type: Optional[SearchType] = None, user: KhojUser = None): # Initialize Content from Config if state.search_models: try: - if init: - logger.info("📬 No-op...") - else: - logger.info("📬 Updating content index...") - all_files = collect_files(user=user) - status = configure_content( - all_files, - regenerate, - search_type, - user=user, - ) - if not status: - raise RuntimeError("Failed to update content index") + logger.info("📬 Updating content index...") + all_files = collect_files(user=user) + status = configure_content( + all_files, + regenerate, + search_type, + user=user, + ) + if not status: + raise RuntimeError("Failed to update content index") except Exception as e: raise e diff --git a/src/khoj/interface/email/welcome.html b/src/khoj/interface/email/welcome.html new file mode 100644 index 00000000..e10f392a --- /dev/null +++ b/src/khoj/interface/email/welcome.html @@ -0,0 +1,61 @@ + + + + Welcome to Khoj + + + + + +
+
+

Merge AI with your brain

+

Hi {{name}}! We are psyched to be part of your journey with personal AI. To better help you, we're committed to staying transparent, accessible, and completely open-source.

+ Get Started +

You're about to get a whole lot more more productive.

+ +
+
+ +

Ditch the search bar

+
+

You don't need to click around Google results and sift through information yourself, because Khoj is connected to the internet.

+
+
+ +

Get a village, not just an agent

+
+

Khoj can fill the need for more specialized assistance, such as tutoring, with its curated agents. You get a whole team, always available.

+
+
+ +

Available where you are

+
+

Build on top of your digital brain. Khoj stores whatever data you share with it, so you can get answers from your personal notes and documents in your native language. You can engage from your desktop, Obsidian, WhatsApp, or the web.

+
+
+ +

Create rich, contextual images

+
+

With your shared data, Khoj can help you create astoundingly personal images depicting scenes of what's important to you.

+
+
+
+
+

Like something? Dislike something? Searching for some other magical feature? Our inbox is always open for feedback! Contact us on team@khoj.dev at anytime.

+ +

- The Khoj Team

+ + + + + + + + +
DocsGitHubTwitterLinkedInDiscord
+ + + diff --git a/src/khoj/routers/api.py b/src/khoj/routers/api.py index 06dca0db..e07e3881 100644 --- a/src/khoj/routers/api.py +++ b/src/khoj/routers/api.py @@ -182,7 +182,7 @@ def update( logger.warning(error_msg) raise HTTPException(status_code=500, detail=error_msg) try: - initialize_content(regenerate=force, search_type=t, init=False, user=user) + initialize_content(regenerate=force, search_type=t, user=user) except Exception as e: error_msg = f"🚨 Failed to update server via API: {e}" logger.error(error_msg, exc_info=True) diff --git a/src/khoj/routers/auth.py b/src/khoj/routers/auth.py index 57baf7f2..1ddbe5f0 100644 --- a/src/khoj/routers/auth.py +++ b/src/khoj/routers/auth.py @@ -1,3 +1,5 @@ +import asyncio +import datetime import logging import os from typing import Optional @@ -15,6 +17,7 @@ from khoj.database.adapters import ( get_khoj_tokens, get_or_create_user, ) +from khoj.routers.email import send_welcome_email from khoj.routers.helpers import update_telemetry_state from khoj.utils import state @@ -110,10 +113,12 @@ async def auth(request: Request): except OAuthError as error: return HTMLResponse(f"

{error.error}

") khoj_user = await get_or_create_user(idinfo) + if khoj_user: request.session["user"] = dict(idinfo) - if not khoj_user.last_login: + if datetime.timedelta(minutes=3) > (datetime.datetime.now(datetime.UTC) - khoj_user.date_joined): + asyncio.create_task(send_welcome_email(idinfo["name"], idinfo["email"])) update_telemetry_state( request=request, telemetry_type="api", diff --git a/src/khoj/routers/email.py b/src/khoj/routers/email.py new file mode 100644 index 00000000..19629943 --- /dev/null +++ b/src/khoj/routers/email.py @@ -0,0 +1,38 @@ +import logging +import os + +import resend +from django.conf import settings +from jinja2 import Environment, FileSystemLoader + +from khoj.utils.helpers import is_none_or_empty + +logger = logging.getLogger(__name__) + + +RESEND_API_KEY = os.getenv("RESEND_API_KEY") + +static_files = os.path.join(settings.BASE_DIR, "static") + +env = Environment(loader=FileSystemLoader(static_files)) + +if not RESEND_API_KEY: + logger.info("RESEND_API_KEY not set - email sending disabled") + + +resend.api_key = RESEND_API_KEY + + +async def send_welcome_email(name, email): + template = env.get_template("welcome.html") + + html_content = template.render(name=name if not is_none_or_empty(name) else "you") + + r = resend.Emails.send( + { + "from": "team@khoj.dev", + "to": email, + "subject": f"Welcome to Khoj, {name}!" if name else "Welcome to Khoj!", + "html": html_content, + } + )