Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing #5

Merged
merged 56 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c22eb7e
Infra for conversation support
vineetshar Aug 12, 2024
900be74
Comment fixes
vineetshar Aug 12, 2024
fbf0fef
Merging migration
vineetshar Aug 12, 2024
890bf33
Conversation Drafts
vineetshar Aug 12, 2024
c1553af
Conversation Drafts
vineetshar Aug 13, 2024
565199b
Merge branch 'main' into DEV-232]-Chat-boilerplate
vineetshar Aug 13, 2024
343b4a9
Conversation Drafts
vineetshar Aug 13, 2024
299501a
Conversation Drafts
vineetshar Aug 13, 2024
032895a
Conversation Drafts
vineetshar Aug 13, 2024
1323876
Remove unused models
vineetshar Aug 13, 2024
9566240
Basic Agent Setup And Integration in place
vineetshar Aug 13, 2024
96a89e6
logic updates
vineetshar Aug 13, 2024
8dff260
Merge branch 'main' into (DEV-216)Chat-backend-logic
vineetshar Aug 14, 2024
5b176dc
core parsing
dhirenmathur Aug 14, 2024
b9281e1
Merge branch 'main' of https://github.com/getmomentum/momentum-server…
dhirenmathur Aug 14, 2024
3be172c
Refactoring for controllers
vineetshar Aug 14, 2024
9368b50
Dummy user and project setup
vineetshar Aug 14, 2024
2fac197
Update models.py
vineetshar Aug 14, 2024
f8f4c46
Add connection pooling to db
vineetshar Aug 14, 2024
abf2c1c
Sanity fixes
vineetshar Aug 14, 2024
3ba06c2
Naming refactors
vineetshar Aug 14, 2024
a18569b
General logic for conversation creation + message management is up
vineetshar Aug 14, 2024
4383b85
moved to uuid7 to have time ordered ids for better indexing
vineetshar Aug 14, 2024
0691e19
Agent Table Support
vineetshar Aug 14, 2024
503fa26
Support for agent table and router
vineetshar Aug 14, 2024
5da2210
System message integration for conversation starter
vineetshar Aug 14, 2024
04022c9
User Conversation Fetching Support
vineetshar Aug 15, 2024
e764ca3
Update conversation_service.py
vineetshar Aug 15, 2024
10ec1d8
Update conversation_service.py
vineetshar Aug 15, 2024
b240a8d
Streaming chat
vineetshar Aug 15, 2024
44519ed
Insertion support in database for message_stream
vineetshar Aug 15, 2024
ef34687
Support for regeneration
vineetshar Aug 15, 2024
ae04449
Update conversation_service.py
vineetshar Aug 15, 2024
871848c
Update projects_service.py
vineetshar Aug 15, 2024
7d6ed31
Fixing agent setup
vineetshar Aug 15, 2024
78978f4
Support for Tool Calling Agent
vineetshar Aug 17, 2024
ec3c18e
removing useless comments
vineetshar Aug 17, 2024
8956889
Update .env.template
vineetshar Aug 17, 2024
df673a1
schema fixes
vineetshar Aug 17, 2024
8cb2fda
Tool fixes
vineetshar Aug 19, 2024
5babd66
Fixing runnable with historuy
vineetshar Aug 19, 2024
b52d9d5
Memory seperation
vineetshar Aug 20, 2024
da0fd07
PG intergation
vineetshar Aug 20, 2024
812e69f
Delete history_manager.py
vineetshar Aug 20, 2024
41605a6
Better naming imports
vineetshar Aug 20, 2024
168eb5f
Naming fixes
vineetshar Aug 20, 2024
b1bac9f
Update intelligent_tool_using_orchestrator.py
vineetshar Aug 20, 2024
d4c3fb2
Tool and chain fix
vineetshar Aug 20, 2024
04b229d
Merge branch '(DEV-216)Chat-backend-logic' of https://github.com/getm…
dhirenmathur Aug 20, 2024
c36ecca
Merge branch 'main' of https://github.com/getmomentum/momentum-server…
dhirenmathur Aug 22, 2024
67364df
merge from master
dhirenmathur Aug 22, 2024
982fb84
merge from master
dhirenmathur Aug 22, 2024
255124a
Parsing and project management
dhirenmathur Aug 23, 2024
9aa3c7a
update migrations
dhirenmathur Aug 23, 2024
5eeab7b
structure changes, logging etc
dhirenmathur Aug 24, 2024
3bb004b
delete test apis
dhirenmathur Aug 24, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,4 @@ def downgrade() -> None:

# Drop the ENUM type if it is no longer used
message_status_enum.drop(op.get_bind(), checkfirst=False)
# ### end Alembic commands ###
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""project id to string anddelete col

Revision ID: 20240823164559_05069444feee
Revises: 20240820182032_d3f532773223
Create Date: 2024-08-23 16:45:59.991109

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision: str = '20240823164559_05069444feee'
down_revision: Union[str, None] = '20240820182032_d3f532773223'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column('projects', 'id',
existing_type=sa.INTEGER(),
type_=sa.Text(),
existing_nullable=False)
op.drop_constraint('projects_directory_key', 'projects', type_='unique')
op.drop_column('projects', 'directory')
op.drop_column('projects', 'is_default')
op.drop_column('projects', 'project_name')
op.drop_constraint('check_status', 'projects', type_='check')
op.create_check_constraint('check_status', 'projects',
"status IN ('submitted', 'cloned', 'parsed', 'ready', 'error')")
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('projects', sa.Column('project_name', sa.TEXT(), autoincrement=False, nullable=True))
op.add_column('projects', sa.Column('is_default', sa.BOOLEAN(), autoincrement=False, nullable=True))
op.add_column('projects', sa.Column('directory', sa.TEXT(), autoincrement=False, nullable=True))
op.create_unique_constraint('projects_directory_key', 'projects', ['directory'])
op.alter_column('projects', 'id',
existing_type=sa.Text(),
type_=sa.INTEGER(),
existing_nullable=False)
op.drop_constraint('check_status', 'projects', type_='check')
op.create_check_constraint('check_status', 'projects',
"status IN ('created', 'ready', 'error')")
# ### end Alembic commands ###
21 changes: 21 additions & 0 deletions app/core/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from dotenv import load_dotenv
import os

load_dotenv()

class ConfigProvider:
def __init__(self):
self.neo4j_config = {
"uri": os.getenv("NEO4J_URI"),
"username": os.getenv("NEO4J_USERNAME"),
"password": os.getenv("NEO4J_PASSWORD"),
}
self.github_key = os.getenv("GITHUB_PRIVATE_KEY")

def get_neo4j_config(self):
return self.neo4j_config

def get_github_key(self):
return self.github_key

config_provider = ConfigProvider()
131 changes: 131 additions & 0 deletions app/core/mongo_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import os
import logging
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure, OperationFailure
from typing import Optional
import certifi

class MongoManager:
_instance = None
_client: Optional[MongoClient] = None
_db = None

@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance

def __init__(self):
if self._instance is not None:
raise RuntimeError("Use get_instance() to get the MongoManager instance")
self._connect()

def _connect(self):
if self._client is None:
try:
mongodb_uri = os.environ.get("MONGO_URI")
if not mongodb_uri:
raise ValueError("MONGO_URI environment variable is not set")

self._client = MongoClient(
mongodb_uri,
maxPoolSize=50,
waitQueueTimeoutMS=2500,
tlsCAFile=certifi.where() # Use the certifi package to locate the CA bundle
)

db_name = os.environ.get("MONGODB_DB_NAME")
if not db_name:
raise ValueError("MONGODB_DB_NAME environment variable is not set")

self._db = self._client[db_name]

# Verify the connection and database
self.verify_connection()

except (ConnectionFailure, ValueError) as e:
logging.error(f"Failed to connect to MongoDB: {str(e)}")
raise

def verify_connection(self):
try:
# Ping the server to check the connection
self._client.admin.command('ping')

# List all collections to verify database access
self._db.list_collection_names()

logging.info("Successfully connected to MongoDB and verified database access")
except OperationFailure as e:
logging.error(f"Failed to verify MongoDB connection: {str(e)}")
raise

def get_collection(self, collection_name: str):
self._connect() # Ensure connection is established
return self._db[collection_name]

def put(self, collection_name: str, document_id: str, data: dict):
try:
collection = self.get_collection(collection_name)
result = collection.update_one(
{"_id": document_id},
{"$set": data},
upsert=True
)
logging.info(f"Document {'updated' if result.modified_count else 'inserted'} in {collection_name}")
return result
except Exception as e:
logging.error(f"Failed to put document in {collection_name}: {str(e)}")
raise

def get(self, collection_name: str, document_id: str):
try:
collection = self.get_collection(collection_name)
document = collection.find_one({"_id": document_id})
if document:
logging.info(f"Document retrieved from {collection_name}")
else:
logging.info(f"Document not found in {collection_name}")
return document
except Exception as e:
logging.error(f"Failed to get document from {collection_name}: {str(e)}")
raise

def delete(self, collection_name: str, document_id: str):
try:
collection = self.get_collection(collection_name)
result = collection.delete_one({"_id": document_id})
if result.deleted_count:
logging.info(f"Document deleted from {collection_name}")
else:
logging.info(f"Document not found in {collection_name}")
return result
except Exception as e:
logging.error(f"Failed to delete document from {collection_name}: {str(e)}")
raise

def close(self):
if self._client:
self._client.close()
self._client = None
self._db = None
logging.info("MongoDB connection closed")

def reconnect(self):
self.close()
self._connect()
logging.info("Reconnected to MongoDB")

@classmethod
def close_connection(cls):
if cls._instance:
cls._instance.close()
cls._instance = None
logging.info("MongoDB connection closed and instance reset")

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
pass # Don't close the connection here
33 changes: 31 additions & 2 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os
import logging

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
Expand All @@ -12,15 +15,35 @@

from app.modules.utils.dummy_setup import DummyDataSetup

from app.modules.utils.firebase_setup import FirebaseSetup
from app.modules.parsing.graph_construction.parsing_router import router as parsing_router
from app.modules.auth.auth_router import auth_router
from app.modules.key_management.secret_manager import router as secret_manager_router

from app.core.mongo_manager import MongoManager

class MainApp:
def __init__(self):
load_dotenv(override=True)
self.app = FastAPI()
self.setup_cors()
self.initialize_database()
self.check_and_set_env_vars()
self.setup_data()
if os.getenv("isDevelopmentMode") == "enabled":
self.setup_data()
else:
FirebaseSetup.firebase_init()
self.include_routers()
self.verify_mongodb_connection()

def verify_mongodb_connection(self):
try:
mongo_manager = MongoManager.get_instance()
mongo_manager.verify_connection()
logging.info("MongoDB connection verified successfully")
except Exception as e:
logging.error(f"Failed to verify MongoDB connection: {str(e)}")
raise

def setup_cors(self):
origins = ["*"]
Expand Down Expand Up @@ -56,6 +79,9 @@ def setup_data(self):
def include_routers(self):
self.app.include_router(user_router, prefix="/api/v1", tags=["User"])
self.app.include_router(conversations_router, prefix="/api/v1", tags=["Conversations"])
self.app.include_router(parsing_router, prefix="/api/v1", tags=["Parsing"])
self.app.include_router(auth_router, prefix="/api/v1", tags=["Auth"])
self.app.include_router(secret_manager_router, prefix="/api/v1", tags=["Secret Manager"])


def add_health_check(self):
Expand All @@ -67,7 +93,10 @@ def run(self):
self.add_health_check()
return self.app


# Create an instance of MainApp and run it
main_app = MainApp()
app = main_app.run()

@app.on_event("shutdown")
def shutdown_event():
MongoManager.close_connection()
65 changes: 65 additions & 0 deletions app/modules/auth/auth_router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import json
import os

from datetime import datetime
from dotenv import load_dotenv

from fastapi import Depends, Request
from fastapi.responses import JSONResponse, Response
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.modules.auth.auth_service import auth_handler
from app.modules.users.user_service import UserService

from app.modules.utils.APIRouter import APIRouter

from .auth_schema import LoginRequest
from app.modules.users.user_schema import CreateUser

import logging

auth_router = APIRouter()
load_dotenv(override=True)

class AuthAPI:
@auth_router.post("/login")
async def login(login_request: LoginRequest):
email, password = login_request.email, login_request.password

try:
res = auth_handler.login(email=email, password=password)
id_token = res.get("idToken")
return JSONResponse(content={"token": id_token}, status_code=200)
except Exception as e:
return JSONResponse(
content={"error": f"ERROR: {str(e)}"}, status_code=400
)

@auth_router.post("/signup")
async def signup(request: Request, db: Session = Depends(get_db)):
body = json.loads(await request.body())
uid = body["uid"]
user_service = UserService(db)
user = user_service.get_user_by_uid(uid)
if user:
message, error = user_service.update_last_login(uid)
if error:
return Response(content=message, status_code=400)
else:
return Response(content=json.dumps({"uid": uid}), status_code=200)
else:
first_login = datetime.utcnow()
user = CreateUser(
uid=uid,
email=body["email"],
display_name=body["displayName"],
email_verified=body["emailVerified"],
created_at=first_login,
last_login_at=first_login,
provider_info=body["providerData"][0],
provider_username=body["providerUsername"]
)
uid, message, error = user_service.create_user(user)
if error:
return Response(content=message, status_code=400)
return Response(content=json.dumps({"uid": uid}), status_code=201)
6 changes: 6 additions & 0 deletions app/modules/auth/auth_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from pydantic import BaseModel


class LoginRequest(BaseModel):
email: str
password: str
Loading