Hamdy005 commited on
Commit
954e0aa
Β·
1 Parent(s): 93ff956

refactor: replace standard logging with a centralized loguru configuration and interception handler

Browse files
asr/batch_workers.py CHANGED
@@ -15,14 +15,12 @@ Architecture (mirrors Raij/src/smart_search/batch_workers.py, audio workers only
15
  import asyncio
16
  import time
17
  import uuid
18
- import logging
19
  from typing import Any
20
 
21
  from .constants import ASR_BATCH_MAX, ASR_BATCH_WINDOW_S, WARMUP_INTERVAL_S, PARAKEET_WARMUP_EVERY
22
  from .schemas import AudioJob
23
 
24
- logger = logging.getLogger(__name__)
25
-
26
 
27
  # ═══════════════════════ Job Store ════════════════════════
28
 
 
15
  import asyncio
16
  import time
17
  import uuid
18
+ from loguru import logger
19
  from typing import Any
20
 
21
  from .constants import ASR_BATCH_MAX, ASR_BATCH_WINDOW_S, WARMUP_INTERVAL_S, PARAKEET_WARMUP_EVERY
22
  from .schemas import AudioJob
23
 
 
 
24
 
25
  # ═══════════════════════ Job Store ════════════════════════
26
 
asr/models.py CHANGED
@@ -16,9 +16,7 @@ Strategy (ported from Raij/src/models.py, hotword biasing removed):
16
 
17
  import os
18
  import threading
19
- import logging
20
-
21
- logger = logging.getLogger(__name__)
22
 
23
  # Force PyTorch path, no TensorFlow
24
  os.environ.setdefault("USE_TF", "0")
 
16
 
17
  import os
18
  import threading
19
+ from loguru import logger
 
 
20
 
21
  # Force PyTorch path, no TensorFlow
22
  os.environ.setdefault("USE_TF", "0")
asr/routes.py CHANGED
@@ -2,7 +2,7 @@ import asyncio
2
  import os
3
  import tempfile
4
  import uuid
5
- import logging
6
  from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Depends
7
  from fastapi.responses import JSONResponse
8
 
@@ -10,8 +10,6 @@ from src.dependencies import get_current_user_id
10
  from src.asr.schemas import AudioJob
11
  from src.asr.batch_workers import audio_en_queue, audio_ar_queue, job_store
12
 
13
- logger = logging.getLogger(__name__)
14
-
15
  router = APIRouter(prefix="/api/asr", tags=["ASR"])
16
 
17
  # Allowed audio MIME types from browsers (MediaRecorder output)
 
2
  import os
3
  import tempfile
4
  import uuid
5
+ from loguru import logger
6
  from fastapi import APIRouter, UploadFile, File, Form, HTTPException, Depends
7
  from fastapi.responses import JSONResponse
8
 
 
10
  from src.asr.schemas import AudioJob
11
  from src.asr.batch_workers import audio_en_queue, audio_ar_queue, job_store
12
 
 
 
13
  router = APIRouter(prefix="/api/asr", tags=["ASR"])
14
 
15
  # Allowed audio MIME types from browsers (MediaRecorder output)
auth/refresh_token_store.py CHANGED
@@ -34,7 +34,7 @@ Table DDL (run once in the Supabase SQL editor):
34
  CREATE INDEX ON refresh_tokens(user_id);
35
  """
36
 
37
- import logging
38
  from datetime import datetime, timedelta, timezone
39
  from typing import Optional
40
 
@@ -47,8 +47,6 @@ from src.auth.constants import (
47
  )
48
  from src.redis_client import get_redis
49
 
50
- logger = logging.getLogger(__name__)
51
-
52
 
53
  def _rt_key(token_hash: str) -> str:
54
  return f"{REFRESH_TOKEN_KEY_PREFIX}{token_hash}"
 
34
  CREATE INDEX ON refresh_tokens(user_id);
35
  """
36
 
37
+ from loguru import logger
38
  from datetime import datetime, timedelta, timezone
39
  from typing import Optional
40
 
 
47
  )
48
  from src.redis_client import get_redis
49
 
 
 
50
 
51
  def _rt_key(token_hash: str) -> str:
52
  return f"{REFRESH_TOKEN_KEY_PREFIX}{token_hash}"
auth/routes.py CHANGED
@@ -1,5 +1,5 @@
1
  import uuid
2
- import logging
3
  import cloudinary
4
  import cloudinary.uploader
5
  from datetime import timezone, datetime
@@ -7,8 +7,6 @@ from fastapi import APIRouter, HTTPException, UploadFile, File, Response, Reques
7
  from fastapi import Depends
8
  from typing import Optional
9
 
10
- logger = logging.getLogger(__name__)
11
-
12
  from src.config import settings
13
  from src.database import get_auth_supabase, get_supabase
14
  from src.store import create_user, get_user_by_email, delete_user_data, update_user_profile, get_user_by_id
 
1
  import uuid
2
+ from loguru import logger
3
  import cloudinary
4
  import cloudinary.uploader
5
  from datetime import timezone, datetime
 
7
  from fastapi import Depends
8
  from typing import Optional
9
 
 
 
10
  from src.config import settings
11
  from src.database import get_auth_supabase, get_supabase
12
  from src.store import create_user, get_user_by_email, delete_user_data, update_user_profile, get_user_by_id
database.py CHANGED
@@ -1,10 +1,8 @@
1
- import logging
2
  from typing import Optional
 
3
  from supabase import Client, create_client
4
  from src.config import settings
5
 
6
- logger = logging.getLogger(__name__)
7
-
8
  # Singletons β€” created once, reused on every request
9
  _supabase_client: Optional[Client] = None
10
  _auth_supabase_client: Optional[Client] = None
 
 
1
  from typing import Optional
2
+ from loguru import logger
3
  from supabase import Client, create_client
4
  from src.config import settings
5
 
 
 
6
  # Singletons β€” created once, reused on every request
7
  _supabase_client: Optional[Client] = None
8
  _auth_supabase_client: Optional[Client] = None
logger.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import logging
4
+ from loguru import logger
5
+
6
+ class InterceptHandler(logging.Handler):
7
+ """
8
+ Standard logging handler to intercept standard logging messages
9
+ and redirect them to Loguru.
10
+ """
11
+ def emit(self, record: logging.LogRecord) -> None:
12
+ # Get corresponding Loguru level if it exists
13
+ try:
14
+ level: str | int = logger.level(record.levelname).name
15
+ except ValueError:
16
+ level = record.levelno
17
+
18
+ # Find caller from where originated the logged message
19
+ frame = logging.currentframe()
20
+ depth = 2
21
+ while frame and frame.f_code.co_filename == logging.__file__:
22
+ frame = frame.f_back
23
+ depth += 1
24
+
25
+ logger.opt(depth=depth, exception=record.exc_info).log(
26
+ level, record.getMessage()
27
+ )
28
+
29
+ def setup_logging():
30
+ """
31
+ Configures Loguru for console and file logging, and intercepts
32
+ standard library logging (uvicorn, httpx, etc.).
33
+ """
34
+ os.makedirs("logs", exist_ok=True)
35
+
36
+ # Remove default handlers
37
+ logger.remove()
38
+
39
+ # Log format specifications
40
+ console_format = (
41
+ "<green>{time:YYYY-MM-DD HH:mm:ss}</green> | "
42
+ "<level>{level: <8}</level> | "
43
+ "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - "
44
+ "<level>{message}</level>"
45
+ )
46
+
47
+ file_format = "{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {name}:{function}:{line} - {message}"
48
+
49
+ # Console Handler (colored)
50
+ logger.add(
51
+ sys.stdout,
52
+ level="INFO",
53
+ format=console_format,
54
+ colorize=True,
55
+ enqueue=True,
56
+ backtrace=True,
57
+ diagnose=True,
58
+ )
59
+
60
+ # Rotating File Handler (5 MB per file, max 3 backups)
61
+ logger.add(
62
+ "logs/app.log",
63
+ level="INFO",
64
+ format=file_format,
65
+ rotation="5 MB",
66
+ retention=3,
67
+ encoding="utf-8",
68
+ enqueue=True,
69
+ )
70
+
71
+ # Intercept standard Python logging
72
+ logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
73
+
74
+ # Ensure uvicorn, fastapi, watchfiles, and httpx use the intercept handler
75
+ for log_name in ("uvicorn", "uvicorn.access", "uvicorn.error", "fastapi", "watchfiles", "httpx"):
76
+ mod_logger = logging.getLogger(log_name)
77
+ mod_logger.handlers = [InterceptHandler()]
78
+ if "watchfiles" in log_name:
79
+ mod_logger.setLevel(logging.WARNING)
80
+
81
+ return logger
82
+
83
+ __all__ = ["logger", "setup_logging", "InterceptHandler"]
main.py CHANGED
@@ -1,5 +1,3 @@
1
- import logging
2
- import logging.handlers
3
  import os
4
  import sys
5
 
@@ -8,6 +6,9 @@ parent_dir = os.path.dirname(current_dir)
8
  if parent_dir not in sys.path:
9
  sys.path.insert(0, parent_dir)
10
 
 
 
 
11
  from contextlib import asynccontextmanager
12
  from fastapi import FastAPI, Depends
13
  from fastapi.middleware.cors import CORSMiddleware
@@ -21,38 +22,7 @@ from src.auth.routes import router as auth_router
21
  from src.asr.routes import router as asr_router
22
  from src.store import get_usage
23
  from src.dependencies import get_current_user_id
24
- from src.config import settings
25
-
26
- # ── Logging Setup ──────────────────────────────────────
27
- os.makedirs("logs", exist_ok=True)
28
-
29
- log_formatter = logging.Formatter(
30
- "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
31
- datefmt="%Y-%m-%d %H:%M:%S",
32
- )
33
-
34
- # File handler β€” rotates at 5MB, keeps 3 backups
35
- file_handler = logging.handlers.RotatingFileHandler(
36
- "logs/app.log", maxBytes=5 * 1024 * 1024, backupCount=3, encoding="utf-8"
37
- )
38
- file_handler.setFormatter(log_formatter)
39
-
40
- # Console handler
41
- console_handler = logging.StreamHandler()
42
- console_handler.setFormatter(log_formatter)
43
-
44
- # Apply to root logger so all src.* modules inherit it
45
- root_logger = logging.getLogger()
46
- root_logger.setLevel(logging.INFO)
47
- root_logger.addHandler(file_handler)
48
- root_logger.addHandler(console_handler)
49
-
50
- # Suppress noisy watchfiles reload logs
51
- logging.getLogger("watchfiles").setLevel(logging.WARNING)
52
- logging.getLogger("watchfiles.main").setLevel(logging.WARNING)
53
-
54
- logger = logging.getLogger(__name__)
55
-
56
 
57
  @asynccontextmanager
58
  async def lifespan(app: FastAPI):
@@ -79,24 +49,24 @@ async def lifespan(app: FastAPI):
79
  except Exception as e:
80
  logger.warning(f"Embedder failed to load: {e}")
81
 
82
- # # Eagerly load ASR models so warmup runs at startup, not on first request
83
- # try:
84
- # from src.asr.models import get_audio_model_en
85
- # get_audio_model_en()
86
- # except Exception as e:
87
- # logger.warning(f"English ASR model failed to load: {e}")
88
 
89
- # try:
90
- # from src.asr.models import get_audio_model_ar
91
- # get_audio_model_ar()
92
- # except Exception as e:
93
- # logger.warning(f"Arabic ASR model failed to load: {e}")
94
 
95
- # from src.rag.batch_workers import start_workers
96
- # start_workers()
97
 
98
- # from src.asr.batch_workers import start_asr_workers
99
- # start_asr_workers()
100
 
101
  yield
102
 
@@ -125,12 +95,28 @@ _raw_origins = settings.cors_allowed_origins if settings.cors_allowed_origins el
125
  _cors_origins = [o.strip() for o in _raw_origins if o.strip() and o.strip() != "*"] or _DEFAULT_ORIGINS
126
 
127
  @app.middleware("http")
128
- async def normalize_path(request, call_next):
 
 
129
  # Fix double slashes in paths (e.g., //api/usage -> /api/usage)
130
  path = request.scope.get("path")
131
  if path and "//" in path:
132
  request.scope["path"] = path.replace("//", "/")
133
- return await call_next(request)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
136
 
 
 
 
1
  import os
2
  import sys
3
 
 
6
  if parent_dir not in sys.path:
7
  sys.path.insert(0, parent_dir)
8
 
9
+ from src.logger import setup_logging, logger
10
+ setup_logging()
11
+
12
  from contextlib import asynccontextmanager
13
  from fastapi import FastAPI, Depends
14
  from fastapi.middleware.cors import CORSMiddleware
 
22
  from src.asr.routes import router as asr_router
23
  from src.store import get_usage
24
  from src.dependencies import get_current_user_id
25
+ from src.config import settings
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  @asynccontextmanager
28
  async def lifespan(app: FastAPI):
 
49
  except Exception as e:
50
  logger.warning(f"Embedder failed to load: {e}")
51
 
52
+ # Eagerly load ASR models so warmup runs at startup, not on first request
53
+ try:
54
+ from src.asr.models import get_audio_model_en
55
+ get_audio_model_en()
56
+ except Exception as e:
57
+ logger.warning(f"English ASR model failed to load: {e}")
58
 
59
+ try:
60
+ from src.asr.models import get_audio_model_ar
61
+ get_audio_model_ar()
62
+ except Exception as e:
63
+ logger.warning(f"Arabic ASR model failed to load: {e}")
64
 
65
+ from src.rag.batch_workers import start_workers
66
+ start_workers()
67
 
68
+ from src.asr.batch_workers import start_asr_workers
69
+ start_asr_workers()
70
 
71
  yield
72
 
 
95
  _cors_origins = [o.strip() for o in _raw_origins if o.strip() and o.strip() != "*"] or _DEFAULT_ORIGINS
96
 
97
  @app.middleware("http")
98
+ async def log_request_timing(request, call_next):
99
+ import time
100
+ start = time.perf_counter()
101
  # Fix double slashes in paths (e.g., //api/usage -> /api/usage)
102
  path = request.scope.get("path")
103
  if path and "//" in path:
104
  request.scope["path"] = path.replace("//", "/")
105
+ response = await call_next(request)
106
+ duration_sec = time.perf_counter() - start
107
+
108
+ status = response.status_code
109
+ if 200 <= status < 300:
110
+ status_str = f"<green>{status}</green>"
111
+ elif 300 <= status < 400:
112
+ status_str = f"<cyan>{status}</cyan>"
113
+ elif 400 <= status < 500:
114
+ status_str = f"<red>{status}</red>"
115
+ else:
116
+ status_str = f"<bold><red>{status}</red></bold>"
117
+
118
+ logger.opt(colors=True).info(f"{request.method} {request.url.path} - {status_str} ({duration_sec:.2f}s)")
119
+ return response
120
 
121
  app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
122
 
materials/routes.py CHANGED
@@ -1,6 +1,6 @@
1
  import time
2
  import asyncio
3
- import logging
4
  import validators
5
  from fastapi import APIRouter, UploadFile, File, HTTPException, Depends, BackgroundTasks, Header, Request
6
  from postgrest.exceptions import APIError
@@ -13,8 +13,6 @@ from src.database import get_supabase, get_auth_supabase
13
  from .constants import ALLOWED_TYPES, MAX_SIZE_MB, MAX_SIZE_BYTES
14
  from .schemas import URLInput, RenameMaterialRequest, BulkDeleteRequest, TopicRequest, SearchRequest
15
 
16
- logger = logging.getLogger(__name__)
17
-
18
  router = APIRouter(prefix="/api/materials", tags=["Materials"])
19
 
20
 
 
1
  import time
2
  import asyncio
3
+ from loguru import logger
4
  import validators
5
  from fastapi import APIRouter, UploadFile, File, HTTPException, Depends, BackgroundTasks, Header, Request
6
  from postgrest.exceptions import APIError
 
13
  from .constants import ALLOWED_TYPES, MAX_SIZE_MB, MAX_SIZE_BYTES
14
  from .schemas import URLInput, RenameMaterialRequest, BulkDeleteRequest, TopicRequest, SearchRequest
15
 
 
 
16
  router = APIRouter(prefix="/api/materials", tags=["Materials"])
17
 
18
 
materials/validator.py CHANGED
@@ -1,10 +1,8 @@
1
  import re
2
- import logging
3
  from src.rag.rag import get_llm
4
  from src.config import settings
5
 
6
- logger = logging.getLogger(__name__)
7
-
8
  # Load English NSFW word list from config settings (kept out of committed code)
9
  LOCAL_NSFW_WORDS = set(settings.local_nsfw_words)
10
 
 
1
  import re
2
+ from loguru import logger
3
  from src.rag.rag import get_llm
4
  from src.config import settings
5
 
 
 
6
  # Load English NSFW word list from config settings (kept out of committed code)
7
  LOCAL_NSFW_WORDS = set(settings.local_nsfw_words)
8
 
quiz_generator/quiz.py CHANGED
@@ -1,7 +1,7 @@
1
  import json
2
  import random
3
  import re
4
- import logging
5
  from typing import Optional
6
  from langchain.agents import create_tool_calling_agent, AgentExecutor
7
  from langchain_core.tools import create_retriever_tool
@@ -18,8 +18,6 @@ from .constants import (
18
  ARXIV_DOC_CONTENT_CHARS_MAX,
19
  )
20
 
21
- logger = logging.getLogger(__name__)
22
-
23
 
24
  def _quiz_prompt():
25
  return QUIZ_PROMPT_TEMPLATE
 
1
  import json
2
  import random
3
  import re
4
+ from loguru import logger
5
  from typing import Optional
6
  from langchain.agents import create_tool_calling_agent, AgentExecutor
7
  from langchain_core.tools import create_retriever_tool
 
18
  ARXIV_DOC_CONTENT_CHARS_MAX,
19
  )
20
 
 
 
21
 
22
  def _quiz_prompt():
23
  return QUIZ_PROMPT_TEMPLATE
quiz_generator/routes.py CHANGED
@@ -1,5 +1,5 @@
1
  import asyncio
2
- import logging
3
  from fastapi import APIRouter, HTTPException, Depends
4
  from typing import Optional
5
  from src.quiz_generator.quiz import smart_quiz_generator
@@ -14,8 +14,6 @@ from .constants import (
14
  MAX_TF_COUNT,
15
  )
16
 
17
- logger = logging.getLogger(__name__)
18
-
19
  router = APIRouter(prefix="/api/quiz", tags=["Quiz"])
20
 
21
 
 
1
  import asyncio
2
+ from loguru import logger
3
  from fastapi import APIRouter, HTTPException, Depends
4
  from typing import Optional
5
  from src.quiz_generator.quiz import smart_quiz_generator
 
14
  MAX_TF_COUNT,
15
  )
16
 
 
 
17
  router = APIRouter(prefix="/api/quiz", tags=["Quiz"])
18
 
19
 
rag/batch_workers.py CHANGED
@@ -12,14 +12,12 @@ Architecture:
12
  import asyncio
13
  import time
14
  import uuid
15
- import logging
16
  from typing import Any
17
 
18
  from .constants import BATCH_MAX_SIZE, BATCH_WINDOW_S, WARMUP_INTERVAL_S
19
  from .schemas import EmbeddingJob
20
 
21
- logger = logging.getLogger(__name__)
22
-
23
 
24
  # ═══════════════════════ Job Store ════════════════════════
25
 
 
12
  import asyncio
13
  import time
14
  import uuid
15
+ from loguru import logger
16
  from typing import Any
17
 
18
  from .constants import BATCH_MAX_SIZE, BATCH_WINDOW_S, WARMUP_INTERVAL_S
19
  from .schemas import EmbeddingJob
20
 
 
 
21
 
22
  # ═══════════════════════ Job Store ════════════════════════
23
 
rag/rag.py CHANGED
@@ -1,7 +1,7 @@
1
  import os
2
  import asyncio
3
  import uuid
4
- import logging
5
  from functools import lru_cache
6
  from typing import Optional
7
  from langchain_community.tools import DuckDuckGoSearchResults
@@ -31,8 +31,6 @@ from .constants import (
31
  )
32
  from .schemas import EmbeddingJob
33
 
34
- logger = logging.getLogger(__name__)
35
-
36
 
37
  # ── Embeddings ─────────────────────────────────────────
38
 
 
1
  import os
2
  import asyncio
3
  import uuid
4
+ from loguru import logger
5
  from functools import lru_cache
6
  from typing import Optional
7
  from langchain_community.tools import DuckDuckGoSearchResults
 
31
  )
32
  from .schemas import EmbeddingJob
33
 
 
 
34
 
35
  # ── Embeddings ─────────────────────────────────────────
36
 
rag/routes.py CHANGED
@@ -1,6 +1,6 @@
1
  import time
2
  import asyncio
3
- import logging
4
  from fastapi import APIRouter, HTTPException, Depends
5
  from typing import Optional, Any
6
 
@@ -20,8 +20,6 @@ from src.store import (
20
  from src.summary_generator.summary import clean_summary
21
  from .schemas import TutorQuery, TutorResponse, SessionRequest, RenameSessionRequest, ExtractTitleRequest, SaveChatRequest
22
 
23
- logger = logging.getLogger(__name__)
24
-
25
  router = APIRouter(prefix="/api/tutor", tags=["Tutor"])
26
 
27
 
 
1
  import time
2
  import asyncio
3
+ from loguru import logger
4
  from fastapi import APIRouter, HTTPException, Depends
5
  from typing import Optional, Any
6
 
 
20
  from src.summary_generator.summary import clean_summary
21
  from .schemas import TutorQuery, TutorResponse, SessionRequest, RenameSessionRequest, ExtractTitleRequest, SaveChatRequest
22
 
 
 
23
  router = APIRouter(prefix="/api/tutor", tags=["Tutor"])
24
 
25
 
redis_client.py CHANGED
@@ -8,13 +8,11 @@ do a simple `r = get_redis(); if r is None: <fallback>` without crashing.
8
  Connection is created once and reused for the lifetime of the process.
9
  """
10
 
11
- import logging
12
  from typing import Optional
 
13
 
14
  import redis
15
 
16
- logger = logging.getLogger(__name__)
17
-
18
  _redis_client: Optional[redis.Redis] = None
19
  _redis_available: bool = False
20
 
@@ -54,6 +52,6 @@ def get_redis() -> Optional[redis.Redis]:
54
  logger.info("Redis connected successfully.")
55
  return _redis_client
56
  except Exception as e:
57
- logger.warning("Redis connection failed (%s) β€” falling back to Supabase/in-memory.", e)
58
  _redis_available = False
59
  return None
 
8
  Connection is created once and reused for the lifetime of the process.
9
  """
10
 
 
11
  from typing import Optional
12
+ from loguru import logger
13
 
14
  import redis
15
 
 
 
16
  _redis_client: Optional[redis.Redis] = None
17
  _redis_available: bool = False
18
 
 
52
  logger.info("Redis connected successfully.")
53
  return _redis_client
54
  except Exception as e:
55
+ logger.warning(f"Redis connection failed ({e}) β€” falling back to Supabase/in-memory.")
56
  _redis_available = False
57
  return None
store.py CHANGED
@@ -3,7 +3,7 @@ import time
3
  import json
4
  from httpx import RemoteProtocolError
5
  from typing import Optional
6
- import logging
7
  from datetime import datetime, timezone, date, timedelta
8
  from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemory
9
  from src.database import get_supabase
@@ -38,9 +38,6 @@ ADMIN_EMAILS = set(
38
  )
39
 
40
 
41
- logger = logging.getLogger(__name__)
42
-
43
-
44
  def _get_next_id() -> str:
45
  _in_memory["next_id"] += 1
46
  return str(_in_memory["next_id"])
 
3
  import json
4
  from httpx import RemoteProtocolError
5
  from typing import Optional
6
+ from loguru import logger
7
  from datetime import datetime, timezone, date, timedelta
8
  from langchain.memory import ConversationBufferMemory, ConversationBufferWindowMemory
9
  from src.database import get_supabase
 
38
  )
39
 
40
 
 
 
 
41
  def _get_next_id() -> str:
42
  _in_memory["next_id"] += 1
43
  return str(_in_memory["next_id"])
summary_generator/routes.py CHANGED
@@ -1,6 +1,6 @@
1
  import asyncio
2
  import time
3
- import logging
4
  from fastapi import APIRouter, HTTPException, Depends
5
 
6
  from src.summary_generator.summary import summarizer, web_summarizer, fetch_web_content
@@ -17,7 +17,6 @@ from .schemas import SummarizeRequest, SummarizeResponse
17
  from .constants import MAX_COMBINED_TEXT_LEN
18
 
19
  router = APIRouter(prefix="/api/materials", tags=["Summarizer"])
20
- logger = logging.getLogger(__name__)
21
 
22
 
23
  @router.post("/summarize", response_model=SummarizeResponse)
 
1
  import asyncio
2
  import time
3
+ from loguru import logger
4
  from fastapi import APIRouter, HTTPException, Depends
5
 
6
  from src.summary_generator.summary import summarizer, web_summarizer, fetch_web_content
 
17
  from .constants import MAX_COMBINED_TEXT_LEN
18
 
19
  router = APIRouter(prefix="/api/materials", tags=["Summarizer"])
 
20
 
21
 
22
  @router.post("/summarize", response_model=SummarizeResponse)
summary_generator/summary.py CHANGED
@@ -1,5 +1,5 @@
1
  import re
2
- import logging
3
  import concurrent.futures
4
  from langchain_community.utilities import WikipediaAPIWrapper, DuckDuckGoSearchAPIWrapper
5
  from src.rag.rag import get_summary_llm, get_summary_fallback_llm
@@ -11,8 +11,6 @@ from .constants import (
11
  WIKI_DOC_CONTENT_CHARS_MAX,
12
  )
13
 
14
- logger = logging.getLogger(__name__)
15
-
16
 
17
  def summarizer_prompt():
18
  return SUMMARIZER_PROMPT_TEMPLATE
 
1
  import re
2
+ from loguru import logger
3
  import concurrent.futures
4
  from langchain_community.utilities import WikipediaAPIWrapper, DuckDuckGoSearchAPIWrapper
5
  from src.rag.rag import get_summary_llm, get_summary_fallback_llm
 
11
  WIKI_DOC_CONTENT_CHARS_MAX,
12
  )
13
 
 
 
14
 
15
  def summarizer_prompt():
16
  return SUMMARIZER_PROMPT_TEMPLATE