langchain-aneforge 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes on a GitHub Release via PyPI Trusted Publishing (OIDC): no API token.
4
+ # One-time setup on PyPI -> the project's Publishing settings -> add a trusted
5
+ # publisher with owner sbryngelson, repo langchain-aneforge, workflow publish.yml,
6
+ # environment pypi.
7
+
8
+ on:
9
+ release:
10
+ types: [published]
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ permissions:
17
+ id-token: write # mint the OIDC token Trusted Publishing checks
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: astral-sh/setup-uv@v5
21
+ - run: uv build
22
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ dist/
4
+ build/
5
+ *.egg-info/
6
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Spencer Bryngelson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: langchain-aneforge
3
+ Version: 0.1.0
4
+ Summary: LangChain embeddings that run on the Apple Neural Engine, via ANEForge (no CoreML).
5
+ Project-URL: Homepage, https://github.com/sbryngelson/langchain-aneforge
6
+ Project-URL: Repository, https://github.com/sbryngelson/langchain-aneforge
7
+ Project-URL: ANEForge, https://github.com/sbryngelson/ANEForge
8
+ Author-email: Spencer Bryngelson <sbryngelson@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ane,aneforge,apple-neural-engine,apple-silicon,embeddings,langchain
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: MacOS :: MacOS X
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: aneforge>=0.1.3
19
+ Requires-Dist: langchain-core>=0.3
20
+ Description-Content-Type: text/markdown
21
+
22
+ # langchain-aneforge
23
+
24
+ LangChain embeddings that run on the Apple Neural Engine, via
25
+ [ANEForge](https://github.com/sbryngelson/ANEForge). The encoder runs on the ANE
26
+ with no CoreML, matching the fp32 reference to cosine ~1.0 at a fraction of the
27
+ GPU's energy.
28
+
29
+ ```sh
30
+ pip install langchain-aneforge
31
+ ```
32
+
33
+ Apple Silicon macOS only (ANEForge reaches the engine through a built dispatch
34
+ shim; see the ANEForge install notes).
35
+
36
+ ## Use
37
+
38
+ ```python
39
+ from langchain_aneforge import ANEEmbeddings
40
+
41
+ emb = ANEEmbeddings(model="sentence-transformers/all-MiniLM-L6-v2")
42
+ vec = emb.embed_query("the Apple Neural Engine runs networks at low power")
43
+ docs = emb.embed_documents(["one passage", "another passage"])
44
+ ```
45
+
46
+ `ANEEmbeddings` is a standard `langchain_core.embeddings.Embeddings`, so it drops
47
+ into any LangChain retriever or vector store:
48
+
49
+ ```python
50
+ from langchain_community.vectorstores import FAISS
51
+
52
+ store = FAISS.from_texts(["...", "..."], ANEEmbeddings())
53
+ hits = store.similarity_search("query", k=3)
54
+ ```
55
+
56
+ `model` is any BERT-family sentence encoder on the Hugging Face hub. Its pooling
57
+ mode and normalize flag are read from the model's own sentence-transformers config,
58
+ so mean-pooled (MiniLM, E5) and cls-pooled (BGE, GTE) models both produce correct
59
+ vectors. Pass `int8=True` to stream int8 weights (half the size, cosine ~0.9999).
60
+
61
+ ## License
62
+
63
+ [MIT](LICENSE). Not affiliated with or endorsed by Apple or LangChain.
@@ -0,0 +1,42 @@
1
+ # langchain-aneforge
2
+
3
+ LangChain embeddings that run on the Apple Neural Engine, via
4
+ [ANEForge](https://github.com/sbryngelson/ANEForge). The encoder runs on the ANE
5
+ with no CoreML, matching the fp32 reference to cosine ~1.0 at a fraction of the
6
+ GPU's energy.
7
+
8
+ ```sh
9
+ pip install langchain-aneforge
10
+ ```
11
+
12
+ Apple Silicon macOS only (ANEForge reaches the engine through a built dispatch
13
+ shim; see the ANEForge install notes).
14
+
15
+ ## Use
16
+
17
+ ```python
18
+ from langchain_aneforge import ANEEmbeddings
19
+
20
+ emb = ANEEmbeddings(model="sentence-transformers/all-MiniLM-L6-v2")
21
+ vec = emb.embed_query("the Apple Neural Engine runs networks at low power")
22
+ docs = emb.embed_documents(["one passage", "another passage"])
23
+ ```
24
+
25
+ `ANEEmbeddings` is a standard `langchain_core.embeddings.Embeddings`, so it drops
26
+ into any LangChain retriever or vector store:
27
+
28
+ ```python
29
+ from langchain_community.vectorstores import FAISS
30
+
31
+ store = FAISS.from_texts(["...", "..."], ANEEmbeddings())
32
+ hits = store.similarity_search("query", k=3)
33
+ ```
34
+
35
+ `model` is any BERT-family sentence encoder on the Hugging Face hub. Its pooling
36
+ mode and normalize flag are read from the model's own sentence-transformers config,
37
+ so mean-pooled (MiniLM, E5) and cls-pooled (BGE, GTE) models both produce correct
38
+ vectors. Pass `int8=True` to stream int8 weights (half the size, cosine ~0.9999).
39
+
40
+ ## License
41
+
42
+ [MIT](LICENSE). Not affiliated with or endorsed by Apple or LangChain.
@@ -0,0 +1,4 @@
1
+ """LangChain integration for ANEForge: embeddings on the Apple Neural Engine."""
2
+ from langchain_aneforge.embeddings import ANEEmbeddings
3
+
4
+ __all__ = ["ANEEmbeddings"]
@@ -0,0 +1,36 @@
1
+ """LangChain embeddings backed by the Apple Neural Engine, via ANEForge."""
2
+ from __future__ import annotations
3
+
4
+ from typing import List
5
+
6
+ from langchain_core.embeddings import Embeddings
7
+
8
+
9
+ class ANEEmbeddings(Embeddings):
10
+ """A LangChain `Embeddings` that runs a sentence encoder on the Apple Neural Engine.
11
+
12
+ The encoder runs on the ANE through ANEForge (no CoreML), matching the fp32
13
+ reference to cosine ~1.0 at a fraction of the GPU's energy. `model` is any
14
+ BERT-family sentence encoder on the Hugging Face hub; its pooling mode and
15
+ normalize flag are read from the model's own sentence-transformers config, so
16
+ mean-pooled (MiniLM, E5) and cls-pooled (BGE, GTE) models both come out right.
17
+
18
+ from langchain_aneforge import ANEEmbeddings
19
+ emb = ANEEmbeddings(model="BAAI/bge-small-en-v1.5")
20
+ vec = emb.embed_query("hello world")
21
+
22
+ Pass `int8=True` to stream int8 weights (half the size, cosine ~0.9999).
23
+ Runs only on Apple Silicon macOS, where ANEForge can reach the engine.
24
+ """
25
+
26
+ def __init__(self, model: str = "sentence-transformers/all-MiniLM-L6-v2", int8: bool = False) -> None:
27
+ from aneforge.sentence_transformers import SentenceTransformer # lazy: Apple-Silicon only
28
+ self.model = model
29
+ self._st = SentenceTransformer(model, int8=int8)
30
+
31
+ def embed_documents(self, texts: List[str]) -> List[List[float]]:
32
+ vecs = self._st.encode(list(texts))
33
+ return vecs.astype(float).tolist()
34
+
35
+ def embed_query(self, text: str) -> List[float]:
36
+ return self._st.encode(text).astype(float).tolist()
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "langchain-aneforge"
7
+ version = "0.1.0"
8
+ description = "LangChain embeddings that run on the Apple Neural Engine, via ANEForge (no CoreML)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Spencer Bryngelson", email = "sbryngelson@gmail.com" }]
14
+ keywords = ["langchain", "embeddings", "apple-neural-engine", "ane", "apple-silicon", "aneforge"]
15
+
16
+ # aneforge reaches the ANE and pulls the encoder deps via its own extras; it runs
17
+ # only on Apple Silicon macOS. langchain-core is the integration surface.
18
+ dependencies = [
19
+ "langchain-core>=0.3",
20
+ "aneforge>=0.1.3",
21
+ ]
22
+
23
+ classifiers = [
24
+ "Development Status :: 3 - Alpha",
25
+ "Programming Language :: Python :: 3",
26
+ "Operating System :: MacOS :: MacOS X",
27
+ "Intended Audience :: Developers",
28
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/sbryngelson/langchain-aneforge"
33
+ Repository = "https://github.com/sbryngelson/langchain-aneforge"
34
+ "ANEForge" = "https://github.com/sbryngelson/ANEForge"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["langchain_aneforge"]
38
+
39
+ [tool.ruff]
40
+ line-length = 120
@@ -0,0 +1,27 @@
1
+ """Interface + on-device tests for ANEEmbeddings.
2
+
3
+ The interface test runs anywhere. The embedding tests need Apple Silicon with a
4
+ working ANEForge install and are skipped otherwise.
5
+ """
6
+ import importlib.util
7
+
8
+ import pytest
9
+
10
+ from langchain_aneforge import ANEEmbeddings
11
+
12
+ _HAS_ANE = importlib.util.find_spec("aneforge") is not None
13
+
14
+
15
+ def test_is_langchain_embeddings():
16
+ from langchain_core.embeddings import Embeddings
17
+ assert issubclass(ANEEmbeddings, Embeddings)
18
+
19
+
20
+ @pytest.mark.skipif(not _HAS_ANE, reason="needs aneforge on Apple Silicon")
21
+ def test_embed_query_and_documents():
22
+ emb = ANEEmbeddings("sentence-transformers/all-MiniLM-L6-v2")
23
+ q = emb.embed_query("hello world")
24
+ assert isinstance(q, list) and len(q) == 384 and all(isinstance(x, float) for x in q)
25
+
26
+ docs = emb.embed_documents(["a passage", "another passage"])
27
+ assert len(docs) == 2 and len(docs[0]) == 384