GitHub Actions commited on
Commit
3b6e5dc
·
1 Parent(s): a066e5a

Deploy from GitHub Actions (2026-03-12 18:14 UTC)

Browse files
app/main.py CHANGED
@@ -14,7 +14,7 @@ from pydantic import BaseModel
14
  from app.utils.config import get_config, get_logger, get_version
15
  from app.models.nlp_engine import NLPEngine
16
  from app.models.conversation_manager import ConversationManager
17
- from app.models.database import init_database, get_database, User, Conversation, Message
18
  from app.models.smart_models import UserPreference, UserInsight, ConversationTopic
19
  from app.data.training_data import TRAINING_DATA
20
  from app.routers import knowledge_base
@@ -34,13 +34,14 @@ async def lifespan(fastapi_app: FastAPI): # pylint: disable=unused-argument
34
 
35
  # Initialize database
36
  try:
37
- db = init_database()
38
- if db.health_check():
 
39
  logger.info("Database connection established successfully")
40
  else:
41
  logger.warning("Database health check failed, but continuing...")
42
- except Exception as e:
43
- logger.error("Database initialization failed: %s", str(e))
44
  logger.warning("Continuing without database - some features may not work...")
45
 
46
  # Train NLP model
@@ -101,7 +102,7 @@ async def health_check():
101
  logger.debug("Health check endpoint accessed")
102
 
103
  # Check database health
104
- db_status = "healthy" if get_database().health_check() else "unhealthy"
105
 
106
  return {
107
  "status": "healthy",
@@ -190,7 +191,7 @@ async def chat(request: ChatRequest):
190
  "threshold_applied": confidence < config.nlp["confidence_threshold"],
191
  "environment": config.env.name,
192
  "response_time_ms": response_time_ms,
193
- "database_enabled": get_database().health_check(),
194
  }
195
 
196
  logger.info("Chat response generated successfully for session %s", session_id)
 
14
  from app.utils.config import get_config, get_logger, get_version
15
  from app.models.nlp_engine import NLPEngine
16
  from app.models.conversation_manager import ConversationManager
17
+ from app.models.database import init_database, health_check as db_health_check
18
  from app.models.smart_models import UserPreference, UserInsight, ConversationTopic
19
  from app.data.training_data import TRAINING_DATA
20
  from app.routers import knowledge_base
 
34
 
35
  # Initialize database
36
  try:
37
+ init_database()
38
+
39
+ if db_health_check():
40
  logger.info("Database connection established successfully")
41
  else:
42
  logger.warning("Database health check failed, but continuing...")
43
+ except Exception as e: # pylint: disable=broad-exception-caught
44
+ logger.error("Database initialization failed: %s: %s", type(e).__name__, str(e))
45
  logger.warning("Continuing without database - some features may not work...")
46
 
47
  # Train NLP model
 
102
  logger.debug("Health check endpoint accessed")
103
 
104
  # Check database health
105
+ db_status = "healthy" if db_health_check() else "unhealthy"
106
 
107
  return {
108
  "status": "healthy",
 
191
  "threshold_applied": confidence < config.nlp["confidence_threshold"],
192
  "environment": config.env.name,
193
  "response_time_ms": response_time_ms,
194
+ "database_enabled": db_health_check(),
195
  }
196
 
197
  logger.info("Chat response generated successfully for session %s", session_id)
app/models/conversation_manager.py CHANGED
@@ -8,7 +8,7 @@ from groq import Groq
8
 
9
  # Absolute imports from project root
10
  from app.utils.config import get_logger
11
- from app.models.database import get_database, User, Conversation, Message
12
  from app.models.information_extractor import InformationExtractor
13
 
14
 
@@ -16,7 +16,6 @@ class ConversationManager:
16
  def __init__(self, config=None):
17
  self.config = config
18
  self.logger = get_logger(__name__)
19
- self.db = get_database()
20
  self.info_extractor = InformationExtractor()
21
 
22
  max_history = config.nlp["max_history"] if config else 50
@@ -28,7 +27,7 @@ class ConversationManager:
28
 
29
  def get_or_create_user(self, session_id: str) -> User:
30
  """Get existing user or create new one"""
31
- with self.db.get_session() as db_session:
32
  user = db_session.query(User).filter(User.session_id == session_id).first()
33
 
34
  if not user:
@@ -46,7 +45,7 @@ class ConversationManager:
46
 
47
  def get_active_conversation(self, user: User) -> Optional[Conversation]:
48
  """Get the most recent active conversation for a user"""
49
- with self.db.get_session() as db_session:
50
  # Refresh user object in this session
51
  user = db_session.merge(user)
52
 
@@ -81,7 +80,7 @@ class ConversationManager:
81
 
82
  def create_conversation(self, user: User) -> Conversation:
83
  """Create a new conversation for the user"""
84
- with self.db.get_session() as db_session:
85
  # Refresh user object in this session
86
  user = db_session.merge(user)
87
 
@@ -97,7 +96,7 @@ class ConversationManager:
97
  self, conversation: Conversation, limit: int = 5
98
  ) -> List[Dict]:
99
  """Get recent messages from conversation for context"""
100
- with self.db.get_session() as db_session:
101
  # Refresh conversation object in this section
102
  conversation = db_session.merge(conversation)
103
 
@@ -178,7 +177,7 @@ class ConversationManager:
178
 
179
  # Update user's preferred language
180
  if user and user.preferred_language != language:
181
- with self.db.get_session() as db_session:
182
  user = db_session.merge(user)
183
  user.preferred_language = language
184
  db_session.commit()
@@ -233,7 +232,7 @@ class ConversationManager:
233
  conversation = self.create_conversation(user)
234
 
235
  # Create message record
236
- with self.db.get_session() as db_session:
237
  # Refresh objects in this session
238
  conversation = db_session.merge(conversation)
239
  user = db_session.merge(user)
@@ -275,7 +274,7 @@ class ConversationManager:
275
  def get_conversation_history(self, session_id: str) -> List[Dict]:
276
  """Get conversation history for a session (for analytics endpoint)"""
277
  try:
278
- with self.db.get_session() as db_session:
279
  user = (
280
  db_session.query(User).filter(User.session_id == session_id).first()
281
  )
@@ -316,7 +315,7 @@ class ConversationManager:
316
  def get_user_stats(self, session_id: str) -> Dict:
317
  """Get user statistics"""
318
  try:
319
- with self.db.get_session() as db_session:
320
  user = (
321
  db_session.query(User).filter(User.session_id == session_id).first()
322
  )
 
8
 
9
  # Absolute imports from project root
10
  from app.utils.config import get_logger
11
+ from app.models.database import User, Conversation, Message, SessionLocal
12
  from app.models.information_extractor import InformationExtractor
13
 
14
 
 
16
  def __init__(self, config=None):
17
  self.config = config
18
  self.logger = get_logger(__name__)
 
19
  self.info_extractor = InformationExtractor()
20
 
21
  max_history = config.nlp["max_history"] if config else 50
 
27
 
28
  def get_or_create_user(self, session_id: str) -> User:
29
  """Get existing user or create new one"""
30
+ with SessionLocal() as db_session:
31
  user = db_session.query(User).filter(User.session_id == session_id).first()
32
 
33
  if not user:
 
45
 
46
  def get_active_conversation(self, user: User) -> Optional[Conversation]:
47
  """Get the most recent active conversation for a user"""
48
+ with SessionLocal() as db_session:
49
  # Refresh user object in this session
50
  user = db_session.merge(user)
51
 
 
80
 
81
  def create_conversation(self, user: User) -> Conversation:
82
  """Create a new conversation for the user"""
83
+ with SessionLocal() as db_session:
84
  # Refresh user object in this session
85
  user = db_session.merge(user)
86
 
 
96
  self, conversation: Conversation, limit: int = 5
97
  ) -> List[Dict]:
98
  """Get recent messages from conversation for context"""
99
+ with SessionLocal() as db_session:
100
  # Refresh conversation object in this section
101
  conversation = db_session.merge(conversation)
102
 
 
177
 
178
  # Update user's preferred language
179
  if user and user.preferred_language != language:
180
+ with SessionLocal() as db_session:
181
  user = db_session.merge(user)
182
  user.preferred_language = language
183
  db_session.commit()
 
232
  conversation = self.create_conversation(user)
233
 
234
  # Create message record
235
+ with SessionLocal() as db_session:
236
  # Refresh objects in this session
237
  conversation = db_session.merge(conversation)
238
  user = db_session.merge(user)
 
274
  def get_conversation_history(self, session_id: str) -> List[Dict]:
275
  """Get conversation history for a session (for analytics endpoint)"""
276
  try:
277
+ with SessionLocal() as db_session:
278
  user = (
279
  db_session.query(User).filter(User.session_id == session_id).first()
280
  )
 
315
  def get_user_stats(self, session_id: str) -> Dict:
316
  """Get user statistics"""
317
  try:
318
+ with SessionLocal() as db_session:
319
  user = (
320
  db_session.query(User).filter(User.session_id == session_id).first()
321
  )
app/models/database.py CHANGED
@@ -1,5 +1,4 @@
1
  # app/models/database.py
2
- import os
3
  from datetime import datetime, timezone
4
  import uuid
5
  from sqlalchemy import (
@@ -19,12 +18,23 @@ from sqlalchemy.orm import sessionmaker, relationship, declarative_base
19
  from sqlalchemy.dialects.postgresql import UUID
20
 
21
  # Absolute import from project root
22
- from app.utils.config import get_logger
 
 
23
 
24
  logger = get_logger(__name__)
25
 
26
  Base = declarative_base()
27
 
 
 
 
 
 
 
 
 
 
28
 
29
  class User(Base):
30
  __tablename__ = "users"
@@ -105,90 +115,28 @@ class Message(Base):
105
  return f"<Message(id={self.id}, intent={self.intent}, confidence={self.confidence})>"
106
 
107
 
108
- class Database:
109
- def __init__(self, database_url=None):
110
- self.database_url = database_url or os.getenv("DATABASE_URL")
111
-
112
- if not self.database_url:
113
- raise ValueError("DATABASE_URL environment variable is required")
114
-
115
- # Create engine
116
- self.engine = create_engine(
117
- self.database_url,
118
- echo=False, # Set to True for SQL debugging
119
- pool_pre_ping=True, # Verify connections before use
120
- pool_recycle=300, # Recycle connections every 5 minutes
121
- )
122
-
123
- # Create session factory
124
- self.SessionLocal = sessionmaker(
125
- autocommit=False, autoflush=False, bind=self.engine
126
- )
127
-
128
- logger.info(
129
- "Database manager initialized with URL: %s",
130
- self.database_url.split("@")[0] + "@***",
131
- )
132
-
133
- def create_tables(self):
134
- """Create all tables in the database"""
135
- Base.metadata.create_all(bind=self.engine)
136
- logger.info("Database tables created successfully")
137
-
138
- def get_session(self):
139
- """Get a database session"""
140
- return self.SessionLocal()
141
-
142
- def health_check(self):
143
- """Check if database connection is working"""
144
- try:
145
- with self.get_session() as session:
146
- from sqlalchemy import text
147
-
148
- session.execute(text("SELECT 1"))
149
- logger.info("Database health check passed")
150
- return True
151
- except Exception as e:
152
- logger.error("Database health check failed: %s", str(e))
153
- return False
154
-
155
-
156
- class DatabaseManager:
157
- """Singleton database manager"""
158
-
159
- def __init__(self):
160
- self.db = None
161
-
162
- def get_database(self) -> Database:
163
- """Get the database instance (create if doesn't exist)"""
164
- if self.db is None:
165
- self.db = Database()
166
- return self.db
167
-
168
- def init_database(self):
169
- """Initialize the database instance and create tables"""
170
- db = self.get_database()
171
- db.create_tables()
172
- return db
173
-
174
-
175
- # Create single instance of DatabaseManager
176
- db_manager = DatabaseManager()
177
-
178
 
179
- # Convenience functions for easier imports
180
- def get_database() -> DatabaseManager:
181
- """Get the global database manager instance"""
182
- return db_manager.get_database()
183
 
 
 
 
 
 
184
 
185
- def init_database():
186
- """Initialize the global database manager instance and create tables"""
187
- return db_manager.init_database()
 
 
 
188
 
189
 
190
  def get_db():
191
- db = get_database().get_session()
192
  try:
193
  yield db
194
  finally:
 
1
  # app/models/database.py
 
2
  from datetime import datetime, timezone
3
  import uuid
4
  from sqlalchemy import (
 
18
  from sqlalchemy.dialects.postgresql import UUID
19
 
20
  # Absolute import from project root
21
+ from app.utils.config import get_logger, config_manager
22
+
23
+ config = config_manager.get_config()
24
 
25
  logger = get_logger(__name__)
26
 
27
  Base = declarative_base()
28
 
29
+ engine = create_engine(
30
+ config.database_url,
31
+ echo=False, # Set to True for SQL debugging
32
+ pool_pre_ping=True, # Verify connections before use
33
+ pool_recycle=300, # Recycle connections every 5 minutes
34
+ )
35
+
36
+ SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
37
+
38
 
39
  class User(Base):
40
  __tablename__ = "users"
 
115
  return f"<Message(id={self.id}, intent={self.intent}, confidence={self.confidence})>"
116
 
117
 
118
+ def init_database():
119
+ # create all tables in the database
120
+ Base.metadata.create_all(bind=engine)
121
+ logger.info("Database tables created successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
 
 
 
 
123
 
124
+ def health_check():
125
+ """Check if database connection is working"""
126
+ try:
127
+ with SessionLocal() as session:
128
+ from sqlalchemy import text # pylint: disable=import-outside-toplevel
129
 
130
+ session.execute(text("SELECT 1"))
131
+ logger.info("Database health check passed")
132
+ return True
133
+ except Exception as e: # pylint: disable=broad-exception-caught
134
+ logger.error("Database health check failed: %s: %s", type(e).__name__, str(e))
135
+ return False
136
 
137
 
138
  def get_db():
139
+ db = SessionLocal()
140
  try:
141
  yield db
142
  finally:
app/utils/config.py CHANGED
@@ -172,6 +172,9 @@ class Config:
172
  self.llm_api_key = os.getenv("GROQ_API_KEY", "")
173
  self.system_prompt = os.getenv("SYSTEM_PROMPT", "")
174
 
 
 
 
175
  def _setup_logging(self):
176
  """Configure logging for the entire application"""
177
  # Create logger
 
172
  self.llm_api_key = os.getenv("GROQ_API_KEY", "")
173
  self.system_prompt = os.getenv("SYSTEM_PROMPT", "")
174
 
175
+ # Database Configuration
176
+ self.database_url = os.getenv("DATABASE_URL", "")
177
+
178
  def _setup_logging(self):
179
  """Configure logging for the entire application"""
180
  # Create logger