Skip to content

Commit f7edf79

Browse files
authored
Merge pull request #1 from embeddr-net/dev
v0.1.5
2 parents 506ac78 + 91f65c5 commit f7edf79

4 files changed

Lines changed: 74 additions & 3 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "embeddr-core"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
description = "Embeddr Core Library"
55
readme = "README.md"
66
authors = [{ name = "Nynxz", email = "contact@nynxz.com" }]

src/embeddr_core/models/library.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from datetime import datetime
22

33
from sqlmodel import Field, Relationship, SQLModel
4+
from embeddr_core.models.lineage import ImageLineage
45

56

67
class LibraryPath(SQLModel, table=True):
@@ -16,14 +17,39 @@ class LocalImage(SQLModel, table=True):
1617
id: int | None = Field(default=None, primary_key=True)
1718
path: str = Field(index=True, unique=True)
1819
filename: str
19-
library_path_id: int | None = Field(default=None, foreign_key="librarypath.id")
20+
library_path_id: int | None = Field(
21+
default=None, foreign_key="librarypath.id")
2022
created_at: datetime = Field(default_factory=datetime.utcnow)
2123

2224
# Metadata
2325
width: int | None = None
2426
height: int | None = None
2527
file_size: int | None = None
2628
mime_type: str | None = None
29+
media_type: str = Field(default="image", index=True)
30+
duration: float | None = None
31+
fps: float | None = None
32+
frame_count: int | None = None
2733
prompt: str | None = None
34+
tags: str | None = None
35+
phash: str | None = Field(default=None, index=True)
36+
is_archived: bool = Field(default=False, index=True)
2837

2938
library: LibraryPath | None = Relationship(back_populates="images")
39+
40+
parents: list["LocalImage"] = Relationship(
41+
back_populates="children",
42+
link_model=ImageLineage,
43+
sa_relationship_kwargs={
44+
"primaryjoin": "LocalImage.id==ImageLineage.child_id",
45+
"secondaryjoin": "LocalImage.id==ImageLineage.parent_id",
46+
},
47+
)
48+
children: list["LocalImage"] = Relationship(
49+
back_populates="parents",
50+
link_model=ImageLineage,
51+
sa_relationship_kwargs={
52+
"primaryjoin": "LocalImage.id==ImageLineage.parent_id",
53+
"secondaryjoin": "LocalImage.id==ImageLineage.child_id",
54+
},
55+
)

src/embeddr_core/models/lineage.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from datetime import datetime
2+
from sqlmodel import Field, SQLModel
3+
4+
5+
class ImageLineage(SQLModel, table=True):
6+
parent_id: int | None = Field(
7+
default=None, foreign_key="localimage.id", primary_key=True)
8+
child_id: int | None = Field(
9+
default=None, foreign_key="localimage.id", primary_key=True)
10+
created_at: datetime = Field(default_factory=datetime.utcnow)

src/embeddr_core/services/scanner.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import os
44
from pathlib import Path
55

6+
import imagehash
7+
from PIL import Image
68
from sqlmodel import Session, select
79

810
from embeddr_core.models.library import LibraryPath, LocalImage
@@ -18,6 +20,9 @@ def scan_library_path(session: Session, library_path: LibraryPath) -> int:
1820
Returns the number of new images added.
1921
"""
2022
root_path = Path(library_path.path)
23+
lib_name = library_path.name or library_path.path
24+
logger.info(f"Starting scan of library: {lib_name} ({root_path})")
25+
2126
if not root_path.exists():
2227
logger.warning(f"Library path not found: {root_path}")
2328
return 0
@@ -28,17 +33,28 @@ def scan_library_path(session: Session, library_path: LibraryPath) -> int:
2833
# For large libraries, this might need optimization (e.g. set of paths)
2934
existing_paths = set(
3035
session.exec(
31-
select(LocalImage.path).where(LocalImage.library_path_id == library_path.id)
36+
select(LocalImage.path).where(
37+
LocalImage.library_path_id == library_path.id)
3238
).all()
3339
)
40+
logger.info(
41+
f"Found {len(existing_paths)} existing images in database for {lib_name}")
3442

43+
total_scanned = 0
3544
for root, dirs, files in os.walk(root_path):
3645
for file in files:
46+
total_scanned += 1
47+
if total_scanned % 100 == 0:
48+
logger.info(
49+
f"Scanning {lib_name}: Checked {total_scanned} files, found {added_count} new images so far..."
50+
)
51+
3752
file_path = Path(root) / file
3853
if file_path.suffix.lower() in IMAGE_EXTENSIONS:
3954
str_path = str(file_path)
4055

4156
if str_path in existing_paths:
57+
logger.debug(f"Skipping existing image: {file}")
4258
continue
4359

4460
# Basic metadata
@@ -50,20 +66,39 @@ def scan_library_path(session: Session, library_path: LibraryPath) -> int:
5066

5167
mime_type, _ = mimetypes.guess_type(file_path)
5268

69+
width = None
70+
height = None
71+
phash = None
72+
73+
try:
74+
with Image.open(file_path) as img:
75+
width, height = img.size
76+
phash = str(imagehash.phash(img))
77+
except Exception as e:
78+
logger.warning(
79+
f"Failed to process image metadata for {file_path}: {e}")
80+
5381
# Create image record
5482
image = LocalImage(
5583
path=str_path,
5684
filename=file,
5785
library_path_id=library_path.id,
5886
file_size=file_size,
5987
mime_type=mime_type,
88+
width=width,
89+
height=height,
90+
phash=phash,
6091
)
6192
session.add(image)
6293
added_count += 1
94+
logger.debug(f"Added new image: {file}")
6395

6496
# Commit in batches if needed, but for now simple
6597

6698
session.commit()
99+
logger.info(
100+
f"Finished scanning {lib_name}. Total files checked: {total_scanned}. New images added: {added_count}."
101+
)
67102
return added_count
68103

69104

0 commit comments

Comments
 (0)