OpenAI Integration
Relevant source files
The following files were used as context for generating this wiki page:The OpenAI integration in MauQNotes provides the capability to generate text embeddings using OpenAI's official API. These embeddings are vector representations of text, which are essential for the application's semantic search functionality. The system is designed to convert text notes into these vectors, which are then stored in a Qdrant vector database for efficient similarity searches.
While the project contains a fully functional client for OpenAI, it is important to note that the primary search service is currently hardcoded to use the Ollama embedding provider. The OpenAI functionality exists as a self-contained module that can be integrated into the search service with minor modifications. This document details the architecture and implementation of the OpenAI embedding client.
Sources: internal/embeddings/openai.go, internal/search/service.go:41, internal/search/service.go:57
Configuration
The OpenAI embedding client is configured using environment variables. These variables must be present in a .env file at the project root or set in the execution environment for the functionality to work correctly.
| Variable | Description | Required |
|---|---|---|
OPENAI_API_KEY | Your secret API key for authenticating with OpenAI. | Yes |
EMBEDDING_MODEL | The specific OpenAI embedding model to use. | Yes |
If either of these variables is missing, the FromOpenAI function will return an error.
Sources: internal/embeddings/openai.go:27-31
Core Functionality: Generating Embeddings
The central piece of the integration is the FromOpenAI function, which handles the entire process of converting a text string into a vector embedding.
Sources: internal/embeddings/openai.go:25-72
Process Flow
The function executes the following steps:
- Loads environment variables (
OPENAI_API_KEY,EMBEDDING_MODEL). - Validates that the required variables are not empty.
- Constructs an
openAIRequestpayload containing the model and the input text. - Serializes the request payload to JSON.
- Creates a new HTTP POST request to the OpenAI embeddings endpoint:
https://api.openai.com/v1/embeddings. - Sets the
Content-TypeandAuthorizationheaders, including the bearer token. - Executes the HTTP request.
- Decodes the JSON response into an
openAIResponsestruct. - Checks for API errors within the response body and returns them if present.
- Converts the resulting
[]float64embedding vector to a[]float32slice, which is the type required by the Qdrant client. - Returns the
[]float32vector or an error.
Sources: internal/embeddings/openai.go:25-72, internal/qdrant/client.go:27
Sequence Diagram
The following diagram illustrates the sequence of operations when calling FromOpenAI.
This diagram shows the interaction between the calling service, the FromOpenAI function, and the external OpenAI API to generate an embedding.
Sources: internal/embeddings/openai.go:25-72
Data Structures
The communication with the OpenAI API relies on two primary data structures for marshalling and unmarshalling JSON data.
openAIRequest
This struct defines the payload sent to the OpenAI API.
// internal/embeddings/openai.go:12-15
type openAIRequest struct {
Model string `json:"model"`
Input []string `json:"input"`
}
openAIResponse
This struct is used to parse the response from the OpenAI API. It includes a field for the embedding data and an optional field for any errors returned by the API.
// internal/embeddings/openai.go:17-23
type openAIResponse struct {
Data []struct {
Embedding []float64 `json:"embedding"`
} `json:"data"`
Error *struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}
Sources: internal/embeddings/openai.go:12-23
Integration with Search Service
The search package orchestrates the process of ingesting notes and querying them. It relies on an embedding function to convert text to vectors before interacting with the Qdrant database.
Ingestion and Query Flow
The overall data flow for ingestion is as follows:
- The
mainfunction callssearch.IngestNoteswith a list of notes. IngestNotesinitializes a Qdrant client.- It determines the required vector dimension by calling
search.Init(), which reads theEMBEDDING_MODELenvironment variable. - It creates a Qdrant collection if one does not already exist.
- For each note, it calls an embedding function to generate a vector.
- The generated vectors and payloads are collected as
qdrant.Pointobjects. - Finally, it calls
client.Upsertto save the points to Qdrant.
This diagram shows the high-level ingestion process, highlighting the embedding generation step.
Sources: cmd/app/main.go:15-17, internal/search/service.go:36-54, internal/qdrant/client.go:142-164
Current Implementation vs. OpenAI
Currently, the IngestNotes and Query functions in internal/search/service.go are hardcoded to use embeddings.FromOllama to generate vectors.
// internal/search/service.go:41
vec, err := embeddings.FromOllama(n)
// internal/search/service.go:57
vec, err := embeddings.FromOllama(q)
To use the OpenAI integration, these lines would need to be changed to call embeddings.FromOpenAI. The EMBEDDING_MODEL environment variable is used by both the Ollama and OpenAI clients, so care must be taken to ensure the model name is compatible with the selected service. The search.Init function maps specific model names to vector dimensions, which is a pattern that would need to be extended for OpenAI-specific models if they differ from the ones listed.
Sources: internal/search/service.go:17-33, internal/embeddings/openai.go:28, internal/embeddings/ollama.go:27