Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bad32d5966 | |||
| 3d375161bd | |||
| 7f08813635 | |||
| 978c70e91a | |||
| 4a82352391 | |||
| 64ee10c182 |
@@ -439,6 +439,15 @@ pip3 install -r pgvector-demo/backend/requirements.txt --break-system-packages
|
|||||||
pip3 install -r oravector-demo/backend/requirements.txt --break-system-packages
|
pip3 install -r oravector-demo/backend/requirements.txt --break-system-packages
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**CLIP model** — not included in the repository. It is downloaded automatically from
|
||||||
|
Hugging Face Hub on first use (~600 MB, cached in `~/.cache/huggingface/hub/`):
|
||||||
|
|
||||||
|
> `sentence-transformers/clip-ViT-B-32`
|
||||||
|
> https://huggingface.co/sentence-transformers/clip-ViT-B-32
|
||||||
|
|
||||||
|
No manual download is required — `sentence-transformers` handles this transparently
|
||||||
|
when `index_images.py` or a backend is started for the first time.
|
||||||
|
|
||||||
### 1. PostgreSQL
|
### 1. PostgreSQL
|
||||||
|
|
||||||
**Start the container:**
|
**Start the container:**
|
||||||
|
|||||||
Binary file not shown.
+164
-42
@@ -83,7 +83,7 @@ def diagram_s3_vectors():
|
|||||||
ax.add_patch(mpatches.Arc((0, 0), 0.52, 0.52, angle=0,
|
ax.add_patch(mpatches.Arc((0, 0), 0.52, 0.52, angle=0,
|
||||||
theta1=a1, theta2=a3,
|
theta1=a1, theta2=a3,
|
||||||
color="#fab387", lw=2))
|
color="#fab387", lw=2))
|
||||||
ax.text(-0.10, 0.34, "groß", color="#fab387", fontsize=10)
|
ax.text(-0.35, 0.28, "groß", color="#fab387", fontsize=10)
|
||||||
|
|
||||||
plt.tight_layout(pad=0.3)
|
plt.tight_layout(pad=0.3)
|
||||||
return _save(fig, "s3_vectors.png")
|
return _save(fig, "s3_vectors.png")
|
||||||
@@ -132,7 +132,7 @@ def diagram_s6_cosine():
|
|||||||
vB = np.array([0.55, 1.0 ]) # text vector
|
vB = np.array([0.55, 1.0 ]) # text vector
|
||||||
|
|
||||||
for v, color, label, lpos in [
|
for v, color, label, lpos in [
|
||||||
(vA, "#89b4fa", "Bild-Vektor", (1.12, 0.18)),
|
(vA, "#89b4fa", "Bild-Vektor", (1.17, 0.08)),
|
||||||
(vB, "#cba6f7", 'Text-Vektor\n"Bäume"', (0.56, 1.07)),
|
(vB, "#cba6f7", 'Text-Vektor\n"Bäume"', (0.56, 1.07)),
|
||||||
]:
|
]:
|
||||||
ax.annotate("", xy=v, xytext=(0, 0),
|
ax.annotate("", xy=v, xytext=(0, 0),
|
||||||
@@ -167,82 +167,120 @@ def diagram_s6_cosine():
|
|||||||
def diagram_architecture():
|
def diagram_architecture():
|
||||||
"""Architecture slide: 3 columns showing app server, database, and where CLIP runs."""
|
"""Architecture slide: 3 columns showing app server, database, and where CLIP runs."""
|
||||||
CLIP_CLR = "#a6e3a1"
|
CLIP_CLR = "#a6e3a1"
|
||||||
# (x, db_name, color, port, clip_app, clip_db, db_tech, vec_embed_fn)
|
# (x, db_name, color, port, clip_app, clip_db, db_tech, vec_embed_fn, foto_storage)
|
||||||
COLS = [
|
COLS = [
|
||||||
(2.3, "PostgreSQL 18", "#89b4fa", "Port 8000", True, False, "pgvector 0.8.2\nHNSW (Disk)", None),
|
(2.3, "PostgreSQL 18", "#89b4fa", "Port 8000", True, False, "pgvector 0.8.2\nHNSW (Disk)", None, "Fotos: Dateipfad (Filesystem)"),
|
||||||
(6.65, "Oracle 26ai\nVECTORS_USER", "#f38ba8", "Port 8001", True, False, "HNSW (SGA)", None),
|
(6.65, "Oracle 26ai\nVECTORS_USER", "#f38ba8", "Port 8001", True, False, "HNSW (SGA)", None, "Fotos: Dateipfad (Filesystem)"),
|
||||||
(11.0, "Oracle 26ai\nVECTOR", "#cba6f7", "Port 8002", False, True, "HNSW (SGA)", "VECTOR_EMBEDDING()"),
|
(11.0, "Oracle 26ai\nVECTOR", "#cba6f7", "Port 8002", False, True, "HNSW (SGA)", "VECTOR_EMBEDDING()", "Fotos: BLOB (in Oracle)"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
BOX_H = 2.2 # all boxes same height
|
||||||
|
DB_Y = 0.15 # database box bottom
|
||||||
|
GAP = 0.60 # space between DB top and app server bottom
|
||||||
|
APP_Y = DB_Y + BOX_H + GAP # = 2.95
|
||||||
|
|
||||||
fig, ax = _fig(13.5, 6.5)
|
fig, ax = _fig(13.5, 6.5)
|
||||||
ax.set_xlim(0, 13.5); ax.set_ylim(-0.8, 6.0)
|
ax.set_xlim(0, 13.5); ax.set_ylim(-0.8, 5.9)
|
||||||
ax.axis("off")
|
ax.axis("off")
|
||||||
|
|
||||||
for x, db_name, color, port, clip_app, clip_db, db_tech, vec_fn in COLS:
|
for x, db_name, color, port, clip_app, clip_db, db_tech, vec_fn, foto_storage in COLS:
|
||||||
# ── Column title + port
|
APP_TOP = APP_Y + BOX_H # = 5.15
|
||||||
ax.text(x, 5.78, port, ha="center", color=color, fontsize=13, fontweight="bold")
|
DB_TOP = DB_Y + BOX_H # = 2.35
|
||||||
|
|
||||||
|
# ── Port label
|
||||||
|
ax.text(x, APP_TOP + 0.28, port, ha="center", color=color,
|
||||||
|
fontsize=13, fontweight="bold")
|
||||||
|
|
||||||
# ── App server box
|
# ── App server box
|
||||||
ax.add_patch(mpatches.FancyBboxPatch(
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
(x-1.7, 3.7), 3.4, 1.85,
|
(x-1.7, APP_Y), 3.4, BOX_H,
|
||||||
boxstyle="round,pad=0.1", facecolor="#28293d", edgecolor=color, lw=2))
|
boxstyle="round,pad=0.1", facecolor="#28293d", edgecolor=color, lw=2))
|
||||||
ax.text(x, 5.38, "App-Server (FastAPI)", ha="center",
|
ax.text(x, APP_TOP - 0.22, "App-Server (FastAPI)", ha="center",
|
||||||
color=color, fontsize=11, fontweight="bold")
|
color=color, fontsize=11, fontweight="bold")
|
||||||
|
|
||||||
if clip_app:
|
if clip_app:
|
||||||
ax.add_patch(mpatches.FancyBboxPatch(
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
(x-1.2, 3.78), 2.4, 0.82,
|
(x-1.2, APP_Y + 0.10), 2.4, 0.75,
|
||||||
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=CLIP_CLR, lw=2))
|
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=CLIP_CLR, lw=2))
|
||||||
ax.text(x, 4.19, "CLIP-Modell\n(sentence-transformers)",
|
ax.text(x, APP_Y + 0.475, "CLIP-Modell\n(sentence-transformers)",
|
||||||
ha="center", va="center", color=CLIP_CLR, fontsize=9.5, fontweight="bold",
|
ha="center", va="center", color=CLIP_CLR, fontsize=9.5, fontweight="bold",
|
||||||
multialignment="center")
|
multialignment="center")
|
||||||
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
|
(x-1.2, APP_Y + 0.95), 2.4, 0.42,
|
||||||
|
boxstyle="round,pad=0.06", facecolor="#1e1e2e", edgecolor=DIAG_AXIS, lw=1,
|
||||||
|
linestyle="dashed"))
|
||||||
|
ax.text(x, APP_Y + 1.16, foto_storage,
|
||||||
|
ha="center", va="center", color=DIAG_AXIS, fontsize=9, style="italic")
|
||||||
else:
|
else:
|
||||||
ax.add_patch(mpatches.FancyBboxPatch(
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
(x-1.2, 3.78), 2.4, 0.82,
|
(x-1.2, APP_Y + 0.10), 2.4, 0.75,
|
||||||
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=DIAG_AXIS, lw=1,
|
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=DIAG_AXIS, lw=1,
|
||||||
linestyle="dashed"))
|
linestyle="dashed"))
|
||||||
ax.text(x, 4.19, "kein CLIP",
|
ax.text(x, APP_Y + 0.475, "kein CLIP",
|
||||||
ha="center", va="center", color=DIAG_AXIS, fontsize=10, style="italic")
|
ha="center", va="center", color=DIAG_AXIS, fontsize=10, style="italic")
|
||||||
|
|
||||||
# ── Arrow + what is sent
|
# ── Arrow with comfortable gap
|
||||||
ax.annotate("", xy=(x, 3.05), xytext=(x, 3.65),
|
ax.annotate("", xy=(x, DB_TOP + 0.05), xytext=(x, APP_Y - 0.05),
|
||||||
arrowprops=dict(arrowstyle="->", color=DIAG_AXIS, lw=2))
|
arrowprops=dict(arrowstyle="->", color=DIAG_AXIS, lw=2))
|
||||||
arrow_lbl = "Vektor (512 floats)" if clip_app else "Text-String"
|
arrow_lbl = "Vektor (512 floats)" if clip_app else "Text-String"
|
||||||
ax.text(x, 3.35, arrow_lbl, ha="center", va="center",
|
ax.text(x + 0.2, (DB_TOP + APP_Y) / 2, arrow_lbl, ha="left", va="center",
|
||||||
color=DIAG_AXIS, fontsize=9, style="italic")
|
color=DIAG_AXIS, fontsize=9, style="italic")
|
||||||
|
|
||||||
# ── Database box
|
# ── Database box
|
||||||
db_h = 2.8 if clip_db else 1.9
|
|
||||||
ax.add_patch(mpatches.FancyBboxPatch(
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
(x-1.7, 0.15), 3.4, db_h,
|
(x-1.7, DB_Y), 3.4, BOX_H,
|
||||||
boxstyle="round,pad=0.1", facecolor="#28293d", edgecolor=color, lw=2))
|
boxstyle="round,pad=0.1", facecolor="#28293d", edgecolor=color, lw=2))
|
||||||
|
|
||||||
if clip_db:
|
if clip_db:
|
||||||
# CLIP ONNX box inside DB
|
|
||||||
ax.add_patch(mpatches.FancyBboxPatch(
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
(x-1.2, 0.25), 2.4, 0.82,
|
(x-1.2, DB_Y + 0.10), 2.4, 0.72,
|
||||||
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=CLIP_CLR, lw=2))
|
boxstyle="round,pad=0.08", facecolor="#1e1e2e", edgecolor=CLIP_CLR, lw=2))
|
||||||
ax.text(x, 0.66, "CLIP-Modell\n(ONNX, in Oracle)",
|
ax.text(x, DB_Y + 0.46, "CLIP-Modell\n(ONNX, in Oracle)",
|
||||||
ha="center", va="center", color=CLIP_CLR, fontsize=9.5, fontweight="bold",
|
ha="center", va="center", color=CLIP_CLR, fontsize=9.5, fontweight="bold",
|
||||||
multialignment="center")
|
multialignment="center")
|
||||||
# VECTOR_EMBEDDING() label
|
ax.add_patch(mpatches.FancyBboxPatch(
|
||||||
ax.text(x, 1.22, vec_fn,
|
(x-1.2, DB_Y + 0.92), 2.4, 0.40,
|
||||||
|
boxstyle="round,pad=0.06", facecolor="#1e1e2e", edgecolor=DIAG_AXIS, lw=1,
|
||||||
|
linestyle="dashed"))
|
||||||
|
ax.text(x, DB_Y + 1.12, foto_storage,
|
||||||
|
ha="center", va="center", color=DIAG_AXIS, fontsize=9, style="italic")
|
||||||
|
ax.text(x, DB_Y + 1.50, vec_fn,
|
||||||
ha="center", color="#fab387", fontsize=10, fontweight="bold",
|
ha="center", color="#fab387", fontsize=10, fontweight="bold",
|
||||||
fontfamily="monospace")
|
fontfamily="monospace")
|
||||||
# DB name
|
ax.text(x, DB_Y + 1.72, "Oracle 26ai", ha="center", color=color,
|
||||||
ax.text(x, 1.65, db_name, ha="center", color=color,
|
|
||||||
fontsize=11, fontweight="bold")
|
fontsize=11, fontweight="bold")
|
||||||
ax.text(x, 2.35, db_tech, ha="center", color=DIAG_AXIS,
|
ax.text(x, DB_Y + 1.92, "Schema: VECTOR", ha="center", color=color,
|
||||||
fontsize=9, multialignment="center")
|
fontsize=9)
|
||||||
|
ax.text(x, DB_Y + 2.10, db_tech, ha="center", color=DIAG_AXIS,
|
||||||
|
fontsize=9)
|
||||||
else:
|
else:
|
||||||
ax.text(x, 1.5, db_name, ha="center", color=color,
|
# Split db_name → ["PostgreSQL 18"] or ["Oracle 26ai", "VECTORS_USER"]
|
||||||
|
# Split db_tech → ["pgvector 0.8.2", "HNSW (Disk)"] or ["HNSW (SGA)"]
|
||||||
|
name_parts = db_name.split("\n")
|
||||||
|
tech_parts = db_tech.split("\n")
|
||||||
|
hnsw = tech_parts[-1] # always last
|
||||||
|
tech_extra = tech_parts[:-1] # e.g. ["pgvector 0.8.2"]
|
||||||
|
|
||||||
|
# HNSW — same height across all three DB boxes
|
||||||
|
ax.text(x, DB_Y + 2.10, hnsw, ha="center", color=DIAG_AXIS, fontsize=9)
|
||||||
|
|
||||||
|
# Middle line: schema name or version info (matches "Schema: VECTOR" in col 3)
|
||||||
|
if len(name_parts) > 1:
|
||||||
|
mid_label = "Schema: " + name_parts[1]
|
||||||
|
elif tech_extra:
|
||||||
|
mid_label = tech_extra[0]
|
||||||
|
else:
|
||||||
|
mid_label = ""
|
||||||
|
if mid_label:
|
||||||
|
ax.text(x, DB_Y + 1.92, mid_label, ha="center", color=color, fontsize=9)
|
||||||
|
|
||||||
|
# Main DB name (matches "Oracle 26ai" in col 3)
|
||||||
|
ax.text(x, DB_Y + 1.72, name_parts[0], ha="center", color=color,
|
||||||
fontsize=11, fontweight="bold")
|
fontsize=11, fontweight="bold")
|
||||||
ax.text(x, 0.72, db_tech, ha="center", color=DIAG_AXIS,
|
|
||||||
fontsize=9, multialignment="center")
|
|
||||||
|
|
||||||
# ── Vertical separators
|
# ── Vertical separators
|
||||||
for xsep in [4.5, 8.85]:
|
for xsep in [4.5, 8.85]:
|
||||||
ax.plot([xsep, xsep], [0.05, 5.9], color=DIAG_GRID, lw=1, linestyle="--")
|
ax.plot([xsep, xsep], [0.05, 5.55], color=DIAG_GRID, lw=1, linestyle="--")
|
||||||
|
|
||||||
# ── Caption — separated from boxes, applies to all three columns
|
# ── Caption — separated from boxes, applies to all three columns
|
||||||
ax.plot([0.3, 13.2], [-0.18, -0.18], color=DIAG_GRID, lw=1)
|
ax.plot([0.3, 13.2], [-0.18, -0.18], color=DIAG_GRID, lw=1)
|
||||||
@@ -437,7 +475,7 @@ def divider(slide, y, color=DIM_CLR):
|
|||||||
s = add_slide(logo=False, footer=False) # title slide: custom layout
|
s = add_slide(logo=False, footer=False) # title slide: custom layout
|
||||||
title_slide_layout(s,
|
title_slide_layout(s,
|
||||||
"Vektoren in der Datenbank",
|
"Vektoren in der Datenbank",
|
||||||
"Semantische Bildsuche mit PostgreSQL/pgvector und Oracle 26ai")
|
"Der VECTOR-Datentyp in Oracle 26ai und PostgreSQL")
|
||||||
# Conference details
|
# Conference details
|
||||||
txb(s, CONFERENCE,
|
txb(s, CONFERENCE,
|
||||||
Inches(1), Inches(5.0), Inches(11.33), Inches(0.5),
|
Inches(1), Inches(5.0), Inches(11.33), Inches(0.5),
|
||||||
@@ -449,7 +487,85 @@ txb(s, f"{EVENT_DATE} · {EVENT_CITY}",
|
|||||||
s.shapes.add_picture(LOGO_PATH, Inches(4.67), Inches(6.1), Inches(4.0), Inches(1.06))
|
s.shapes.add_picture(LOGO_PATH, Inches(4.67), Inches(6.1), Inches(4.0), Inches(1.06))
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
# Slide 2 — Agenda
|
# Slide 2 — Über den Referenten
|
||||||
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
|
s = add_slide(logo=False, footer=False)
|
||||||
|
section_header(s, "Über den Referenten", ACCENT_PG)
|
||||||
|
|
||||||
|
# Logo top-right — below the accent bar (y=0.14), correct 4.46:1 ratio
|
||||||
|
s.shapes.add_picture(LOGO_PATH, Inches(9.63), Inches(0.22), Inches(3.5), Inches(0.785))
|
||||||
|
|
||||||
|
# Photo — correct 2:3 ratio (3471×5206 px), dark bg blends with slide theme
|
||||||
|
s.shapes.add_picture("/home/dierk/Bilder/Porträt Pro Neg 2.jpg",
|
||||||
|
Inches(0.4), Inches(1.1), Inches(3.4), Inches(5.1))
|
||||||
|
|
||||||
|
# Name + title
|
||||||
|
txb(s, "Dierk Lenz",
|
||||||
|
Inches(4.3), Inches(1.2), Inches(8.7), Inches(0.7),
|
||||||
|
size=32, bold=True, color=TITLE_CLR)
|
||||||
|
txb(s, "Inhaber & Geschäftsführer · Dierk Lenz Consulting GmbH",
|
||||||
|
Inches(4.3), Inches(1.9), Inches(8.7), Inches(0.45),
|
||||||
|
size=18, color=ACCENT_PG)
|
||||||
|
|
||||||
|
# Dividers starting after the photo (x=4.2, not cutting into photo)
|
||||||
|
for div_y in [Inches(2.45), Inches(4.65)]:
|
||||||
|
ln = s.shapes.add_shape(1, Inches(4.2), div_y, Inches(8.83), Pt(1))
|
||||||
|
ln.fill.solid(); ln.fill.fore_color.rgb = RGBColor(0x44, 0x47, 0x5a)
|
||||||
|
ln.line.fill.background()
|
||||||
|
|
||||||
|
# Career timeline — year in accent, description in body colour
|
||||||
|
for y_pos, year, desc in [
|
||||||
|
(2.60, "1983 – 1989", "Informatik-Studium, RWTH Aachen"),
|
||||||
|
(3.10, "1989 – 1995", "Senior Systemberater, Oracle Deutschland, Düsseldorf"),
|
||||||
|
(3.60, "1995 / 1996", "Co-Gründer Herrmann & Lenz (GbR & GmbH)"),
|
||||||
|
(4.10, "2026", "Gründer & Geschäftsführer, Dierk Lenz Consulting GmbH"),
|
||||||
|
]:
|
||||||
|
txb(s, year, Inches(4.3), Inches(y_pos), Inches(1.7), Inches(0.45),
|
||||||
|
size=15, bold=True, color=ACCENT_PG)
|
||||||
|
txb(s, desc, Inches(6.1), Inches(y_pos), Inches(6.9), Inches(0.45),
|
||||||
|
size=15, color=BODY_CLR)
|
||||||
|
|
||||||
|
# Oracle expertise
|
||||||
|
txb(s, "Oracle Database von Version 6 bis Oracle AI Database 26ai",
|
||||||
|
Inches(4.3), Inches(4.78), Inches(8.7), Inches(0.4),
|
||||||
|
size=16, bold=True, color=ACCENT_ORA)
|
||||||
|
txb(s, "Schulungen · Workshops · Vorträge · Projekte",
|
||||||
|
Inches(4.3), Inches(5.22), Inches(8.7), Inches(0.4),
|
||||||
|
size=15, color=BODY_CLR)
|
||||||
|
|
||||||
|
# Books
|
||||||
|
txb(s, "Co-Autor:",
|
||||||
|
Inches(4.3), Inches(5.7), Inches(1.3), Inches(0.35),
|
||||||
|
size=13, bold=True, color=DIM_CLR)
|
||||||
|
txb(s, "Oracle 7.3 · Oracle8 für den DBA · Oracle 9i für den DBA · Oracle 10g für den DBA · Oracle 11g R2 für den DBA",
|
||||||
|
Inches(5.65), Inches(5.7), Inches(7.35), Inches(0.35),
|
||||||
|
size=13, color=DIM_CLR, italic=True)
|
||||||
|
|
||||||
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
|
# Slide 3 — Motivation: Der VECTOR-Datentyp
|
||||||
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
|
s = add_slide()
|
||||||
|
section_header(s, "Der VECTOR-Datentyp", ACCENT_PG)
|
||||||
|
bullet_box(s, [
|
||||||
|
"▸ VECTOR ist ein neuer nativer Datentyp in Oracle AI Database 26ai und PostgreSQL (pgvector)",
|
||||||
|
"▸ Ermöglicht das Speichern hochdimensionaler Vektoren direkt in der Datenbank",
|
||||||
|
"▸ Bringt optimierte Suchoperatoren und Indizes für Ähnlichkeitssuche (k-NN) mit",
|
||||||
|
"▸ Macht KI-Embeddings zu einem First-Class-Citizen in relationalen Datenbanken",
|
||||||
|
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(2.2), size=22)
|
||||||
|
|
||||||
|
divider(s, Inches(3.7))
|
||||||
|
|
||||||
|
txb(s, "Ziel dieses Vortrags", Inches(0.8), Inches(3.85), Inches(11.5), Inches(0.5),
|
||||||
|
size=22, bold=True, color=ACCENT_PG)
|
||||||
|
bullet_box(s, [
|
||||||
|
"▸ Den VECTOR-Datentyp erklären — was er ist, wie er funktioniert",
|
||||||
|
"▸ Gemeinsamkeiten und Unterschiede zwischen Oracle 26ai und PostgreSQL/pgvector zeigen",
|
||||||
|
"▸ Eine konkrete Demo: semantische Bildsuche mit 116 Street-Fotos",
|
||||||
|
"▸ Drei Ansätze vergleichen: pgvector, Oracle (Python-Embedding), Oracle (In-Database-Embedding)",
|
||||||
|
], Inches(0.8), Inches(4.4), Inches(11.5), Inches(2.3), size=20)
|
||||||
|
|
||||||
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
|
# Slide 3 — Agenda
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
s = add_slide()
|
s = add_slide()
|
||||||
section_header(s, "Agenda", ACCENT_PG)
|
section_header(s, "Agenda", ACCENT_PG)
|
||||||
@@ -483,8 +599,8 @@ bullet_box(s, [
|
|||||||
s.shapes.add_picture(DIAG_S3, Inches(7.8), Inches(1.1), Inches(5.3), Inches(5.3))
|
s.shapes.add_picture(DIAG_S3, Inches(7.8), Inches(1.1), Inches(5.3), Inches(5.3))
|
||||||
|
|
||||||
txb(s, "Vektoren machen Ähnlichkeit berechenbar.",
|
txb(s, "Vektoren machen Ähnlichkeit berechenbar.",
|
||||||
Inches(0.8), Inches(5.8), Inches(6.8), Inches(0.7),
|
Inches(0.3), Inches(5.75), Inches(7.4), Inches(0.8),
|
||||||
size=22, bold=True, color=ACCENT_GRN)
|
size=26, bold=True, color=ACCENT_GRN)
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
# Slide 4 — Semantische Suche
|
# Slide 4 — Semantische Suche
|
||||||
@@ -531,6 +647,10 @@ txb(s, "Bild-Vektor und Text-Vektor zeigen in dieselbe Richtung,\nwenn Bild und
|
|||||||
Inches(0.8), Inches(5.0), Inches(11.5), Inches(1.0),
|
Inches(0.8), Inches(5.0), Inches(11.5), Inches(1.0),
|
||||||
size=18, italic=True, color=ACCENT_IDB)
|
size=18, italic=True, color=ACCENT_IDB)
|
||||||
|
|
||||||
|
txb(s, "🔗 huggingface.co/sentence-transformers/clip-ViT-B-32 — wird beim ersten Start automatisch heruntergeladen (~600 MB)",
|
||||||
|
Inches(0.8), Inches(6.55), Inches(12.0), Inches(0.35),
|
||||||
|
size=11, color=DIM_CLR, italic=True)
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
# Slide 6 — Cosinus-Distanz
|
# Slide 6 — Cosinus-Distanz
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
@@ -696,11 +816,11 @@ bullet_box(s, [
|
|||||||
"▸ Der Text-String ist der einzige Parameter aus Python",
|
"▸ Der Text-String ist der einzige Parameter aus Python",
|
||||||
"▸ Schema: VECTOR — Tabelle: FOTO_VEKTOR — Bilder als BLOB gespeichert",
|
"▸ Schema: VECTOR — Tabelle: FOTO_VEKTOR — Bilder als BLOB gespeichert",
|
||||||
"▸ HNSW-Index auf FOTO_VEKTOR (wie in Schema VECTORS_USER)",
|
"▸ HNSW-Index auf FOTO_VEKTOR (wie in Schema VECTORS_USER)",
|
||||||
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(3.0), size=19)
|
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(2.4), size=16)
|
||||||
|
|
||||||
code_box(s,
|
code_box(s,
|
||||||
"-- Gesamte Logik in einem SQL-Statement\nSELECT filename,\n 1 - VECTOR_DISTANCE(\n foto_vek,\n VECTOR_EMBEDDING(CLIP_TXT USING :q AS data),\n COSINE\n ) AS score\nFROM VECTOR.FOTO_VEKTOR\nORDER BY VECTOR_DISTANCE(\n foto_vek,\n VECTOR_EMBEDDING(CLIP_TXT USING :q AS data), COSINE)\nFETCH FIRST 12 ROWS ONLY;",
|
"-- Gesamte Logik in einem SQL-Statement\nSELECT filename,\n 1 - VECTOR_DISTANCE(\n foto_vek,\n VECTOR_EMBEDDING(CLIP_TXT USING :q AS data),\n COSINE\n ) AS score\nFROM VECTOR.FOTO_VEKTOR\nORDER BY VECTOR_DISTANCE(\n foto_vek,\n VECTOR_EMBEDDING(CLIP_TXT USING :q AS data), COSINE)\nFETCH FIRST 12 ROWS ONLY;",
|
||||||
Inches(0.8), Inches(3.6), Inches(7.5), Inches(3.3), size=13)
|
Inches(0.8), Inches(3.8), Inches(7.5), Inches(3.0), size=11)
|
||||||
|
|
||||||
bullet_box(s, [
|
bullet_box(s, [
|
||||||
":q = reiner Text aus Python",
|
":q = reiner Text aus Python",
|
||||||
@@ -711,7 +831,7 @@ bullet_box(s, [
|
|||||||
" • Vektorsuche",
|
" • Vektorsuche",
|
||||||
"",
|
"",
|
||||||
"→ Architektur vereinfacht sich",
|
"→ Architektur vereinfacht sich",
|
||||||
], Inches(9.0), Inches(3.6), Inches(4.0), Inches(3.4), size=18, color=DIM_CLR)
|
], Inches(9.0), Inches(3.8), Inches(4.0), Inches(3.0), size=16, color=DIM_CLR)
|
||||||
|
|
||||||
# ════════════════════════════════════════════════════════════════════════════
|
# ════════════════════════════════════════════════════════════════════════════
|
||||||
# Slide 12 — ONNX in Oracle: Besonderheit
|
# Slide 12 — ONNX in Oracle: Besonderheit
|
||||||
@@ -809,7 +929,9 @@ bullet_box(s, [
|
|||||||
"▸ Oracle In-DB Embedding: Architektur ohne ML-Laufzeit im App-Server",
|
"▸ Oracle In-DB Embedding: Architektur ohne ML-Laufzeit im App-Server",
|
||||||
"▸ CLIP ermöglicht Bildersuche per Freitext — ohne Tagging oder Metadaten",
|
"▸ CLIP ermöglicht Bildersuche per Freitext — ohne Tagging oder Metadaten",
|
||||||
"▸ HNSW liefert schnelle approximative k-NN-Suche in beiden Datenbanken",
|
"▸ HNSW liefert schnelle approximative k-NN-Suche in beiden Datenbanken",
|
||||||
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(3.5), size=21)
|
"▸ VECTOR ist eine sehr willkommene Erweiterung — relationale Datenbanken",
|
||||||
|
" nutzen damit KI-Embeddings als First-Class-Citizen",
|
||||||
|
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(4.2), size=21)
|
||||||
|
|
||||||
divider(s, Inches(5.1))
|
divider(s, Inches(5.1))
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ _model = None
|
|||||||
def _get_model():
|
def _get_model():
|
||||||
# Lazy load: the CLIP model is ~600 MB and takes several seconds to initialise.
|
# Lazy load: the CLIP model is ~600 MB and takes several seconds to initialise.
|
||||||
# Loading on first call avoids the cost at import time and during indexing warmup.
|
# Loading on first call avoids the cost at import time and during indexing warmup.
|
||||||
|
# Downloaded automatically from Hugging Face Hub on first use:
|
||||||
|
# https://huggingface.co/sentence-transformers/clip-ViT-B-32
|
||||||
|
# Cached in ~/.cache/huggingface/hub/
|
||||||
global _model
|
global _model
|
||||||
if _model is None:
|
if _model is None:
|
||||||
_model = SentenceTransformer("clip-ViT-B-32")
|
_model = SentenceTransformer("clip-ViT-B-32")
|
||||||
|
|||||||
@@ -147,18 +147,18 @@
|
|||||||
|
|
||||||
<div class="search-area">
|
<div class="search-area">
|
||||||
<div class="search-row">
|
<div class="search-row">
|
||||||
<input id="query" type="text" placeholder="Search photos, e.g. trees, water, night…" />
|
<input id="query" type="text" placeholder="Fotos suchen, z.B. Bäume, Wasser, Nacht…" />
|
||||||
<button class="search-btn" onclick="doSearch()">Search</button>
|
<button class="search-btn" onclick="doSearch()">Suchen</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="chips">
|
<div class="chips">
|
||||||
<span class="chip" onclick="setQuery('trees')">trees</span>
|
<span class="chip" onclick="setQuery('Bäume')">Bäume</span>
|
||||||
<span class="chip" onclick="setQuery('water')">water</span>
|
<span class="chip" onclick="setQuery('Wasser')">Wasser</span>
|
||||||
<span class="chip" onclick="setQuery('people')">people</span>
|
<span class="chip" onclick="setQuery('Menschen')">Menschen</span>
|
||||||
<span class="chip" onclick="setQuery('buildings')">buildings</span>
|
<span class="chip" onclick="setQuery('Gebäude')">Gebäude</span>
|
||||||
<span class="chip" onclick="setQuery('sky')">sky</span>
|
<span class="chip" onclick="setQuery('Himmel')">Himmel</span>
|
||||||
<span class="chip" onclick="setQuery('street')">street</span>
|
<span class="chip" onclick="setQuery('Straße')">Straße</span>
|
||||||
<span class="chip" onclick="setQuery('night')">night</span>
|
<span class="chip" onclick="setQuery('Nacht')">Nacht</span>
|
||||||
<span class="chip" onclick="setQuery('cars')">cars</span>
|
<span class="chip" onclick="setQuery('Autos')">Autos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -147,18 +147,18 @@
|
|||||||
|
|
||||||
<div class="search-area">
|
<div class="search-area">
|
||||||
<div class="search-row">
|
<div class="search-row">
|
||||||
<input id="query" type="text" placeholder="Search photos, e.g. trees, water, night…" />
|
<input id="query" type="text" placeholder="Fotos suchen, z.B. Bäume, Wasser, Nacht…" />
|
||||||
<button class="search-btn" onclick="doSearch()">Search</button>
|
<button class="search-btn" onclick="doSearch()">Suchen</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="chips">
|
<div class="chips">
|
||||||
<span class="chip" onclick="setQuery('trees')">trees</span>
|
<span class="chip" onclick="setQuery('Bäume')">Bäume</span>
|
||||||
<span class="chip" onclick="setQuery('water')">water</span>
|
<span class="chip" onclick="setQuery('Wasser')">Wasser</span>
|
||||||
<span class="chip" onclick="setQuery('people')">people</span>
|
<span class="chip" onclick="setQuery('Menschen')">Menschen</span>
|
||||||
<span class="chip" onclick="setQuery('buildings')">buildings</span>
|
<span class="chip" onclick="setQuery('Gebäude')">Gebäude</span>
|
||||||
<span class="chip" onclick="setQuery('sky')">sky</span>
|
<span class="chip" onclick="setQuery('Himmel')">Himmel</span>
|
||||||
<span class="chip" onclick="setQuery('street')">street</span>
|
<span class="chip" onclick="setQuery('Straße')">Straße</span>
|
||||||
<span class="chip" onclick="setQuery('night')">night</span>
|
<span class="chip" onclick="setQuery('Nacht')">Nacht</span>
|
||||||
<span class="chip" onclick="setQuery('cars')">cars</span>
|
<span class="chip" onclick="setQuery('Autos')">Autos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ _model = None
|
|||||||
def _get_model():
|
def _get_model():
|
||||||
# Lazy load: the CLIP model is ~600 MB and takes several seconds to initialise.
|
# Lazy load: the CLIP model is ~600 MB and takes several seconds to initialise.
|
||||||
# Loading on first call avoids the cost at import time and during indexing warmup.
|
# Loading on first call avoids the cost at import time and during indexing warmup.
|
||||||
|
# Downloaded automatically from Hugging Face Hub on first use:
|
||||||
|
# https://huggingface.co/sentence-transformers/clip-ViT-B-32
|
||||||
|
# Cached in ~/.cache/huggingface/hub/
|
||||||
global _model
|
global _model
|
||||||
if _model is None:
|
if _model is None:
|
||||||
_model = SentenceTransformer("clip-ViT-B-32")
|
_model = SentenceTransformer("clip-ViT-B-32")
|
||||||
|
|||||||
@@ -147,18 +147,18 @@
|
|||||||
|
|
||||||
<div class="search-area">
|
<div class="search-area">
|
||||||
<div class="search-row">
|
<div class="search-row">
|
||||||
<input id="query" type="text" placeholder="Search photos, e.g. trees, water, night…" />
|
<input id="query" type="text" placeholder="Fotos suchen, z.B. Bäume, Wasser, Nacht…" />
|
||||||
<button class="search-btn" onclick="doSearch()">Search</button>
|
<button class="search-btn" onclick="doSearch()">Suchen</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="chips">
|
<div class="chips">
|
||||||
<span class="chip" onclick="setQuery('trees')">trees</span>
|
<span class="chip" onclick="setQuery('Bäume')">Bäume</span>
|
||||||
<span class="chip" onclick="setQuery('water')">water</span>
|
<span class="chip" onclick="setQuery('Wasser')">Wasser</span>
|
||||||
<span class="chip" onclick="setQuery('people')">people</span>
|
<span class="chip" onclick="setQuery('Menschen')">Menschen</span>
|
||||||
<span class="chip" onclick="setQuery('buildings')">buildings</span>
|
<span class="chip" onclick="setQuery('Gebäude')">Gebäude</span>
|
||||||
<span class="chip" onclick="setQuery('sky')">sky</span>
|
<span class="chip" onclick="setQuery('Himmel')">Himmel</span>
|
||||||
<span class="chip" onclick="setQuery('street')">street</span>
|
<span class="chip" onclick="setQuery('Straße')">Straße</span>
|
||||||
<span class="chip" onclick="setQuery('night')">night</span>
|
<span class="chip" onclick="setQuery('Nacht')">Nacht</span>
|
||||||
<span class="chip" onclick="setQuery('cars')">cars</span>
|
<span class="chip" onclick="setQuery('Autos')">Autos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user