Skip to content
Merged
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
93 changes: 0 additions & 93 deletions docs/getting-started/genai.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,99 +65,6 @@ Feast supports transformations that can be used to:
* Normalize and preprocess features before serving to LLMs
* Apply custom transformations to adapt features for specific LLM requirements

## Getting Started with Feast for GenAI

Choose a reason for hiding this comment

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

Uh oh, this was removed. I wonder why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

wth?!


### Installation

To use Feast with vector database support, install with the appropriate extras:

```bash
# For Milvus support
pip install feast[milvus,nlp]

# For Elasticsearch support
pip install feast[elasticsearch]

# For Qdrant support
pip install feast[qdrant]

# For SQLite support (Python 3.10 only)
pip install feast[sqlite_vec]
```

### Configuration

Configure your feature store to use a vector database as the online store:

```yaml
project: genai-project
provider: local
registry: data/registry.db
online_store:
type: milvus
path: data/online_store.db
vector_enabled: true
embedding_dim: 384 # Adjust based on your embedding model
index_type: "IVF_FLAT"

offline_store:
type: file
entity_key_serialization_version: 3
```

### Defining Vector Features

Create feature views with vector index support:

```python
from feast import FeatureView, Field, Entity
from feast.types import Array, Float32, String

document = Entity(
name="document_id",
description="Document identifier",
join_keys=["document_id"],
)

document_embeddings = FeatureView(
name="document_embeddings",
entities=[document],
schema=[
Field(
name="vector",
dtype=Array(Float32),
vector_index=True, # Enable vector search
vector_search_metric="COSINE", # Similarity metric
),
Field(name="document_id", dtype=String),
Field(name="content", dtype=String),
],
source=document_source,
ttl=timedelta(days=30),
)
```

### Retrieving Similar Documents

Use the `retrieve_online_documents_v2` method to find similar documents:

```python
# Generate query embedding
query = "How does Feast support vector databases?"
query_embedding = embed_text(query) # Your embedding function

# Retrieve similar documents
context_data = store.retrieve_online_documents_v2(
features=[
"document_embeddings:vector",
"document_embeddings:document_id",
"document_embeddings:content",
],
query=query_embedding,
top_k=3,
distance_metric='COSINE',
).to_df()
```
## Use Cases

### Document Question-Answering
Expand Down
26 changes: 26 additions & 0 deletions sdk/python/feast/feature_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ class ReadDocumentRequest(BaseModel):
file_path: str


class SaveDocumentRequest(BaseModel):
file_path: str
data: dict


def _get_features(request: GetOnlineFeaturesRequest, store: "feast.FeatureStore"):
if request.feature_service:
feature_service = store.get_feature_service(
Expand Down Expand Up @@ -375,6 +380,27 @@ async def read_document_endpoint(request: ReadDocumentRequest):
except Exception as e:
return {"error": str(e)}

@app.post("/save-document")
async def save_document_endpoint(request: SaveDocumentRequest):
try:
import json
import os
from pathlib import Path

file_path = Path(request.file_path).resolve()
if not str(file_path).startswith(os.getcwd()):
return {"error": "Invalid file path"}

base_name = file_path.stem
labels_file = file_path.parent / f"{base_name}-labels.json"

with open(labels_file, "w", encoding="utf-8") as file:
json.dump(request.data, file, indent=2, ensure_ascii=False)

return {"success": True, "saved_to": str(labels_file)}
except Exception as e:
return {"error": str(e)}

@app.get("/chat")
async def chat_ui():
# Serve the chat UI
Expand Down
1 change: 1 addition & 0 deletions sdk/python/feast/feature_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -1495,6 +1495,7 @@ async def push_async(
df: pd.DataFrame,
allow_registry_cache: bool = True,
to: PushMode = PushMode.ONLINE,
**kwargs,
):
fvs = self._fvs_for_push_source_or_raise(push_source_name, allow_registry_cache)

Expand Down
26 changes: 26 additions & 0 deletions sdk/python/feast/ui_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
from fastapi import FastAPI, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel

import feast


class SaveDocumentRequest(BaseModel):
file_path: str
data: dict


def get_app(
store: "feast.FeatureStore",
project_id: str,
Expand Down Expand Up @@ -76,6 +82,26 @@ def read_registry():
media_type="application/octet-stream",
)

@app.post("/save-document")
async def save_document_endpoint(request: SaveDocumentRequest):
try:
import os
from pathlib import Path

file_path = Path(request.file_path).resolve()
if not str(file_path).startswith(os.getcwd()):
return {"error": "Invalid file path"}

base_name = file_path.stem
labels_file = file_path.parent / f"{base_name}-labels.json"

with open(labels_file, "w", encoding="utf-8") as file:
json.dump(request.data, file, indent=2, ensure_ascii=False)

return {"success": True, "saved_to": str(labels_file)}
except Exception as e:
return {"error": str(e)}

# For all other paths (such as paths that would otherwise be handled by react router), pass to React
@app.api_route("/p/{path_name:path}", methods=["GET"])
def catch_all():
Expand Down
2 changes: 1 addition & 1 deletion ui/src/FeastUISansProviders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const FeastUISansProvidersInner = ({
element={<DatasetInstance />}
/>
<Route
path="document-labeling/"
path="data-labeling/"
element={<DocumentLabelingPage />}
/>
<Route path="permissions/" element={<PermissionsIndex />} />
Expand Down
12 changes: 6 additions & 6 deletions ui/src/custom-tabs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,18 +136,18 @@ interface DatasetCustomTabRegistrationInterface
}: DatasetCustomTabProps) => JSX.Element;
}

// Type for Document Labeling Custom Tabs
interface DocumentLabelingCustomTabProps {
// Type for Data Labeling Custom Tabs
interface DataLabelingCustomTabProps {
id: string | undefined;
feastObjectQuery: RegularFeatureViewQueryReturnType;
}
interface DocumentLabelingCustomTabRegistrationInterface
interface DataLabelingCustomTabRegistrationInterface
extends CustomTabRegistrationInterface {
Component: ({
id,
feastObjectQuery,
...args
}: DocumentLabelingCustomTabProps) => JSX.Element;
}: DataLabelingCustomTabProps) => JSX.Element;
}

export type {
Expand All @@ -171,6 +171,6 @@ export type {
FeatureCustomTabProps,
DatasetCustomTabRegistrationInterface,
DatasetCustomTabProps,
DocumentLabelingCustomTabRegistrationInterface,
DocumentLabelingCustomTabProps,
DataLabelingCustomTabRegistrationInterface,
DataLabelingCustomTabProps,
};
10 changes: 5 additions & 5 deletions ui/src/pages/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ const SideNav = () => {
isSelected: useMatchSubpath(`${baseUrl}/data-set`),
},
{
name: "Document Labeling",
id: htmlIdGenerator("documentLabeling")(),
icon: <EuiIcon type="documentEdit" />,
name: "Data Labeling",
id: htmlIdGenerator("dataLabeling")(),
icon: <EuiIcon type="documentEdit" color="#006BB4" />,
renderItem: (props) => (
<Link {...props} to={`${baseUrl}/document-labeling`} />
<Link {...props} to={`${baseUrl}/data-labeling`} />
),
isSelected: useMatchSubpath(`${baseUrl}/document-labeling`),
isSelected: useMatchSubpath(`${baseUrl}/data-labeling`),
},
{
name: "Permissions",
Expand Down
Loading
Loading