Skip to content
Open
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
2 changes: 1 addition & 1 deletion backend/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def _build_prompt(problem, current_time: str) -> str:
- CELL CONTENT: If a cell contains a bitwise OR operator `|` or any pipe character, you MUST escape it as `\\|` (e.g., `(a \\| b)`). Failing to escape pipes inside cells will break the table structure.
- Ensure the separator line is continuous (no line breaks) and uses at least 3 dashes per column.
- Always provide an EMPTY LINE before and after the table to ensure correct rendering.
"""
"""
if hasattr(problem, "custom_prompt") and problem.custom_prompt:
cleaned = problem.custom_prompt.strip()
if cleaned:
Expand Down
1 change: 0 additions & 1 deletion backend/ai_core/blog_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from fastapi import HTTPException
from tenacity import retry, stop_after_attempt, wait_exponential

from .prompts import build_prompt, get_current_time
from .prompts import build_prompt, build_tag_prompt, get_current_time
from .provider_manager import ProviderManager

Expand Down
2 changes: 1 addition & 1 deletion backend/ai_core/provider_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import os

from .providers.gemini_provider import GeminiProvider
from .providers.grok_provider import GrokProvider
from .providers.openai_provider import OpenAIProvider
from .providers.perplexity_provider import PerplexityProvider
from .providers.grok_provider import GrokProvider

logger = logging.getLogger(__name__)

Expand Down
1 change: 0 additions & 1 deletion backend/ai_core/providers/openai_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,3 @@ async def generate_blog(self, payload: dict):
raise HTTPException(status_code=502, detail=f"OpenAI service error: {str(e)}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Unexpected internal error: {str(e)}")

99 changes: 7 additions & 92 deletions backend/alerts/progress_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,97 +226,12 @@ async def enqueue_due_reminders(now_utc: datetime | None = None) -> dict:
if await db.reminder_jobs.find_one({"key": queue_key}, {"_id": 0}):
skipped += 1
continue
# Check if there is a blog post created today
# Date is stored as ISO format string, we can do a regex or range query
# Since it's stored as '2026-05-23T...', we can do a prefix match
today_str = today.isoformat()

solved_today_count = await db.problem_info.count_documents({
"date": {"$regex": f"^{today_str}"}
})

has_solved = solved_today_count > 0

# Also check Leetcode submissions
lc_username = user.get("leetcode_username", "vanshaggarwal27")
if not has_solved and lc_username:
try:

import requests

def check_lc():
query = """
query($username: String!, $limit: Int!) {
recentAcSubmissionList(username: $username, limit: $limit) {
timestamp
}
}
"""
return requests.post("https://leetcode.com/graphql", json={
"query": query,
"variables": {"username": lc_username, "limit": 10}
}, timeout=10).json()

data = await asyncio.to_thread(check_lc)
submissions = data.get("data", {}).get("recentAcSubmissionList", [])

# Check if any submission has a timestamp from today (UTC)
midnight_utc = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)

midnight_timestamp = int(midnight_utc.timestamp())

for sub in submissions:
if int(sub["timestamp"]) >= midnight_timestamp:
has_solved = True
print(f"Found recent Leetcode submission today for {lc_username}!")
break
except Exception as e:
print(f"Failed to check Leetcode for {lc_username}:", e)

if not has_solved:
# Not solved today, send reminder!
name = "Vansh" # Fallback or could add name to DB
message = generate_message(name)

print("Triggering alert for:", name)
print(message)
try:
send_whatsapp_message(phone, message)
print(f"WhatsApp message sent successfully to {phone}!")
except Exception as e:
print(f"Failed to send WhatsApp message to {phone}:", e)

try:
# 1. Try to Generate Audio via ElevenLabs
from alerts.elevenlabs_service import generate_audio
from alerts.twilio_service import make_call

print("Generating audio via ElevenLabs...")
try:
audio_file = generate_audio(message)

# 2. Construct public URL to the static file
backend_url = os.getenv("BACKEND_URL", "https://leetcodeai-backend.onrender.com")
if backend_url.endswith("/"):
backend_url = backend_url[:-1]

audio_url = f"{backend_url}/{audio_file}"
print(f"Audio available at: {audio_url}, making voice call...")

call_sid = make_call(phone, audio_url=audio_url)
print(f"Call placed successfully with ElevenLabs to {phone}, SID: {call_sid}")
except Exception as el_err:
print("ElevenLabs failed (possibly Free Tier VPN block):", el_err)
print("Falling back to standard Twilio Robot Voice...")
# Fallback to standard Twilio voice
call_sid = make_call(phone, text_to_say=message)
print(f"Call placed successfully with Twilio TTS to {phone}, SID: {call_sid}")

except Exception as e:
print(f"Failed to generate audio or make call to {phone}:", e)

else:
print(f"User {phone} has already solved {solved_today_count} problems today!")

await db.reminder_jobs.insert_one({"key": queue_key, "queued_at": now_utc.isoformat()})
check_user_progress_and_alert_task.delay(user_id)
queued += 1

return {"queued": queued, "skipped": skipped}

def check_unsolved_users() -> dict:
return asyncio.run(enqueue_due_reminders())
return asyncio.run(enqueue_due_reminders())
6 changes: 3 additions & 3 deletions backend/devto.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async def publish(
api_key = None
if credentials:
api_key = credentials.get("access_token") or credentials.get("devto_api_key")

if not api_key:
api_key = os.getenv("DEVTO_API_KEY")

Expand Down Expand Up @@ -163,7 +163,7 @@ async def publish(
}
}
"""
response = self._post_with_retries(
response = await self._post_with_retries(
"https://gql.hashnode.com/",
headers={
"Authorization": token,
Expand Down Expand Up @@ -352,7 +352,7 @@ async def publish_to_platforms(

async def post_to_platform(title: str, content: str) -> dict[str, Any]:
"""Backward-compatible Dev.to-only wrapper used by older integrations."""
results = publish_to_platforms(title, content, platforms=["devto"])
results = await publish_to_platforms(title, content, platforms=["devto"])
first = results[0]
if first["status"] != "success":
raise Exception(first.get("message", "Dev.to publishing failed."))
Expand Down
4 changes: 3 additions & 1 deletion backend/github_integration.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import base64

import requests


def push_solution_to_github(title: str, code: str, access_token: str, repo_name: str) -> dict:
"""
Pushes the LeetCode solution code to the user's GitHub repository.
Expand All @@ -13,7 +15,7 @@ def push_solution_to_github(title: str, code: str, access_token: str, repo_name:
file_path = f"solutions/{filename}.py"

url = f"https://api.github.com/repos/{repo_name}/contents/{file_path}"

headers = {
"Authorization": f"token {access_token}",
"Accept": "application/vnd.github.v3+json"
Expand Down
Loading
Loading