6 Commits

Author SHA1 Message Date
dierk 5a8985440e Presentation polish: logo aspect ratio, German consistency, contact details
- Fix logo aspect ratio (4.458:1) on title slide and all footer instances
- Speaker slide: simplify 2026 career entry
- Last slide: add website www.dl-cons.de alongside email
- CLIP slide: mention larger model variants (ViT-L-14, ~1.7 GB) for higher precision
- Slide 6: replace 'trees' with 'Bäume' for consistency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 15:18:08 +02:00
dierk bad32d5966 Add speaker intro slide with photo, career timeline, and company info
Slide 2: Dierk Lenz — photo (correct 2:3 ratio), career timeline 1983–2026,
Oracle expertise, co-authored books. No footer, logo top-right.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 14:49:19 +02:00
dierk 3d375161bd Change Search button label to Suchen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:14:57 +02:00
dierk 7f08813635 Switch frontend search chips and placeholder to German
Matches the German search words shown on the demo slide in the presentation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:12:10 +02:00
dierk 978c70e91a Add HuggingFace URL note to CLIP slide
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:07:11 +02:00
dierk 4a82352391 Document CLIP model source in embedder.py and README
Model downloads automatically from HuggingFace Hub on first use.
No manual download required.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 12:04:10 +02:00
8 changed files with 113 additions and 35 deletions
+9
View File
@@ -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.
+68 -5
View File
@@ -338,7 +338,7 @@ def add_slide(logo=True, footer=True):
fill.fore_color.rgb = BG fill.fore_color.rgb = BG
if logo: if logo:
slide.shapes.add_picture(LOGO_PATH, slide.shapes.add_picture(LOGO_PATH,
Inches(11.6), Inches(7.0), Inches(1.6), Inches(0.42)) Inches(11.6), Inches(7.03), Inches(1.6), Inches(0.36))
if footer: if footer:
_slide_num[0] += 1 _slide_num[0] += 1
# thin separator line # thin separator line
@@ -484,10 +484,65 @@ txb(s, f"{EVENT_DATE} · {EVENT_CITY}",
Inches(1), Inches(5.5), Inches(11.33), Inches(0.45), Inches(1), Inches(5.5), Inches(11.33), Inches(0.45),
size=18, color=DIM_CLR, align=PP_ALIGN.CENTER) size=18, color=DIM_CLR, align=PP_ALIGN.CENTER)
# Larger centred logo # Larger centred logo
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.2), Inches(4.0), Inches(0.90))
# ════════════════════════════════════════════════════════════════════════════ # ════════════════════════════════════════════════════════════════════════════
# Slide 2 — Motivation: Der VECTOR-Datentyp # 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ündung 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() s = add_slide()
section_header(s, "Der VECTOR-Datentyp", ACCENT_PG) section_header(s, "Der VECTOR-Datentyp", ACCENT_PG)
@@ -553,9 +608,9 @@ txb(s, "Vektoren machen Ähnlichkeit berechenbar.",
s = add_slide() s = add_slide()
section_header(s, "Semantische Suche — jenseits von Schlüsselwörtern", ACCENT_PG) section_header(s, "Semantische Suche — jenseits von Schlüsselwörtern", ACCENT_PG)
bullet_box(s, [ bullet_box(s, [
"Klassische Suche: \"trees\" findet nur Dokumente mit dem Wort \"trees\"", "Klassische Suche: \"Bäume\" findet nur Dokumente mit dem Wort \"Bäume\"",
"", "",
"Semantische Suche: \"trees\" findet Bilder von Wäldern, Parks, Natur —", "Semantische Suche: \"Bäume\" findet Bilder von Wäldern, Parks, Natur —",
" ohne dass das Wort irgendwo steht", " ohne dass das Wort irgendwo steht",
], Inches(0.8), Inches(1.3), Inches(11.5), Inches(2.2), size=20) ], Inches(0.8), Inches(1.3), Inches(11.5), Inches(2.2), size=20)
@@ -592,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 — ~600 MB, automatischer Download beim ersten Start · Größere Varianten (ViT-L-14, ~1,7 GB) liefern höhere Präzision",
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
# ════════════════════════════════════════════════════════════════════════════ # ════════════════════════════════════════════════════════════════════════════
@@ -883,6 +942,10 @@ txb(s, "https://gitea.dl-cons.de/dierk/vector-search-demo",
Inches(0.8), Inches(5.7), Inches(11), Inches(0.5), Inches(0.8), Inches(5.7), Inches(11), Inches(0.5),
size=20, color=ACCENT_PG) size=20, color=ACCENT_PG)
txb(s, "dierk.lenz@dl-cons.de · www.dl-cons.de",
Inches(0.8), Inches(6.2), Inches(11), Inches(0.4),
size=18, color=BODY_CLR)
txb(s, "Programmierung und Folien unterstützt durch Claude (Anthropic)", txb(s, "Programmierung und Folien unterstützt durch Claude (Anthropic)",
Inches(0.8), Inches(6.55), Inches(11.33), Inches(0.35), Inches(0.8), Inches(6.55), Inches(11.33), Inches(0.35),
size=13, italic=True, color=DIM_CLR, align=PP_ALIGN.CENTER) size=13, italic=True, color=DIM_CLR, align=PP_ALIGN.CENTER)
+3
View File
@@ -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")
+10 -10
View File
@@ -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>
+10 -10
View File
@@ -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>
+3
View File
@@ -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")
+10 -10
View File
@@ -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>