Files
neonail-database/resources/views/nail-polish-imports/index.blade.php
T
HousemannandClaude Sonnet 4.6 f715bc4552 Add AI photo import via Ollama Vision
Users can upload a photo of a nail polish bottle; a background queue
job sends it to Ollama (llama3.2-vision at 192.168.30.172:11434),
extracts name, number and manufacturer, then creates the nail polish
and adds it to the user's collection automatically.

- ProcessNailPolishImage job (180s timeout, 2 tries)
- NailPolishImport model + migration (status tracking)
- AiSetting model + migration (Ollama URL + model, admin-configurable)
- NailPolishImportController: upload, status page (auto-refresh every 5s)
- Admin\AiSettingController: configure Ollama connection
- Views: drag-drop upload form, live status page, import history
- Navbar: "Foto importieren" link for all users
- Admin dropdown: "KI-Einstellungen"
- neonail-worker.conf: Supervisor config for the queue worker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 17:37:26 +02:00

84 lines
3.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('layouts.app')
@section('title', 'Meine Importe NeoNail DB')
@section('content')
<div class="page-hero d-flex align-items-center justify-content-between flex-wrap gap-3 mb-4">
<div>
<h1><i class="fas fa-history me-2"></i>Meine Importe</h1>
<p>KI-Analysen deiner hochgeladenen Fotos</p>
</div>
<a href="{{ route('nail-polish-imports.create') }}" class="btn btn-glass">
<i class="fas fa-camera me-2"></i>Neues Foto
</a>
</div>
@if($imports->isEmpty())
<div class="empty-state">
<div class="empty-icon"><i class="fas fa-camera"></i></div>
<h4>Noch keine Importe</h4>
<p>Lade ein Foto hoch und lass die KI deinen Nagellack erkennen.</p>
<a href="{{ route('nail-polish-imports.create') }}" class="btn btn-primary">
<i class="fas fa-camera me-2"></i>Jetzt importieren
</a>
</div>
@else
<div class="card">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table mb-0" style="font-size:.875rem;">
<thead style="background:#f9fafb; border-bottom:1px solid #f3f4f6;">
<tr>
<th style="padding:12px 16px; font-weight:600; color:#374151;">Bild</th>
<th style="padding:12px 16px; font-weight:600; color:#374151;">Ergebnis</th>
<th style="padding:12px 16px; font-weight:600; color:#374151;">Status</th>
<th style="padding:12px 16px; font-weight:600; color:#374151;">Datum</th>
<th style="padding:12px 16px;"></th>
</tr>
</thead>
<tbody>
@foreach($imports as $import)
<tr style="border-bottom:1px solid #f3f4f6;">
<td style="padding:12px 16px;">
<img src="{{ Storage::url($import->image_path) }}"
alt=""
style="width:52px; height:52px; object-fit:cover; border-radius:10px;">
</td>
<td style="padding:12px 16px;">
@if($import->result)
<div style="font-weight:600; color:#111827;">{{ $import->result['name'] ?? '—' }}</div>
<div style="color:#9ca3af; font-size:.78rem;">{{ $import->result['manufacturer'] ?? '' }}</div>
@elseif($import->status === 'failed')
<span style="color:#dc2626; font-size:.8rem;">{{ Str::limit($import->error_message, 60) }}</span>
@else
<span style="color:#9ca3af;">wird analysiert…</span>
@endif
</td>
<td style="padding:12px 16px;">
<span class="badge bg-{{ $import->statusColor() }}">{{ $import->statusLabel() }}</span>
</td>
<td style="padding:12px 16px; color:#9ca3af;">
{{ $import->created_at->format('d.m.Y H:i') }}
</td>
<td style="padding:12px 16px; text-align:right;">
<a href="{{ route('nail-polish-imports.show', $import) }}"
class="btn btn-outline-secondary btn-sm">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
<div class="mt-3">
{{ $imports->links() }}
</div>
@endif
@endsection