尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證AI photo sharing
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Event photos, found by face. Photographers upload an event once. Guests take a selfie and get back only the photos they're in.
For guests
For photographers and event owners
Accounts
Browser ── presigned PUT ──▶ S3 events/{event_id}/originals/{photo_id}.ext
│
└─ POST /photos/upload-complete ─▶ photo row (status = pending)
│
background photo worker
│
┌───────────────────────────┼────────────────────────────┐
▼ ▼ ▼
read dimensions make thumbnail + preview Rekognition IndexFaces
(Pillow) ─▶ S3 (thumbnails/) (event's own collection)
│
▼
faces rows written, photo marked processed
PHOTO_WORKER_CONCURRENCY, REKOGNITION_MAX_TPS).cron_worker.py runs once on container start and resets photos or guests left stuck by an interrupted run.Guest selfie ─▶ Rekognition SearchFacesByImage (event collection)
─▶ matched photo ids, de-duplicated, best match first
─▶ guest record updated
─▶ gallery rendered with presigned S3 URLs
Each event gets its own Rekognition collection, so guests can only ever match inside the event they opened.
| Layer | Technology |
|---|---|
| Backend | Python 3.12, FastAPI, Uvicorn |
| Frontend | Next.js 16, React 19, Tailwind CSS v4, shadcn/ui |
| Database | SQLite via aiosqlite |
| Face recognition | AWS Rekognition |
| File storage | AWS S3 |
| Auth | JWT, bcrypt, optional Google OAuth 2.0 |
| Any SMTP server (printed to the console if none is set) | |
| Packaging | Docker and Docker Compose; pip (backend), bun (frontend) |
| Need | Why |
|---|---|
| Docker and Docker Compose | Runs the whole stack |
| An AWS account, an S3 bucket, and an IAM user | Photo storage and face matching |
| Python 3.12+ and Bun 1.3+ | Only for local development |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET_NAME",
"arn:aws:s3:::YOUR_BUCKET_NAME/*"
]
},
{
"Effect": "Allow",
"Action": [
"rekognition:CreateCollection",
"rekognition:DeleteCollection",
"rekognition:IndexFaces",
"rekognition:SearchFacesByImage",
"rekognition:ListCollections"
],
"Resource": "*"
}
]
}
Browsers upload straight to S3, so the bucket also needs a CORS rule for your frontend's origin. backend/set_s3_cors.py sets one up.
backend/.envAt minimum:
SECRET_KEY=<32+ random characters>
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
S3_BUCKET_NAME=your-bucket
Generate a key with:
python -c "import secrets; print(secrets.token_hex(32))"
Everything else has a default. See Configuration.
docker-compose up -d
| Service | Container | URL |
|---|---|---|
| Frontend | pixello-frontend | http://localhost:3005 |
| Backend API | pixello-backend | http://localhost:8000 |
| Interactive API docs | http://localhost:8000/docs |
The data/ folder is mounted into the backend container, so the SQLite database and staging files survive restarts.
SMTP_HOST set, the confirmation link is printed in the backend logs (docker logs pixello-backend).All backend settings are environment variables, read from backend/.env. Defaults are in backend/app/core/config.py.
| Variable | Description | Default |
|---|---|---|
SECRET_KEY | Required, 32+ characters. Signs JWTs. Changing it logs everyone out and invalidates client selection sessions. | none (app won't start) |
ALGORITHM | JWT algorithm | HS256 |
ACCESS_TOKEN_EXPIRE_MINUTES | Login token lifetime | 1440 |
FRONTEND_URL | Used for links in emails and for the CORS origin | http://localhost:3000 |
| Variable | Description | Default |
|---|---|---|
SMTP_HOST | Mail server. Empty means emails are printed to the backend console (fine locally, not for real users). | empty |
SMTP_PORT | Mail server port | 587 |
SMTP_USERNAME / SMTP_PASSWORD | Mail login, if the server needs one | empty |
SMTP_USE_SSL | true = TLS from the start (usually port 465); false = STARTTLS | false |
EMAIL_FROM | Sender shown on emails | Pixello <no-reply@localhost> |
EMAIL_VERIFY_EXPIRE_HOURS | How long the confirmation link works | 24 |
PASSWORD_RESET_EXPIRE_MINUTES | How long the reset link works | 60 |
| Variable | Description | Default |
|---|---|---|
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | From Google Cloud Console → APIs & Services → Credentials → OAuth client ID → Web application. Empty hides the button. | empty |
GOOGLE_REDIRECT_URI | The API's /auth/google/callback as the browser reaches it (behind the frontend proxy: https://your-site/api/auth/google/callback). Add the same URL under Authorized redirect URIs. | http://localhost:8000/auth/google/callback |
| Variable | Description | Default |
|---|---|---|
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | IAM credentials | required |
AWS_REGION | Region for S3 and Rekognition | us-east-1 |
S3_BUCKET_NAME | Bucket for photos and thumbnails | required |
REKOGNITION_FACE_MATCH_THRESHOLD | Minimum match confidence, 0–100 | 80.0 |
REKOGNITION_MAX_TPS | Max IndexFaces calls per second. AWS's default quota is 50 in us-east-1, us-west-2 and eu-west-1, and 5 elsewhere. | 5 |
PHOTO_WORKER_CONCURRENCY | Photos processed at once. Each decodes a full-size image, so keep it low on a laptop. | 4 |
| Variable | Description | Default |
|---|---|---|
PAYMENT_REQUIRED | If false, owners can skip checkout (dev only) | false |
PAYMENT_PROVIDER | Only mock (simulated checkout) exists today | mock |
PAYMENT_CURRENCY | Currency code | usd |
PRICE_PER_GB_CENTS | Price per GB of event storage, in cents | 100 |
PRICE_FACE_SCAN_CENTS / PRICE_SELECTION_CENTS | Flat per-event add-on, in cents. 0 = included. | 0 / 0 |
MIN_STORAGE_GB / MAX_STORAGE_GB | Allowed storage when creating an event | 1 / 1000 |
| Variable | Description | Default |
|---|---|---|
DB_PATH | SQLite file | data/app.db |
UPLOAD_ROOT | Local staging for originals | data/uploads/originals |
THUMBNAIL_ROOT | Local staging for thumbnails | data/thumbnails |
GUEST_SELFIES_DIR | Guest selfies | data/uploads/selfies |
INGEST_QUEUE_URL, LIVE_POLL_SECONDS, LIVE_SAFETY_SCAN_SECONDS | Live-mode settings (see limits) | empty / 15 / 300 |
The frontend reads one variable, NEXT_PUBLIC_API_URL. In Docker it is /api (a proxy to the backend). For local development set it to http://localhost:8000.
cd backend
python -m venv venv
.\venv\Scripts\activate # Windows
# source venv/bin/activate # macOS / Linux
pip install -r requirements.txt
uvicorn app.main:app --reload
The API runs at http://localhost:8000. To run the stuck-record recovery pass by hand:
python cron_worker.py
reset_app.py wipes the local database and data folders. It is a development utility, so use it carefully.
cd frontend
bun install
echo NEXT_PUBLIC_API_URL=http://localhost:8000 > .env.local
bun run dev
The app runs at http://localhost:3000, matching the default FRONTEND_URL.
PICSHARE/
├── backend/
│ ├── app/
│ │ ├── api/
│ │ │ ├── auth.py # register, login, verify email, password reset
│ │ │ ├── oauth.py # Sign in with Google
│ │ │ ├── events.py # event CRUD, public listing, storage stats
│ │ │ ├── photos.py # presigned uploads, status, gallery, delete, download
│ │ │ ├── guests.py # selfie requests, matches, ZIP download
│ │ │ ├── selection.py # client photo-selection links and picks
│ │ │ └── payments.py # checkout, confirm, skip
│ │ ├── core/config.py # settings (reads .env)
│ │ ├── services/
│ │ │ ├── db.py # SQLite connection, schema, migrations
│ │ │ ├── photo_worker.py # background processing queue
│ │ │ ├── rekognition_service.py # collections, IndexFaces, SearchFaces
│ │ │ ├── s3_service.py # presigned URLs, delete, storage size
│ │ │ ├── thumbnail_service.py # thumbnails and previews
│ │ │ ├── email_service.py # SMTP or console output
│ │ │ ├── payment_service.py # payment provider hook (mock)
│ │ │ ├── live_ingest.py # FTP/SFTP live mode (switched off)
│ │ │ └── recovery.py # reset stuck photos and guests
│ │ └── main.py # app, CORS, routers, worker lifecycle
│ ├── cron_worker.py # one-shot recovery on container start
│ ├── set_s3_cors.py # configure bucket CORS for browser uploads
│ ├── setup_live_ingest.py # SQS setup for live mode
│ └── Dockerfile
├── frontend/
│ └── src/
│ ├── app/ # App Router pages
│ │ ├── dashboard/ # events, new event, payment, event detail
│ │ ├── event/[slug]/ # guest portal and gallery
│ │ ├── select/[token] # client photo selection
│ │ ├── login, register, forgot-password, reset-password, verify-email, oauth/
│ │ └── events/ # public event listing
│ ├── components/ # UI, dashboard, auth and gallery components
│ └── lib/ # API client, upload engine and worker, QR card, auth hook
├── docker-compose.yml
├── CONTRIBUTING.md
└── SECURITY.md
Full, interactive docs are at /docs on the running backend.
| Prefix | Purpose |
|---|---|
/auth | Register, login, email verification, password reset, /me, Google sign-in |
/events | Event CRUD, public listing and lookup, secret-code check, storage usage |
/photos | Upload URLs and completion, status, gallery, retry, delete (single and bulk), original, thumbnail and download URLs |
/guests | Selfie request, status polling, matches, ZIP download, delete |
/selection | Owner side: create and manage client selection links, export picks |
/select | Client side: enter code, browse previews, pick, submit |
/payments | Pricing config, checkout, confirm, skip |
SQLite, created automatically on first start at DB_PATH. New columns are added by small startup migrations in backend/app/services/db.py.
| Table | Holds |
|---|---|
users, auth_tokens, oauth_identities | Accounts, email and reset tokens, linked Google identities |
events | Event details, owner, plan, storage, payment status, optional secret code |
photos | S3 keys, dimensions, face count, processing status, retries |
faces | Rekognition face id per detected face |
guests | Guest requests, selfie path, match results |
selection_links, selections | Client selection links and the photos each client picked |
mock provider exists. A real gateway (for example Stripe) plugs into app/services/payment_service.py.main.py until it is finished.The full list of what's done, in progress and still to do is in CHANGELOG.md.