Spaces:
Sleeping
Sleeping
Commit
Β·
99ec0c6
0
Parent(s):
Initial commit
Browse files- .gitignore +64 -0
- pickup-line-generator/.gitignore +88 -0
- pickup-line-generator/app/api/generate/route.ts +58 -0
- pickup-line-generator/app/globals.css +14 -0
- pickup-line-generator/app/layout.tsx +31 -0
- pickup-line-generator/app/page.tsx +120 -0
- pickup-line-generator/next.config.js +7 -0
- pickup-line-generator/package-lock.json +0 -0
- pickup-line-generator/package.json +28 -0
- pickup-line-generator/postcss.config.js +6 -0
- pickup-line-generator/tailwind.config.ts +28 -0
- pickup-line-generator/tsconfig.json +27 -0
- pickup-line-generator/vercel.json +18 -0
- smollm_web_pickuplinegenerator.py +216 -0
.gitignore
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Python
|
2 |
+
__pycache__/
|
3 |
+
*.py[cod]
|
4 |
+
*$py.class
|
5 |
+
*.so
|
6 |
+
.Python
|
7 |
+
build/
|
8 |
+
develop-eggs/
|
9 |
+
dist/
|
10 |
+
downloads/
|
11 |
+
eggs/
|
12 |
+
.eggs/
|
13 |
+
lib/
|
14 |
+
lib64/
|
15 |
+
parts/
|
16 |
+
sdist/
|
17 |
+
var/
|
18 |
+
wheels/
|
19 |
+
*.egg-info/
|
20 |
+
.installed.cfg
|
21 |
+
*.egg
|
22 |
+
|
23 |
+
# Virtual Environment
|
24 |
+
venv/
|
25 |
+
env/
|
26 |
+
ENV/
|
27 |
+
.env
|
28 |
+
|
29 |
+
# IDE
|
30 |
+
.idea/
|
31 |
+
.vscode/
|
32 |
+
*.swp
|
33 |
+
*.swo
|
34 |
+
|
35 |
+
# OS
|
36 |
+
.DS_Store
|
37 |
+
Thumbs.db
|
38 |
+
|
39 |
+
# Model files and cache
|
40 |
+
.cache/
|
41 |
+
models/
|
42 |
+
*.bin
|
43 |
+
*.pt
|
44 |
+
*.pth
|
45 |
+
*.onnx
|
46 |
+
*.h5
|
47 |
+
*.hdf5
|
48 |
+
|
49 |
+
# Logs
|
50 |
+
*.log
|
51 |
+
logs/
|
52 |
+
|
53 |
+
# Gradio
|
54 |
+
flagged/
|
55 |
+
|
56 |
+
# Next.js
|
57 |
+
.next/
|
58 |
+
out/
|
59 |
+
build/
|
60 |
+
dist/
|
61 |
+
.env*.local
|
62 |
+
.env.development.local
|
63 |
+
.env.test.local
|
64 |
+
.env.production.local
|
pickup-line-generator/.gitignore
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# dependencies
|
2 |
+
/node_modules
|
3 |
+
/.pnp
|
4 |
+
.pnp.js
|
5 |
+
|
6 |
+
# testing
|
7 |
+
/coverage
|
8 |
+
|
9 |
+
# next.js
|
10 |
+
/.next/
|
11 |
+
/out/
|
12 |
+
|
13 |
+
# production
|
14 |
+
/build
|
15 |
+
|
16 |
+
# misc
|
17 |
+
.DS_Store
|
18 |
+
*.pem
|
19 |
+
|
20 |
+
# debug
|
21 |
+
npm-debug.log*
|
22 |
+
yarn-debug.log*
|
23 |
+
yarn-error.log*
|
24 |
+
|
25 |
+
# local env files
|
26 |
+
.env*.local
|
27 |
+
.env
|
28 |
+
|
29 |
+
# vercel
|
30 |
+
.vercel
|
31 |
+
|
32 |
+
# typescript
|
33 |
+
*.tsbuildinfo
|
34 |
+
next-env.d.ts
|
35 |
+
|
36 |
+
# IDE specific files
|
37 |
+
.idea
|
38 |
+
.vscode
|
39 |
+
*.swp
|
40 |
+
*.swo
|
41 |
+
|
42 |
+
# OS generated files
|
43 |
+
.DS_Store
|
44 |
+
.DS_Store?
|
45 |
+
._*
|
46 |
+
.Spotlight-V100
|
47 |
+
.Trashes
|
48 |
+
ehthumbs.db
|
49 |
+
Thumbs.db
|
50 |
+
|
51 |
+
# Python virtual environment (if you're using Python for the model)
|
52 |
+
venv/
|
53 |
+
env/
|
54 |
+
ENV/
|
55 |
+
|
56 |
+
# Model files and cache
|
57 |
+
.cache/
|
58 |
+
models/
|
59 |
+
*.bin
|
60 |
+
*.pt
|
61 |
+
*.pth
|
62 |
+
*.onnx
|
63 |
+
*.h5
|
64 |
+
*.hdf5
|
65 |
+
|
66 |
+
# Logs
|
67 |
+
logs
|
68 |
+
*.log
|
69 |
+
|
70 |
+
# Optional npm cache directory
|
71 |
+
.npm
|
72 |
+
|
73 |
+
# Optional eslint cache
|
74 |
+
.eslintcache
|
75 |
+
|
76 |
+
# Optional REPL history
|
77 |
+
.node_repl_history
|
78 |
+
|
79 |
+
# Output of 'npm pack'
|
80 |
+
*.tgz
|
81 |
+
|
82 |
+
# Yarn Integrity file
|
83 |
+
.yarn-integrity
|
84 |
+
|
85 |
+
# dotenv environment variable files
|
86 |
+
.env.development.local
|
87 |
+
.env.test.local
|
88 |
+
.env.production.local
|
pickup-line-generator/app/api/generate/route.ts
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { NextResponse } from 'next/server';
|
2 |
+
import { getVibeGuidance } from '@/lib/prompts';
|
3 |
+
|
4 |
+
export async function POST(request: Request) {
|
5 |
+
// Handle CORS
|
6 |
+
if (request.method === 'OPTIONS') {
|
7 |
+
return new NextResponse(null, {
|
8 |
+
status: 200,
|
9 |
+
headers: {
|
10 |
+
'Access-Control-Allow-Origin': '*',
|
11 |
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
12 |
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
13 |
+
},
|
14 |
+
});
|
15 |
+
}
|
16 |
+
|
17 |
+
try {
|
18 |
+
const { vibe } = await request.json();
|
19 |
+
|
20 |
+
// Get the vibe guidance
|
21 |
+
const vibeGuide = getVibeGuidance(vibe);
|
22 |
+
|
23 |
+
// Create the prompt
|
24 |
+
const prompt = `Instructions: Generate a pickup line with a ${vibe} vibe.\n${vibeGuide}`;
|
25 |
+
|
26 |
+
// TODO: Replace this with actual model inference
|
27 |
+
// For now, return a mock response
|
28 |
+
const mockResponses = {
|
29 |
+
romantic: "Are you a magician? Because whenever I look at you, everyone else disappears. β€οΈ",
|
30 |
+
cheesy: "Are you a parking ticket? Because you've got FINE written all over you! π",
|
31 |
+
nerdy: "Are you made of copper and tellurium? Because you're Cu-Te! π¬",
|
32 |
+
cringe: "Are you a dictionary? Because you're adding meaning to my life! π",
|
33 |
+
flirty: "Is your name Google? Because you've got everything I've been searching for! π"
|
34 |
+
};
|
35 |
+
|
36 |
+
const response = NextResponse.json({ pickupLine: mockResponses[vibe as keyof typeof mockResponses] });
|
37 |
+
|
38 |
+
// Add CORS headers to the response
|
39 |
+
response.headers.set('Access-Control-Allow-Origin', '*');
|
40 |
+
response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
41 |
+
response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
42 |
+
|
43 |
+
return response;
|
44 |
+
} catch (error) {
|
45 |
+
console.error('Error generating pickup line:', error);
|
46 |
+
const errorResponse = NextResponse.json(
|
47 |
+
{ error: 'Failed to generate pickup line' },
|
48 |
+
{ status: 500 }
|
49 |
+
);
|
50 |
+
|
51 |
+
// Add CORS headers to the error response
|
52 |
+
errorResponse.headers.set('Access-Control-Allow-Origin', '*');
|
53 |
+
errorResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
54 |
+
errorResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
55 |
+
|
56 |
+
return errorResponse;
|
57 |
+
}
|
58 |
+
}
|
pickup-line-generator/app/globals.css
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@tailwind base;
|
2 |
+
@tailwind components;
|
3 |
+
@tailwind utilities;
|
4 |
+
|
5 |
+
:root {
|
6 |
+
--foreground-rgb: 0, 0, 0;
|
7 |
+
--background-start-rgb: 254, 246, 249;
|
8 |
+
--background-end-rgb: 255, 255, 255;
|
9 |
+
}
|
10 |
+
|
11 |
+
body {
|
12 |
+
color: rgb(var(--foreground-rgb));
|
13 |
+
background: rgb(var(--background-start-rgb));
|
14 |
+
}
|
pickup-line-generator/app/layout.tsx
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Metadata } from 'next';
|
2 |
+
import { Inter, Lobster } from 'next/font/google';
|
3 |
+
import { Toaster } from 'react-hot-toast';
|
4 |
+
import './globals.css';
|
5 |
+
|
6 |
+
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
|
7 |
+
const lobster = Lobster({
|
8 |
+
weight: '400',
|
9 |
+
subsets: ['latin'],
|
10 |
+
variable: '--font-lobster',
|
11 |
+
});
|
12 |
+
|
13 |
+
export const metadata: Metadata = {
|
14 |
+
title: 'Pickup Line Generator',
|
15 |
+
description: 'Generate fun, clever, or cringey pickup lines using SmolLM!',
|
16 |
+
};
|
17 |
+
|
18 |
+
export default function RootLayout({
|
19 |
+
children,
|
20 |
+
}: {
|
21 |
+
children: React.ReactNode;
|
22 |
+
}) {
|
23 |
+
return (
|
24 |
+
<html lang="en">
|
25 |
+
<body className={`${inter.variable} ${lobster.variable} font-sans`}>
|
26 |
+
{children}
|
27 |
+
<Toaster position="bottom-center" />
|
28 |
+
</body>
|
29 |
+
</html>
|
30 |
+
);
|
31 |
+
}
|
pickup-line-generator/app/page.tsx
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'use client';
|
2 |
+
|
3 |
+
import { useState } from 'react';
|
4 |
+
import { toast } from 'react-hot-toast';
|
5 |
+
|
6 |
+
const vibes = [
|
7 |
+
{ id: 'romantic', label: 'π Romantic', emoji: 'β€οΈ' },
|
8 |
+
{ id: 'cheesy', label: 'π§ Cheesy', emoji: 'π' },
|
9 |
+
{ id: 'nerdy', label: 'π€ Nerdy', emoji: 'π¬' },
|
10 |
+
{ id: 'cringe', label: 'π¬ Cringe', emoji: 'π' },
|
11 |
+
{ id: 'flirty', label: 'π Flirty', emoji: 'π' },
|
12 |
+
];
|
13 |
+
|
14 |
+
export default function Home() {
|
15 |
+
const [selectedVibe, setSelectedVibe] = useState(vibes[0].id);
|
16 |
+
const [pickupLine, setPickupLine] = useState('');
|
17 |
+
const [isLoading, setIsLoading] = useState(false);
|
18 |
+
|
19 |
+
const generatePickupLine = async () => {
|
20 |
+
setIsLoading(true);
|
21 |
+
try {
|
22 |
+
const response = await fetch('/api/generate', {
|
23 |
+
method: 'POST',
|
24 |
+
headers: {
|
25 |
+
'Content-Type': 'application/json',
|
26 |
+
},
|
27 |
+
body: JSON.stringify({ vibe: selectedVibe }),
|
28 |
+
});
|
29 |
+
|
30 |
+
if (!response.ok) throw new Error('Failed to generate pickup line');
|
31 |
+
|
32 |
+
const data = await response.json();
|
33 |
+
setPickupLine(data.pickupLine);
|
34 |
+
} catch (error) {
|
35 |
+
toast.error('Failed to generate pickup line');
|
36 |
+
console.error(error);
|
37 |
+
} finally {
|
38 |
+
setIsLoading(false);
|
39 |
+
}
|
40 |
+
};
|
41 |
+
|
42 |
+
const copyToClipboard = async () => {
|
43 |
+
try {
|
44 |
+
await navigator.clipboard.writeText(pickupLine);
|
45 |
+
toast.success('Copied to clipboard!');
|
46 |
+
} catch (error) {
|
47 |
+
toast.error('Failed to copy');
|
48 |
+
}
|
49 |
+
};
|
50 |
+
|
51 |
+
return (
|
52 |
+
<main className="min-h-screen bg-pink-50 py-12 px-4 sm:px-6 lg:px-8">
|
53 |
+
<div className="max-w-2xl mx-auto">
|
54 |
+
<div className="text-center mb-12">
|
55 |
+
<h1 className="text-4xl font-display font-bold text-pink-600 mb-4">
|
56 |
+
π Pickup Line Generator
|
57 |
+
</h1>
|
58 |
+
<p className="text-gray-600">
|
59 |
+
Generate fun, clever, or cringey pickup lines using SmolLM! Select a vibe and click generate to get started! π
|
60 |
+
</p>
|
61 |
+
</div>
|
62 |
+
|
63 |
+
<div className="bg-white rounded-2xl shadow-xl p-8 space-y-6">
|
64 |
+
<div className="space-y-4">
|
65 |
+
<label htmlFor="vibe" className="block text-sm font-medium text-gray-700">
|
66 |
+
Choose a vibe
|
67 |
+
</label>
|
68 |
+
<select
|
69 |
+
id="vibe"
|
70 |
+
value={selectedVibe}
|
71 |
+
onChange={(e) => setSelectedVibe(e.target.value)}
|
72 |
+
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-pink-500 focus:border-pink-500 sm:text-sm rounded-md"
|
73 |
+
>
|
74 |
+
{vibes.map((vibe) => (
|
75 |
+
<option key={vibe.id} value={vibe.id}>
|
76 |
+
{vibe.label}
|
77 |
+
</option>
|
78 |
+
))}
|
79 |
+
</select>
|
80 |
+
</div>
|
81 |
+
|
82 |
+
<button
|
83 |
+
onClick={generatePickupLine}
|
84 |
+
disabled={isLoading}
|
85 |
+
className="w-full bg-gradient-to-r from-pink-500 to-pink-600 text-white py-3 px-4 rounded-lg font-medium hover:from-pink-600 hover:to-pink-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-pink-500 transition-all duration-200 shadow-md hover:shadow-lg disabled:opacity-50 disabled:cursor-not-allowed"
|
86 |
+
>
|
87 |
+
{isLoading ? 'Generating...' : 'Generate Line'}
|
88 |
+
</button>
|
89 |
+
|
90 |
+
{pickupLine && (
|
91 |
+
<div className="space-y-4">
|
92 |
+
<div className="bg-pink-50 rounded-lg p-4">
|
93 |
+
<p className="text-gray-800 text-lg">{pickupLine}</p>
|
94 |
+
</div>
|
95 |
+
|
96 |
+
<div className="flex space-x-4">
|
97 |
+
<button
|
98 |
+
onClick={generatePickupLine}
|
99 |
+
className="flex-1 bg-white border border-pink-500 text-pink-500 py-2 px-4 rounded-lg font-medium hover:bg-pink-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-pink-500 transition-all duration-200"
|
100 |
+
>
|
101 |
+
π Generate Again
|
102 |
+
</button>
|
103 |
+
<button
|
104 |
+
onClick={copyToClipboard}
|
105 |
+
className="flex-1 bg-white border border-pink-500 text-pink-500 py-2 px-4 rounded-lg font-medium hover:bg-pink-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-pink-500 transition-all duration-200"
|
106 |
+
>
|
107 |
+
π Copy
|
108 |
+
</button>
|
109 |
+
</div>
|
110 |
+
</div>
|
111 |
+
)}
|
112 |
+
</div>
|
113 |
+
|
114 |
+
<div className="mt-8 text-center text-gray-500">
|
115 |
+
Built by Nath with SmolLM π₯
|
116 |
+
</div>
|
117 |
+
</div>
|
118 |
+
</main>
|
119 |
+
);
|
120 |
+
}
|
pickup-line-generator/next.config.js
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/** @type {import('next').NextConfig} */
|
2 |
+
const nextConfig = {
|
3 |
+
reactStrictMode: true,
|
4 |
+
swcMinify: true,
|
5 |
+
}
|
6 |
+
|
7 |
+
module.exports = nextConfig
|
pickup-line-generator/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
pickup-line-generator/package.json
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "pickup-line-generator",
|
3 |
+
"version": "0.1.0",
|
4 |
+
"private": true,
|
5 |
+
"scripts": {
|
6 |
+
"dev": "next dev",
|
7 |
+
"build": "next build",
|
8 |
+
"start": "next start",
|
9 |
+
"lint": "next lint"
|
10 |
+
},
|
11 |
+
"dependencies": {
|
12 |
+
"next": "14.1.0",
|
13 |
+
"react": "^18.2.0",
|
14 |
+
"react-dom": "^18.2.0",
|
15 |
+
"react-hot-toast": "^2.4.1"
|
16 |
+
},
|
17 |
+
"devDependencies": {
|
18 |
+
"@types/node": "20.17.27",
|
19 |
+
"@types/react": "18.3.20",
|
20 |
+
"@types/react-dom": "^18.2.19",
|
21 |
+
"autoprefixer": "^10.4.17",
|
22 |
+
"eslint": "^8.56.0",
|
23 |
+
"eslint-config-next": "14.1.0",
|
24 |
+
"postcss": "^8.4.35",
|
25 |
+
"tailwindcss": "^3.4.1",
|
26 |
+
"typescript": "5.8.2"
|
27 |
+
}
|
28 |
+
}
|
pickup-line-generator/postcss.config.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
module.exports = {
|
2 |
+
plugins: {
|
3 |
+
tailwindcss: {},
|
4 |
+
autoprefixer: {},
|
5 |
+
},
|
6 |
+
}
|
pickup-line-generator/tailwind.config.ts
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import type { Config } from 'tailwindcss';
|
2 |
+
|
3 |
+
const config: Config = {
|
4 |
+
content: [
|
5 |
+
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
6 |
+
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
7 |
+
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
8 |
+
],
|
9 |
+
theme: {
|
10 |
+
extend: {
|
11 |
+
fontFamily: {
|
12 |
+
sans: ['var(--font-inter)'],
|
13 |
+
display: ['var(--font-lobster)'],
|
14 |
+
},
|
15 |
+
colors: {
|
16 |
+
pink: {
|
17 |
+
50: '#fef6f9',
|
18 |
+
500: '#ff69b4',
|
19 |
+
600: '#ff1493',
|
20 |
+
700: '#db2777',
|
21 |
+
},
|
22 |
+
},
|
23 |
+
},
|
24 |
+
},
|
25 |
+
plugins: [],
|
26 |
+
};
|
27 |
+
|
28 |
+
export default config;
|
pickup-line-generator/tsconfig.json
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"target": "es5",
|
4 |
+
"lib": ["dom", "dom.iterable", "esnext"],
|
5 |
+
"allowJs": true,
|
6 |
+
"skipLibCheck": true,
|
7 |
+
"strict": true,
|
8 |
+
"noEmit": true,
|
9 |
+
"esModuleInterop": true,
|
10 |
+
"module": "esnext",
|
11 |
+
"moduleResolution": "bundler",
|
12 |
+
"resolveJsonModule": true,
|
13 |
+
"isolatedModules": true,
|
14 |
+
"jsx": "preserve",
|
15 |
+
"incremental": true,
|
16 |
+
"plugins": [
|
17 |
+
{
|
18 |
+
"name": "next"
|
19 |
+
}
|
20 |
+
],
|
21 |
+
"paths": {
|
22 |
+
"@/*": ["./*"]
|
23 |
+
}
|
24 |
+
},
|
25 |
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
26 |
+
"exclude": ["node_modules"]
|
27 |
+
}
|
pickup-line-generator/vercel.json
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"version": 2,
|
3 |
+
"builds": [
|
4 |
+
{
|
5 |
+
"src": "package.json",
|
6 |
+
"use": "@vercel/next"
|
7 |
+
}
|
8 |
+
],
|
9 |
+
"routes": [
|
10 |
+
{
|
11 |
+
"src": "/(.*)",
|
12 |
+
"dest": "/"
|
13 |
+
}
|
14 |
+
],
|
15 |
+
"env": {
|
16 |
+
"NEXT_PUBLIC_API_URL": "https://your-vercel-domain.vercel.app/api"
|
17 |
+
}
|
18 |
+
}
|
smollm_web_pickuplinegenerator.py
ADDED
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
3 |
+
import gradio as gr
|
4 |
+
import re
|
5 |
+
|
6 |
+
# Set page title and description
|
7 |
+
title = "π Pickup Line Generator"
|
8 |
+
description = """
|
9 |
+
<div style="text-align: center; max-width: 650px; margin: 0 auto;">
|
10 |
+
<div>
|
11 |
+
<p>Generate fun, clever, or cringey pickup lines using SmolLM-135M! Select a vibe and click generate to get started! π</p>
|
12 |
+
</div>
|
13 |
+
</div>
|
14 |
+
"""
|
15 |
+
|
16 |
+
# Load model and tokenizer
|
17 |
+
print("Loading SmolLM-135M model...")
|
18 |
+
MODEL_NAME = "HuggingFaceTB/SmolLM-135M"
|
19 |
+
|
20 |
+
# Check for CUDA availability
|
21 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
22 |
+
print(f"Using device: {device}")
|
23 |
+
|
24 |
+
# Load the model and tokenizer
|
25 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
26 |
+
# Set pad_token to eos_token to handle padding
|
27 |
+
tokenizer.pad_token = tokenizer.eos_token
|
28 |
+
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME).to(device)
|
29 |
+
|
30 |
+
print(f"Model loaded successfully! Memory footprint: {model.get_memory_footprint() / 1e6:.2f} MB")
|
31 |
+
|
32 |
+
def get_vibe_guidance(vibe):
|
33 |
+
"""Get specific guidance for each vibe with examples"""
|
34 |
+
vibe_patterns = {
|
35 |
+
"romantic": """Generate a romantic and sweet pickup line that's genuine and heartfelt.
|
36 |
+
Example:
|
37 |
+
Input: Generate a romantic pickup line
|
38 |
+
Output: Are you a magician? Because whenever I look at you, everyone else disappears. β€οΈ
|
39 |
+
|
40 |
+
Now generate a romantic pickup line: """,
|
41 |
+
|
42 |
+
"cheesy": """Generate a super cheesy and over-the-top pickup line.
|
43 |
+
Example:
|
44 |
+
Input: Generate a cheesy pickup line
|
45 |
+
Output: Are you a parking ticket? Because you've got FINE written all over you! π
|
46 |
+
|
47 |
+
Now generate a cheesy pickup line: """,
|
48 |
+
|
49 |
+
"nerdy": """Generate a nerdy, science-themed pickup line.
|
50 |
+
Example:
|
51 |
+
Input: Generate a nerdy pickup line
|
52 |
+
Output: Are you made of copper and tellurium? Because you're Cu-Te! π¬
|
53 |
+
|
54 |
+
Now generate a nerdy pickup line: """,
|
55 |
+
|
56 |
+
"cringe": """Generate the most cringey and over-the-top pickup line imaginable.
|
57 |
+
Example:
|
58 |
+
Input: Generate a cringe pickup line
|
59 |
+
Output: Are you a dictionary? Because you're adding meaning to my life! π
|
60 |
+
|
61 |
+
Now generate a cringe pickup line: """,
|
62 |
+
|
63 |
+
"flirty": """Generate a bold and flirty pickup line.
|
64 |
+
Example:
|
65 |
+
Input: Generate a flirty pickup line
|
66 |
+
Output: Is your name Google? Because you've got everything I've been searching for! π
|
67 |
+
|
68 |
+
Now generate a flirty pickup line: """
|
69 |
+
}
|
70 |
+
return vibe_patterns.get(vibe, "Generate a pickup line with a ")
|
71 |
+
|
72 |
+
def generate_pickup_line(vibe):
|
73 |
+
"""Generate a pickup line based on the selected vibe"""
|
74 |
+
# Get the vibe guidance
|
75 |
+
vibe_guide = get_vibe_guidance(vibe)
|
76 |
+
|
77 |
+
# Create the prompt
|
78 |
+
prompt = f"""Instructions: Generate a pickup line with a {vibe} vibe.
|
79 |
+
{vibe_guide}"""
|
80 |
+
|
81 |
+
# Prepare inputs with explicit attention mask
|
82 |
+
encoded_input = tokenizer.encode_plus(
|
83 |
+
prompt,
|
84 |
+
return_tensors="pt",
|
85 |
+
padding=True,
|
86 |
+
return_attention_mask=True
|
87 |
+
)
|
88 |
+
input_ids = encoded_input["input_ids"].to(device)
|
89 |
+
attention_mask = encoded_input["attention_mask"].to(device)
|
90 |
+
|
91 |
+
# Generate multiple responses and pick the best one
|
92 |
+
num_tries = 3
|
93 |
+
best_response = None
|
94 |
+
|
95 |
+
for _ in range(num_tries):
|
96 |
+
with torch.no_grad():
|
97 |
+
outputs = model.generate(
|
98 |
+
input_ids,
|
99 |
+
attention_mask=attention_mask,
|
100 |
+
max_new_tokens=100,
|
101 |
+
do_sample=True,
|
102 |
+
temperature=0.8,
|
103 |
+
top_p=0.92,
|
104 |
+
top_k=50,
|
105 |
+
pad_token_id=tokenizer.eos_token_id,
|
106 |
+
eos_token_id=tokenizer.eos_token_id,
|
107 |
+
)
|
108 |
+
|
109 |
+
# Get the full generated text
|
110 |
+
full_response = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
111 |
+
|
112 |
+
# Extract just the pickup line
|
113 |
+
if full_response.startswith(prompt):
|
114 |
+
response = full_response[len(prompt):].strip()
|
115 |
+
else:
|
116 |
+
response = full_response.replace(prompt, "").strip()
|
117 |
+
|
118 |
+
# Clean up the response
|
119 |
+
for marker in ["Instructions:", "Generate a pickup line:", "\n"]:
|
120 |
+
if marker in response:
|
121 |
+
response = response.split(marker, 1)[0].strip()
|
122 |
+
|
123 |
+
# Add appropriate emoji based on vibe
|
124 |
+
if vibe == "romantic":
|
125 |
+
response += " β€οΈ"
|
126 |
+
elif vibe == "cheesy":
|
127 |
+
response += " π"
|
128 |
+
elif vibe == "nerdy":
|
129 |
+
response += " π¬"
|
130 |
+
elif vibe == "cringe":
|
131 |
+
response += " π"
|
132 |
+
elif vibe == "flirty":
|
133 |
+
response += " π"
|
134 |
+
|
135 |
+
best_response = response
|
136 |
+
break
|
137 |
+
|
138 |
+
return best_response
|
139 |
+
|
140 |
+
# Create custom CSS
|
141 |
+
custom_css = """
|
142 |
+
.gradio-container {
|
143 |
+
background-color: #fef6f9 !important;
|
144 |
+
}
|
145 |
+
.title {
|
146 |
+
font-family: 'Lobster', cursive !important;
|
147 |
+
color: #ff69b4 !important;
|
148 |
+
}
|
149 |
+
.button {
|
150 |
+
background: linear-gradient(45deg, #ff69b4, #ff1493) !important;
|
151 |
+
color: white !important;
|
152 |
+
border: none !important;
|
153 |
+
transition: all 0.3s ease !important;
|
154 |
+
}
|
155 |
+
.button:hover {
|
156 |
+
transform: translateY(-2px);
|
157 |
+
box-shadow: 0 4px 8px rgba(255, 105, 180, 0.3);
|
158 |
+
}
|
159 |
+
"""
|
160 |
+
|
161 |
+
# Create the Gradio interface
|
162 |
+
with gr.Blocks(theme="soft", css=custom_css) as demo:
|
163 |
+
gr.Markdown(f"# {title}")
|
164 |
+
gr.Markdown(description)
|
165 |
+
|
166 |
+
with gr.Row():
|
167 |
+
with gr.Column():
|
168 |
+
vibe_dropdown = gr.Dropdown(
|
169 |
+
choices=[
|
170 |
+
"romantic",
|
171 |
+
"cheesy",
|
172 |
+
"nerdy",
|
173 |
+
"cringe",
|
174 |
+
"flirty"
|
175 |
+
],
|
176 |
+
label="Pick a vibe",
|
177 |
+
value="romantic"
|
178 |
+
)
|
179 |
+
generate_btn = gr.Button("Generate Line", elem_classes="button")
|
180 |
+
|
181 |
+
with gr.Column():
|
182 |
+
output = gr.Textbox(
|
183 |
+
label="Your pickup line",
|
184 |
+
lines=3,
|
185 |
+
interactive=False
|
186 |
+
)
|
187 |
+
copy_btn = gr.Button("π Copy to Clipboard", elem_classes="button")
|
188 |
+
|
189 |
+
# Example inputs
|
190 |
+
gr.Examples(
|
191 |
+
examples=[
|
192 |
+
["romantic"],
|
193 |
+
["cheesy"],
|
194 |
+
["nerdy"],
|
195 |
+
["cringe"],
|
196 |
+
["flirty"]
|
197 |
+
],
|
198 |
+
inputs=[vibe_dropdown]
|
199 |
+
)
|
200 |
+
|
201 |
+
generate_btn.click(
|
202 |
+
fn=generate_pickup_line,
|
203 |
+
inputs=[vibe_dropdown],
|
204 |
+
outputs=output
|
205 |
+
)
|
206 |
+
|
207 |
+
# Footer
|
208 |
+
gr.Markdown("""
|
209 |
+
<div style="text-align: center; margin-top: 20px; color: #666;">
|
210 |
+
Built by Nath with SmolLM π₯
|
211 |
+
</div>
|
212 |
+
""")
|
213 |
+
|
214 |
+
# Launch the app
|
215 |
+
if __name__ == "__main__":
|
216 |
+
demo.launch(share=True) # Set share=False if you don't want to create a public link
|