Merge pull request #150 from presenton/fix/embedding-issue-in-arm
fix/embedding issue in arm
This commit is contained in:
commit
cd327451c0
11 changed files with 148 additions and 583680 deletions
39
nginx.conf
39
nginx.conf
|
|
@ -30,28 +30,41 @@ http {
|
|||
proxy_connect_timeout 30m;
|
||||
}
|
||||
|
||||
location /static {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_read_timeout 30m;
|
||||
proxy_connect_timeout 30m;
|
||||
}
|
||||
|
||||
location /app_data {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_read_timeout 30m;
|
||||
proxy_connect_timeout 30m;
|
||||
}
|
||||
|
||||
location /docs {
|
||||
proxy_pass http://localhost:8000/docs;
|
||||
proxy_read_timeout 30m;
|
||||
proxy_connect_timeout 30m;
|
||||
}
|
||||
|
||||
|
||||
location /openapi.json {
|
||||
proxy_pass http://localhost:8000/openapi.json;
|
||||
proxy_read_timeout 30m;
|
||||
proxy_connect_timeout 30m;
|
||||
}
|
||||
|
||||
# Static
|
||||
location /static {
|
||||
alias /app/servers/fastapi/static/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
location /app_data/images/ {
|
||||
alias /app_data/images/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
location /app_data/exports/ {
|
||||
alias /app_data/exports/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
location /app_data/uploads/ {
|
||||
alias /app_data/uploads/;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ from models.generate_presentation_api import (
|
|||
PresentationPathAndEditPath,
|
||||
)
|
||||
from services.get_layout_by_name import get_layout_by_name
|
||||
from services.icon_finder_service import IconFinderService
|
||||
from services.image_generation_service import ImageGenerationService
|
||||
from utils.llm_calls.generate_presentation_outlines import generate_ppt_outline
|
||||
from models.sql.slide import SlideModel
|
||||
from models.sse_response import SSECompleteResponse, SSEResponse
|
||||
|
|
@ -30,7 +32,7 @@ from services.database import get_sql_session
|
|||
from services.documents_loader import DocumentsLoader
|
||||
from models.sql.presentation import PresentationModel
|
||||
from services.pptx_presentation_creator import PptxPresentationCreator
|
||||
from utils.asset_directory_utils import get_exports_directory
|
||||
from utils.asset_directory_utils import get_exports_directory, get_images_directory
|
||||
from utils.llm_calls.generate_document_summary import generate_document_summary
|
||||
from utils.llm_calls.generate_presentation_structure import (
|
||||
generate_presentation_structure,
|
||||
|
|
@ -195,6 +197,9 @@ async def stream_presentation(presentation_id: str):
|
|||
detail="Outlines can not be empty",
|
||||
)
|
||||
|
||||
image_generation_service = ImageGenerationService(get_images_directory())
|
||||
icon_finder_service = IconFinderService()
|
||||
|
||||
async def inner():
|
||||
structure = presentation.get_structure()
|
||||
layout = presentation.get_layout()
|
||||
|
|
@ -223,7 +228,11 @@ async def stream_presentation(presentation_id: str):
|
|||
slides.append(slide)
|
||||
|
||||
# This will mutate slide
|
||||
async_assets_generation_tasks.append(process_slide_and_fetch_assets(slide))
|
||||
async_assets_generation_tasks.append(
|
||||
process_slide_and_fetch_assets(
|
||||
image_generation_service, icon_finder_service, slide
|
||||
)
|
||||
)
|
||||
|
||||
# Give control to the event loop
|
||||
await asyncio.sleep(0)
|
||||
|
|
@ -423,9 +432,13 @@ async def generate_presentation_api(
|
|||
|
||||
# Process slides to fetch assets (images, icons, etc.)
|
||||
print("Processing slides to fetch assets")
|
||||
image_generation_service = ImageGenerationService(get_images_directory())
|
||||
icon_finder_service = IconFinderService()
|
||||
for slide in slides:
|
||||
try:
|
||||
await process_slide_and_fetch_assets(slide)
|
||||
await process_slide_and_fetch_assets(
|
||||
image_generation_service, icon_finder_service, slide
|
||||
)
|
||||
print(f"Processed slide {slide.index} successfully")
|
||||
except Exception as e:
|
||||
print(f"Error processing slide {slide.index}: {e}")
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ from fastapi import APIRouter, Body, HTTPException
|
|||
from models.sql.presentation import PresentationModel
|
||||
from models.sql.slide import SlideModel
|
||||
from services.database import get_sql_session
|
||||
from services.icon_finder_service import IconFinderService
|
||||
from services.image_generation_service import ImageGenerationService
|
||||
from utils.asset_directory_utils import get_images_directory
|
||||
from utils.llm_calls.edit_slide import get_edited_slide_content
|
||||
from utils.llm_calls.edit_slide_html import get_edited_slide_html
|
||||
from utils.llm_calls.select_slide_type_on_edit import get_slide_layout_from_prompt
|
||||
|
|
@ -34,9 +37,15 @@ async def edit_slide(id: Annotated[str, Body()], prompt: Annotated[str, Body()])
|
|||
prompt, slide_layout, slide, presentation.language
|
||||
)
|
||||
|
||||
image_generation_service = ImageGenerationService(get_images_directory())
|
||||
icon_finder_service = IconFinderService()
|
||||
|
||||
# This will mutate edited_slide_content
|
||||
new_assets = await process_old_and_new_slides_and_fetch_assets(
|
||||
slide.content, edited_slide_content
|
||||
image_generation_service,
|
||||
icon_finder_service,
|
||||
slide.content,
|
||||
edited_slide_content,
|
||||
)
|
||||
|
||||
# Always assign a new unique id to the slide
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
1
servers/fastapi/qdrant/.lock
Normal file
1
servers/fastapi/qdrant/.lock
Normal file
|
|
@ -0,0 +1 @@
|
|||
tmp lock file
|
||||
BIN
servers/fastapi/qdrant/collection/icons/storage.sqlite
Normal file
BIN
servers/fastapi/qdrant/collection/icons/storage.sqlite
Normal file
Binary file not shown.
1
servers/fastapi/qdrant/meta.json
Normal file
1
servers/fastapi/qdrant/meta.json
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"collections": {"icons": {"vectors": {"fast-bge-small-en-v1.5": {"size": 384, "distance": "Cosine", "hnsw_config": null, "quantization_config": null, "on_disk": null, "datatype": null, "multivector_config": null}}, "shard_number": null, "sharding_method": null, "replication_factor": null, "write_consistency_factor": null, "on_disk_payload": null, "hnsw_config": null, "wal_config": null, "optimizers_config": null, "init_from": null, "quantization_config": null, "sparse_vectors": null, "strict_mode_config": null}}, "aliases": {}}
|
||||
|
|
@ -5,70 +5,120 @@ annotated-types==0.7.0
|
|||
anyio==4.9.0
|
||||
async-timeout==5.0.1
|
||||
attrs==25.3.0
|
||||
backoff==2.2.1
|
||||
bcrypt==4.3.0
|
||||
build==1.2.2.post1
|
||||
cachetools==5.5.2
|
||||
certifi==2025.7.14
|
||||
cffi==1.17.1
|
||||
charset-normalizer==3.4.2
|
||||
click==8.2.1
|
||||
coloredlogs==15.0.1
|
||||
cryptography==45.0.5
|
||||
distro==1.9.0
|
||||
dnspython==2.7.0
|
||||
durationpy==0.10
|
||||
email_validator==2.2.0
|
||||
fastapi==0.116.1
|
||||
fastapi-cli==0.0.8
|
||||
fastapi-cloud-cli==0.1.4
|
||||
fastembed_vectorstore==0.1.6
|
||||
fastembed==0.7.1
|
||||
filelock==3.18.0
|
||||
flatbuffers==25.2.10
|
||||
frozenlist==1.7.0
|
||||
fsspec==2025.7.0
|
||||
google-auth==2.40.3
|
||||
google-genai==1.25.0
|
||||
googleapis-common-protos==1.70.0
|
||||
greenlet==3.2.3
|
||||
grpcio==1.74.0
|
||||
h11==0.16.0
|
||||
h2==4.2.0
|
||||
hf-xet==1.1.5
|
||||
hpack==4.1.0
|
||||
httpcore==1.0.9
|
||||
httptools==0.6.4
|
||||
httpx==0.28.1
|
||||
huggingface-hub==0.34.1
|
||||
humanfriendly==10.0
|
||||
hyperframe==6.1.0
|
||||
idna==3.10
|
||||
importlib_metadata==8.7.0
|
||||
importlib_resources==6.5.2
|
||||
iniconfig==2.1.0
|
||||
Jinja2==3.1.6
|
||||
jiter==0.10.0
|
||||
jsonschema==4.25.0
|
||||
jsonschema-specifications==2025.4.1
|
||||
kubernetes==33.1.0
|
||||
loguru==0.7.3
|
||||
lxml==6.0.0
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==3.0.2
|
||||
mdurl==0.1.2
|
||||
mmh3==5.1.0
|
||||
mpmath==1.3.0
|
||||
multidict==6.6.3
|
||||
numpy==2.3.2
|
||||
oauthlib==3.3.1
|
||||
onnxruntime==1.22.1
|
||||
openai==1.95.1
|
||||
opentelemetry-api==1.35.0
|
||||
opentelemetry-exporter-otlp-proto-common==1.35.0
|
||||
opentelemetry-exporter-otlp-proto-grpc==1.35.0
|
||||
opentelemetry-proto==1.35.0
|
||||
opentelemetry-sdk==1.35.0
|
||||
opentelemetry-semantic-conventions==0.56b0
|
||||
orjson==3.11.1
|
||||
overrides==7.7.0
|
||||
packaging==25.0
|
||||
pathvalidate==3.3.1
|
||||
pdfminer.six==20250506
|
||||
pdfplumber==0.11.7
|
||||
pillow==11.3.0
|
||||
pluggy==1.6.0
|
||||
portalocker==3.2.0
|
||||
posthog==5.4.0
|
||||
propcache==0.3.2
|
||||
protobuf==6.31.1
|
||||
py_rust_stemmers==0.1.5
|
||||
pyasn1==0.6.1
|
||||
pyasn1_modules==0.4.2
|
||||
pybase64==1.4.2
|
||||
pycparser==2.22
|
||||
pydantic==2.11.7
|
||||
pydantic_core==2.33.2
|
||||
Pygments==2.19.2
|
||||
pypdfium2==4.30.1
|
||||
PyPika==0.48.9
|
||||
pyproject_hooks==1.2.0
|
||||
pytest==8.4.1
|
||||
python-dateutil==2.9.0.post0
|
||||
python-docx==1.2.0
|
||||
python-dotenv==1.1.1
|
||||
python-multipart==0.0.20
|
||||
python-pptx==1.0.2
|
||||
PyYAML==6.0.2
|
||||
qdrant-client==1.15.0
|
||||
redis==6.2.0
|
||||
referencing==0.36.2
|
||||
requests==2.32.4
|
||||
requests-oauthlib==2.0.0
|
||||
rich==14.0.0
|
||||
rich-toolkit==0.14.8
|
||||
rignore==0.6.2
|
||||
rpds-py==0.26.0
|
||||
rsa==4.9.1
|
||||
sentry-sdk==2.32.0
|
||||
shellingham==1.5.4
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
SQLAlchemy==2.0.41
|
||||
sqlmodel==0.0.24
|
||||
starlette==0.47.1
|
||||
sympy==1.14.0
|
||||
tenacity==8.5.0
|
||||
tokenizers==0.21.2
|
||||
tqdm==4.67.1
|
||||
typer==0.16.0
|
||||
typing-inspection==0.4.1
|
||||
|
|
@ -77,6 +127,8 @@ urllib3==2.5.0
|
|||
uvicorn==0.35.0
|
||||
uvloop==0.21.0
|
||||
watchfiles==1.1.0
|
||||
websocket-client==1.8.0
|
||||
websockets==15.0.1
|
||||
xlsxwriter==3.2.5
|
||||
yarl==1.20.1
|
||||
zipp==3.23.0
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import os
|
||||
import uvicorn
|
||||
import argparse
|
||||
|
||||
from services.icon_finder_service import IconFinderService
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Run the FastAPI server")
|
||||
|
|
@ -13,6 +14,9 @@ if __name__ == "__main__":
|
|||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Initialize the Icons Collection
|
||||
IconFinderService()
|
||||
|
||||
uvicorn.run(
|
||||
"api.main:app",
|
||||
host="0.0.0.0",
|
||||
|
|
|
|||
|
|
@ -1,35 +1,48 @@
|
|||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from fastembed_vectorstore import FastembedVectorstore, FastembedEmbeddingModel
|
||||
from qdrant_client import QdrantClient
|
||||
|
||||
|
||||
class IconFinderService:
|
||||
def __init__(self):
|
||||
self.vector_store = self.get_icons_vectorstore()
|
||||
self.collection_name = "icons"
|
||||
self.client = QdrantClient(path="qdrant")
|
||||
print("Initializing icons collection...")
|
||||
self.client.set_model("BAAI/bge-small-en-v1.5")
|
||||
self._initialize_icons_collection()
|
||||
print("Icons collection initialized")
|
||||
|
||||
def get_icons_vectorstore(self):
|
||||
vector_store_path = "assets/icons_vectorstore.json"
|
||||
embedding_model = FastembedEmbeddingModel.BGESmallENV15
|
||||
def _initialize_icons_collection(self):
|
||||
try:
|
||||
self.client.get_collection(self.collection_name)
|
||||
except Exception:
|
||||
self._populate_icons_collection()
|
||||
|
||||
if os.path.exists(vector_store_path):
|
||||
return FastembedVectorstore.load(embedding_model, vector_store_path)
|
||||
|
||||
vector_store = FastembedVectorstore(embedding_model)
|
||||
def _populate_icons_collection(self):
|
||||
with open("assets/icons.json", "r") as f:
|
||||
icons = json.load(f)
|
||||
|
||||
documents = []
|
||||
metadata = []
|
||||
|
||||
for each in icons["icons"]:
|
||||
if each["name"].split("-")[-1] == "bold":
|
||||
documents.append(f"{each['name']}||{each['tags']}")
|
||||
doc_text = f"{each['name']} {each['tags']}"
|
||||
documents.append(doc_text)
|
||||
metadata.append({"name": each["name"]})
|
||||
|
||||
vector_store.embed_documents(documents)
|
||||
vector_store.save(vector_store_path)
|
||||
|
||||
return vector_store
|
||||
if documents:
|
||||
self.client.add(
|
||||
collection_name=self.collection_name,
|
||||
documents=documents,
|
||||
metadata=metadata,
|
||||
)
|
||||
|
||||
async def search_icons(self, query: str, k: int = 1):
|
||||
result = await asyncio.to_thread(self.vector_store.search, query, k)
|
||||
return [
|
||||
f"/static/icons/bold/{result[0].split('||')[0]}.png" for result in result
|
||||
]
|
||||
result = await asyncio.to_thread(
|
||||
self.client.query,
|
||||
collection_name=self.collection_name,
|
||||
query_text=query,
|
||||
limit=k,
|
||||
)
|
||||
return [f"/static/icons/bold/{each.metadata['name']}.png" for each in result]
|
||||
|
|
|
|||
|
|
@ -10,12 +10,10 @@ from utils.dict_utils import get_dict_at_path, get_dict_paths_with_key, set_dict
|
|||
|
||||
|
||||
async def process_slide_and_fetch_assets(
|
||||
image_generation_service: ImageGenerationService,
|
||||
icon_finder_service: IconFinderService,
|
||||
slide: SlideModel,
|
||||
) -> List[ImageAsset]:
|
||||
image_directory = get_images_directory()
|
||||
|
||||
image_generation_service = ImageGenerationService(image_directory)
|
||||
icon_finder_service = IconFinderService()
|
||||
|
||||
async_tasks = []
|
||||
|
||||
|
|
@ -61,6 +59,8 @@ async def process_slide_and_fetch_assets(
|
|||
|
||||
|
||||
async def process_old_and_new_slides_and_fetch_assets(
|
||||
image_generation_service: ImageGenerationService,
|
||||
icon_finder_service: IconFinderService,
|
||||
old_slide_content: dict,
|
||||
new_slide_content: dict,
|
||||
) -> List[ImageAsset]:
|
||||
|
|
@ -98,10 +98,6 @@ async def process_old_and_new_slides_and_fetch_assets(
|
|||
get_dict_at_path(new_slide_content, path) for path in new_icon_dict_paths
|
||||
]
|
||||
|
||||
# Creates services
|
||||
image_generation_service = ImageGenerationService(get_images_directory())
|
||||
icon_finder_service = IconFinderService()
|
||||
|
||||
# Creates async tasks for fetching new images
|
||||
async_image_fetch_tasks = []
|
||||
new_images_fetch_status = []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue