Update
This commit is contained in:
@@ -12,7 +12,7 @@ public static function getMemeKeywords(string $name, string $description)
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . $apiKey,
|
||||
'Authorization' => 'Bearer '.$apiKey,
|
||||
])->post('https://api.openai.com/v1/responses', [
|
||||
'model' => 'gpt-4.1-nano',
|
||||
'input' => [
|
||||
@@ -56,70 +56,68 @@ public static function getSingleMemeGenerator($user_prompt)
|
||||
$captions = [
|
||||
[
|
||||
'caption_description' => 'A humorous, funny one-liner meme caption that starts with "When you", describes a specific visual or situational moment, avoids vagueness, and ends with no punctuation',
|
||||
'caption_style' => 'Relatable one-liners starting with "When you"'
|
||||
'caption_style' => 'Relatable one-liners starting with "When you"',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A POV meme that starts with "POV: ", clearly describes a specific scenario or feeling with high context, and ends with no punctuation',
|
||||
'caption_style' => 'POV-style captions (e.g., "POV: finally logging off after pretending to work for 3 hours")'
|
||||
'caption_style' => 'POV-style captions (e.g., "POV: finally logging off after pretending to work for 3 hours")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A humorous, funny one-liner meme caption that starts with "I", grounded in a relatable, situational experience with visual context, and ends with no punctuation',
|
||||
'caption_style' => 'Relatable one-liners starting with "I"'
|
||||
'caption_style' => 'Relatable one-liners starting with "I"',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A humorous, funny one-liner meme caption that starts with "You", focused on a clear, specific reaction or moment, and ends with no punctuation',
|
||||
'caption_style' => 'Relatable one-liners starting with "You"'
|
||||
'caption_style' => 'Relatable one-liners starting with "You"',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A humorous, funny one-liner meme caption with no punctuation that describes a vivid, realistic scenario or reaction in a clearly defined context',
|
||||
'caption_style' => 'Visual punchlines (e.g., "Wearing a suit and contemplating my life in the elevator")'
|
||||
'caption_style' => 'Visual punchlines (e.g., "Wearing a suit and contemplating my life in the elevator")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A juxtaposition-style one-liner meme caption expressing a contrast or contradiction in a witty, punchy way, often revealing irony or absurdity, and ends with no punctuation (e.g., "I want a salary without a job"). Start with "I" or "You" to create a sense of contrast',
|
||||
'caption_style' => 'Juxtaposition (e.g., "I want a salary without a job")'
|
||||
'caption_style' => 'Juxtaposition (e.g., "I want a salary without a job")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "TIL: ", presents a short, punchy, and ironic realization about work or life that feels meme-worthy, clearly sets up a visual or exaggerated truth, and ends with no punctuation (e.g., "TIL: rent is just a subscription to be alive")',
|
||||
'caption_style' => 'TIL captions (e.g., "TIL: rent is just a subscription to be alive")'
|
||||
'caption_style' => 'TIL captions (e.g., "TIL: rent is just a subscription to be alive")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "TL;DR: ", provides a blunt, dry, or brutally honest summary of a situation, ideally workplace- or life-related, and ends with no punctuation (e.g., "TL;DR: we had a meeting about having fewer meetings")',
|
||||
'caption_style' => 'TL;DR captions (e.g., "TL;DR: we had a meeting about having fewer meetings")'
|
||||
'caption_style' => 'TL;DR captions (e.g., "TL;DR: we had a meeting about having fewer meetings")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "The moment you realize", sets up an unexpected or awkward realization in a relatable work or life setting, and ends with no punctuation',
|
||||
'caption_style' => 'The moment you realize... (e.g., "The moment you realize your boss joined the call 5 minutes ago")'
|
||||
'caption_style' => 'The moment you realize... (e.g., "The moment you realize your boss joined the call 5 minutes ago")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that uses the "Nobody:" format to exaggerate a reaction or absurd behavior, often with a silent or empty setup followed by an over-the-top response, and ends with no punctuation',
|
||||
'caption_style' => 'Nobody: ... (e.g., "Nobody: \nMe: sends 3 follow-up emails and panics")'
|
||||
'caption_style' => 'Nobody: ... (e.g., "Nobody: \nMe: sends 3 follow-up emails and panics")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "Me trying to", describes a personal struggle or awkward attempt to do something relatable, and ends with no punctuation',
|
||||
'caption_style' => 'Me trying to... (e.g., "Me trying to stay calm after 2 hours on hold")'
|
||||
'caption_style' => 'Me trying to... (e.g., "Me trying to stay calm after 2 hours on hold")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "It\'s giving", followed by a cultural, emotional, or exaggerated vibe that humorously labels the situation, and ends with no punctuation',
|
||||
'caption_style' => 'It\'s giving... (e.g., "It\'s giving corporate despair in HD")'
|
||||
'caption_style' => 'It\'s giving... (e.g., "It\'s giving corporate despair in HD")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "Meanwhile", contrasts expected behavior with a chaotic or unexpected reality, and ends with no punctuation',
|
||||
'caption_style' => 'Meanwhile... (e.g., "Meanwhile: I\'m Googling how to quit politely")'
|
||||
'caption_style' => 'Meanwhile... (e.g., "Meanwhile: I\'m Googling how to quit politely")',
|
||||
],
|
||||
[
|
||||
'caption_description' => 'A meme caption that starts with "My toxic trait is", followed by an ironic or self-aware confession that highlights flawed logic or behavior, and ends with no punctuation',
|
||||
'caption_style' => 'My toxic trait is... (e.g., "My toxic trait is checking Slack and getting mad")'
|
||||
'caption_style' => 'My toxic trait is... (e.g., "My toxic trait is checking Slack and getting mad")',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
//$random_caption = $captions[rand(0, count($captions) - 1)];
|
||||
// $random_caption = $captions[rand(0, count($captions) - 1)];
|
||||
$random_caption = $captions[count($captions) - 1];
|
||||
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . env('OPENAI_API_KEY'),
|
||||
'Authorization' => 'Bearer '.env('OPENAI_API_KEY'),
|
||||
])
|
||||
->post('https://api.openai.com/v1/responses', [
|
||||
'model' => 'gpt-4.1-nano',
|
||||
@@ -231,11 +229,10 @@ public static function getSingleMemeGenerator($user_prompt)
|
||||
if ($response->successful()) {
|
||||
return $data;
|
||||
} else {
|
||||
throw new \Exception('API request failed: ' . $response->body());
|
||||
throw new \Exception('API request failed: '.$response->body());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function getOpenAIOutput($data)
|
||||
{
|
||||
// dump($data);
|
||||
|
||||
169
app/Helpers/FirstParty/Purchase/PurchaseHelper.php
Normal file
169
app/Helpers/FirstParty/Purchase/PurchaseHelper.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers\FirstParty\Purchase;
|
||||
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class PurchaseHelper
|
||||
{
|
||||
public static function getPricingPageSubscriptions()
|
||||
{
|
||||
|
||||
$subscriptions = self::getSubscriptions('subscription_plans', true, true);
|
||||
|
||||
$subscriptions = self::filterShowInPricing($subscriptions);
|
||||
|
||||
$subscriptions = self::setSystemPlan($subscriptions, 'stripe.current_stripe_price_id.month');
|
||||
|
||||
$subscriptions = self::filterUnsetSystem($subscriptions);
|
||||
|
||||
$subscriptions = self::reiterateArray($subscriptions);
|
||||
|
||||
return $subscriptions;
|
||||
}
|
||||
|
||||
public static function getPricingPageOneTime()
|
||||
{
|
||||
$one_time = self::getOneTimePurchases(true, true);
|
||||
|
||||
$one_time = PurchaseHelper::filterShowInPricing($one_time);
|
||||
|
||||
$one_time = PurchaseHelper::setSystemPlan($one_time, 'stripe.current_stripe_price_id');
|
||||
|
||||
$one_time = PurchaseHelper::filterUnsetSystem($one_time);
|
||||
|
||||
$one_time = self::reiterateArray($one_time);
|
||||
|
||||
return $one_time;
|
||||
}
|
||||
|
||||
public static function getPlanSystemProperty($plan, $property)
|
||||
{
|
||||
// Get the environment (test or prod)
|
||||
$environment = self::getStripeEnvironment();
|
||||
|
||||
// Split the property path
|
||||
$propertyParts = explode('.', $property);
|
||||
|
||||
// Check if this is a stripe-related property that needs environment injection
|
||||
if (count($propertyParts) >= 2 && $propertyParts[0] === 'stripe') {
|
||||
// Inject environment into the path
|
||||
// stripe.product_id.month becomes system.stripe.product_id.{env}.month
|
||||
array_splice($propertyParts, 2, 0, $environment);
|
||||
$fullPath = 'system.'.implode('.', $propertyParts);
|
||||
} else {
|
||||
// For non-stripe properties, just prepend 'system.'
|
||||
$fullPath = 'system.'.$property;
|
||||
}
|
||||
|
||||
return data_get($plan, $fullPath);
|
||||
}
|
||||
|
||||
public static function getSubscriptions($type, $enabled = null, $system = false)
|
||||
{
|
||||
|
||||
$tmp_subscriptions = config('platform.purchases.subscriptions');
|
||||
|
||||
if (isset($enabled)) {
|
||||
|
||||
$tmp_subscriptions = array_filter($tmp_subscriptions, function ($value) use ($type) {
|
||||
return $value['type'] == $type;
|
||||
});
|
||||
|
||||
$tmp_subscriptions = array_filter($tmp_subscriptions, function ($value) use ($enabled) {
|
||||
return $value['enabled'] == $enabled;
|
||||
});
|
||||
|
||||
if (! $system) {
|
||||
$tmp_subscriptions = array_map(function ($item) {
|
||||
|
||||
unset($item['system']);
|
||||
|
||||
return $item;
|
||||
}, $tmp_subscriptions);
|
||||
}
|
||||
}
|
||||
|
||||
$env = App::environment();
|
||||
|
||||
return $tmp_subscriptions;
|
||||
}
|
||||
|
||||
public static function getOneTimePurchases(?bool $enabled, $system = false)
|
||||
{
|
||||
$tmp_otp = config('platform.purchases.one_time');
|
||||
|
||||
if (isset($enabled)) {
|
||||
$tmp_otp = array_filter($tmp_otp, function ($value) use ($enabled) {
|
||||
return $value['enabled'] == $enabled;
|
||||
});
|
||||
}
|
||||
|
||||
if (! $system) {
|
||||
$tmp_otp = array_map(function ($item) {
|
||||
|
||||
unset($item['system']);
|
||||
|
||||
return $item;
|
||||
}, $tmp_otp);
|
||||
}
|
||||
|
||||
return $tmp_otp;
|
||||
}
|
||||
|
||||
public static function setSystemPlan($arr, $property)
|
||||
{
|
||||
foreach ($arr as $key => $item) {
|
||||
|
||||
$arr[$key]['stripe_monthly_price_id'] = PurchaseHelper::getPlanSystemProperty($item, $property);
|
||||
|
||||
// $stripe_monthly_price_id = PurchaseHelper::getPlanSystemProperty($subscription, 'stripe.product_id.month');
|
||||
|
||||
// $stripe_current_monthly_price_id = PurchaseHelper::getPlanSystemProperty($subscription, 'stripe.current_stripe_price_id.month');
|
||||
|
||||
// $stripe_all_monthly_price_ids = PurchaseHelper::getPlanSystemProperty($subscription, 'stripe.stripe_price_ids.month');
|
||||
|
||||
// dump($stripe_monthly_price_id);
|
||||
// dump($stripe_current_monthly_price_id);
|
||||
// dump($stripe_all_monthly_price_ids);
|
||||
}
|
||||
|
||||
return $arr;
|
||||
}
|
||||
|
||||
public static function filterUnsetSystem($arr)
|
||||
{
|
||||
return array_map(function ($item) {
|
||||
|
||||
unset($item['system']);
|
||||
|
||||
return $item;
|
||||
}, $arr);
|
||||
}
|
||||
|
||||
public static function filterShowInPricing($arr)
|
||||
{
|
||||
return array_filter($arr, function ($item) {
|
||||
return $item['show_in_pricing'] == true;
|
||||
});
|
||||
}
|
||||
|
||||
private static function getStripeEnvironment()
|
||||
{
|
||||
$env = App::environment();
|
||||
|
||||
// Return 'prod' for production environment, 'test' for everything else
|
||||
return $env === 'production' ? 'prod' : 'test';
|
||||
}
|
||||
|
||||
private static function reiterateArray($arr)
|
||||
{
|
||||
$tmp = [];
|
||||
|
||||
foreach ($arr as $key => $item) {
|
||||
$tmp[] = $item;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
}
|
||||
93
app/Http/Controllers/SocialAuthController.php
Normal file
93
app/Http/Controllers/SocialAuthController.php
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
class SocialAuthController extends Controller
|
||||
{
|
||||
public function redirectToGoogle()
|
||||
{
|
||||
return Socialite::driver('google')
|
||||
->with(['prompt' => 'consent'])
|
||||
->redirect();
|
||||
}
|
||||
|
||||
public function handleGoogleCallback()
|
||||
{
|
||||
try {
|
||||
if (App::environment('production')) {
|
||||
$googleUser = Socialite::driver('google')->user();
|
||||
} else {
|
||||
$googleUser = Socialite::driver('google')->user();
|
||||
|
||||
// /$googleUser = $this->getMockGoogleUser();
|
||||
}
|
||||
|
||||
// First, check if the user exists by google_id
|
||||
$user = User::where('google_id', $googleUser->id)->whereNotNull('google_id')->first();
|
||||
|
||||
if ($user) {
|
||||
$this->setupUser($user);
|
||||
|
||||
Auth::login($user);
|
||||
} else {
|
||||
// If no user found by google_id, check by email
|
||||
$user = User::where('email', $googleUser->email)->first();
|
||||
|
||||
if ($user) {
|
||||
// If the google_id is empty, update it
|
||||
if (empty($user->google_id)) {
|
||||
$user->google_id = $googleUser->id;
|
||||
$user->save();
|
||||
}
|
||||
$this->setupUser($user);
|
||||
Auth::login($user);
|
||||
} else {
|
||||
// Create a new user if neither exists
|
||||
$user = User::create([
|
||||
'email' => $googleUser->email,
|
||||
'google_id' => $googleUser->id,
|
||||
]);
|
||||
$this->setupUser($user);
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
$intended_route = route('home');
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->intended(route('home'));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
throw $e;
|
||||
$error_message = 'Google login failed. Please try again.';
|
||||
if (config('app.debug')) {
|
||||
$error_message = $e->getMessage();
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', $error_message);
|
||||
}
|
||||
}
|
||||
|
||||
private function setupUser($user) {}
|
||||
|
||||
private function getMockGoogleUser()
|
||||
{
|
||||
// Create a mock user object that mimics Socialite's user structure
|
||||
return new class
|
||||
{
|
||||
public $email = 'memeaigen.com@gmail.com';
|
||||
|
||||
public $id = 'xxx';
|
||||
|
||||
// public $email = 'patrick.christener@gmail.com';
|
||||
|
||||
// public $id = '104771940181889934768';
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
use App\Helpers\FirstParty\AI\RunwareAI;
|
||||
use App\Helpers\FirstParty\AspectRatio;
|
||||
use App\Helpers\FirstParty\Meme\MemeGenerator;
|
||||
use App\Helpers\FirstParty\Purchase\PurchaseHelper;
|
||||
use App\Models\Category;
|
||||
use App\Models\Meme;
|
||||
use App\Models\MemeMedia;
|
||||
@@ -18,6 +19,16 @@ public function index()
|
||||
//
|
||||
}
|
||||
|
||||
public function testPurchase()
|
||||
{
|
||||
$subscriptions = PurchaseHelper::getPricingPageSubscriptions();
|
||||
|
||||
$one_time = PurchaseHelper::getPricingPageOneTime();
|
||||
|
||||
dump($subscriptions);
|
||||
dump($one_time);
|
||||
}
|
||||
|
||||
public function getSuitableMemeMedia()
|
||||
{
|
||||
$meme = Meme::inRandomOrder()->first();
|
||||
@@ -68,7 +79,7 @@ public function writeMeme()
|
||||
{
|
||||
$meme_response = OpenAI::getSingleMemeGenerator('Write me 1 meme about adult life');
|
||||
|
||||
//dump($meme_response);
|
||||
// dump($meme_response);
|
||||
|
||||
$meme_output = json_decode(OpenAI::getOpenAIOutput($meme_response));
|
||||
|
||||
|
||||
132
app/Http/Controllers/UserPurchaseController.php
Normal file
132
app/Http/Controllers/UserPurchaseController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\FirstParty\Purchase\PurchaseHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
||||
class UserPurchaseController extends Controller
|
||||
{
|
||||
public function pricingPage(Request $request)
|
||||
{
|
||||
|
||||
$subscriptions = PurchaseHelper::getPricingPageSubscriptions();
|
||||
|
||||
return response()->json([
|
||||
'success' => [
|
||||
'data' => [
|
||||
'subscription' => $subscriptions[0],
|
||||
'one_times' => PurchaseHelper::getPricingPageOneTime(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
// SUBSCRIBE (RECURRING)
|
||||
|
||||
public function subscribe(Request $request)
|
||||
{
|
||||
$price_id = $request->input('price_id');
|
||||
|
||||
$payload = [
|
||||
'mode' => 'subscription',
|
||||
'success_url' => route('subscribe.success').'?'.'session_id={CHECKOUT_SESSION_ID}',
|
||||
'cancel_url' => route('subscribe.cancelled').'?'.'session_id={CHECKOUT_SESSION_ID}',
|
||||
'line_items' => [[
|
||||
'price' => $price_id,
|
||||
]],
|
||||
];
|
||||
|
||||
$checkout_session = Auth::user()->checkout([$price_id => 1], $payload);
|
||||
|
||||
Session::put('checkout_session_id', $checkout_session->id);
|
||||
|
||||
return response()->json([
|
||||
'success' => [
|
||||
'data' => [
|
||||
'redirect' => $checkout_session->url,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function subscribeSuccess(Request $request)
|
||||
{
|
||||
if (! Session::has('checkout_session_id')) {
|
||||
abort(401);
|
||||
}
|
||||
|
||||
Session::forget('checkout_session_id');
|
||||
|
||||
return redirect()->route('home')->with('success', [
|
||||
'message' => 'Thank you for subscribing! Your subscription should be active momentarily. Please refresh the page if you do not see your plan.',
|
||||
'action' => 'subscription_success',
|
||||
]);
|
||||
}
|
||||
|
||||
public function subscribeCancelled(Request $request)
|
||||
{
|
||||
|
||||
if (Session::has('checkout_session_id')) {
|
||||
Session::forget('checkout_session_id');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', [
|
||||
'message' => "You've decided not to complete the payment at this time. No charges have been made to your account.",
|
||||
'action' => 'subscription_cancelled',
|
||||
]);
|
||||
}
|
||||
|
||||
// PURCHASE (ONE TIME)
|
||||
|
||||
public function purchase(Request $request)
|
||||
{
|
||||
$price_id = $request->input('price_id');
|
||||
|
||||
$payload = [
|
||||
'success_url' => route('subscribe.success').'?'.'session_id={CHECKOUT_SESSION_ID}',
|
||||
'cancel_url' => route('subscribe.cancelled').'?'.'session_id={CHECKOUT_SESSION_ID}',
|
||||
];
|
||||
|
||||
$checkout_session = Auth::user()->checkout([$price_id => 1], $payload);
|
||||
|
||||
Session::put('checkout_session_id', $checkout_session->id);
|
||||
|
||||
return response()->json([
|
||||
'success' => [
|
||||
'data' => [
|
||||
'redirect' => $checkout_session->url,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function purchaseSuccess(Request $request)
|
||||
{
|
||||
|
||||
if (! Session::has('checkout_session_id')) {
|
||||
abort(401);
|
||||
}
|
||||
|
||||
Session::forget('checkout_session_id');
|
||||
|
||||
return redirect()->route('home')->with('success', [
|
||||
'message' => 'Thank you for purchasing! Your purchase should be active momentarily. Please refresh the page if you do not see your plan.',
|
||||
'action' => 'purchase_success',
|
||||
]);
|
||||
}
|
||||
|
||||
public function purchaseCancelled(Request $request)
|
||||
{
|
||||
if (Session::has('checkout_session_id')) {
|
||||
Session::forget('checkout_session_id');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', [
|
||||
'message' => "You've decided not to complete the payment at this time. No charges have been made to your account.",
|
||||
'action' => 'purchase_cancelled',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user