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
59 changes: 54 additions & 5 deletions .github/workflows/run-python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,58 @@ jobs:
- name: Download sample data
run: curl https://atlas-education.s3.amazonaws.com/sampledata.archive -o sampledata.archive

- name: Add sample data to database
run: mongorestore --archive=sampledata.archive --port=27017
- name: Setup Database (Data & Indexes)
run: |
# 1. Restore the data
mongorestore --archive=sampledata.archive --port=27017

# 2. Prepare the Search Index Definition
echo '{
"name": "movieSearchIndex",
"database": "sample_mflix",
"collectionName": "movies",
"mappings": {
"dynamic": false,
"fields": {
"plot": {"type": "string", "analyzer": "lucene.standard"},
"fullplot": {"type": "string", "analyzer": "lucene.standard"},
"directors": {"type": "string", "analyzer": "lucene.standard"},
"writers": {"type": "string", "analyzer": "lucene.standard"},
"cast": {"type": "string", "analyzer": "lucene.standard"}
}
}
}' > search_index.json

# 3. Create the Search Index
atlas deployments search indexes create \
--deploymentName myLocalRs1 \
--file search_index.json

# 4. Prepare the Vector Index Definition
echo '{
"name": "vector_index",
"database": "sample_mflix",
"collectionName": "embedded_movies",
"type": "vectorSearch",
"fields": [
{
"type": "vector",
"path": "plot_embedding_voyage_3_large",
"numDimensions": 2048,
"similarity": "cosine"
}
]
}' > vector_index.json

# 5. Create the Vector Index
atlas deployments search indexes create \
--deploymentName myLocalRs1 \
--file vector_index.json

# 6. Wait for indexes to build
echo "Waiting for indexes to build..."
sleep 20

- name: Set up Python
uses: actions/setup-python@v5
with:
Expand All @@ -63,10 +112,10 @@ jobs:

- name: Run integration tests
working-directory: mflix/server/python-fastapi
run: pytest -m integration --verbose --tb=short --junit-xml=test-results-integration.xml || true
run: pytest -m integration --verbose --tb=short --junit-xml=test-results-integration.xml
env:
MONGO_URI: mongodb://localhost:27017
MONGO_DB: sample_mflix
MONGO_URI: mongodb://localhost:27017/?directConnection=true
MONGO_DB: sample_mflix

- name: Upload test results
uses: actions/upload-artifact@v4
Expand Down
32 changes: 25 additions & 7 deletions mflix/server/python-fastapi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from src.routers import movies
from src.utils.errorHandler import register_error_handlers
from src.database.mongo_client import db, get_collection

import os
Expand All @@ -15,8 +14,9 @@
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Create search indexes
await ensure_search_index()
await vector_search_index()
await ensure_mongodb_search_index()
await ensure_vector_search_index()
await ensure_standard_index()

# Print server information
print(f"\n{'='*60}")
Expand All @@ -30,10 +30,9 @@ async def lifespan(app: FastAPI):
# Add any cleanup code here


async def ensure_search_index():
async def ensure_mongodb_search_index():
try:
movies_collection = db.get_collection("movies")
comments_collection = db.get_collection("comments")

# Check and create search index for movies collection
result = await movies_collection.list_search_indexes()
Expand Down Expand Up @@ -71,7 +70,7 @@ async def ensure_search_index():
)


async def vector_search_index():
async def ensure_vector_search_index():
"""
Creates vector search index on application startup if it doesn't already exist.
This ensures the index is ready before any vector search requests are made.
Expand Down Expand Up @@ -114,6 +113,26 @@ async def vector_search_index():
f"and verify the 'embedded_movies' collection exists with the required embedding field."
)

async def ensure_standard_index():
"""
Creates a standard MongoDB index on the comments collection on application startup.
This improves performance for queries filtering by movie_id such as ReportingByComments().
"""

try:
comments_collection = db.get_collection("comments")

existing_indexes_cursor = await comments_collection.list_indexes()
existing_indexes = [index async for index in existing_indexes_cursor]
index_names = [index.get("name") for index in existing_indexes]
standard_index_name = "movie_id_index"
if standard_index_name not in index_names:
await comments_collection.create_index([("movie_id", 1)], name=standard_index_name)

except Exception as e:
print(f"Failed to create standard index on 'comments' collection: {str(e)}. ")
print(f"Performance may be degraded. Please check your MongoDB configuration.")


app = FastAPI(lifespan=lifespan)

Expand All @@ -127,6 +146,5 @@ async def vector_search_index():
allow_headers=["*"],
)

register_error_handlers(app)
app.include_router(movies.router, prefix="/api/movies", tags=["movies"])

2 changes: 2 additions & 0 deletions mflix/server/python-fastapi/src/database/mongo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ def get_collection(name:str):
def voyage_ai_available():
"""Check if Voyage API Key is available and valid."""
api_key = os.getenv("VOYAGE_API_KEY")
if api_key is None or api_key =="your_voyage_api_key":
return None
return api_key is not None and api_key.strip() != ""
13 changes: 0 additions & 13 deletions mflix/server/python-fastapi/src/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,9 @@ class SuccessResponse(BaseModel, Generic[T]):
timestamp: str
pagination: Optional[Pagination] = None


class ErrorDetails(BaseModel):
message: str
code: Optional[str]
details: Optional[Any] = None

class BatchUpdateRequest(BaseModel):
filter: MovieFilter
update: UpdateMovieRequest

class BatchDeleteRequest(BaseModel):
filter: MovieFilter

class ErrorResponse(BaseModel):
success: bool = False
message: str
error: ErrorDetails
timestamp: str

Loading