diff --git a/app/Helpers/FirstParty/OpenAI/OpenAI.php b/app/Helpers/FirstParty/OpenAI/OpenAI.php
index 64e732a..3b56b63 100644
--- a/app/Helpers/FirstParty/OpenAI/OpenAI.php
+++ b/app/Helpers/FirstParty/OpenAI/OpenAI.php
@@ -14,7 +14,7 @@ public static function getSiteSummary($parent_categories, $user_prompt, $model_m
$category_list = implode('|', $parent_categories->pluck('name')->toArray());
- $system_prompt = "Based on the website content containing an AI tool, return a valid JSON containing:\n{\n\"is_ai_tool\":(true|false),\n\"ai_tool_name\":\"(AI Tool Name)\",\n\"is_app_web_both\":\"(app|web|both)\",\n\"tagline\":\"(One line tagline in 6-8 words)\",\n\"summary\": \"(Summary of AI tool in 2-3 parapgraphs, 140-180 words using grade 8 US english)\",\n\"pricing_type\": \"(Free|Free Trial|Freemium|Subscription|Usage Based)\",\n\"main_category\": \"(AI Training|Art|Audio|Avatars|Business|Chatbots|Coaching|Content Generation|Data|Dating|Design|Dev|Education|Emailing|Finance|Gaming|GPTs|Health|Legal|Marketing|Music|Networking|Personal Assistance|Planning|Podcasting|Productivity|Project Management|Prompting|Reporting|Research|Sales|Security|SEO|Shopping|Simulation|Social|Speech|Support|Task|Testing|Training|Translation|UI\/UX|Video|Workflow|Writing)\",\n\"keywords\":[\"(Identify relevant keywords for this AI Tool, 1-2 words each, at least)\"],\n\"qna\":[{\"q\":\"Typical FAQ that readers want to know, up to 5 questions\",\"a\":\"Answer of the question\"}]\n}";
+ $system_prompt = "Based on the website content containing an AI tool, return a valid JSON containing:\n{\n\"is_ai_tool\":(true|false),\n\"ai_tool_name\":\"(AI Tool Name)\",\n\"is_app_web_both\":\"(app|web|both)\",\n\"tagline\":\"(One line tagline in 6-8 words)\",\n\"summary\": \"(Summary of AI tool in 2-3 parapgraphs, 200-240 words using grade 8 US english, start with AI tool name)\",\n\"pricing_type\": \"(Free|Free Trial|Freemium|Subscription|Usage Based)\",\n\"main_category\": \"(AI Training|Art|Audio|Avatars|Business|Chatbots|Coaching|Content Generation|Data|Dating|Design|Dev|Education|Emailing|Finance|Gaming|GPTs|Health|Legal|Marketing|Music|Networking|Personal Assistance|Planning|Podcasting|Productivity|Project Management|Prompting|Reporting|Research|Sales|Security|SEO|Shopping|Simulation|Social|Speech|Support|Task|Testing|Training|Translation|UI\/UX|Video|Workflow|Writing)\",\n\"keywords\":[\"(Identify relevant keywords for this AI Tool, 1-2 words each, at least)\"],\n\"qna\":[{\"q\":\"Typical FAQ that readers want to know, up to 5 questions\",\"a\":\"Answer of the question\"}]\n}";
return self::getChatCompletion($user_prompt, $system_prompt, $openai_config, $model_max_tokens, $timeout);
}
diff --git a/app/Helpers/Global/helpers.php b/app/Helpers/Global/helpers.php
index 6666268..34f95f9 100644
--- a/app/Helpers/Global/helpers.php
+++ b/app/Helpers/Global/helpers.php
@@ -3,3 +3,4 @@
require 'string_helper.php';
require 'geo_helper.php';
require 'proxy_helper.php';
+require 'route_helper.php';
diff --git a/app/Helpers/Global/route_helper.php b/app/Helpers/Global/route_helper.php
new file mode 100644
index 0000000..d95002f
--- /dev/null
+++ b/app/Helpers/Global/route_helper.php
@@ -0,0 +1,13 @@
+ strtolower(urlencode($query)),
+ ]);
+ }
+}
diff --git a/app/Helpers/Global/string_helper.php b/app/Helpers/Global/string_helper.php
index b205091..475cd6a 100644
--- a/app/Helpers/Global/string_helper.php
+++ b/app/Helpers/Global/string_helper.php
@@ -1,11 +1,42 @@
format('d M Y');
+
+ }
+}
+
+if (! function_exists('epoch_now_timestamp')) {
+ function epoch_now_timestamp($multiplier = 1000)
+ {
+ return (int) round(microtime(true) * $multiplier);
+ }
+}
+
+if (! function_exists('add_params_to_url')) {
+ function add_params_to_url(string $url, array $newParams): string
+ {
+ $url = parse_url($url);
+ parse_str($url['query'] ?? '', $existingParams);
+
+ $newQuery = array_merge($existingParams, $newParams);
+
+ $newUrl = $url['scheme'].'://'.$url['host'].($url['path'] ?? '');
+ if ($newQuery) {
+ $newUrl .= '?'.http_build_query($newQuery);
+ }
+
+ if (isset($url['fragment'])) {
+ $newUrl .= '#'.$url['fragment'];
+ }
+
+ return $newUrl;
}
}
@@ -175,6 +206,34 @@ function str_first_sentence($str)
}
+if (! function_exists('str_extract_sentences')) {
+ function str_extract_sentences($str, $count = 1)
+ {
+ // Split the string at ., !, or ?, including the punctuation in the result
+ $sentences = preg_split('/([.!?])\s*/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+
+ $extractedSentences = [];
+ $currentSentence = '';
+
+ foreach ($sentences as $key => $sentence) {
+ if ($key % 2 == 0) {
+ // This is a sentence fragment
+ $currentSentence = $sentence;
+ } else {
+ // This is a punctuation mark
+ $currentSentence .= $sentence;
+ $extractedSentences[] = trim($currentSentence);
+
+ if (count($extractedSentences) >= $count) {
+ break;
+ }
+ }
+ }
+
+ return $extractedSentences;
+ }
+}
+
if (! function_exists('unslug')) {
function unslug($slug, $delimiter = '-')
{
diff --git a/app/Http/Controllers/Front/FrontDiscoverController.php b/app/Http/Controllers/Front/FrontDiscoverController.php
index 1503212..88cbd02 100644
--- a/app/Http/Controllers/Front/FrontDiscoverController.php
+++ b/app/Http/Controllers/Front/FrontDiscoverController.php
@@ -3,7 +3,9 @@
namespace App\Http\Controllers\Front;
use App\Http\Controllers\Controller;
+use App\Models\AiTool;
use App\Models\Category;
+use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Http\Request;
use JsonLd\Context;
@@ -36,7 +38,7 @@ public function discover(Request $request, $category_slug = null)
SEOTools::opengraph();
SEOTools::jsonLd();
SEOTools::setTitle($category->name.' AI Tools', false);
- //SEOTools::setDescription($description);
+ //SEOTools::setDescription($description);
} else {
$breadcrumbs = collect([
['name' => 'Home', 'url' => route('front.home')],
@@ -65,6 +67,15 @@ public function discover(Request $request, $category_slug = null)
'itemListElement' => $listItems,
]);
- return view('front.discover', compact('breadcrumbs', 'breadcrumb_context', 'category'));
+ $ai_tools = AiTool::when(! is_null($category), function ($query) use ($category) {
+ $query->where('category_id', $category->id);
+ })
+ ->orderBy('updated_at', 'DESC')->paginate(6);
+
+ if ($ai_tools->count() <= 0) {
+ SEOMeta::setRobots('noindex');
+ }
+
+ return view('front.discover', compact('breadcrumbs', 'breadcrumb_context', 'category', 'ai_tools'));
}
}
diff --git a/app/Http/Controllers/Front/FrontHomeController.php b/app/Http/Controllers/Front/FrontHomeController.php
index 8d0e8a4..fd808f6 100644
--- a/app/Http/Controllers/Front/FrontHomeController.php
+++ b/app/Http/Controllers/Front/FrontHomeController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Front;
use App\Http\Controllers\Controller;
+use App\Models\AiTool;
use Artesaos\SEOTools\Facades\SEOMeta;
use Artesaos\SEOTools\Facades\SEOTools;
use GrahamCampbell\Markdown\Facades\Markdown;
@@ -12,7 +13,9 @@ class FrontHomeController extends Controller
{
public function index(Request $request)
{
- return view('front.home');
+ $latest_ai_tools = AiTool::orderBy('created_at', 'DESC')->take(12)->get();
+
+ return view('front.home', compact('latest_ai_tools'));
}
public function terms(Request $request)
diff --git a/app/Http/Controllers/Front/FrontSearchController.php b/app/Http/Controllers/Front/FrontSearchController.php
index 2bdbb19..c6deff8 100644
--- a/app/Http/Controllers/Front/FrontSearchController.php
+++ b/app/Http/Controllers/Front/FrontSearchController.php
@@ -2,9 +2,107 @@
namespace App\Http\Controllers\Front;
+use App\Helpers\FirstParty\Aictio\Aictio;
use App\Http\Controllers\Controller;
+use App\Models\SearchEmbedding;
+use App\Models\SearchResult;
+use Artesaos\SEOTools\Facades\SEOTools;
+use Illuminate\Http\Request;
+use JsonLd\Context;
class FrontSearchController extends Controller
{
- //
+ public function search(Request $request)
+ {
+ if (is_empty($request->input('query'))) {
+ return redirect()->back();
+ }
+
+ return redirect()->to(get_route_search_result($request->input('query')));
+ }
+
+ public function searchResult(Request $request, $query)
+ {
+ if ($request->input('page') > 10) {
+ abort(404);
+ }
+
+ if (is_empty(trim($query))) {
+ return abort(404);
+ }
+
+ $query = trim($query);
+
+ $pagination_results = 10;
+
+ $search_result = SearchResult::where('query', $query)
+ ->orderBy('id', 'desc')
+ ->first();
+
+ $embedding = null;
+
+ if (! is_null($search_result) && ! is_null($search_result->embedding)) {
+ $embedding = $search_result->embedding;
+ $search_result->increment('counts');
+ } else {
+ $embedding = Aictio::getVectorEmbedding($query);
+
+ $search_result = new SearchResult;
+ $search_result->query = $query;
+ $search_result->counts = 1;
+ $search_result->embedding = $embedding;
+
+ if ($search_result->save()) {
+
+ }
+ }
+
+ $results = SearchEmbedding::query()
+ ->with('ai_tool')
+ ->selectRaw('DISTINCT ON (ai_tool_id) ai_tool_id, embedding <-> ? AS distance', [$embedding])
+ ->orderBy('ai_tool_id')
+ ->orderByRaw('embedding <-> ? ASC', [$embedding])
+ ->whereRaw('embedding <-> ? < 0.65', [$embedding])
+ ->where('ai_tool_id', '!=', null)
+ ->paginate($pagination_results);
+
+ //dd($results->toArray());
+
+ if ($results->total() < $pagination_results) {
+ // TODO: Signal Serp Crawling Engine
+ }
+
+ $query = strtolower(urldecode($query));
+
+ session()->put('query', $query);
+
+ SEOTools::metatags();
+ SEOTools::twitter();
+ SEOTools::opengraph();
+ SEOTools::jsonLd();
+ SEOTools::setTitle(ucwords($query).' AI Tool');
+
+ $breadcrumbs = collect([
+ ['name' => 'Home', 'url' => route('front.home')],
+ ['name' => 'AI Tool Search', 'url' => null],
+ ['name' => ucwords($query), 'url' => null],
+ ]);
+
+ // breadcrumb json ld
+ $listItems = [];
+
+ foreach ($breadcrumbs as $index => $breadcrumb) {
+ $listItems[] = [
+ 'name' => $breadcrumb['name'],
+ 'url' => $breadcrumb['url'],
+ ];
+ }
+
+ $breadcrumb_context = Context::create('breadcrumb_list', [
+ 'itemListElement' => $listItems,
+ ]);
+
+ return view('front.search_results', compact('results', 'query', 'breadcrumbs', 'breadcrumb_context'));
+
+ }
}
diff --git a/app/Http/Controllers/Front/FrontToolController.php b/app/Http/Controllers/Front/FrontToolController.php
new file mode 100644
index 0000000..50a324d
--- /dev/null
+++ b/app/Http/Controllers/Front/FrontToolController.php
@@ -0,0 +1,81 @@
+first();
+
+ if (is_null($ai_tool)) {
+ return abort(404);
+ }
+
+ $ai_tool->load('category');
+
+ $breadcrumbs = collect([
+ ['name' => 'Home', 'url' => route('front.home')],
+ ['name' => 'AI Tools', 'url' => route('front.discover.home')],
+ ['name' => $ai_tool->category->name, 'url' => route('front.discover.category', ['category_slug' => $ai_tool->category->slug])],
+ ['name' => $ai_tool->tool_name, 'url' => null],
+ ]);
+
+ // breadcrumb json ld
+ $listItems = [];
+
+ foreach ($breadcrumbs as $index => $breadcrumb) {
+ $listItems[] = [
+ 'name' => $breadcrumb['name'],
+ 'url' => $breadcrumb['url'],
+ ];
+ }
+
+ $breadcrumb_context = Context::create('breadcrumb_list', [
+ 'itemListElement' => $listItems,
+ ]);
+
+ $applicationCategory = '';
+
+ if ($ai_tool->is_app_web_both == 'both') {
+ $applicationCategory = 'App & Web Application';
+ } else {
+ $applicationCategory = ucwords($ai_tool->is_app_web_both).' Application';
+ }
+
+ $qnaMainEntity = [];
+
+ foreach ($ai_tool->qna as $qna) {
+ $qnaMainEntity[] = [
+ '@type' => 'Question',
+ 'name' => $qna->q,
+ 'acceptedAnswer' => [
+ '@type' => 'Answer',
+ 'text' => $qna->a,
+ ],
+ ];
+ }
+
+ $faqData = [
+ 'mainEntity' => $qnaMainEntity,
+ ];
+
+ $faq_context = Context::create(FAQPage::class, $faqData);
+
+ SEOTools::metatags();
+ SEOTools::twitter()->addImage($ai_tool->screenshot_img);
+ SEOTools::opengraph()->addImage($ai_tool->screenshot_img);
+ SEOTools::jsonLd()->addImage($ai_tool->screenshot_img);
+
+ //dd($faq_context);
+
+ return view('front.aitool', compact('ai_tool', 'breadcrumb_context', 'breadcrumbs', 'faq_context'));
+ }
+}
diff --git a/app/Jobs/Tasks/GetAIToolScreenshotTask.php b/app/Jobs/Tasks/GetAIToolScreenshotTask.php
index a33ac2b..d47fc39 100644
--- a/app/Jobs/Tasks/GetAIToolScreenshotTask.php
+++ b/app/Jobs/Tasks/GetAIToolScreenshotTask.php
@@ -4,8 +4,6 @@
use App\Helpers\FirstParty\OSSUploader\OSSUploader;
use App\Models\AiTool;
-use App\Models\BusinessProfile;
-use App\Models\SerpUrl;
use App\Models\UrlToCrawl;
use Exception;
use Image;
@@ -13,25 +11,21 @@
class GetAIToolScreenshotTask
{
-
public static function handle($url_to_crawl_id, $ai_tool_id)
{
$url_to_crawl = UrlToCrawl::find($url_to_crawl_id);
- if (is_null($url_to_crawl))
- {
- return ;
+ if (is_null($url_to_crawl)) {
+ return;
}
$ai_tool = AiTool::find($ai_tool_id);
- if (is_null($ai_tool))
- {
- return ;
+ if (is_null($ai_tool)) {
+ return;
}
- $userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";
-
+ $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36';
$browsershot = Browsershot::url($url_to_crawl->url)
->timeout(30)
diff --git a/app/Jobs/Tasks/GetUrlBodyTask.php b/app/Jobs/Tasks/GetUrlBodyTask.php
index ef43001..b6b5db2 100644
--- a/app/Jobs/Tasks/GetUrlBodyTask.php
+++ b/app/Jobs/Tasks/GetUrlBodyTask.php
@@ -23,25 +23,29 @@ public static function handle(int $url_to_crawl_id)
return null;
}
+ $enable_proxy = false;
+
$url_to_crawl->is_crawling = true;
$url_to_crawl->save();
$url_to_crawl->refresh();
- try {
- $user_agent = config('platform.proxy.user_agent');
+ // try {
+ $user_agent = config('platform.proxy.user_agent');
- $response = Http::withHeaders([
- 'User-Agent' => $user_agent,
+ $response = Http::withHeaders([
+ 'User-Agent' => $user_agent,
+ ])
+ ->withOptions([
+ 'proxy' => ($enable_proxy) ? get_smartproxy_rotating_server() : null,
+ 'timeout' => 10,
+ 'verify' => false,
])
- ->withOptions([
- 'proxy' => get_smartproxy_rotating_server(),
- 'timeout' => 10,
- 'verify' => false,
- ])
- ->get($url_to_crawl->url);
+ ->get($url_to_crawl->url);
- if ($response->successful()) {
- $raw_html = $response->body();
+ if ($response->successful()) {
+ $raw_html = $response->body();
+ if ($enable_proxy)
+ {
$cost = calculate_smartproxy_cost(round(strlen($raw_html) / 1024, 2), 'rotating_global');
$service_cost_usage = new ServiceCostUsage;
@@ -51,17 +55,19 @@ public static function handle(int $url_to_crawl_id)
$service_cost_usage->reference_2 = strval($url_to_crawl_id);
$service_cost_usage->output = self::getMarkdownFromHtml($raw_html);
$service_cost_usage->save();
-
- } else {
- $raw_html = null;
- $response->throw();
}
- } catch (Exception $e) {
+
+ } else {
$raw_html = null;
- //throw $e;
+ $response->throw();
}
+ // } catch (Exception $e) {
+ // $raw_html = null;
+ // //throw $e;
+ // }
+
if (! is_empty($raw_html)) {
$url_to_crawl->output_type = 'markdown';
$url_to_crawl->output = self::getMarkdownFromHtml($raw_html);
diff --git a/app/Jobs/Tasks/ParseUrlBodyTask.php b/app/Jobs/Tasks/ParseUrlBodyTask.php
index 45605b7..70172af 100644
--- a/app/Jobs/Tasks/ParseUrlBodyTask.php
+++ b/app/Jobs/Tasks/ParseUrlBodyTask.php
@@ -65,23 +65,28 @@ public static function handle(int $url_to_crawl_id)
$ai_tool->url_to_crawl_id = $url_to_crawl->id;
}
+ $ai_tool->external_url = $url_to_crawl->url;
+
// Tool Name
- if ((isset($url_meta_response->output->tool_name)) && (! is_empty($url_meta_response->output->tool_name))) {
- $ai_tool->tool_name = $url_meta_response->output->tool_name;
+ if ((isset($url_meta_response->output->ai_tool_name)) && (! is_empty($url_meta_response->output->ai_tool_name))) {
+ $ai_tool->tool_name = $url_meta_response->output->ai_tool_name;
+ $ai_tool->slug = epoch_now_timestamp(1).'-'.str_slug($url_meta_response->output->ai_tool_name);
} else {
throw new Exception('OpenAI::getSiteSummary failed, no tool name');
}
// Is AI Tool
- if ((isset($url_meta_response->output->is_ai_tool)) && (! is_null($url_meta_response->output->is_at_tool)) && is_bool($url_meta_response->output->is_ai_tool)) {
+ if ((isset($url_meta_response->output->is_ai_tool)) && (! is_null($url_meta_response->output->is_ai_tool)) && is_bool($url_meta_response->output->is_ai_tool)) {
$ai_tool->is_ai_tool = $url_meta_response->output->is_ai_tool;
} else {
$ai_tool->is_ai_tool = true;
}
// Is App/Web/Both
- if ((isset($url_meta_response->output->is_app_web_both)) && (is_array($url_meta_response->output->is_app_web_both)) && in_array($url_meta_response->output->is_app_web_both, ['app', 'web', 'both'])) {
+ if ((isset($url_meta_response->output->is_app_web_both)) && (! is_empty($url_meta_response->output->is_app_web_both)) && in_array($url_meta_response->output->is_app_web_both, ['app', 'web', 'both'])) {
$ai_tool->is_app_web_both = $url_meta_response->output->is_app_web_both;
+ } else {
+ $ai_tool->is_app_web_both = 'web';
}
// Tagline
@@ -130,9 +135,8 @@ public static function handle(int $url_to_crawl_id)
$query = $ai_tool->tool_name;
- if (!is_empty($ai_tool->tagline))
- {
- $query .= ": " . $ai_tool->tagline;
+ if (! is_empty($ai_tool->tagline)) {
+ $query .= ': '.$ai_tool->tagline;
}
StoreSearchEmbeddingJob::dispatch(
@@ -176,8 +180,7 @@ public static function handle(int $url_to_crawl_id)
// Q&A
if ((isset($url_meta_response->output->qna)) && (is_array($url_meta_response->output->qna))) {
- foreach ($url_meta_response->output->qna as $qna)
- {
+ foreach ($url_meta_response->output->qna as $qna) {
$q = $qna->q;
$a = $qna->a;
@@ -187,7 +190,7 @@ public static function handle(int $url_to_crawl_id)
'qna',
$ai_tool->category_id,
$ai_tool->id,
- ($qna->q . " " . $qna->a)
+ ($qna->q.' '.$qna->a)
);
}
}
diff --git a/app/JsonLd/FAQPage.php b/app/JsonLd/FAQPage.php
new file mode 100644
index 0000000..f40a049
--- /dev/null
+++ b/app/JsonLd/FAQPage.php
@@ -0,0 +1,17 @@
+ [],
+ ];
+
+ protected function setMainEntityAttribute($value)
+ {
+ return (array) $value;
+ }
+}
diff --git a/app/JsonLd/SoftwareApplication.php b/app/JsonLd/SoftwareApplication.php
new file mode 100644
index 0000000..0434dd0
--- /dev/null
+++ b/app/JsonLd/SoftwareApplication.php
@@ -0,0 +1,77 @@
+ null,
+ 'description' => null,
+ 'url' => null,
+ 'applicationCategory' => null,
+ 'screenshot' => ImageObject::class,
+ ];
+
+ /**
+ * Set the name attribute.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function setNameAttribute($value)
+ {
+ return (string) $value;
+ }
+
+ /**
+ * Set the description attribute.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function setDescriptionAttribute($value)
+ {
+ return $this->truncate($value, 260);
+ }
+
+ /**
+ * Set the url attribute.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function setUrlAttribute($value)
+ {
+ return (string) $value;
+ }
+
+ /**
+ * Set the application category attribute.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function setApplicationCategoryAttribute($value)
+ {
+ return (string) $value;
+ }
+
+ /**
+ * Set the screenshot attribute.
+ *
+ * @param ImageObject|array $value
+ * @return ImageObject
+ */
+ protected function setScreenshotAttribute($value)
+ {
+ return new ImageObject([$value]);
+ }
+}
diff --git a/app/Models/AiTool.php b/app/Models/AiTool.php
index 1d545c3..e7ce55d 100644
--- a/app/Models/AiTool.php
+++ b/app/Models/AiTool.php
@@ -7,12 +7,14 @@
namespace App\Models;
use Carbon\Carbon;
+use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Facades\Storage;
/**
* Class AiTool
- *
+ *
* @property int $id
* @property int $category_id
* @property int $url_to_crawl_id
@@ -27,56 +29,72 @@
* @property string|null $qna
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
- *
* @property Category $category
* @property UrlToCrawl $url_to_crawl
* @property Collection|SearchEmbedding[] $search_embeddings
* @property Collection|AiToolKeyword[] $ai_tool_keywords
- *
- * @package App\Models
*/
class AiTool extends Model
{
- protected $table = 'ai_tools';
+ protected $table = 'ai_tools';
- protected $casts = [
- 'category_id' => 'int',
- 'url_to_crawl_id' => 'int',
- 'is_ai_tool' => 'bool',
- 'qna' => 'object'
- ];
+ protected $casts = [
+ 'category_id' => 'int',
+ 'url_to_crawl_id' => 'int',
+ 'view_count' => 'int',
+ 'is_ai_tool' => 'bool',
+ 'qna' => 'object',
+ ];
- protected $fillable = [
- 'category_id',
- 'url_to_crawl_id',
- 'screenshot_img',
- 'is_ai_tool',
- 'tool_name',
- 'is_app_web_both',
- 'tagline',
- 'summary',
- 'pricing_type',
- 'keyword_string',
- 'qna'
- ];
+ protected $fillable = [
+ 'category_id',
+ 'url_to_crawl_id',
+ 'screenshot_img',
+ 'is_ai_tool',
+ 'tool_name',
+ 'slug',
+ 'is_app_web_both',
+ 'tagline',
+ 'summary',
+ 'pricing_type',
+ 'keyword_string',
+ 'view_count',
+ 'qna',
+ 'external_url
+ ',
+ ];
- public function category()
- {
- return $this->belongsTo(Category::class);
- }
+ protected function screenshotImg(): Attribute
+ {
+ return Attribute::make(
+ get: function ($value = null) {
+ if (! is_empty($value)) {
- public function url_to_crawl()
- {
- return $this->belongsTo(UrlToCrawl::class);
- }
+ return Storage::disk(config('platform.uploads.ai_tools.screenshot.driver'))->url(config('platform.uploads.ai_tools.screenshot.path').$value);
+ }
- public function search_embeddings()
- {
- return $this->hasMany(SearchEmbedding::class);
- }
+ return null;
+ }
+ );
+ }
- public function ai_tool_keywords()
- {
- return $this->hasMany(AiToolKeyword::class);
- }
+ public function category()
+ {
+ return $this->belongsTo(Category::class);
+ }
+
+ public function url_to_crawl()
+ {
+ return $this->belongsTo(UrlToCrawl::class);
+ }
+
+ public function search_embeddings()
+ {
+ return $this->hasMany(SearchEmbedding::class);
+ }
+
+ public function keywords()
+ {
+ return $this->hasMany(AiToolKeyword::class);
+ }
}
diff --git a/app/Models/SearchResult.php b/app/Models/SearchResult.php
new file mode 100644
index 0000000..9588c25
--- /dev/null
+++ b/app/Models/SearchResult.php
@@ -0,0 +1,41 @@
+ Vector::class,
+ 'indexed_at' => 'datetime',
+ 'counts' => 'int',
+ ];
+
+ protected $fillable = [
+ 'query',
+ 'embedding',
+ 'indexed_at',
+ 'counts',
+ ];
+}
diff --git a/app/Models/ServiceCostUsage.php b/app/Models/ServiceCostUsage.php
index 920b598..4add750 100644
--- a/app/Models/ServiceCostUsage.php
+++ b/app/Models/ServiceCostUsage.php
@@ -29,7 +29,7 @@ class ServiceCostUsage extends Model
protected $casts = [
'cost' => 'float',
- 'output' => 'binary',
+ 'output' => 'object',
];
protected $fillable = [
diff --git a/composer.json b/composer.json
index cd90ff1..d9ca3c7 100644
--- a/composer.json
+++ b/composer.json
@@ -28,6 +28,7 @@
"laravel/tinker": "^2.8",
"laravel/ui": "^4.0",
"league/flysystem-aws-s3-v3": "^3.0",
+ "league/html-to-markdown": "^5.1",
"masterminds/html5": "^2.8",
"mews/purifier": "^3.4",
"pfaciana/tiny-html-minifier": "^3.0",
diff --git a/composer.lock b/composer.lock
index 754a1e9..3ab8ca6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "2b41c19d85eb74a7fb7b976437ef4861",
+ "content-hash": "84f90f6b5010de195dcd0fead0d21daf",
"packages": [
{
"name": "alaminfirdows/laravel-editorjs",
@@ -3516,6 +3516,95 @@
},
"time": "2023-07-08T06:26:07+00:00"
},
+ {
+ "name": "league/html-to-markdown",
+ "version": "5.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/html-to-markdown.git",
+ "reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0b4066eede55c48f38bcee4fb8f0aa85654390fd",
+ "reference": "0b4066eede55c48f38bcee4fb8f0aa85654390fd",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xml": "*",
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "mikehaertl/php-shellcommand": "^1.1.0",
+ "phpstan/phpstan": "^1.8.8",
+ "phpunit/phpunit": "^8.5 || ^9.2",
+ "scrutinizer/ocular": "^1.6",
+ "unleashedtech/php-coding-standard": "^2.7 || ^3.0",
+ "vimeo/psalm": "^4.22 || ^5.0"
+ },
+ "bin": [
+ "bin/html-to-markdown"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.2-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\HTMLToMarkdown\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Colin O'Dell",
+ "email": "colinodell@gmail.com",
+ "homepage": "https://www.colinodell.com",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Nick Cernis",
+ "email": "nick@cern.is",
+ "homepage": "http://modernnerd.net",
+ "role": "Original Author"
+ }
+ ],
+ "description": "An HTML-to-markdown conversion helper for PHP",
+ "homepage": "https://github.com/thephpleague/html-to-markdown",
+ "keywords": [
+ "html",
+ "markdown"
+ ],
+ "support": {
+ "issues": "https://github.com/thephpleague/html-to-markdown/issues",
+ "source": "https://github.com/thephpleague/html-to-markdown/tree/5.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://www.colinodell.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://www.paypal.me/colinpodell/10.00",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/colinodell",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-07-12T21:21:09+00:00"
+ },
{
"name": "league/mime-type-detection",
"version": "1.14.0",
diff --git a/config/platform/ai.php b/config/platform/ai.php
index c30e042..cd35fa8 100644
--- a/config/platform/ai.php
+++ b/config/platform/ai.php
@@ -6,4 +6,42 @@
'api_key' => env('OPENAI_API_KEY'),
],
+ // GPT 4
+ 'openai-gpt-4-turbo' => [
+ 'tokens' => 128000,
+ 'model' => 'gpt-4-1106-preview',
+ 'input_cost_per_thousand_tokens' => 0.01,
+ 'output_cost_per_thousand_tokens' => 0.03,
+ ],
+
+ 'openai-gpt-4' => [
+ 'tokens' => 8192,
+ 'model' => 'gpt-4-0613',
+ 'input_cost_per_thousand_tokens' => 0.03,
+ 'output_cost_per_thousand_tokens' => 0.06,
+ ],
+
+ // GPT 3.5
+
+ 'openai-gpt-3-5-turbo-1106' => [
+ 'tokens' => 16385,
+ 'model' => 'gpt-3.5-turbo-1106',
+ 'input_cost_per_thousand_tokens' => 0.0010,
+ 'output_cost_per_thousand_tokens' => 0.002,
+ ],
+
+ 'openai-3-5-turbo' => [
+ 'tokens' => 4096,
+ 'model' => 'gpt-3.5-turbo',
+ 'input_cost_per_thousand_tokens' => 0.0015,
+ 'output_cost_per_thousand_tokens' => 0.002,
+ ],
+
+ 'openai-3-5-turbo-16k' => [
+ 'tokens' => 16385,
+ 'model' => 'gpt-3.5-turbo-16k',
+ 'input_cost_per_thousand_tokens' => 0.003,
+ 'output_cost_per_thousand_tokens' => 0.004,
+ ],
+
];
diff --git a/config/seotools.php b/config/seotools.php
index 13b60a5..d95376d 100644
--- a/config/seotools.php
+++ b/config/seotools.php
@@ -11,9 +11,12 @@
'defaults' => [
'title' => 'AI Buddy Tools', // set false to total remove
'titleBefore' => false, // Put defaults.title before page title, like 'It's Over 9000! - Dashboard'
- 'description' => 'The leading AI tools directory and search engine, Discover the best AI tools, apps and services list and take your business to the next level.', // set false to total remove
+ 'description' => 'Your friendly AI tool directory platform. Discover AI Tools for any task!', // set false to total remove
'separator' => ' - ',
- 'keywords' => [],
+ 'keywords' => [
+ 'ai tools directory',
+ 'yellow page ai tools',
+ ],
'canonical' => 'full', // Set to null or 'full' to use Url::full(), set to 'current' to use Url::current(), set false to total remove
'robots' => false, // Set to 'all', 'none' or any combination of index/noindex and follow/nofollow
],
@@ -36,12 +39,16 @@
* The default configurations to be used by the opengraph generator.
*/
'defaults' => [
- 'title' => 'AI Buddy Tools', // set false to total remove
- 'description' => 'The leading AI tools directory and search engine, Discover the best AI tools, apps and services list and take your business to the next level.', // set false to total remove
- 'url' => false, // Set null for using Url::current(), set false to total remove
+ 'title' => 'AI Buddy Tool', // set false to total remove
+ 'description' => 'Your friendly AI tool directory platform. Discover AI Tools for any task!', // set false to total remove
+ 'url' => null, // Set null for using Url::current(), set false to total remove
'type' => false,
- 'site_name' => false,
- 'images' => [],
+ 'site_name' => 'AI Buddy Tool',
+ 'images' => [
+ 'https://cdn.aibuddytool.com/aibuddytool-og.webp',
+ 'https://cdn.aibuddytool.com/aibuddytool-og.png',
+ 'https://cdn.aibuddytool.com/aibuddytool-og.jpg'
+ ],
],
],
'twitter' => [
@@ -58,11 +65,15 @@
* The default configurations to be used by the json-ld generator.
*/
'defaults' => [
- 'title' => 'AI Buddy Tools', // set false to total remove
- 'description' => 'The leading AI tools directory and search engine, Discover the best AI tools, apps and services list and take your business to the next level.', // set false to total remove
- 'url' => false, // Set to null or 'full' to use Url::full(), set to 'current' to use Url::current(), set false to total remove
+ 'title' => 'AI Buddy Tool', // set false to total remove
+ 'description' => 'Your friendly AI tool directory platform. Discover AI Tools for any task!', // set false to total remove
+ 'url' => 'current', // Set to null or 'full' to use Url::full(), set to 'current' to use Url::current(), set false to total remove
'type' => 'WebPage',
- 'images' => [],
+ 'images' => [
+ 'https://cdn.aibuddytool.com/aibuddytool-og.webp',
+ 'https://cdn.aibuddytool.com/aibuddytool-og.png',
+ 'https://cdn.aibuddytool.com/aibuddytool-og.jpg'
+ ],
],
],
];
diff --git a/database/migrations/2023_11_26_071759_create_ai_tools_table.php b/database/migrations/2023_11_26_071759_create_ai_tools_table.php
index 37eafe8..72b9a81 100644
--- a/database/migrations/2023_11_26_071759_create_ai_tools_table.php
+++ b/database/migrations/2023_11_26_071759_create_ai_tools_table.php
@@ -17,10 +17,14 @@ public function up(): void
$table->foreignId('category_id');
$table->foreignId('url_to_crawl_id');
+ $table->string('view_count')->default(0);
+
$table->string('screenshot_img')->nullable();
$table->boolean('is_ai_tool')->default(true);
$table->string('tool_name');
+ $table->string('slug');
+ $table->string('external_url');
$table->string('is_app_web_both');
$table->text('tagline')->nullable();
@@ -32,6 +36,9 @@ public function up(): void
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('url_to_crawl_id')->references('id')->on('url_to_crawls');
+
+ $table->index('view_count');
+ $table->index('slug');
});
}
diff --git a/database/migrations/2023_11_26_072107_create_ai_tool_keywords_table.php b/database/migrations/2023_11_26_072107_create_ai_tool_keywords_table.php
index c048b66..9b11090 100644
--- a/database/migrations/2023_11_26_072107_create_ai_tool_keywords_table.php
+++ b/database/migrations/2023_11_26_072107_create_ai_tool_keywords_table.php
@@ -24,6 +24,8 @@ public function up(): void
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('ai_tool_id')->references('id')->on('ai_tools');
+
+ $table->index('ai_tool_id');
});
}
diff --git a/database/migrations/2023_11_26_072145_create_search_embeddings_table.php b/database/migrations/2023_11_26_072145_create_search_embeddings_table.php
index 9bea264..e57c3be 100644
--- a/database/migrations/2023_11_26_072145_create_search_embeddings_table.php
+++ b/database/migrations/2023_11_26_072145_create_search_embeddings_table.php
@@ -2,6 +2,7 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
@@ -25,7 +26,11 @@ public function up(): void
$table->foreign('ai_tool_id')->references('id')->on('ai_tools');
$table->foreign('category_id')->references('id')->on('categories');
+
});
+
+ DB::statement('CREATE INDEX search_embeddings_embedding_idx ON search_embeddings USING ivfflat (embedding vector_l2_ops) WITH (lists = 100)');
+
}
/**
diff --git a/database/migrations/2023_11_27_034006_create_search_results_table.php b/database/migrations/2023_11_27_034006_create_search_results_table.php
new file mode 100644
index 0000000..cf5e277
--- /dev/null
+++ b/database/migrations/2023_11_27_034006_create_search_results_table.php
@@ -0,0 +1,35 @@
+id();
+ $table->string('query');
+ $table->vector('embedding', 384)->nullable();
+ $table->datetime('indexed_at')->nullable();
+ $table->bigInteger('counts')->default(1);
+ $table->timestamps();
+ });
+
+ DB::statement('CREATE INDEX search_results_embedding_idx ON search_results USING ivfflat (embedding vector_l2_ops) WITH (lists = 100)');
+
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('search_results');
+ }
+};
diff --git a/database/seeders/ParentCategorySeeder.php b/database/seeders/ParentCategorySeeder.php
index fbdc988..3122318 100644
--- a/database/seeders/ParentCategorySeeder.php
+++ b/database/seeders/ParentCategorySeeder.php
@@ -45,8 +45,8 @@ public function run(): void
['name' => 'Content Generation', 'emoji' => '📝', 'is_top' => true],
['name' => 'Support', 'emoji' => '🛠️', 'is_top' => false],
['name' => 'Health', 'emoji' => '🍏', 'is_top' => false],
- ['name' => 'Networking', 'emoji' => '🔗', 'is_top' => false],
- ['name' => 'Personal Assistance', 'emoji' => '🤝', 'is_top' => false],
+ ['name' => 'Networking', 'emoji' => '🤝', 'is_top' => false],
+ ['name' => 'Personal Assistance', 'emoji' => '📱', 'is_top' => false],
['name' => 'Planning', 'emoji' => '📅', 'is_top' => false],
['name' => 'Project Management', 'emoji' => '📈', 'is_top' => false],
['name' => 'Reporting', 'emoji' => '📑', 'is_top' => false],
diff --git a/public/ai-buddy-tool-logo-1024x1024.png b/public/ai-buddy-tool-logo-1024x1024.png
new file mode 100644
index 0000000..7adaef7
Binary files /dev/null and b/public/ai-buddy-tool-logo-1024x1024.png differ
diff --git a/public/ai-buddy-tool-logo-1024x1024.svg b/public/ai-buddy-tool-logo-1024x1024.svg
new file mode 100644
index 0000000..d1a2cfb
--- /dev/null
+++ b/public/ai-buddy-tool-logo-1024x1024.svg
@@ -0,0 +1,59 @@
+
diff --git a/public/ai-buddy-tool-logo-512x512.png b/public/ai-buddy-tool-logo-512x512.png
new file mode 100644
index 0000000..ab0137d
Binary files /dev/null and b/public/ai-buddy-tool-logo-512x512.png differ
diff --git a/public/ai-buddy-tool-logo-512x512.svg b/public/ai-buddy-tool-logo-512x512.svg
new file mode 100644
index 0000000..8187557
--- /dev/null
+++ b/public/ai-buddy-tool-logo-512x512.svg
@@ -0,0 +1,64 @@
+
diff --git a/public/aibuddytool-og.jpg b/public/aibuddytool-og.jpg
new file mode 100644
index 0000000..be51e78
Binary files /dev/null and b/public/aibuddytool-og.jpg differ
diff --git a/public/aibuddytool-og.png b/public/aibuddytool-og.png
new file mode 100644
index 0000000..380f436
Binary files /dev/null and b/public/aibuddytool-og.png differ
diff --git a/public/aibuddytool-og.webp b/public/aibuddytool-og.webp
new file mode 100644
index 0000000..4e5c25d
Binary files /dev/null and b/public/aibuddytool-og.webp differ
diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png
index 685d5e5..bd3f1a1 100644
Binary files a/public/android-chrome-192x192.png and b/public/android-chrome-192x192.png differ
diff --git a/public/android-chrome-512x512.png b/public/android-chrome-512x512.png
index fde46e8..3ccf4db 100644
Binary files a/public/android-chrome-512x512.png and b/public/android-chrome-512x512.png differ
diff --git a/public/android-chrome-maskable-192x192.png b/public/android-chrome-maskable-192x192.png
new file mode 100644
index 0000000..53f5498
Binary files /dev/null and b/public/android-chrome-maskable-192x192.png differ
diff --git a/public/android-chrome-maskable-512x512.png b/public/android-chrome-maskable-512x512.png
new file mode 100644
index 0000000..3ccf4db
Binary files /dev/null and b/public/android-chrome-maskable-512x512.png differ
diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
index 2c385ca..4a8d88d 100644
Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ
diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png
deleted file mode 100644
index a8154e3..0000000
Binary files a/public/favicon-16x16.png and /dev/null differ
diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png
deleted file mode 100644
index b00018b..0000000
Binary files a/public/favicon-32x32.png and /dev/null differ
diff --git a/public/favicon.ico b/public/favicon.ico
index 78e4bd0..a91b12e 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/featured-on-aibuddytool-1-1000.png b/public/featured-on-aibuddytool-1-1000.png
new file mode 100644
index 0000000..2f51fca
Binary files /dev/null and b/public/featured-on-aibuddytool-1-1000.png differ
diff --git a/public/featured-on-aibuddytool-1-1000.webp b/public/featured-on-aibuddytool-1-1000.webp
new file mode 100644
index 0000000..aa688df
Binary files /dev/null and b/public/featured-on-aibuddytool-1-1000.webp differ
diff --git a/public/icon-128x128.png b/public/icon-128x128.png
deleted file mode 100644
index 866f153..0000000
Binary files a/public/icon-128x128.png and /dev/null differ
diff --git a/public/icon-144x144.png b/public/icon-144x144.png
deleted file mode 100644
index 14b12ed..0000000
Binary files a/public/icon-144x144.png and /dev/null differ
diff --git a/public/icon-152x152.png b/public/icon-152x152.png
deleted file mode 100644
index 6096a40..0000000
Binary files a/public/icon-152x152.png and /dev/null differ
diff --git a/public/icon-192x192.png b/public/icon-192x192.png
deleted file mode 100644
index 7e6524f..0000000
Binary files a/public/icon-192x192.png and /dev/null differ
diff --git a/public/icon-384x384.png b/public/icon-384x384.png
deleted file mode 100644
index 456550d..0000000
Binary files a/public/icon-384x384.png and /dev/null differ
diff --git a/public/icon-48x48.png b/public/icon-48x48.png
deleted file mode 100644
index e17462f..0000000
Binary files a/public/icon-48x48.png and /dev/null differ
diff --git a/public/icon-512x512.png b/public/icon-512x512.png
deleted file mode 100644
index 801fd81..0000000
Binary files a/public/icon-512x512.png and /dev/null differ
diff --git a/public/icon-570x570.png b/public/icon-570x570.png
deleted file mode 100644
index 75e8c5e..0000000
Binary files a/public/icon-570x570.png and /dev/null differ
diff --git a/public/icon-72x72.png b/public/icon-72x72.png
deleted file mode 100644
index 66df1fb..0000000
Binary files a/public/icon-72x72.png and /dev/null differ
diff --git a/public/icon-96x96.png b/public/icon-96x96.png
deleted file mode 100644
index 2249643..0000000
Binary files a/public/icon-96x96.png and /dev/null differ
diff --git a/public/site.webmanifest b/public/site.webmanifest
index 45dc8a2..5289599 100644
--- a/public/site.webmanifest
+++ b/public/site.webmanifest
@@ -1 +1 @@
-{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
+{"name":"AI Buddy Tool","short_name":"AI Buddy","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
\ No newline at end of file
diff --git a/resources/js/FrontApp.vue b/resources/js/FrontApp.vue
new file mode 100644
index 0000000..6b4f436
--- /dev/null
+++ b/resources/js/FrontApp.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/resources/js/app-front.js b/resources/js/app-front.js
index 93349a7..7ea68be 100644
--- a/resources/js/app-front.js
+++ b/resources/js/app-front.js
@@ -1 +1,57 @@
-import * as bootstrap from "~bootstrap";
+import "@tabler/core/src/js/tabler.js";
+
+import "./bootstrap";
+
+import { createApp, defineAsyncComponent } from "vue";
+
+import FrontApp from "@/FrontApp.vue";
+
+const app = createApp({ FrontApp });
+const vueComponents = import.meta.glob("@/vue/**/*.vue", {
+ eager: false,
+});
+
+console.log(vueComponents);
+
+import.meta.glob(["../images/**", "../fonts/**"]);
+
+import { createPinia } from "pinia";
+app.use(createPinia());
+
+import axios from "./plugins/axios";
+import VueAxios from "vue-axios";
+app.use(VueAxios, axios);
+
+import auth from "./plugins/auth";
+app.use(auth);
+
+import eventBus from "./plugins/event-bus";
+app.use(eventBus);
+
+import Vue3Toastify from "vue3-toastify";
+import "../css/toastify.css";
+app.use(Vue3Toastify);
+
+import { Ziggy as ZiggyRoute } from "./ziggy";
+import { ZiggyVue } from "ziggy-js/dist/vue";
+app.use(ZiggyVue, ZiggyRoute);
+
+window.Ziggy = ZiggyRoute;
+
+Object.entries({ ...vueComponents }).forEach(([path, definition]) => {
+ // Get name of component, based on filename
+ // "./components/Fruits.vue" will become "Fruits"
+ const componentName = path
+ .split("/")
+ .pop()
+ .replace(/\.\w+$/, "")
+ .replace(/([a-z])([A-Z])/g, "$1-$2")
+ .toLowerCase();
+ // console.log(componentName);
+ // console.log(typeof definition);
+
+ // Register component on this Vue instance
+ app.component(componentName, defineAsyncComponent(definition));
+});
+
+app.mount("#app");
diff --git a/resources/js/vue/GetEmbedCode.vue b/resources/js/vue/GetEmbedCode.vue
new file mode 100644
index 0000000..55ed7bf
--- /dev/null
+++ b/resources/js/vue/GetEmbedCode.vue
@@ -0,0 +1,75 @@
+
+
+
+
| Pricing Structure | +{{ $ai_tool->pricing_type }} | +
|---|---|
| AI Tool Platform | ++ @if ($ai_tool->is_app_web_both == 'both') + App & Web + @else + {{ ucwords($ai_tool->is_app_web_both) }} Only + @endif + | +
😱 Yikes!
+This is embarassing, there are no AI tools in this category yet.
We will find
+ more AI to add here. In the meantime:
Featured AI Tools
-Featured AI Tools
+
+
+
{{ config('app.name') }}
+
Rewin.ai is an AI tool that helps content creators generate unique and engaging scripts - for their chicken rice that is very tasty.
- -{!! str_first_sentence($ai_tool->summary) !!}
++ @foreach (str_extract_sentences($result->ai_tool->summary, 2) as $sentence) + {!! $sentence !!} + @endforeach +
+ ++ {!! __('Showing') !!} + {{ $paginator->firstItem() }} + {!! __('to') !!} + {{ $paginator->lastItem() }} + {{-- {!! __('of') !!} + {{ $paginator->total() }} --}} + {!! __('results') !!} +
+@endif diff --git a/resources/views/vendor/pagination/bootstrap-5.blade.php b/resources/views/vendor/pagination/bootstrap-5.blade.php new file mode 100644 index 0000000..4904c12 --- /dev/null +++ b/resources/views/vendor/pagination/bootstrap-5.blade.php @@ -0,0 +1,94 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/default.blade.php b/resources/views/vendor/pagination/default.blade.php new file mode 100644 index 0000000..9399131 --- /dev/null +++ b/resources/views/vendor/pagination/default.blade.php @@ -0,0 +1,47 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/semantic-ui.blade.php b/resources/views/vendor/pagination/semantic-ui.blade.php new file mode 100644 index 0000000..af16ede --- /dev/null +++ b/resources/views/vendor/pagination/semantic-ui.blade.php @@ -0,0 +1,40 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-4.blade.php b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php new file mode 100644 index 0000000..4bb4917 --- /dev/null +++ b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php @@ -0,0 +1,27 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-5.blade.php b/resources/views/vendor/pagination/simple-bootstrap-5.blade.php new file mode 100644 index 0000000..cf2e049 --- /dev/null +++ b/resources/views/vendor/pagination/simple-bootstrap-5.blade.php @@ -0,0 +1,30 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-default.blade.php b/resources/views/vendor/pagination/simple-default.blade.php new file mode 100644 index 0000000..36bdbc1 --- /dev/null +++ b/resources/views/vendor/pagination/simple-default.blade.php @@ -0,0 +1,19 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-tailwind.blade.php b/resources/views/vendor/pagination/simple-tailwind.blade.php new file mode 100644 index 0000000..18b6ef5 --- /dev/null +++ b/resources/views/vendor/pagination/simple-tailwind.blade.php @@ -0,0 +1,29 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/tailwind.blade.php b/resources/views/vendor/pagination/tailwind.blade.php new file mode 100644 index 0000000..647ec1f --- /dev/null +++ b/resources/views/vendor/pagination/tailwind.blade.php @@ -0,0 +1,130 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/routes/tests.php b/routes/tests.php index 5febfdb..224cbdd 100644 --- a/routes/tests.php +++ b/routes/tests.php @@ -21,12 +21,17 @@ $url_to_crawl = UrlToCrawl::find(1); - if (is_null($url_to_crawl)) - { - return ; + if (is_null($url_to_crawl)) { + return; } GetUrlBodyJob::dispatch($url_to_crawl->id)->onQueue('default')->onConnection('default'); return 'ok'; -}); \ No newline at end of file +}); + +Route::get('/epoch', function () { + + dd(epoch_now_timestamp(1)); + +}); diff --git a/routes/web.php b/routes/web.php index d25f593..a6cd0c0 100644 --- a/routes/web.php +++ b/routes/web.php @@ -51,6 +51,20 @@ }); +Route::prefix('ai-search')->group(function () { + + Route::post('/', [\App\Http\Controllers\Front\FrontSearchController::class, 'search'])->name('front.search.post'); + + Route::get('/{query}', [\App\Http\Controllers\Front\FrontSearchController::class, 'searchResult'])->name('front.search.results'); + +}); + +Route::prefix('ai-tool')->group(function () { + + Route::get('/{ai_tool_slug}', [\App\Http\Controllers\Front\FrontToolController::class, 'show'])->name('front.aitool.show'); + +}); + Route::get('/terms', [App\Http\Controllers\Front\FrontHomeController::class, 'terms'])->name('front.terms')->middleware('cacheResponse:2630000'); Route::get('/privacy', [App\Http\Controllers\Front\FrontHomeController::class, 'privacy'])->name('front.privacy')->middleware('cacheResponse:2630000');