Skip to content

Conversation

desmondcheongzx
Copy link
Collaborator

@desmondcheongzx desmondcheongzx commented Sep 1, 2025

Changes Made

Add LM Studio as a text embedding provider.

For example

import daft
from daft.ai.provider import load_provider
from daft.functions.ai import embed_text

provider = load_provider("lm_studio", base_url="http://127.0.0.1:1234")  # This base_url parameter is optional if you're using the defaults for LM Studio. You can modify this as needed.
model = "text-embedding-nomic-embed-text-v1.5"  # Select a text embedding model that you've loaded into LM Studio.

(
    daft.read_huggingface("Open-Orca/OpenOrca")
    .with_column("embedding", embed_text(daft.col("response"), provider=provider, model=model))
    .show()
)

@github-actions github-actions bot added the feat label Sep 1, 2025
@desmondcheongzx desmondcheongzx marked this pull request as ready for review September 2, 2025 19:26
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Summary

This PR adds LM Studio as a new text embedding provider to the Daft AI framework. LM Studio is a local AI server that provides an OpenAI-compatible API for running embedding models locally, making it an attractive option for users who want to avoid external API calls or run custom models.

The implementation cleverly extends the existing OpenAI provider architecture since LM Studio maintains API compatibility with OpenAI. The key changes include:

  1. New LMStudioProvider class in daft/ai/openai/__init__.py that inherits from OpenAIProvider but configures defaults for local usage (localhost:1234/v1) and sets a dummy API key since LM Studio doesn't require authentication
  2. LMStudioTextEmbedderDescriptor that dynamically discovers embedding dimensions by making a probe request to the server, which is necessary because LM Studio can load arbitrary models with varying dimensions
  3. Provider registration in daft/ai/provider.py that adds 'lm_studio' to the available providers list
  4. Comprehensive test coverage in tests/ai/test_lm_studio.py that validates the provider functionality with proper mocking

The base_url handling includes smart logic to automatically append '/v1' if not present, ensuring compatibility with LM Studio's expected endpoint format. This implementation maintains the same interface as other providers while accommodating LM Studio's unique characteristics of local deployment and variable model dimensions.

Confidence score: 3/5

  • This PR introduces architectural complexity with the dynamic dimension discovery mechanism that could fail in various scenarios
  • Score reflects concerns about network calls during descriptor initialization and potential reliability issues with the probe request approach
  • Pay close attention to the dimension discovery logic in LMStudioTextEmbedderDescriptor.get_dimensions() method

4 files reviewed, 3 comments

Edit Code Review Bot Settings | Greptile

Comment on lines +110 to +121
def get_dimensions(self) -> EmbeddingDimensions:
try:
client = OpenAI(**self.provider_options)
response = client.embeddings.create(
input="dimension probe",
model=self.model_name,
encoding_format="float",
)
size = len(response.data[0].embedding)
return EmbeddingDimensions(size=size, dtype=DataType.float32())
except Exception as ex:
raise ValueError("Failed to determine embedding dimensions from LM Studio.") from ex
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The dimension probing creates a new OpenAI client and makes a network request during descriptor creation. This could be expensive if called repeatedly and may fail if the LM Studio server is temporarily unavailable. Consider caching the dimensions or moving this logic to instantiation time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a local network request

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"I am not concerned"

Comment on lines +120 to +121
except Exception as ex:
raise ValueError("Failed to determine embedding dimensions from LM Studio.") from ex
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: The broad exception catch could mask specific connection errors. Consider catching more specific exceptions like OpenAIError or connection-related exceptions to provide better error messages.

Copy link
Contributor

@rchowell rchowell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So cool!!

Copy link

codecov bot commented Sep 2, 2025

Codecov Report

❌ Patch coverage is 72.09302% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.07%. Comparing base (c3afb60) to head (590f849).
⚠️ Report is 6 commits behind head on main.

Files with missing lines Patch % Lines
daft/ai/provider.py 16.66% 5 Missing ⚠️
daft/ai/openai/__init__.py 73.33% 4 Missing ⚠️
daft/ai/openai/text_embedder.py 86.36% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #5103      +/-   ##
==========================================
- Coverage   76.10%   76.07%   -0.04%     
==========================================
  Files         950      953       +3     
  Lines      130488   130628     +140     
==========================================
+ Hits        99310    99377      +67     
- Misses      31178    31251      +73     
Files with missing lines Coverage Δ
daft/ai/openai/text_embedder.py 94.59% <86.36%> (-2.04%) ⬇️
daft/ai/openai/__init__.py 84.84% <73.33%> (-15.16%) ⬇️
daft/ai/provider.py 55.55% <16.66%> (-12.19%) ⬇️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@desmondcheongzx desmondcheongzx changed the title feat: Support LM Studio as a provider feat(embed_text): Support LM Studio as a provider Sep 2, 2025
@desmondcheongzx desmondcheongzx merged commit 58e9cb2 into main Sep 3, 2025
58 of 59 checks passed
@desmondcheongzx desmondcheongzx deleted the desmond/lm-studio-provider branch September 3, 2025 00:01
venkateshdb pushed a commit to venkateshdb/Daft that referenced this pull request Sep 6, 2025
## Changes Made

Add LM Studio as a text embedding provider.

For example

```
import daft
from daft.ai.provider import load_provider
from daft.functions.ai import embed_text

provider = load_provider("lm_studio", base_url="http://127.0.0.1:1234")  # This base_url parameter is optional if you're using the defaults for LM Studio. You can modify this as needed.
model = "text-embedding-nomic-embed-text-v1.5"  # Select a text embedding model that you've loaded into LM Studio.

(
    daft.read_huggingface("Open-Orca/OpenOrca")
    .with_column("embedding", embed_text(daft.col("response"), provider=provider, model=model))
    .show()
)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants