Skip to content

Instantly share code, notes, and snippets.

@LuceCarter
Created April 8, 2024 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LuceCarter/fb314d431fc47b1a7baed641720e6f45 to your computer and use it in GitHub Desktop.
Save LuceCarter/fb314d431fc47b1a7baed641720e6f45 to your computer and use it in GitHub Desktop.
Code snippets for the MongoDB Atlas Vector Search with C# and Blazor tutorial
.search-bar {
padding: 5%;
}
.search-bar-button {
padding: 4px;
}
namespace SeeSharpMovies.Models
{
public class EmbeddingResponse
{
public string @object { get; set; }
public List<Data> data { get; set; }
public string model { get; set; }
public Usage usage { get; set; }
}
public class Data
{
public string @object { get; set; }
public int index { get; set; }
public List<double> embedding { get; set; }
}
public class Usage
{
public int prompt_tokens { get; set; }
public int total_tokens { get; set; }
}
}
private async Task<List<double>> GetEmbeddingsFromText(string text)
{
Dictionary<string, object> body = new Dictionary<string, object>
{
{ "model", "text-embedding-ada-002" },
{ "input", text }
};
_httpClient.BaseAddress = new Uri("https://api.openai.com");
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAPIKey}");
string requestBody = JsonSerializer.Serialize(body);
StringContent requestContent =
new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("/v1/embeddings", requestContent)
.ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string responseBody = await response.Content.ReadAsStringAsync();
EmbeddingResponse embeddingResponse = JsonSerializer.Deserialize<EmbeddingResponse>(responseBody);
return embeddingResponse.data[0].embedding;
}
return new List<double>();
}
@page "/"
@inject MongoDBService MongoDBService
@rendermode InteractiveServer
<header class="top-bar">
<a href="/">See Sharp Movies</a>
<div class="form-inline search-bar">
<input class="form-control mr-sm-2"
type="search" placeholder="Search"
aria-label="Search"
@bind="searchTerm">
<button class="btn btn-outline-success my-2 my-sm-0" @onclick="SearchMovies">Search</button>
</div>
</header>
<div class="moviecard-container">
@foreach (var movie in movies)
{
<div class="moviecard">
<MovieCard Movie="@movie" />
</div>
}
</div>
<div class="pagination-controls">
<button disabled="@isPreviousDisabled" @onclick="GoToPreviousPage"> Previous</button>
<span>Page @currentPage</span>
<button @onclick="GoToNextPage" disabled="@isNextDisabled">Next</button>
</div>
@code {
bool isPreviousDisabled;
bool isNextDisabled;
int currentPage = 1;
int pageSize = 25;
string searchTerm = "";
IEnumerable<Movie> movies;
protected override async Task OnInitializedAsync()
{
movies = MongoDBService.GetMoviesPerPage(currentPage, pageSize);
}
private void SearchMovies()
{
if (string.IsNullOrWhiteSpace(searchTerm))
{
movies = MongoDBService.GetAllMovies();
}
else
{
movies = MongoDBService.MovieSearch(searchTerm);
}
}
private void GoToPreviousPage()
{
if (currentPage > 1)
{
currentPage--;
movies = MongoDBService.GetMoviesPerPage(currentPage, pageSize);
}
}
private void GoToNextPage()
{
currentPage++;
movies = MongoDBService.GetMoviesPerPage(currentPage, pageSize);
}
}
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace SeeSharpMovies.Models;
public class Movie
{
[BsonId]
[BsonElement("_id")]
public ObjectId Id { get; set; }
[BsonElement("plot")]
public string Plot { get; set; }
[BsonElement("genres")]
public string[] Genres { get; set; }
[BsonElement("runtime")]
public int Runtime { get; set; }
[BsonElement("cast")]
public string[] Cast { get; set; }
[BsonElement("num_mflix_comments")]
public int NumMflixComments { get; set; }
[BsonElement("poster")]
public string Poster { get; set; }
[BsonElement("title")]
public string Title { get; set; }
[BsonElement("fullplot")]
public string FullPlot { get; set; }
[BsonElement("languages")]
public string[] Languages { get; set; }
[BsonElement("directors")]
public string[] Directors { get; set; }
[BsonElement("writers")]
public string[] Writers { get; set; }
[BsonElement("awards")]
public Awards Awards { get; set; }
[BsonElement("year")]
public string Year { get; set; }
[BsonElement("imdb")]
public Imdb Imdb { get; set; }
[BsonElement("countries")]
public string[] Countries { get; set; }
[BsonElement("type")]
public string Type { get; set; }
[BsonElement("plot_embedding")]
public float[] PlotEmbedding { get; set; }
}
public class Awards
{
[BsonElement("wins")]
public int Wins { get; set; }
[BsonElement("nominations")]
public int Nominations { get; set; }
[BsonElement("text")]
public string Text { get; set; }
}
public class Imdb
{
[BsonElement("rating")]
public float Rating { get; set; }
[BsonElement("votes")]
public int Votes { get; set; }
[BsonElement("id")]
public int Id { get; set; }
}
public IEnumerable<Movie> MovieSearch(string textToSearch)
{
var vector = GetEmbeddingsFromText(textToSearch).Result.ToArray();
var vectorOptions = new VectorSearchOptions<Movie>()
{
IndexName = "vector_index",
NumberOfCandidates = 150
};
var movies = _movies.Aggregate()
.VectorSearch(movie => movie.PlotEmbedding, vector, 150, vectorOptions)
.Project<Movie>(Builders<Movie>.Projection
.Include(m => m.Title)
.Include(m => m.Plot))
.ToList();
return movies;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment