Add (jsonld)

This commit is contained in:
2023-09-26 00:09:51 +08:00
parent 2c12b8857d
commit 8da977daeb
23 changed files with 238 additions and 85 deletions

View File

@@ -2,10 +2,9 @@
namespace App\Exceptions;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Throwable;
class Handler extends ExceptionHandler
@@ -36,7 +35,7 @@ public function register()
$this->renderable(function (NotFoundHttpException $e, $request) {
if ($request->is('api/*')) {
return response()->json([
'status' => -1
'status' => -1,
], 404);
}
});
@@ -52,21 +51,15 @@ public function register()
public function render($request, Throwable $exception)
{
if ($exception instanceof NotFoundHttpException)
{
if ($exception instanceof NotFoundHttpException) {
}
else if ($exception instanceof AuthenticationException)
{
} elseif ($exception instanceof AuthenticationException) {
}
else
{
} else {
inspector()->reportException($exception);
}
}
//default laravel response
return parent::render($request, $exception);
}
}

View File

@@ -4,12 +4,9 @@
use Exception;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class OpenAI
{
public static function writeArticle($title, $description, $article_type, $min, $max)
@@ -62,7 +59,6 @@ public static function createNewArticleTitle($current_title, $supporting_data)
return in following json format {\"main_keyword\":\"(Main Keyword)\",\"title\":\"(Title in 90-130 letters)\",\"short_title\":\"(Short Title in 30-40 letters)\",\"article_type\":\"(How-tos|Guides|Interview|Review|Commentary|Feature|News|Editorial|Report|Research|Case-study|Overview|Tutorial|Update|Spotlight|Insights)\",\"description\":\"(Cliffhanger SEO description based on main keyword, do not start with action verb)\",\"photo_keywords\":[\"photo keyword 1\",\"photo keyword 2\"]}";
$supporting_data = Str::substr($supporting_data, 0, 2100);
$user_prompt = "Article Title: {$current_title}\n Article Description: {$supporting_data}\n";
@@ -103,29 +99,26 @@ public static function suggestArticleTitles($current_title, $supporting_data, $s
public static function chatCompletion($system_prompt, $user_prompt, $model, $max_token = 2500)
{
try {
$response = Http::timeout(800)->withToken(config('platform.ai.openai.api_key'))
->post('https://api.openai.com/v1/chat/completions', [
'model' => $model,
'max_tokens' => $max_token,
'messages' => [
['role' => 'system', 'content' => $system_prompt],
['role' => 'user', 'content' => $user_prompt],
],
]);
$response = Http::timeout(800)->withToken(config('platform.ai.openai.api_key'))
->post('https://api.openai.com/v1/chat/completions', [
'model' => $model,
'max_tokens' => $max_token,
'messages' => [
['role' => 'system', 'content' => $system_prompt],
['role' => 'user', 'content' => $user_prompt],
],
]);
$json_response = json_decode($response->body());
$json_response = json_decode($response->body());
$reply = $json_response?->choices[0]?->message?->content;
$reply = $json_response?->choices[0]?->message?->content;
return $reply;
return $reply;
} catch (Exception $e) {
Log::error($response->body());
inspector()->reportException($e);
throw ($e);
}
catch(Exception $e) {
Log::error($response->body());
inspector()->reportException($e);
throw($e);
}
return null;

View File

@@ -5,13 +5,19 @@
use App\Http\Controllers\Controller;
use App\Models\Category;
use App\Models\Post;
use App\Models\PostCategory;
use Artesaos\SEOTools\Facades\SEOTools;
use Illuminate\Http\Request;
use JsonLd\Context;
class FrontListController extends Controller
{
public function index(Request $request)
{
$breadcrumbs = collect([
['name' => 'Home', 'url' => route('front.home')],
['name' => 'Latest News', 'url' => null], // or you can set a route for Latest News if there's a specific one
]);
$title = 'Latest News from EchoScoop';
@@ -23,23 +29,69 @@ public function index(Request $request)
$posts = Post::where('status', 'publish')->orderBy('published_at', 'desc')->simplePaginate(10) ?? collect();
return view('front.post_list', compact('posts'));
// 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.post_list', compact('posts', 'breadcrumbs', 'breadcrumb_context'));
}
public function category(Request $request, $category_slug)
{
// Fetch the category by slug
$category = Category::where('slug', $category_slug)->first();
$posts = $category?->posts()->where('status', 'publish')->orderBy('published_at', 'desc')->simplePaginate(10) ?? collect();
// Check if the category exists
if (! $category) {
abort(404, 'Category not found');
}
// Breadcrumb logic
$breadcrumbs = collect([['name' => 'Home', 'url' => route('front.home')]]);
foreach ($category->ancestors as $ancestor) {
$breadcrumbs->push(['name' => $ancestor->name, 'url' => route('front.category', $ancestor->slug)]);
}
$breadcrumbs->push(['name' => $category->name, 'url' => route('front.category', $category->slug)]);
// Get the IDs of the category and its descendants
$categoryIds = $category->descendants->pluck('id')->push($category->id);
// Get the posts associated with these category IDs
$postIds = PostCategory::whereIn('category_id', $categoryIds)->pluck('post_id');
$posts = Post::whereIn('id', $postIds)->where('status', 'publish')->orderBy('published_at', 'desc')->simplePaginate(10);
$title = $category->name.' News from EchoScoop';
SEOTools::metatags();
SEOTools::twitter();
SEOTools::opengraph();
SEOTools::jsonLd();
SEOTools::setTitle($title, false);
SEOTools::jsonLd();
return view('front.post_list', compact('category', 'posts'));
// 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.post_list', compact('category', 'posts', 'breadcrumbs', 'breadcrumb_context'));
}
}

View File

@@ -9,6 +9,7 @@
use Artesaos\SEOTools\Facades\SEOMeta;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Http\Request;
use JsonLd\Context;
use Symfony\Component\DomCrawler\Crawler;
class FrontPostController extends Controller
@@ -25,11 +26,36 @@ public function index(Request $request, $slug)
//dd($content);
$content = $this->injectBootstrapClasses($content);
$content = $this->injectTableOfContents($content);
$content = $this->injectFeaturedImage($post, $content);
$content = $this->injectPublishDateAndAuthor($post, $content);
$content = $this->injectTableOfContents($content);
$post_description = $post->excerpt.' '.$post->title.' by EchoScoop.';
// Generate breadcrumb data
$breadcrumbs = collect([
['name' => 'Home', 'url' => route('front.home')],
]);
if ($post->category) {
foreach ($post->category->ancestors as $ancestor) {
$breadcrumbs->push([
'name' => $ancestor->name,
'url' => route('front.category', $ancestor->slug),
]);
}
$breadcrumbs->push([
'name' => $post->category->name,
'url' => route('front.category', $post->category->slug),
]);
}
$breadcrumbs->push([
'name' => $post->title,
'url' => url()->current(), // The current page URL; the breadcrumb is not clickable
]);
SEOMeta::setTitle($post->title, false);
SEOMeta::setDescription($post_description);
SEOMeta::addMeta('article:published_time', $post->published_at->format('Y-m-d'), 'property');
@@ -68,7 +94,21 @@ public function index(Request $request, $slug)
->addValue('description', $post_description)
->addValue('articleBody', trim(preg_replace('/\s\s+/', ' ', strip_tags($content))));
return view('front.single_post', compact('post', 'content'));
// 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.single_post', compact('post', 'content', 'breadcrumbs', 'breadcrumb_context'));
}
private function injectBootstrapClasses($content)
@@ -77,7 +117,7 @@ private function injectBootstrapClasses($content)
// Handle Headings
$crawler->filter('h1')->each(function (Crawler $node) {
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' display-6 fw-bolder mt-3 mb-4'));
$node->getNode(0)->setAttribute('class', trim($node->attr('class').' display-6 fw-bolder mt-3 mb-2'));
});
$crawler->filter('h2')->each(function (Crawler $node) {
@@ -171,6 +211,20 @@ private function injectTableOfContents($html)
return $updatedHtml;
}
private function injectPublishDateAndAuthor($post, $content)
{
$publishedAtFormatted = $post->published_at->format('F j, Y');
$authorName = $post->author->name;
// Create the HTML structure for publish date and author
$publishInfo = "<div class=\"mb-4\"><span class=\"text-secondary small\">Published on {$publishedAtFormatted} by {$authorName}</span></div>";
// Inject the publish date and author information after the `h1` tag
$content = preg_replace('/(<\/h1>)/', '$1'.$publishInfo, $content, 1);
return $content;
}
private function injectFeaturedImage($post, $content)
{
if (! empty($post->featured_image)) {