140 lines
6.2 KiB
PHP
140 lines
6.2 KiB
PHP
<?php
|
|
// V96 LinkedIn Automation Hub — auto-generate posts + stats tracking + queue
|
|
header('Content-Type: application/json');
|
|
header('Access-Control-Allow-Origin: *');
|
|
|
|
$action = $_GET['action'] ?? 'overview';
|
|
$queue_file = '/opt/weval-l99/linkedin-post-queue.jsonl';
|
|
$published_file = '/opt/weval-l99/linkedin-published.jsonl';
|
|
$stats_file = '/opt/weval-l99/linkedin-page-stats.json';
|
|
|
|
// Ensure files exist
|
|
if (!file_exists($queue_file)) @file_put_contents($queue_file, '');
|
|
if (!file_exists($published_file)) @file_put_contents($published_file, '');
|
|
if (!file_exists($stats_file)) @file_put_contents($stats_file, json_encode([
|
|
'page' => 'Weval',
|
|
'followers' => 921,
|
|
'last_7d_new_followers' => 5,
|
|
'last_7d_search_appearances' => 176,
|
|
'last_7d_post_impressions' => 762,
|
|
'last_7d_page_visitors' => 15,
|
|
'pct_growth_search' => 87.2,
|
|
'pct_growth_followers' => 66.7,
|
|
'pct_growth_impressions' => 172.1,
|
|
'pct_growth_visitors' => 25.0,
|
|
'updated_at' => date('c'),
|
|
'source' => 'linkedin.com/company/69533182/admin/dashboard Yacine screenshot 20-avr'
|
|
]));
|
|
|
|
switch ($action) {
|
|
case 'overview':
|
|
$stats = json_decode(@file_get_contents($stats_file), true) ?: [];
|
|
$queue = [];
|
|
foreach (@file($queue_file) ?: [] as $l) { $e=@json_decode(trim($l),true); if($e)$queue[]=$e; }
|
|
$published = [];
|
|
foreach (@file($published_file) ?: [] as $l) { $e=@json_decode(trim($l),true); if($e)$published[]=$e; }
|
|
$pixel_tracker = @json_decode(@file_get_contents('http://localhost/api/v85-demo-tracker.php'), true) ?: [];
|
|
|
|
echo json_encode([
|
|
'v' => 'V96-linkedin-automation',
|
|
'ts' => date('c'),
|
|
'page_stats' => $stats,
|
|
'queue_pending' => count($queue),
|
|
'queue_preview' => array_slice($queue, -5),
|
|
'published_count' => count($published),
|
|
'recent_published' => array_slice($published, -3),
|
|
'pixel_hits_month' => $pixel_tracker['month_hits_total'] ?? 0,
|
|
'pixel_linkedin_referrer' => $pixel_tracker['linkedin_referrer_month'] ?? 0,
|
|
'kpis_to_push_score_10' => [
|
|
'posts_with_metric' => '71% -> 90% (add concrete numbers to 5 more posts)',
|
|
'avg_reach_30d' => '517 -> 800 (3-5 posts/week native video)',
|
|
'unique_proofs_cited' => '11 -> 15 (add 4 more client names: Abbott, Servier, OCP, Marjane)',
|
|
'linkedin_to_demo' => sprintf('%d -> 30 (pixel live)', $pixel_tracker['month_hits_total'] ?? 0),
|
|
],
|
|
], JSON_PRETTY_PRINT);
|
|
break;
|
|
|
|
case 'generate_post':
|
|
$theme = $_GET['theme'] ?? 'wevia_sovereign_ai';
|
|
// Generate post from sovereign Ollama llama3.2
|
|
$themes = [
|
|
'wevia_sovereign_ai' => 'Generate a LinkedIn post (150-200 words, FR, professional tone) about WEVIA sovereign AI. Include: 157K HCPs, 626 tools, 153/153 NR, 9.1/10 LinkedIn alignment score. Add hashtags #WEVAL #AI #SAP. Include at least 3 concrete numbers. End with CTA: demo request.',
|
|
'ethica_hcp' => 'Generate a LinkedIn post (150-200 words, FR) about WEVAL Ethica HCP platform. Include: 126K medecins, 109K emails verified 87%, 121K phones, 18 marques pharma, 34 specialites. Add #PharmaMarketing #HCP. Concrete numbers + CTA.',
|
|
'vistex_sap' => 'Generate LinkedIn post (150 words, FR) about WEVAL Vistex SAP partnership. Include: SAP Ecosystem Partner, Vistex lead protection, B2B enterprise. Hashtags #SAP #Vistex #Enterprise. Numbers + CTA.',
|
|
'case_study' => 'Generate LinkedIn case study post (200 words, FR) showcasing a WEVAL client success. Mention: 1.2M EUR waste eliminated, -40% delays, ROI 4 months. Hashtag #Lean6Sigma #CaseStudy. Include client name placeholder [CLIENT] + CTA demo.',
|
|
];
|
|
$prompt = $themes[$theme] ?? $themes['wevia_sovereign_ai'];
|
|
|
|
$ch = curl_init('http://127.0.0.1:11434/api/generate');
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => 1,
|
|
CURLOPT_POST => 1,
|
|
CURLOPT_POSTFIELDS => json_encode([
|
|
'model' => 'llama3.2:latest',
|
|
'prompt' => $prompt,
|
|
'stream' => false,
|
|
'options' => ['num_predict' => 300, 'temperature' => 0.6],
|
|
]),
|
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
|
CURLOPT_TIMEOUT => 60,
|
|
]);
|
|
$t0 = microtime(true);
|
|
$resp = curl_exec($ch);
|
|
$ms = round((microtime(true) - $t0) * 1000);
|
|
curl_close($ch);
|
|
$data = @json_decode($resp, true);
|
|
$post = trim($data['response'] ?? '');
|
|
|
|
// Metrics check
|
|
$metrics_found = preg_match_all('/\d+[K%]?|\d+\.\d+/', $post, $m);
|
|
$hashtags_found = preg_match_all('/#\w+/', $post, $h);
|
|
|
|
// Add to queue
|
|
$entry = [
|
|
'id' => 'v96-' . uniqid(),
|
|
'ts' => date('c'),
|
|
'theme' => $theme,
|
|
'post' => $post,
|
|
'chars' => strlen($post),
|
|
'metrics_count' => $metrics_found,
|
|
'hashtags_count' => $hashtags_found,
|
|
'status' => 'draft_queued',
|
|
'provider' => 'ollama-llama3.2-sovereign',
|
|
'cost_eur' => 0,
|
|
'latency_ms' => $ms,
|
|
];
|
|
@file_put_contents($queue_file, json_encode($entry) . "\n", FILE_APPEND);
|
|
|
|
echo json_encode($entry, JSON_PRETTY_PRINT);
|
|
break;
|
|
|
|
case 'queue':
|
|
$queue = [];
|
|
foreach (@file($queue_file) ?: [] as $l) { $e=@json_decode(trim($l),true); if($e)$queue[]=$e; }
|
|
echo json_encode(['ok' => true, 'count' => count($queue), 'queue' => $queue], JSON_PRETTY_PRINT);
|
|
break;
|
|
|
|
case 'clear_queue':
|
|
@file_put_contents($queue_file, '');
|
|
echo json_encode(['ok' => true, 'action' => 'queue_cleared']);
|
|
break;
|
|
|
|
case 'update_stats':
|
|
// Update LinkedIn page stats (manual feed from Yacine screenshot)
|
|
$new = [
|
|
'followers' => intval($_POST['followers'] ?? $_GET['followers'] ?? 921),
|
|
'last_7d_new_followers' => intval($_POST['new_followers'] ?? $_GET['new_followers'] ?? 5),
|
|
'last_7d_search_appearances' => intval($_POST['search'] ?? $_GET['search'] ?? 176),
|
|
'last_7d_post_impressions' => intval($_POST['impressions'] ?? $_GET['impressions'] ?? 762),
|
|
'last_7d_page_visitors' => intval($_POST['visitors'] ?? $_GET['visitors'] ?? 15),
|
|
'updated_at' => date('c'),
|
|
'source' => 'manual_update',
|
|
];
|
|
@file_put_contents($stats_file, json_encode($new, JSON_PRETTY_PRINT));
|
|
echo json_encode(['ok'=>true,'stats'=>$new]);
|
|
break;
|
|
|
|
default:
|
|
echo json_encode(['err'=>'unknown_action','available'=>['overview','generate_post','queue','clear_queue','update_stats']]);
|
|
}
|