Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions restaurant-comparison-tool/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_MINO_API_KEY=sk-mino-YOUR_API_KEY_HERE
27 changes: 27 additions & 0 deletions restaurant-comparison-tool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local
.env

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

.vercel
115 changes: 115 additions & 0 deletions restaurant-comparison-tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# SafeDine

**Live:** [https://restaurant-comparison-tool.vercel.app](https://restaurant-comparison-tool.vercel.app)

SafeDine is a pre-visit restaurant safety intelligence tool that compares 2–5 restaurants before dining by analyzing Google Maps reviews, menu photos, and allergen signals. It uses the TinyFish API to dispatch parallel web agents — one per restaurant — that each navigate Google Maps, read 8–12 reviews, check menu images, and return a structured safety report with scores, allergen risks, and dietary suitability ratings.

## Demo

https://github.com/user-attachments/assets/c684dac5-5e89-43fe-9592-0665a31513f6


## TinyFish API Usage

The app calls the TinyFish SSE endpoint once per restaurant, in parallel. Each agent navigates Google Maps, samples reviews for safety signals, checks menu photos for allergen labeling, and returns a structured JSON report:

```typescript
const response = await fetch("https://agent.tinyfish.ai/v1/automation/run-sse", {
method: "POST",
headers: {
"X-API-Key": import.meta.env.VITE_MINO_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://www.google.com/maps",
goal: `You are a fast food-safety research agent. Investigate "${restaurantName}" in ${city}.
Stay ONLY on Google Maps — do NOT visit external websites.

STEP 1 — FIND THE RESTAURANT on Google Maps:
Search "${restaurantName} ${city}". Confirm the correct listing.

STEP 2 — SAMPLE REVIEWS (keep it fast):
Open the Reviews tab. Read 8–12 recent reviews. Prioritize mentions of:
- Food poisoning, allergic reactions, cross-contamination
- Hygiene, cleanliness, staff responsiveness
Focus on user allergens: ${allergenList}

STEP 3 — CHECK MENU IMAGES (if available on Maps):
Look at the Menu tab or Photos section (3–4 images max).

STEP 4 — RETURN RESULTS as JSON:
{ "restaurantName": "...", "overallSafetyScore": 75,
"allergenRisks": [...], "safetySignals": [...], ... }`,
}),
});
```

The response streams SSE events including a `streamingUrl` (live view of the agent navigating Google Maps) and a final `COMPLETE` event with the extracted safety data JSON.

## How to Run

### Prerequisites

- Node.js 18+
- A TinyFish API key ([get one here](https://agent.tinyfish.ai))

### Setup

1. Install dependencies:

```bash
cd restaurant-comparison-tool
npm install
```

2. Create a `.env` file with your TinyFish API key:

```
VITE_MINO_API_KEY=your_tinyfish_api_key_here
```

3. Start the dev server:

```bash
npm run dev
```

4. Open [http://localhost:5173](http://localhost:5173)

## Architecture Diagram

```
┌──────────────────────────────────────────────────────────────┐
│ User (Browser) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ React + Vite Frontend (Tailwind + shadcn + Framer) │ │
│ │ │ │
│ │ 1. Enter city + 2–5 restaurant names │ │
│ │ 2. Select allergens & dietary preferences │ │
│ │ 3. Click "Compare Restaurants" │ │
│ │ 4. Watch live browser previews as agents research │ │
│ │ 5. View ranked safety cards + detail panel │ │
│ └────────────────────┬───────────────────────────────────┘ │
└───────────────────────┼──────────────────────────────────────┘
│ POST /v1/automation/run-sse (x N restaurants, parallel)
┌──────────────────────────────────────────────────────────────┐
│ TinyFish API (agent.tinyfish.ai) │
│ │
│ Receives goal prompt + Google Maps URL per restaurant │
│ Spins up a web agent for each request │
│ │
│ SSE Stream Events: │
│ • streamingUrl → live browser preview (iframe) │
│ • STEP → agent progress updates │
│ • COMPLETE → structured safety JSON │
│ • ERROR → failure message │
└────────┬──────────────┬──────────────┬───────────────────────┘
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Google │ │ Google │ │ Google │ ... (2–5 restaurants)
│ Maps: │ │ Maps: │ │ Maps: │
│ Rest. A │ │ Rest. B │ │ Rest. C │
└───────────┘ └───────────┘ └───────────┘
```
23 changes: 23 additions & 0 deletions restaurant-comparison-tool/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"rtl": false,
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"registries": {}
}
23 changes: 23 additions & 0 deletions restaurant-comparison-tool/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
])
16 changes: 16 additions & 0 deletions restaurant-comparison-tool/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SafeDine - Restaurant Safety Intelligence</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading