141 lines
4.4 KiB
PHP
141 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs\Tasks;
|
|
|
|
use App\Helpers\FirstParty\OpenAI\OpenAI;
|
|
use App\Jobs\FillPostMetadataJob;
|
|
use App\Models\Post;
|
|
use App\Models\SerpUrl;
|
|
use App\Models\SerpUrlResearch;
|
|
use App\Models\ServiceCostUsage;
|
|
use Exception;
|
|
use Mis3085\Tiktoken\Facades\Tiktoken;
|
|
|
|
class WriteWithAITask
|
|
{
|
|
public static function handle(int $serp_url_id)
|
|
{
|
|
$serp_url = SerpUrl::find($serp_url_id);
|
|
|
|
if (is_null($serp_url)) {
|
|
return;
|
|
}
|
|
|
|
$serp_url_researches = SerpUrlResearch::where('serp_url_id', $serp_url->id)->where('content', '!=', 'EMPTY CONTENT')->whereNotNull('content')->get();
|
|
|
|
$user_prompt = '';
|
|
$total_tokens = 0;
|
|
|
|
foreach ($serp_url_researches as $serp_url_research) {
|
|
|
|
$sentences = self::markdownToSentences($serp_url_research->content);
|
|
|
|
//dump($sentences);
|
|
|
|
foreach ($sentences as $key => $sentence) {
|
|
|
|
if ($key == 0) {
|
|
$user_prompt .= "ARTICLE:\n";
|
|
}
|
|
|
|
$current_tokens = Tiktoken::count($sentence);
|
|
|
|
if ($current_tokens + $total_tokens > 4096) {
|
|
break 2;
|
|
} else {
|
|
$user_prompt .= $sentence."\n";
|
|
$total_tokens += $current_tokens;
|
|
}
|
|
|
|
}
|
|
$user_prompt .= "\n\n";
|
|
}
|
|
|
|
//dd($user_prompt);
|
|
|
|
$ai_writeup_response = OpenAI::writeArticle($user_prompt, 1536, 30);
|
|
|
|
//dd($ai_writeup_response);
|
|
|
|
if ((isset($ai_writeup_response->output)) && (! is_empty($ai_writeup_response->output))) {
|
|
$output = self::extractRemoveFirstHeading($ai_writeup_response->output);
|
|
|
|
$service_cost_usage = new ServiceCostUsage;
|
|
$service_cost_usage->cost = $ai_writeup_response->cost;
|
|
$service_cost_usage->name = 'openai-writeArticle';
|
|
$service_cost_usage->reference_1 = 'serp_url';
|
|
$service_cost_usage->reference_2 = strval($serp_url->id);
|
|
$service_cost_usage->output = $ai_writeup_response;
|
|
$service_cost_usage->save();
|
|
|
|
$post = Post::where('serp_url_id', $serp_url->id)->first();
|
|
|
|
if (is_null($post)) {
|
|
$post = new Post;
|
|
$post->serp_url_id = $serp_url->id;
|
|
}
|
|
|
|
if (! is_empty($output->title)) {
|
|
$post->title = $output->title;
|
|
} else {
|
|
|
|
if (! is_null($serp_url->suggestion_data)) {
|
|
if (isset($serp_url->suggestion_data->article_headings)) {
|
|
if (count($serp_url->suggestion_data->article_headings) > 0) {
|
|
$post->title = $serp_url->suggestion_data?->article_headings[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_empty($post->title)) {
|
|
$post->title = $serp_url->title;
|
|
}
|
|
|
|
$post->slug = str_slug($post->title);
|
|
|
|
$post->body = $output->content;
|
|
|
|
$post->bites = null;
|
|
$post->metadata = null;
|
|
|
|
if ($post->save()) {
|
|
FillPostMetadataJob::dispatch($post->id)->onQueue('default')->onConnection('default');
|
|
}
|
|
} else {
|
|
throw new Exception('OpenAI failed to write');
|
|
}
|
|
}
|
|
|
|
private static function markdownToSentences($markdownContent)
|
|
{
|
|
// Split the content on punctuation followed by a space or end of string
|
|
$pattern = '/(?<=[.!?])\s+|\z/';
|
|
|
|
// Split the content into sentences
|
|
$sentences = preg_split($pattern, $markdownContent, -1, PREG_SPLIT_NO_EMPTY);
|
|
|
|
// Return the array of sentences
|
|
return $sentences;
|
|
}
|
|
|
|
private static function extractRemoveFirstHeading($markdownContent)
|
|
{
|
|
// Pattern to match the first markdown heading of any level
|
|
$pattern = '/^(#+)\s*(.+)$/m';
|
|
|
|
// Try to find the first heading
|
|
if (preg_match($pattern, $markdownContent, $matches)) {
|
|
$title = $matches[2]; // The first heading becomes the title
|
|
|
|
// Remove the first heading from the content
|
|
$updatedContent = preg_replace($pattern, '', $markdownContent, 1);
|
|
|
|
return (object) ['title' => $title, 'content' => trim($updatedContent)];
|
|
}
|
|
|
|
// Return original content if no heading found
|
|
return (object) ['title' => '', 'content' => $markdownContent];
|
|
}
|
|
}
|