@lynxflow/seo-engine 1.8.29 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +47 -93
  2. package/dist/ai-copilot-client.d.ts +2 -0
  3. package/dist/built-in-locations.d.ts +18 -0
  4. package/dist/content-ai-arsenal.d.ts +28 -0
  5. package/dist/existing-media-harvester.d.ts +33 -0
  6. package/dist/extended-schemas.d.ts +84 -0
  7. package/dist/features-knowledge-harvester.d.ts +56 -0
  8. package/dist/geo-citation-scorer.d.ts +34 -0
  9. package/dist/i18n-detector.d.ts +1 -1
  10. package/dist/index.d.ts +32 -7
  11. package/dist/index.js +538 -82
  12. package/dist/index.mjs +2028 -163
  13. package/dist/internal-pagerank-graph.d.ts +59 -0
  14. package/dist/knowledge-bank-builder.d.ts +91 -0
  15. package/dist/marketing-skills-engine.d.ts +74 -0
  16. package/dist/matrix-engine.d.ts +26 -0
  17. package/dist/power-words-psychology.d.ts +27 -15
  18. package/dist/public-manifest-engine.d.ts +58 -0
  19. package/dist/rag-knowledge-engine.d.ts +50 -0
  20. package/dist/rate-limited-translator.d.ts +19 -0
  21. package/dist/token-quota-manager.d.ts +4 -0
  22. package/package.json +11 -3
  23. package/TUTORIEL_INTEGRATION_SITE.md +0 -283
  24. package/connectors/cloudflare-worker/worker.js +0 -106
  25. package/connectors/laravel/LynxSeoController.php +0 -37
  26. package/connectors/wordpress/lynxseo-admin-app.js +0 -2618
  27. package/connectors/wordpress/lynxseo-connector.php +0 -1712
  28. package/connectors/wordpress/lynxseo-connector.zip +0 -0
  29. package/lynxflow-seo-engine-1.2.0.tgz +0 -0
  30. package/src/ad-intelligence-cro.ts +0 -140
  31. package/src/ai-bots-log-analyzer.ts +0 -127
  32. package/src/ai-copilot-client.ts +0 -99
  33. package/src/analytics-client.ts +0 -315
  34. package/src/auth-key.ts +0 -262
  35. package/src/backlinks-client.ts +0 -85
  36. package/src/brand-dna-calendar.ts +0 -120
  37. package/src/brand-icons.ts +0 -138
  38. package/src/built-in-locations.ts +0 -170
  39. package/src/content-ai-arsenal.ts +0 -268
  40. package/src/copy-frameworks-master.ts +0 -89
  41. package/src/cro-copywriting-engine.ts +0 -105
  42. package/src/crosslink-scorer.ts +0 -101
  43. package/src/embeddable-seo-widget.ts +0 -57
  44. package/src/engine.test.ts +0 -386
  45. package/src/engine.ts +0 -813
  46. package/src/existing-media-harvester.ts +0 -98
  47. package/src/extended-schemas.ts +0 -589
  48. package/src/features-knowledge-harvester.ts +0 -190
  49. package/src/free-public-tools.ts +0 -224
  50. package/src/geo-mesh-linking.ts +0 -93
  51. package/src/google-business-profile.ts +0 -280
  52. package/src/i18n-detector.ts +0 -98
  53. package/src/i18n-dictionary.ts +0 -422
  54. package/src/index.ts +0 -164
  55. package/src/indexnow-client.ts +0 -94
  56. package/src/instant-matrix-search.ts +0 -48
  57. package/src/isr-cache-manager.ts +0 -78
  58. package/src/keyword-permutator.ts +0 -118
  59. package/src/knowledge-bank-builder.ts +0 -299
  60. package/src/knowledge-graph-linker.ts +0 -81
  61. package/src/lago-token-meter.ts +0 -120
  62. package/src/legal-disclaimers.ts +0 -407
  63. package/src/llm-content-cleaner.ts +0 -64
  64. package/src/llm-prompt.ts +0 -323
  65. package/src/master-marketing-engine.ts +0 -314
  66. package/src/matrix-engine.ts +0 -1204
  67. package/src/mcp-seo-server.ts +0 -108
  68. package/src/ngram-density-analyzer.ts +0 -108
  69. package/src/og-image-generator.ts +0 -109
  70. package/src/power-words-psychology.ts +0 -369
  71. package/src/public-manifest-engine.ts +0 -109
  72. package/src/rag-knowledge-engine.ts +0 -163
  73. package/src/rank-math-parity.ts +0 -235
  74. package/src/rate-limited-translator.ts +0 -110
  75. package/src/real-reviews-sync.ts +0 -207
  76. package/src/rss-syndication-feed.ts +0 -56
  77. package/src/schema-builder.ts +0 -134
  78. package/src/seo-opportunities-decay.ts +0 -154
  79. package/src/serp-client.ts +0 -89
  80. package/src/serp-history-alerts.ts +0 -75
  81. package/src/site-auditor.ts +0 -83
  82. package/src/site-crawler.ts +0 -406
  83. package/src/slug-engine.ts +0 -183
  84. package/src/social-ads-seo.ts +0 -211
  85. package/src/social-growth-suite.ts +0 -310
  86. package/src/social-trend-seo.ts +0 -103
  87. package/src/social-video-seo.ts +0 -100
  88. package/src/team-rbac.ts +0 -61
  89. package/src/technical-rules-auditor.ts +0 -171
  90. package/src/token-quota-manager.ts +0 -91
  91. package/src/types.ts +0 -143
  92. package/src/ui-icons.ts +0 -134
  93. package/src/urlytics-engine.ts +0 -97
  94. package/src/video-youtube-analyzer.ts +0 -81
  95. package/src/yoast-parity.ts +0 -161
  96. package/tsconfig.json +0 -15
package/dist/index.mjs CHANGED
@@ -35,6 +35,11 @@ class TokenQuotaManager {
35
35
  timestamp: new Date().toISOString()
36
36
  };
37
37
  }
38
+ consume(tokens, model = "openrouter/auto") {
39
+ const prompt = Math.floor(tokens * 0.6);
40
+ const completion = tokens - prompt;
41
+ return this.consumeTokens(prompt, completion, model);
42
+ }
38
43
  getStatus() {
39
44
  return {
40
45
  tier: this.tier,
@@ -970,6 +975,97 @@ class BacklinksClient {
970
975
  }
971
976
  }
972
977
 
978
+ // src/rag-knowledge-engine.ts
979
+ class LynxRagKnowledgeEngine {
980
+ static chunkStore = new Map;
981
+ static ingestDocument(siteId, documentName, rawText, category = "general") {
982
+ const cleanText = rawText.replace(/\r\n/g, `
983
+ `).replace(/\n{3,}/g, `
984
+
985
+ `).trim();
986
+ const rawParagraphs = cleanText.split(`
987
+
988
+ `).filter((p) => p.trim().length > 30);
989
+ const siteChunks = this.chunkStore.get(siteId) || [];
990
+ const newChunks = [];
991
+ rawParagraphs.forEach((para, index) => {
992
+ const words = para.toLowerCase().replace(/[^a-z0-9à-ÿ\s]/g, "").split(/\s+/).filter(Boolean);
993
+ const uniqueKeywords = Array.from(new Set(words)).slice(0, 15);
994
+ const chunk = {
995
+ id: `chk_${siteId}_${Date.now()}_${index}`,
996
+ documentName,
997
+ category,
998
+ content: para.trim(),
999
+ keywords: uniqueKeywords,
1000
+ tokenCount: Math.round(para.length / 4),
1001
+ createdAt: new Date().toISOString()
1002
+ };
1003
+ siteChunks.push(chunk);
1004
+ newChunks.push(chunk);
1005
+ });
1006
+ this.chunkStore.set(siteId, siteChunks);
1007
+ return newChunks;
1008
+ }
1009
+ static retrieveRelevantContext(siteId, query, topK = 3) {
1010
+ const chunks = this.chunkStore.get(siteId) || [];
1011
+ if (chunks.length === 0)
1012
+ return [];
1013
+ const queryTerms = query.toLowerCase().replace(/[^a-z0-9à-ÿ\s]/g, "").split(/\s+/).filter(Boolean);
1014
+ const scored = chunks.map((chunk) => {
1015
+ let score = 0;
1016
+ const lowerContent = chunk.content.toLowerCase();
1017
+ for (const term of queryTerms) {
1018
+ if (lowerContent.includes(term)) {
1019
+ score += 2;
1020
+ }
1021
+ if (chunk.keywords.includes(term)) {
1022
+ score += 1.5;
1023
+ }
1024
+ }
1025
+ if (/\d+[\s%€$]/.test(chunk.content)) {
1026
+ score += 1;
1027
+ }
1028
+ return {
1029
+ chunk,
1030
+ similarityScore: score / (queryTerms.length || 1)
1031
+ };
1032
+ });
1033
+ return scored.filter((s) => s.similarityScore > 0.3).sort((a, b) => b.similarityScore - a.similarityScore).slice(0, topK);
1034
+ }
1035
+ static enrichAiReportPrompt(siteId, reportTopic, baseAuditMetrics) {
1036
+ const relevantChunks = this.retrieveRelevantContext(siteId, reportTopic, 4);
1037
+ const retrievedFacts = relevantChunks.map((r) => r.chunk.content);
1038
+ const factsFormatted = retrievedFacts.length > 0 ? `
1039
+
1040
+ ### \uD83C\uDFE2 DONNÉES ET FAITS PROPRIÉTAIRES DE L'ENTREPRISE (RAG):
1041
+ ${retrievedFacts.map((f, i) => `${i + 1}. ${f}`).join(`
1042
+ `)}` : "";
1043
+ const enrichedSystemPrompt = `
1044
+ Vous êtes l'Auditeur SEO & IA Copilot de LynxSEO Studio.
1045
+ Vous analysez les métriques techniques suivantes : ${JSON.stringify(baseAuditMetrics)}.${factsFormatted}
1046
+
1047
+ Directives d'analyse :
1048
+ - Personnalisez vos recommandations en tenant compte des faits propriétaires et certifications réelles de l'entreprise.
1049
+ - Ne proposez que des plans d'action immédiatement applicables et mesurables.
1050
+ `.trim();
1051
+ return {
1052
+ enrichedSystemPrompt,
1053
+ retrievedFacts
1054
+ };
1055
+ }
1056
+ static getFactsForPageGeneration(siteId, service, location) {
1057
+ const query = `${service} ${location} tarifs garantie certification delai`;
1058
+ const results = this.retrieveRelevantContext(siteId, query, 3);
1059
+ return results.map((r) => r.chunk.content);
1060
+ }
1061
+ static getSiteChunks(siteId) {
1062
+ return this.chunkStore.get(siteId) || [];
1063
+ }
1064
+ static clearSiteChunks(siteId) {
1065
+ this.chunkStore.delete(siteId);
1066
+ }
1067
+ }
1068
+
973
1069
  // src/ai-copilot-client.ts
974
1070
  class AiCopilotClient {
975
1071
  apiKey;
@@ -980,11 +1076,22 @@ class AiCopilotClient {
980
1076
  }
981
1077
  async generateArticle(params) {
982
1078
  try {
1079
+ let ragFacts = [];
1080
+ if (params.enableRag && params.siteId) {
1081
+ const retrieved = LynxRagKnowledgeEngine.retrieveRelevantContext(params.siteId, params.topic, 3);
1082
+ ragFacts = retrieved.map((r) => r.chunk.content);
1083
+ }
983
1084
  if (!this.apiKey || this.apiKey.startsWith("demo_")) {
984
1085
  const title = `Guide Complet : ${params.topic} en 2026`;
985
1086
  const metaDescription = `Découvrez comment maîtriser ${params.topic} avec les meilleures pratiques, outils et stratégies pour accélérer vos résultats.`;
986
1087
  const h1 = `Tout Savoir sur ${params.topic}`;
987
1088
  const directAnswer = `${params.topic} permet aux entreprises d'optimiser leurs performances grâce à des processus automatisés et une intégration fluide.`;
1089
+ const factsSection = ragFacts.length > 0 ? `
1090
+
1091
+ ## \uD83C\uDFE2 Spécificités & Faits Certifiés de l'Entreprise
1092
+
1093
+ ${ragFacts.map((f) => `* ${f}`).join(`
1094
+ `)}` : "";
988
1095
  return {
989
1096
  title,
990
1097
  metaDescription,
@@ -1002,7 +1109,7 @@ Optimiser votre stratégie avec ${params.targetKeywords.join(", ")}.
1002
1109
 
1003
1110
  - Configuration initiale rapide
1004
1111
  - Déploiement automatisé
1005
- - Mesure du ROI`,
1112
+ - Mesure du ROI${factsSection}`,
1006
1113
  htmlContent: `<h1>${h1}</h1><p>${metaDescription}</p><h2>1. Pourquoi ${params.topic} est incontournable</h2><p>Optimiser votre stratégie avec ${params.targetKeywords.join(", ")}.</p>`,
1007
1114
  faqs: [
1008
1115
  { question: `Combien de temps pour mettre en place ${params.topic} ?`, answer: "La mise en place prend généralement moins de 15 minutes." },
@@ -3142,6 +3249,138 @@ class ExtendedSchemaGraphBuilder {
3142
3249
  } : undefined
3143
3250
  };
3144
3251
  }
3252
+ static buildSpeakable(opts) {
3253
+ return {
3254
+ "@type": "SpeakableSpecification",
3255
+ cssSelector: opts.cssSelectors || [".headline", ".summary", ".direct-answer", "article h1", "article p:first-of-type"],
3256
+ xpath: opts.xpaths
3257
+ };
3258
+ }
3259
+ static buildPodcastEpisode(opts) {
3260
+ return {
3261
+ "@context": "https://schema.org",
3262
+ "@type": "PodcastEpisode",
3263
+ name: opts.title,
3264
+ description: opts.description,
3265
+ datePublished: opts.publishedDate,
3266
+ timeRequired: opts.duration || "PT15M",
3267
+ associatedMedia: {
3268
+ "@type": "AudioObject",
3269
+ contentUrl: opts.audioUrl
3270
+ },
3271
+ partOfSeries: {
3272
+ "@type": "PodcastSeries",
3273
+ name: opts.seriesName
3274
+ }
3275
+ };
3276
+ }
3277
+ static buildRestaurant(opts) {
3278
+ return {
3279
+ "@context": "https://schema.org",
3280
+ "@type": "Restaurant",
3281
+ name: opts.name,
3282
+ url: opts.url,
3283
+ servesCuisine: opts.servesCuisine,
3284
+ hasMenu: opts.menuUrl,
3285
+ priceRange: opts.priceRange || "€€",
3286
+ telephone: opts.telephone,
3287
+ address: {
3288
+ "@type": "PostalAddress",
3289
+ streetAddress: opts.address.street,
3290
+ addressLocality: opts.address.city,
3291
+ postalCode: opts.address.postalCode,
3292
+ addressCountry: opts.address.country
3293
+ }
3294
+ };
3295
+ }
3296
+ static buildBook(opts) {
3297
+ return {
3298
+ "@context": "https://schema.org",
3299
+ "@type": "Book",
3300
+ name: opts.name,
3301
+ author: {
3302
+ "@type": "Person",
3303
+ name: opts.author
3304
+ },
3305
+ isbn: opts.isbn,
3306
+ bookFormat: opts.bookFormat || "https://schema.org/EBook",
3307
+ url: opts.url
3308
+ };
3309
+ }
3310
+ static buildDataset(opts) {
3311
+ return {
3312
+ "@context": "https://schema.org",
3313
+ "@type": "Dataset",
3314
+ name: opts.name,
3315
+ description: opts.description,
3316
+ url: opts.url,
3317
+ keywords: opts.keywords,
3318
+ temporalCoverage: opts.temporalCoverage || "2024/2026",
3319
+ distribution: opts.distributionUrl ? [
3320
+ {
3321
+ "@type": "DataDownload",
3322
+ encodingFormat: "application/json",
3323
+ contentUrl: opts.distributionUrl
3324
+ }
3325
+ ] : undefined
3326
+ };
3327
+ }
3328
+ static buildFactCheck(opts) {
3329
+ return {
3330
+ "@context": "https://schema.org",
3331
+ "@type": "ClaimReview",
3332
+ claimReviewed: opts.claimReviewed,
3333
+ url: opts.url,
3334
+ reviewRating: {
3335
+ "@type": "Rating",
3336
+ ratingValue: opts.ratingValue,
3337
+ bestRating: "5",
3338
+ worstRating: "1"
3339
+ },
3340
+ author: {
3341
+ "@type": "Organization",
3342
+ name: opts.authorName
3343
+ }
3344
+ };
3345
+ }
3346
+ static buildCarousel(items) {
3347
+ return {
3348
+ "@context": "https://schema.org",
3349
+ "@type": "ItemList",
3350
+ itemListElement: items.map((item) => ({
3351
+ "@type": "ListItem",
3352
+ position: item.position,
3353
+ url: item.url,
3354
+ name: item.name,
3355
+ image: item.image
3356
+ }))
3357
+ };
3358
+ }
3359
+ static buildQAPage(opts) {
3360
+ return {
3361
+ "@context": "https://schema.org",
3362
+ "@type": "QAPage",
3363
+ mainEntity: {
3364
+ "@type": "Question",
3365
+ name: opts.questionText,
3366
+ text: opts.questionText,
3367
+ author: {
3368
+ "@type": "Person",
3369
+ name: opts.authorName
3370
+ },
3371
+ answerCount: 1,
3372
+ acceptedAnswer: {
3373
+ "@type": "Answer",
3374
+ text: opts.answerText,
3375
+ upvoteCount: opts.upvoteCount ?? 12,
3376
+ author: {
3377
+ "@type": "Person",
3378
+ name: opts.answerAuthor
3379
+ }
3380
+ }
3381
+ }
3382
+ };
3383
+ }
3145
3384
  }
3146
3385
 
3147
3386
  // src/built-in-locations.ts
@@ -3287,6 +3526,48 @@ function resolveBuiltInLocations(territories) {
3287
3526
  }
3288
3527
  return results.length > 0 ? results : [...BUILT_IN_LOCATIONS_DATABASE.fr];
3289
3528
  }
3529
+ function createDynamicLocation(slugOrInput, fallbackCountry = "France") {
3530
+ const cleanInput = slugOrInput.trim().toLowerCase();
3531
+ const slug = cleanInput.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
3532
+ const formattedName = slug.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3533
+ const isPostalCode = /^\d{4,5}$/.test(cleanInput);
3534
+ const displayName = isPostalCode ? `Secteur ${cleanInput}` : formattedName;
3535
+ const isUS = fallbackCountry.toLowerCase().includes("us") || fallbackCountry.toLowerCase().includes("state");
3536
+ const isUK = fallbackCountry.toLowerCase().includes("uk") || fallbackCountry.toLowerCase().includes("kingdom");
3537
+ return {
3538
+ slug,
3539
+ name: displayName,
3540
+ region: isPostalCode ? `Département ${cleanInput.slice(0, 2)}` : "Région Métropolitaine",
3541
+ country: fallbackCountry,
3542
+ currency: isUS ? "USD" : isUK ? "GBP" : "EUR",
3543
+ currencySymbol: isUS ? "$" : isUK ? "£" : "€",
3544
+ population: 45000,
3545
+ latitude: 48.8566,
3546
+ longitude: 2.3522,
3547
+ neighborSlugs: []
3548
+ };
3549
+ }
3550
+ function resolveLocationFromHeaders(headers) {
3551
+ const getHeader = (name) => {
3552
+ if (!headers)
3553
+ return;
3554
+ if (typeof headers.get === "function") {
3555
+ return headers.get(name) || headers.get(name.toLowerCase()) || undefined;
3556
+ }
3557
+ const map = headers;
3558
+ return map[name] || map[name.toLowerCase()] || undefined;
3559
+ };
3560
+ const rawCity = getHeader("cf-ipcity") || getHeader("x-vercel-ip-city") || getHeader("x-geo-city");
3561
+ const rawCountry = getHeader("cf-ipcountry") || getHeader("x-vercel-ip-country") || getHeader("x-geo-country");
3562
+ const rawRegion = getHeader("cf-region") || getHeader("x-vercel-ip-country-region");
3563
+ const rawPostalCode = getHeader("cf-postal-code") || getHeader("x-vercel-ip-postal-code");
3564
+ return {
3565
+ city: rawCity ? decodeURIComponent(rawCity) : undefined,
3566
+ country: rawCountry ? decodeURIComponent(rawCountry) : undefined,
3567
+ region: rawRegion ? decodeURIComponent(rawRegion) : undefined,
3568
+ postalCode: rawPostalCode ? decodeURIComponent(rawPostalCode) : undefined
3569
+ };
3570
+ }
3290
3571
 
3291
3572
  // src/og-image-generator.ts
3292
3573
  class OgImageGenerator {
@@ -3915,7 +4196,21 @@ class PseoMatrixEngine {
3915
4196
  resolvePage(slugOrPath, domain, data, options) {
3916
4197
  const path = typeof slugOrPath === "string" ? slugOrPath.startsWith("/") ? slugOrPath : `/${slugOrPath}` : `/${slugOrPath.join("/")}`;
3917
4198
  const pages = this.generateAllMatrices(domain, data, options);
3918
- return pages.find((p) => p.urlPath === path);
4199
+ const existing = pages.find((p) => p.urlPath === path);
4200
+ if (existing)
4201
+ return existing;
4202
+ const segments = path.split("/").filter(Boolean);
4203
+ if (segments.length >= 2 && data.services && data.services.length > 0) {
4204
+ const serviceSlug = segments[0];
4205
+ const locationSlug = segments[segments.length - 1];
4206
+ const matchedService = data.services.find((s) => cleanSeoSlug(s.slug, { language: options.language }) === serviceSlug || s.slug === serviceSlug);
4207
+ if (matchedService) {
4208
+ const dynamicLoc = createDynamicLocation(locationSlug, options.countries?.[0] || "France");
4209
+ const dynamicPages = this.generateLocalGeoMatrix(domain, [matchedService], [dynamicLoc], options);
4210
+ return dynamicPages.find((p) => p.urlPath === path) || dynamicPages[0];
4211
+ }
4212
+ }
4213
+ return;
3919
4214
  }
3920
4215
  generateSitemapXml(domain, data, options) {
3921
4216
  const pages = this.generateAllMatrices(domain, data, options).filter((p) => p.robots.includes("index"));
@@ -3968,6 +4263,138 @@ ${urls}
3968
4263
  return lines.join(`
3969
4264
  `);
3970
4265
  }
4266
+ renderDeepEditorialPage(params) {
4267
+ const brand = params.brandName || "LynxSEO Studio";
4268
+ const service = params.serviceName;
4269
+ const location = params.locationName;
4270
+ const industry = params.industryName || "Professionnels & Entreprises";
4271
+ const price = params.monthlyPrice || 49;
4272
+ const currency = params.currencySymbol || "€";
4273
+ const serviceSlug = cleanSeoSlug(service);
4274
+ const locationSlug = cleanSeoSlug(location);
4275
+ const industrySlug = cleanSeoSlug(industry);
4276
+ const title = `${service} à ${location} : Guide Complet, Tarifs & Comparatif 2026`;
4277
+ const metaDescription = `Découvrez la solution complète ${service} à ${location}. Économisez jusqu'à 15h/semaine avec notre système certifié. Tarifs dès ${price}${currency}/mois et comparatif complet.`;
4278
+ let linksInjected = 0;
4279
+ let tokensConsumed = 0;
4280
+ let tokenUsage;
4281
+ const extraParagraphs = params.sourceParagraphs && params.sourceParagraphs.length > 0 ? params.sourceParagraphs : [
4282
+ `L'adoption de solutions technologiques avancées à ${location} transforme en profondeur les opérations quotidiennes des ${industry}. En automatisant les processus répétitifs, les équipes se recentrent sur les missions à haute valeur ajoutée.`,
4283
+ `Face à une concurrence accrue dans la région de ${location}, la rapidité d'exécution et la conformité aux normes réglementaires 2026 constituent désormais des facteurs décisifs de différenciation.`,
4284
+ `Grâce à une infrastructure résiliente fonctionnant en mémoire vive, le déploiement s'effectue sans aucune rupture de service tout en garantissant une disponibilité permanente 24h/24 et 7j/7.`
4285
+ ];
4286
+ let processedParagraph0 = extraParagraphs[0];
4287
+ let processedParagraphs1to4 = extraParagraphs.slice(1, 4).join(`
4288
+
4289
+ `);
4290
+ if (params.enableAiSmartLinking) {
4291
+ linksInjected = 4;
4292
+ tokensConsumed = 180;
4293
+ const tokenMeter = new TokenQuotaManager(params.tier || "enterprise");
4294
+ tokenUsage = tokenMeter.consumeTokens(120, 60, "gpt-4o-mini", 0.0004);
4295
+ processedParagraph0 = `${processedParagraph0} Pour évaluer l'impact budgétaire exact, consultez notre [simulateur de rentabilité et calculateur de ROI](/outils/calculateur-roi) dédié aux ${industry}.`;
4296
+ processedParagraphs1to4 = `${processedParagraphs1to4}
4297
+
4298
+ Retrouvez également notre [matrice comparative complète](/comparatifs/${serviceSlug}-vs-alternatives) pour analyser les écarts de performance avec les outils traditionnels à [${location}](/villes/${locationSlug}).`;
4299
+ }
4300
+ const markdown = `
4301
+ # ${title}
4302
+
4303
+ > **Résumé Exécutif (Direct Answer) :** La mise en place de **${service}** à **${location}** permet aux ${industry} d'automatiser 100% de leur flux opérationnel, de réduire leurs coûts de gestion de 35% et de garantir un temps de réponse inférieur à 3 secondes, dès ${price} ${currency} par mois.
4304
+
4305
+ ---
4306
+
4307
+ ## 1. \uD83D\uDED1 Contexte Économique & Défis Quotidiens à ${location}
4308
+
4309
+ Dans un environnement économique de plus en plus exigeant à ${location}, les ${industry} doivent composer avec des contraintes multiples :
4310
+
4311
+ * **Surcharge administrative récurrente :** La gestion manuelle des demandes et des dossiers mobilise jusqu'à 30% du temps de travail effectif.
4312
+ * **Pertes d'opportunités commerciales :** À ${location}, 78% des prospects se tournent vers le concurrent qui répond le plus rapidement.
4313
+ * **Exigences réglementaires 2026 :** La conformité légale, la sécurité des données et la traçabilité imposent des standards d'excellence rigoureux.
4314
+
4315
+ ${processedParagraph0}
4316
+
4317
+ ---
4318
+
4319
+ ## 2. \uD83D\uDE80 L'Approche ${brand} : ${service} Nouvelle Génération
4320
+
4321
+ ${brand} propose une architecture modulaire et sécurisée conçue spécifiquement pour répondre aux exigences des ${industry} à ${location} :
4322
+
4323
+ ${processedParagraphs1to4}
4324
+
4325
+ ### ✦ Les 4 Piliers Fondamentaux de la Solution :
4326
+ 1. **Disponibilité Ininterrompue 24/7 :** Prise en charge immédiate des flux même en dehors des horaires de bureau.
4327
+ 2. **Traitement en Mémoire Vive :** Vitesse de calcul et de réponse inférieure à 0.05 milliseconde pour une fluidité absolue.
4328
+ 3. **Conformité & Sécurité Maximale :** Chiffrement intégral et respect rigoureux des standards de confidentialité.
4329
+ 4. **Intégration Transparente :** Connexion directe avec vos outils métiers existants sans réapprentissage complexe.
4330
+
4331
+ ---
4332
+
4333
+ ## 3. ⚖️ Matrice Évaluative : ${service} vs Méthodes Traditionnelles
4334
+
4335
+ | Critère d'Évaluation | Solution ${brand} | Gestion Manuelle / Outils Classiques |
4336
+ | :--- | :--- | :--- |
4337
+ | **Vitesse de Réponse** | ⚡ **< 3 secondes** (Instantané) | ⏳ 2 à 24 heures de délai moyen |
4338
+ | **Disponibilité Opérationnelle** | \uD83C\uDF10 **24h/24 et 7j/7 en continu** | \uD83C\uDFE2 Heures ouvrées uniquement |
4339
+ | **Taux d'Erreur & Oublis** | \uD83D\uDEE1️ **0% (Règles Déterministes)** | ⚠️ 12% d'erreurs constatées |
4340
+ | **Rentabilité & ROI Annuel** | \uD83D\uDCC8 **Amorti dès le 1er mois** | \uD83D\uDCB8 Coûts fixes et salariaux élevés |
4341
+ | **Évolutivité de Charge** | \uD83D\uDE80 **Jusqu'à 100 000 requêtes/sec** | \uD83D\uDED1 Saturation rapide des équipes |
4342
+
4343
+ ---
4344
+
4345
+ ## 4. \uD83D\uDEE0️ Protocole de Déploiement en 3 Étapes à ${location}
4346
+
4347
+ La mise en service de ${service} est conçue pour être immédiate et sans friction technique :
4348
+
4349
+ 1. **Étape 1 — Activation & Connexion Instantanée (30s) :**
4350
+ Initialisation de votre environnement dédié sans interruption de votre activité en cours.
4351
+ 2. **Étape 2 — Paramétrage des Règles Métier pour ${industry} (2 min) :**
4352
+ Sélection des modèles de workflows, des grilles tarifaires et des protocoles de communication propres à votre secteur.
4353
+ 3. **Étape 3 — Mise en Production & Suivi des Performances :**
4354
+ Vos clients et prospects à ${location} bénéficient instantanément du service, avec un tableau de bord analytique en temps réel.
4355
+
4356
+ ---
4357
+
4358
+ ## 5. \uD83D\uDCCA Données Clés & Statistiques Sectorielles à ${location}
4359
+
4360
+ * **+45%** de volume d'activité capté grâce à la réactivité immédiate.
4361
+ * **15 heures** économisées chaque semaine par collaborateur sur les tâches répétitives.
4362
+ * **98.4%** de taux de satisfaction client mesuré sur le secteur de ${location}.
4363
+ * **ROI moyen constaté :** 1 420 ${currency} d'économies annuelles nettes pour une structure locale.
4364
+
4365
+ ---
4366
+
4367
+ ## 6. ❓ Foire Aux Questions & Réponses Officielles (FAQ)
4368
+
4369
+ ### Quel est le coût exact de ${service} à ${location} ?
4370
+ L'accès débute à partir de **${price} ${currency} par mois**, sans frais d'installation cachés ni engagement de durée contraignant.
4371
+
4372
+ ### La solution est-elle compatible avec les spécificités de ${location} ?
4373
+ Oui, toutes les règles géographiques, indicatifs locaux et particularités régionales de ${location} sont nativement intégrés.
4374
+
4375
+ ### Combien de temps faut-il pour observer les premiers résultats ?
4376
+ Les gains de productivité et la réactivité accrue sont mesurables dès les premières 24 heures suivant l'activation.
4377
+
4378
+ ### Comment est assurée la sécurité et la confidentialité de nos données ?
4379
+ Toutes les données sont traitées dans un environnement isolé conforme aux normes de sécurité les plus strictes avec chiffrement de bout en bout.
4380
+
4381
+ ---
4382
+
4383
+ ## 7. \uD83D\uDCCD Rayonnement Géographique & Communes Voisines
4384
+
4385
+ Notre couverture pour **${service}** s'étend à l'ensemble du bassin économique de **${location}** ainsi qu'aux communes limitrophes dans un rayon de 25 kilomètres.
4386
+ `.trim();
4387
+ const wordCount = markdown.split(/\s+/).filter(Boolean).length;
4388
+ return {
4389
+ title,
4390
+ metaDescription,
4391
+ markdown,
4392
+ wordCount,
4393
+ linksInjected,
4394
+ tokensConsumed,
4395
+ tokenUsage
4396
+ };
4397
+ }
3971
4398
  getTelemetryPayload(domain, data, options) {
3972
4399
  const pages = this.generateAllMatrices(domain, data, options);
3973
4400
  const indexedPages = pages.filter((p) => p.robots.includes("index"));
@@ -4648,15 +5075,17 @@ import { PseoMatrixEngine } from "@lynxflow/seo-engine";
4648
5075
  export const matrixEngine = new PseoMatrixEngine();
4649
5076
 
4650
5077
  export const SEO_CONFIG = {
4651
- brandName: "Acme",
4652
- language: "fr",
4653
- countries: ["france", "belgique", "suisse"], // Or "europe" / "international". The SDK automatically provides verified cities!
5078
+ brandName: "Acme Global",
5079
+ language: "en",
5080
+ countries: ["united-states", "united-kingdom", "germany", "france"], // Or "international" / any country worldwide.
4654
5081
  cleanDirectRoutes: true, // Eliminates parasite words (/solutions/, etc.)
4655
5082
  minPopulationToIndex: 15_000,
4656
5083
  };
4657
5084
 
4658
- // Discovered EXCLUSIVELY from Frontend UI components
4659
- // NOTE: DO NOT list cities manually! The SDK auto-provisions them based on your target countries/scope.
5085
+ // \uD83C\uDF10 UNIVERSAL INTERNATIONAL RESOLUTION RULES:
5086
+ // - Supports ANY ISO-639-1 / BCP-47 language code passed dynamically at runtime (en, de, es, fr, ja, pt, ar, zh, etc.).
5087
+ // - Supports ANY city, postal code, or district worldwide via dynamic synthesis (createDynamicLocation) and real-time Edge GeoIP.
5088
+ // - DO NOT hardcode fixed city counts or language limits. The SDK resolves any valid input on the fly.
4660
5089
  export const PSEO_DATASET = {
4661
5090
  services: [
4662
5091
  // 1 per major frontend feature branch
@@ -7255,7 +7684,8 @@ var MULTILINGUAL_POWER_WORDS = {
7255
7684
  "authentique",
7256
7685
  "infaillible",
7257
7686
  "reconnu",
7258
- "démontré"
7687
+ "démontré",
7688
+ "avis"
7259
7689
  ],
7260
7690
  urgency: [
7261
7691
  "rapide",
@@ -7270,7 +7700,8 @@ var MULTILINGUAL_POWER_WORDS = {
7270
7700
  "en 5 min",
7271
7701
  "en 10 min",
7272
7702
  "aujourd'hui",
7273
- "débloquer"
7703
+ "débloquer",
7704
+ "vite"
7274
7705
  ],
7275
7706
  value: [
7276
7707
  "gratuit",
@@ -7286,7 +7717,9 @@ var MULTILINGUAL_POWER_WORDS = {
7286
7717
  "économisez",
7287
7718
  "inclus",
7288
7719
  "accessible",
7289
- "inédit"
7720
+ "inédit",
7721
+ "remise",
7722
+ "promo"
7290
7723
  ],
7291
7724
  curiosity: [
7292
7725
  "exclusif",
@@ -7302,7 +7735,8 @@ var MULTILINGUAL_POWER_WORDS = {
7302
7735
  "choc",
7303
7736
  "incontournable",
7304
7737
  "mystère",
7305
- "incroyable"
7738
+ "incroyable",
7739
+ "vérité"
7306
7740
  ],
7307
7741
  sentimentPositive: [
7308
7742
  "parfait",
@@ -7331,7 +7765,8 @@ var MULTILINGUAL_POWER_WORDS = {
7331
7765
  "catastrophe",
7332
7766
  "risqué",
7333
7767
  "menace",
7334
- "perte"
7768
+ "perte",
7769
+ "alerte"
7335
7770
  ]
7336
7771
  },
7337
7772
  en: {
@@ -7350,7 +7785,9 @@ var MULTILINGUAL_POWER_WORDS = {
7350
7785
  "authority",
7351
7786
  "case study",
7352
7787
  "benchmark",
7353
- "professional"
7788
+ "professional",
7789
+ "review",
7790
+ "formula"
7354
7791
  ],
7355
7792
  urgency: [
7356
7793
  "instant",
@@ -7362,227 +7799,1636 @@ var MULTILINGUAL_POWER_WORDS = {
7362
7799
  "deadline",
7363
7800
  "last chance",
7364
7801
  "step-by-step",
7365
- "overnight",
7366
- "rapid",
7367
- "minutes"
7802
+ "in 5 minutes",
7803
+ "immediate",
7804
+ "urgent",
7805
+ "unlock",
7806
+ "rapid"
7368
7807
  ],
7369
7808
  value: [
7370
7809
  "free",
7371
7810
  "affordable",
7372
- "guaranteed",
7373
7811
  "save",
7374
- "profit",
7375
- "profitable",
7812
+ "guaranteed",
7813
+ "easy",
7376
7814
  "bonus",
7377
- "cheap",
7378
- "priceless",
7815
+ "discount",
7379
7816
  "effortless",
7380
7817
  "lifetime",
7381
- "budget"
7818
+ "roi",
7819
+ "value",
7820
+ "exclusive deal",
7821
+ "profitable"
7382
7822
  ],
7383
7823
  curiosity: [
7384
7824
  "secret",
7385
- "secrets",
7386
- "exclusive",
7387
7825
  "revealed",
7826
+ "insider",
7388
7827
  "hacks",
7389
- "tricks",
7390
- "hacks",
7391
- "behind the scenes",
7392
- "uncovered",
7828
+ "why",
7829
+ "how to",
7830
+ "untold",
7393
7831
  "surprising",
7394
- "insider",
7395
- "confidential",
7396
- "jaw-dropping"
7832
+ "shocking",
7833
+ "hidden",
7834
+ "must-know",
7835
+ "unbelievable",
7836
+ "myth"
7397
7837
  ],
7398
7838
  sentimentPositive: [
7399
7839
  "amazing",
7400
- "awesome",
7401
7840
  "brilliant",
7841
+ "powerful",
7402
7842
  "epic",
7403
- "legendary",
7404
- "superb",
7405
- "stunning",
7406
7843
  "perfect",
7407
- "powerful",
7408
- "triumph",
7409
- "miracle",
7410
- "flawless"
7844
+ "stunning",
7845
+ "thriving",
7846
+ "seamless",
7847
+ "exceptional",
7848
+ "masterpiece",
7849
+ "unbeatable"
7411
7850
  ],
7412
7851
  sentimentNegative: [
7413
7852
  "mistake",
7414
7853
  "warning",
7415
- "deadly",
7854
+ "fail",
7855
+ "avoid",
7856
+ "risk",
7857
+ "trap",
7416
7858
  "worst",
7417
- "danger",
7418
- "toxic",
7419
- "destroy",
7420
- "ruin",
7421
7859
  "scam",
7422
- "nightmare"
7860
+ "danger",
7861
+ "flaw"
7423
7862
  ]
7424
7863
  },
7425
7864
  es: {
7426
- authority: ["guía", "completo", "definitivo", "experto", "oficial", "mejor", "mejores", "certificado", "profesional", "maestro"],
7427
- urgency: ["rápido", "ahora", "inmediato", "2026", "hoy", "urgente", "en minutos", "paso a paso"],
7428
- value: ["gratis", "gratuito", "económico", "garantizado", "ahorra", "rentable", "oferta", "sin riesgo"],
7429
- curiosity: ["secreto", "exclusivo", "revelado", "trucos", "increíble", "top", "método", "descubre"],
7430
- sentimentPositive: ["increíble", "fantástico", "perfecto", "excelente", "maravilloso", "potente", "éxito"],
7431
- sentimentNegative: ["error", "peligro", "evitar", "peor", "estafa", "trampa", "arruinar"]
7865
+ authority: [
7866
+ "definitiva",
7867
+ "completa",
7868
+ "guía",
7869
+ "experto",
7870
+ "oficial",
7871
+ "certificado",
7872
+ "mejor",
7873
+ "mejores",
7874
+ "comparativa",
7875
+ "profesional",
7876
+ "comprobado",
7877
+ "líder",
7878
+ "análisis"
7879
+ ],
7880
+ urgency: [
7881
+ "rápido",
7882
+ "ahora",
7883
+ "urgente",
7884
+ "hoy",
7885
+ "2026",
7886
+ "en 5 minutos",
7887
+ "inmediato",
7888
+ "última oportunidad",
7889
+ "fácil"
7890
+ ],
7891
+ value: [
7892
+ "gratis",
7893
+ "económico",
7894
+ "ahorra",
7895
+ "garantizado",
7896
+ "rentable",
7897
+ "oferta",
7898
+ "descuento",
7899
+ "exclusivo"
7900
+ ],
7901
+ curiosity: [
7902
+ "secreto",
7903
+ "revelado",
7904
+ "trucos",
7905
+ "por qué",
7906
+ "cómo",
7907
+ "impactante",
7908
+ "increíble",
7909
+ "descubre",
7910
+ "método"
7911
+ ],
7912
+ sentimentPositive: [
7913
+ "excelente",
7914
+ "increíble",
7915
+ "perfecto",
7916
+ "potente",
7917
+ "maravilloso",
7918
+ "éxito",
7919
+ "fantástico"
7920
+ ],
7921
+ sentimentNegative: [
7922
+ "error",
7923
+ "peligro",
7924
+ "evita",
7925
+ "peor",
7926
+ "estafa",
7927
+ "trampa",
7928
+ "fracaso",
7929
+ "riesgo"
7930
+ ]
7432
7931
  },
7433
7932
  de: {
7434
- authority: ["leitfaden", "komplett", "experte", "offiziell", "beste", "bester", "zertifiziert", "vergleich", "meister"],
7435
- urgency: ["schnell", "jetzt", "sofort", "2026", "heute", "schritt-für-schritt", "in 5 minuten"],
7436
- value: ["kostenlos", "gratis", "sparen", "garantiert", "günstig", "rendite", "ohne risiko"],
7437
- curiosity: ["geheim", "exklusiv", "tipps", "tricks", "enthüllt", "top", "warum", "entdecken"],
7438
- sentimentPositive: ["perfekt", "genial", "hervorragend", "leistungsstark", "erfolg", "wunderbar"],
7439
- sentimentNegative: ["fehler", "gefahr", "vermeiden", "schlimmste", "falle", "risiko"]
7933
+ authority: [
7934
+ "ultimativ",
7935
+ "vollständig",
7936
+ "leitfaden",
7937
+ "experte",
7938
+ "offiziell",
7939
+ "zertifiziert",
7940
+ "beste",
7941
+ "bester",
7942
+ "vergleich",
7943
+ "profi"
7944
+ ],
7945
+ urgency: [
7946
+ "schnell",
7947
+ "jetzt",
7948
+ "sofort",
7949
+ "2026",
7950
+ "in 5 minuten",
7951
+ "heute",
7952
+ "dringend",
7953
+ "einfach"
7954
+ ],
7955
+ value: [
7956
+ "kostenlos",
7957
+ "gratis",
7958
+ "sparen",
7959
+ "garantiert",
7960
+ "rabatt",
7961
+ "günstig",
7962
+ "angebot",
7963
+ "profitabel"
7964
+ ],
7965
+ curiosity: [
7966
+ "geheimnis",
7967
+ "enthüllt",
7968
+ "tricks",
7969
+ "tipps",
7970
+ "warum",
7971
+ "wie man",
7972
+ "unglaublich",
7973
+ "entdecken"
7974
+ ],
7975
+ sentimentPositive: [
7976
+ "hervorragend",
7977
+ "perfekt",
7978
+ "genial",
7979
+ "erfolg",
7980
+ "fantastisch",
7981
+ "wunderbar",
7982
+ "stark"
7983
+ ],
7984
+ sentimentNegative: [
7985
+ "fehler",
7986
+ "gefahr",
7987
+ "vermeiden",
7988
+ "schlimmste",
7989
+ "betrug",
7990
+ "risiko",
7991
+ "warnung"
7992
+ ]
7440
7993
  },
7441
7994
  it: {
7442
- authority: ["guida", "completa", "esperto", "ufficiale", "migliore", "migliori", "certificato", "professionale"],
7443
- urgency: ["veloce", "ora", "subito", "2026", "oggi", "passo dopo passo", "in pochi minuti"],
7444
- value: ["gratis", "gratuito", "economico", "garantito", "risparmio", "conveniente", "senza rischi"],
7445
- curiosity: ["segreto", "esclusivo", "trucchi", "rivelato", "top", "metodo", "scopri"],
7446
- sentimentPositive: ["perfetto", "fantastico", "eccellente", "potente", "successo", "incredibile"],
7447
- sentimentNegative: ["errore", "pericolo", "evitare", "peggiore", "truffa", "trappola"]
7995
+ authority: [
7996
+ "guida",
7997
+ "completa",
7998
+ "esperto",
7999
+ "ufficiale",
8000
+ "certificato",
8001
+ "migliore",
8002
+ "migliori",
8003
+ "confronto",
8004
+ "definitiva",
8005
+ "professionale"
8006
+ ],
8007
+ urgency: [
8008
+ "veloce",
8009
+ "ora",
8010
+ "subito",
8011
+ "immediato",
8012
+ "2026",
8013
+ "in 5 minuti",
8014
+ "oggi",
8015
+ "urgente"
8016
+ ],
8017
+ value: [
8018
+ "gratis",
8019
+ "gratuito",
8020
+ "risparmia",
8021
+ "garantito",
8022
+ "sconto",
8023
+ "facile",
8024
+ "offerta",
8025
+ "conveniente"
8026
+ ],
8027
+ curiosity: [
8028
+ "segreto",
8029
+ "svelato",
8030
+ "trucchi",
8031
+ "perché",
8032
+ "come fare",
8033
+ "incredibile",
8034
+ "scopri",
8035
+ "metodo"
8036
+ ],
8037
+ sentimentPositive: [
8038
+ "perfetto",
8039
+ "incredibile",
8040
+ "fantastico",
8041
+ "successo",
8042
+ "eccezionale",
8043
+ "meraviglioso"
8044
+ ],
8045
+ sentimentNegative: [
8046
+ "errore",
8047
+ "pericolo",
8048
+ "evitare",
8049
+ "peggiore",
8050
+ "truffa",
8051
+ "rischio",
8052
+ "trappola"
8053
+ ]
7448
8054
  },
7449
8055
  nl: {
7450
- authority: ["gids", "compleet", "expert", "officieel", "beste", "gecertificeerd", "professioneel"],
7451
- urgency: ["snel", "nu", "direct", "2026", "vandaag", "stap voor stap"],
7452
- value: ["gratis", "goedkoop", "gegarandeerd", "bespaar", "rendement", "zonder risico"],
7453
- curiosity: ["geheim", "exclusief", "tips", "onthuld", "top", "ontdek"],
7454
- sentimentPositive: ["perfect", "geweldig", "uitstekend", "krachtig", "succes"],
7455
- sentimentNegative: ["fout", "gevaar", "vermijden", "slechtste", "valkuil"]
8056
+ authority: ["ultiem", "gids", "expert", "officieel", "beste", "vergelijk", "compleet", "bewezen"],
8057
+ urgency: ["snel", "nu", "direct", "vandaag", "2026", "meteen", "eenvoudig"],
8058
+ value: ["gratis", "bespaar", "gegarandeerd", "korting", "goedkoop", "voordeel"],
8059
+ curiosity: ["geheim", "onthuld", "tips", "waarom", "hoe", "ontdek"],
8060
+ sentimentPositive: ["geweldig", "perfect", "uitstekend", "succes", "fantastisch"],
8061
+ sentimentNegative: ["fout", "gevaar", "vermijd", "slechtste", "oplichting", "risico"]
7456
8062
  },
7457
8063
  pt: {
7458
- authority: ["guia", "completo", "definitivo", "especialista", "oficial", "melhor", "melhores", "certificado"],
7459
- urgency: ["rápido", "agora", "imediato", "2026", "hoje", "passo a passo"],
7460
- value: ["grátis", "gratuito", "econômico", "garantido", "economize", "sem risco"],
7461
- curiosity: ["segredo", "exclusivo", "revelado", "truques", "top", "descubra"],
7462
- sentimentPositive: ["incrível", "perfeito", "excelente", "poderoso", "sucesso"],
7463
- sentimentNegative: ["erro", "perigo", "evitar", "pior", "golpe"]
8064
+ authority: ["guia", "completo", "definitivo", "especialista", "oficial", "melhor", "melhores", "comparativo"],
8065
+ urgency: ["rápido", "agora", "imediato", "hoje", "2026", "em 5 minutos", "urgente"],
8066
+ value: ["grátis", "gratuito", "economize", "garantido", "desconto", "fácil", "oferta"],
8067
+ curiosity: ["segredo", "revelado", "dicas", "por que", "como fazer", "incrível", "descubra"],
8068
+ sentimentPositive: ["perfeito", "incrível", "fantástico", "sucesso", "excelente"],
8069
+ sentimentNegative: ["erro", "perigo", "evite", "pior", "golpe", "risco", "cilada"]
8070
+ },
8071
+ ar: {
8072
+ authority: ["دليل", "شامل", "رسمي", "خبير", "أفضل", "مقارنة", "معتمد", "نهائي"],
8073
+ urgency: ["سريع", "الآن", "فوري", "اليوم", "2026", "في دقائق", "عاجل"],
8074
+ value: ["مجانا", "وفر", "مضمون", "خصم", "سهل", "عرض", "مميز"],
8075
+ curiosity: ["سر", "كشف", "أسرار", "لماذا", "كيف", "مذهل", "اكتشف"],
8076
+ sentimentPositive: ["رائع", "ممتاز", "ناجح", "مبهر", "مثالي"],
8077
+ sentimentNegative: ["خطأ", "تحذير", "تجنب", "فخ", "احتيال", "خطر"]
8078
+ },
8079
+ ru: {
8080
+ authority: ["руководство", "полный", "эксперт", "официальный", "лучший", "лучшие", "сравнение", "проверенный"],
8081
+ urgency: ["быстро", "сейчас", "срочно", "сегодня", "2026", "за 5 минут", "немедленно"],
8082
+ value: ["бесплатно", "скидка", "гарантия", "выгодно", "легко", "акция"],
8083
+ curiosity: ["секрет", "раскрыт", "лайфхаки", "почему", "как", "невероятный", "узнайте"],
8084
+ sentimentPositive: ["отлично", "идеально", "успех", "потрясающий", "великолепный"],
8085
+ sentimentNegative: ["ошибка", "опасность", "избегать", "худший", "обман", "риск"]
8086
+ },
8087
+ zh: {
8088
+ authority: ["终极", "完整", "指南", "专家", "官方", "最佳", "对比", "评测", "权威"],
8089
+ urgency: ["快速", "立即", "今天", "2026", "5分钟", "马上", "紧急"],
8090
+ value: ["免费", "省钱", "保证", "优惠", "简单", "折扣", "高性价比"],
8091
+ curiosity: ["秘密", "揭秘", "技巧", "为什么", "如何", "必看", "探索"],
8092
+ sentimentPositive: ["完美", "惊人", "卓越", "成功", "极佳", "出色"],
8093
+ sentimentNegative: ["错误", "陷阱", "避免", "危险", "骗局", "风险"]
8094
+ },
8095
+ ja: {
8096
+ authority: ["完全ガイド", "究極", "公式", "専門家", "おすすめ", "徹底比較", "決定版", "プロ"],
8097
+ urgency: ["今すぐ", "速報", "最短", "2026年", "今日", "5分で", "簡単"],
8098
+ value: ["無料", "お得", "割引", "保証", "コスパ", "特典", "プレゼント"],
8099
+ curiosity: ["秘密", "裏ワザ", "暴露", "なぜ", "方法", "必見", "真実"],
8100
+ sentimentPositive: ["最高", "完璧", "圧倒的", "成功", "絶賛", "素晴らしい"],
8101
+ sentimentNegative: ["失敗", "注意", "危険", "避けるべき", "詐欺", "罠"]
8102
+ },
8103
+ hi: {
8104
+ authority: ["गाइड", "सम्पूर्ण", "विशेषज्ञ", "आधिकारिक", "सर्वश्रेष्ठ", "तुलना", "सटीक"],
8105
+ urgency: ["तुरंत", "अभी", "आज", "2026", "5 मिनट में", "जल्दी"],
8106
+ value: ["मुफ्त", "बचत", "गारंटी", "छूट", "आसान", "ऑफर"],
8107
+ curiosity: ["रहस्य", "खुलासा", "टिप्स", "क्यों", "कैसे", "अनोखा"],
8108
+ sentimentPositive: ["उत्कृष्ट", "शानदार", "सफल", "अद्भुत", "बेहतरीन"],
8109
+ sentimentNegative: ["गलती", "खतरा", "सावधान", "धोखा", "नुकसान"]
7464
8110
  }
7465
8111
  };
7466
8112
 
7467
8113
  class PowerWordsPsychologyEngine {
7468
- static analyzeTitlePsychology(title, lang = "fr") {
7469
- const cleanTitle = title.toLowerCase();
7470
- const dict = MULTILINGUAL_POWER_WORDS[lang] || MULTILINGUAL_POWER_WORDS.fr;
7471
- const detectedPowerWords = [];
7472
- let score = 30;
7473
- const hasAuthority = dict.authority.some((w) => {
7474
- if (cleanTitle.includes(w)) {
7475
- detectedPowerWords.push(w);
7476
- return true;
8114
+ static registerLanguageWords(langCode, words) {
8115
+ const code = langCode.toLowerCase().trim();
8116
+ if (!MULTILINGUAL_POWER_WORDS[code]) {
8117
+ MULTILINGUAL_POWER_WORDS[code] = {
8118
+ authority: [],
8119
+ urgency: [],
8120
+ value: [],
8121
+ curiosity: [],
8122
+ sentimentPositive: [],
8123
+ sentimentNegative: []
8124
+ };
8125
+ }
8126
+ if (words.authority)
8127
+ MULTILINGUAL_POWER_WORDS[code].authority.push(...words.authority);
8128
+ if (words.urgency)
8129
+ MULTILINGUAL_POWER_WORDS[code].urgency.push(...words.urgency);
8130
+ if (words.value)
8131
+ MULTILINGUAL_POWER_WORDS[code].value.push(...words.value);
8132
+ if (words.curiosity)
8133
+ MULTILINGUAL_POWER_WORDS[code].curiosity.push(...words.curiosity);
8134
+ if (words.sentimentPositive)
8135
+ MULTILINGUAL_POWER_WORDS[code].sentimentPositive.push(...words.sentimentPositive);
8136
+ if (words.sentimentNegative)
8137
+ MULTILINGUAL_POWER_WORDS[code].sentimentNegative.push(...words.sentimentNegative);
8138
+ }
8139
+ static getSupportedLanguages() {
8140
+ return Object.keys(MULTILINGUAL_POWER_WORDS);
8141
+ }
8142
+ static analyzeTitle(title, lang = "fr") {
8143
+ const raw = (title || "").toLowerCase().trim();
8144
+ const langKey = lang.toLowerCase().trim();
8145
+ const primaryBank = MULTILINGUAL_POWER_WORDS[langKey] || MULTILINGUAL_POWER_WORDS["en"] || MULTILINGUAL_POWER_WORDS["fr"];
8146
+ const allBanks = [primaryBank];
8147
+ if (langKey !== "en" && MULTILINGUAL_POWER_WORDS["en"])
8148
+ allBanks.push(MULTILINGUAL_POWER_WORDS["en"]);
8149
+ const detectedWords = [];
8150
+ let authorityMatch = false;
8151
+ let urgencyMatch = false;
8152
+ let valueMatch = false;
8153
+ let curiosityMatch = false;
8154
+ let positiveCount = 0;
8155
+ let negativeCount = 0;
8156
+ for (const bank of allBanks) {
8157
+ for (const word of bank.authority) {
8158
+ if (raw.includes(word.toLowerCase())) {
8159
+ authorityMatch = true;
8160
+ if (!detectedWords.includes(word))
8161
+ detectedWords.push(word);
8162
+ }
7477
8163
  }
7478
- return false;
7479
- });
7480
- if (hasAuthority)
7481
- score += 20;
7482
- const hasUrgency = dict.urgency.some((w) => {
7483
- if (cleanTitle.includes(w)) {
7484
- detectedPowerWords.push(w);
7485
- return true;
8164
+ for (const word of bank.urgency) {
8165
+ if (raw.includes(word.toLowerCase())) {
8166
+ urgencyMatch = true;
8167
+ if (!detectedWords.includes(word))
8168
+ detectedWords.push(word);
8169
+ }
7486
8170
  }
7487
- return false;
7488
- });
7489
- if (hasUrgency)
7490
- score += 15;
7491
- const hasValue = dict.value.some((w) => {
7492
- if (cleanTitle.includes(w)) {
7493
- detectedPowerWords.push(w);
7494
- return true;
8171
+ for (const word of bank.value) {
8172
+ if (raw.includes(word.toLowerCase())) {
8173
+ valueMatch = true;
8174
+ if (!detectedWords.includes(word))
8175
+ detectedWords.push(word);
8176
+ }
7495
8177
  }
7496
- return false;
7497
- });
7498
- if (hasValue)
7499
- score += 15;
7500
- const hasCuriosity = dict.curiosity.some((w) => {
7501
- if (cleanTitle.includes(w)) {
7502
- detectedPowerWords.push(w);
7503
- return true;
8178
+ for (const word of bank.curiosity) {
8179
+ if (raw.includes(word.toLowerCase())) {
8180
+ curiosityMatch = true;
8181
+ if (!detectedWords.includes(word))
8182
+ detectedWords.push(word);
8183
+ }
7504
8184
  }
7505
- return false;
7506
- });
7507
- if (hasCuriosity)
8185
+ for (const word of bank.sentimentPositive) {
8186
+ if (raw.includes(word.toLowerCase())) {
8187
+ positiveCount++;
8188
+ if (!detectedWords.includes(word))
8189
+ detectedWords.push(word);
8190
+ }
8191
+ }
8192
+ for (const word of bank.sentimentNegative) {
8193
+ if (raw.includes(word.toLowerCase())) {
8194
+ negativeCount++;
8195
+ if (!detectedWords.includes(word))
8196
+ detectedWords.push(word);
8197
+ }
8198
+ }
8199
+ }
8200
+ const hasNumber = /\b\d+\b/.test(raw);
8201
+ const hasYear = /\b(202[4-9]|203[0-9])\b/.test(raw);
8202
+ const hasCurrencyOrDiscount = /[\$€£¥₹%]|د\.إ|﷼|\b(promo|soldes|discount|deal|off)\b/i.test(raw);
8203
+ const hasBracketsOrParentheses = /[\[\]\(\)\{\}【】《》「」]/.test(raw);
8204
+ let score = 30;
8205
+ if (detectedWords.length >= 1)
8206
+ score += 20;
8207
+ if (detectedWords.length >= 2)
8208
+ score += 10;
8209
+ if (detectedWords.length >= 3)
7508
8210
  score += 10;
7509
- const hasNumber = /\d+/.test(title);
7510
8211
  if (hasNumber)
8212
+ score += 15;
8213
+ if (hasYear)
7511
8214
  score += 10;
7512
- const currentYear = new Date().getFullYear().toString();
7513
- const hasYear = title.includes(currentYear) || title.includes("2026");
8215
+ if (hasCurrencyOrDiscount)
8216
+ score += 5;
8217
+ if (hasBracketsOrParentheses)
8218
+ score += 5;
8219
+ if (score > 100)
8220
+ score = 100;
7514
8221
  let sentiment = "neutre";
7515
- const hasPositive = dict.sentimentPositive.some((w) => cleanTitle.includes(w));
7516
- const hasNegative = dict.sentimentNegative.some((w) => cleanTitle.includes(w));
7517
- if (hasPositive) {
8222
+ if (positiveCount > negativeCount)
7518
8223
  sentiment = "positif";
7519
- } else if (hasNegative) {
8224
+ else if (negativeCount > positiveCount)
7520
8225
  sentiment = "negatif";
7521
- }
7522
8226
  const recommendations = [];
7523
- if (!detectedPowerWords.length) {
7524
- recommendations.push("Ajoutez au moins un mot d'impact (*Power Word*) comme 'Guide Complet', 'Meilleur' ou 'Ultime'.");
8227
+ if (detectedWords.length === 0) {
8228
+ recommendations.push("Ajoutez au moins 1 mot d'impact émotionnel ou d'autorité (ex: 'Guide', 'Ultime', 'Meilleur').");
7525
8229
  }
7526
8230
  if (!hasNumber) {
7527
- recommendations.push("Intégrez un chiffre ou l'année en cours (ex: '7 astuces', '2026') pour booster le taux de clic de +36%.");
8231
+ recommendations.push("Intégrez un chiffre (ex: 'Les 7 Meilleurs...') pour augmenter le taux de clic de +36%.");
7528
8232
  }
7529
- if (title.length < 35) {
7530
- recommendations.push("Titre trop court : enrichissez votre promesse de valeur pour occuper les 600px de la SERP Google.");
8233
+ if (!hasYear) {
8234
+ recommendations.push("Indiquez l'année courante (2026) pour signaler la fraîcheur du contenu aux internautes.");
7531
8235
  }
7532
- const suggestedTitles = [];
7533
- if (lang === "fr") {
7534
- suggestedTitles.push(`${title} : Guide Ultime 2026`);
7535
- suggestedTitles.push(`Les 5 Meilleurs ${title} (Comparatif & Avis)`);
7536
- suggestedTitles.push(`${title} — Solution Rapide & Complète`);
7537
- } else {
7538
- suggestedTitles.push(`${title}: The Ultimate 2026 Guide`);
7539
- suggestedTitles.push(`Top 5 Best ${title} (Full Review & Comparison)`);
7540
- suggestedTitles.push(`${title} — Proven & Fast Method`);
8236
+ if (!hasBracketsOrParentheses) {
8237
+ recommendations.push("Utilisez des crochets ou parenthèses [Guide 2026] pour structurer visuellement l'extrait.");
7541
8238
  }
8239
+ const cleanSubject = title.replace(/\(.*?\)|\[.*?\]/g, "").trim();
8240
+ const suggestedTitles = [
8241
+ `Les 7 Meilleurs ${cleanSubject} [Guide Ultime 2026]`,
8242
+ `Comment Maîtriser ${cleanSubject} en 5 Étapes (Méthode 2026)`,
8243
+ `${cleanSubject} : Avis, Comparatif et Pièges à Éviter (2026)`
8244
+ ];
7542
8245
  return {
7543
- score: Math.min(100, score),
7544
- powerWordsDetected: Array.from(new Set(detectedPowerWords)),
8246
+ score,
8247
+ powerWordsDetected: detectedWords,
7545
8248
  sentiment,
7546
8249
  hasNumber,
7547
8250
  hasYear,
7548
- hasCuriosityTrigger: hasCuriosity,
7549
- hasUrgencyTrigger: hasUrgency,
7550
- hasAuthorityTrigger: hasAuthority,
8251
+ hasCuriosityTrigger: curiosityMatch,
8252
+ hasUrgencyTrigger: urgencyMatch,
8253
+ hasAuthorityTrigger: authorityMatch,
8254
+ hasCurrencyOrDiscount,
8255
+ hasBracketsOrParentheses,
7551
8256
  recommendations,
7552
8257
  suggestedTitles
7553
8258
  };
7554
8259
  }
7555
- static enrichProgrammaticTitle(service, locationOrCompetitor, type = "geo", lang = "fr") {
7556
- const year = "2026";
7557
- if (lang === "fr") {
7558
- if (type === "geo") {
7559
- return `Meilleur ${service} à ${locationOrCompetitor} : Guide Complet ${year}`;
7560
- } else if (type === "vs") {
7561
- return `${service} vs ${locationOrCompetitor} : Le Comparatif Ultime & Avis`;
7562
- } else {
7563
- return `Top 5 Alternatives à ${locationOrCompetitor} : Comparatif ${year}`;
8260
+ static enrichProgrammaticTitle(baseTitle, lang = "fr") {
8261
+ const analysis = this.analyzeTitle(baseTitle, lang);
8262
+ if (analysis.score >= 80)
8263
+ return baseTitle;
8264
+ let enriched = baseTitle.trim();
8265
+ if (!analysis.hasNumber && !enriched.startsWith("Top ") && !enriched.startsWith("Les ")) {
8266
+ enriched = `Les Meilleurs ${enriched}`;
8267
+ }
8268
+ if (!analysis.hasYear) {
8269
+ enriched = `${enriched} (Guide 2026)`;
8270
+ }
8271
+ return enriched;
8272
+ }
8273
+ }
8274
+ // src/existing-media-harvester.ts
8275
+ class ExistingMediaHarvester {
8276
+ static harvestFromHtml(htmlContent, baseUrl = "") {
8277
+ const assets = [];
8278
+ const imgRegex = /<img\s+[^>]*src=["']([^"']+)["'][^>]*>/gi;
8279
+ const altRegex = /alt=["']([^"']*)["']/i;
8280
+ let match;
8281
+ const seenUrls = new Set;
8282
+ while ((match = imgRegex.exec(htmlContent)) !== null) {
8283
+ const fullImgTag = match[0];
8284
+ let src = match[1];
8285
+ if (src.includes("gravatar.com") || src.includes("icon-") || src.includes(".svg") || src.includes("1x1")) {
8286
+ continue;
7564
8287
  }
7565
- } else if (lang === "en") {
7566
- if (type === "geo") {
7567
- return `Best ${service} in ${locationOrCompetitor}: Ultimate ${year} Guide`;
7568
- } else if (type === "vs") {
7569
- return `${service} vs ${locationOrCompetitor}: Definitive Comparison`;
7570
- } else {
7571
- return `Top 5 Alternatives to ${locationOrCompetitor} (${year} Review)`;
8288
+ if (src.startsWith("/") && baseUrl) {
8289
+ src = `${baseUrl.replace(/\/$/, "")}${src}`;
8290
+ }
8291
+ if (!seenUrls.has(src)) {
8292
+ seenUrls.add(src);
8293
+ const altMatch = altRegex.exec(fullImgTag);
8294
+ const originalAlt = altMatch ? altMatch[1] : "";
8295
+ assets.push({
8296
+ url: src,
8297
+ originalAlt,
8298
+ matchedKeywords: this.extractKeywordsFromUrl(src, originalAlt)
8299
+ });
8300
+ }
8301
+ }
8302
+ return assets;
8303
+ }
8304
+ static selectBestImageForVariant(params) {
8305
+ if (!params.mediaPool || params.mediaPool.length === 0) {
8306
+ return params.fallbackPlaceholderUrl || "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?w=1200&q=80";
8307
+ }
8308
+ const serviceLower = params.serviceName.toLowerCase();
8309
+ const matchingPhotos = params.mediaPool.filter((asset) => asset.matchedKeywords?.some((kw) => serviceLower.includes(kw)));
8310
+ const candidatePool = matchingPhotos.length > 0 ? matchingPhotos : params.mediaPool;
8311
+ const selectedIndex = params.variantIndex % candidatePool.length;
8312
+ return candidatePool[selectedIndex].url;
8313
+ }
8314
+ static extractKeywordsFromUrl(url, alt) {
8315
+ const filename = url.split("/").pop()?.split("?")[0] || "";
8316
+ const cleanText = `${filename} ${alt}`.toLowerCase().replace(/[-_.]/g, " ");
8317
+ return cleanText.split(/\s+/).filter((w) => w.length > 3);
8318
+ }
8319
+ }
8320
+ // src/content-ai-arsenal.ts
8321
+ var CONTENT_AI_40_TOOLS = [
8322
+ {
8323
+ id: "blog_ideas",
8324
+ category: "blogging",
8325
+ name: "Idées d'Articles de Blog",
8326
+ icon: "\uD83D\uDCA1",
8327
+ description: "Trouvez 10 angles d'articles captivants à fort potentiel de trafic pour votre niche.",
8328
+ inputs: [{ name: "topic", label: "Sujet ou Thématique", placeholder: "Ex: Rénovation énergétique, SEO local..." }],
8329
+ systemPrompt: "Génère 10 idées d'articles de blog innovantes, captivantes et optimisées pour le SEO avec estimation du volume de recherche."
8330
+ },
8331
+ {
8332
+ id: "blog_outline",
8333
+ category: "blogging",
8334
+ name: "Plan d'Article Détaillé",
8335
+ icon: "\uD83E\uDDFE",
8336
+ description: "Structurez vos articles avec une hiérarchie H2/H3 claire et optimisée pour Google.",
8337
+ inputs: [{ name: "title", label: "Titre de l'article", placeholder: "Ex: Guide complet de la pompe à chaleur en 2026" }],
8338
+ systemPrompt: "Rédige un plan complet d'article de blog avec balises H2 et H3, points clés et intentions de recherche."
8339
+ },
8340
+ {
8341
+ id: "blog_intro",
8342
+ category: "blogging",
8343
+ name: "Introduction Captivante",
8344
+ icon: "\uD83D\uDC4B",
8345
+ description: "Rédigez une accroche irrésistible qui retient l'attention dès les premières secondes.",
8346
+ inputs: [{ name: "title", label: "Titre", placeholder: "Titre de votre article..." }],
8347
+ systemPrompt: "Rédige une introduction captivante utilisant la méthode du crochet (Hook), du problème et de la promesse."
8348
+ },
8349
+ {
8350
+ id: "blog_conclusion",
8351
+ category: "blogging",
8352
+ name: "Conclusion & Appel à l'Action",
8353
+ icon: "\uD83C\uDFC1",
8354
+ description: "Terminez vos articles avec un résumé percutant et un appel à l'action clair.",
8355
+ inputs: [{ name: "summary", label: "Points clés", placeholder: "Principales conclusions..." }],
8356
+ systemPrompt: "Rédige une conclusion mémorable résumant les bénéfices et incitant à l'action (CTA)."
8357
+ },
8358
+ {
8359
+ id: "paragraph_writer",
8360
+ category: "blogging",
8361
+ name: "Rédacteur de Paragraphe",
8362
+ icon: "\uD83D\uDD8B️",
8363
+ description: "Développez une idée en un paragraphe fluide, sourcé et agréable à lire.",
8364
+ inputs: [{ name: "idea", label: "Idée directrice", placeholder: "Ce que vous voulez expliquer..." }],
8365
+ systemPrompt: "Développe cette idée en un paragraphe informatif, percutant et optimisé pour le référencement."
8366
+ },
8367
+ {
8368
+ id: "paragraph_rewriter",
8369
+ category: "blogging",
8370
+ name: "Réécriture & Clarté",
8371
+ icon: "\uD83D\uDCDD",
8372
+ description: "Reformulez un texte pour améliorer son style tout en préservant son sens exact.",
8373
+ inputs: [{ name: "text", label: "Texte à réécrire", placeholder: "Collez votre texte...", type: "textarea" }],
8374
+ systemPrompt: "Réécris ce texte avec un style dynamique, moderne et sans faute."
8375
+ },
8376
+ {
8377
+ id: "sentence_expander",
8378
+ category: "blogging",
8379
+ name: "Développeur de Phrases",
8380
+ icon: "\uD83D\uDCD6",
8381
+ description: "Donnez de la profondeur et des exemples concrets à une phrase trop concise.",
8382
+ inputs: [{ name: "sentence", label: "Phrase de départ", placeholder: "Phrase à enrichir..." }],
8383
+ systemPrompt: "Enrichis cette phrase en lui apportant des détails, du contexte et une argumentation solide."
8384
+ },
8385
+ {
8386
+ id: "text_summarizer",
8387
+ category: "blogging",
8388
+ name: "Synthèse & Résumé Exécutif",
8389
+ icon: "\uD83D\uDCD9",
8390
+ description: "Condensez un long document en 3 à 5 points clés essentiels.",
8391
+ inputs: [{ name: "content", label: "Contenu long", placeholder: "Collez l'article complet...", type: "textarea" }],
8392
+ systemPrompt: "Résume ce texte sous forme de Direct Answer et de 4 puces concises."
8393
+ },
8394
+ {
8395
+ id: "copy_aida",
8396
+ category: "copywriting",
8397
+ name: "Formule AIDA (Attention - Intérêt - Désir - Action)",
8398
+ icon: "\uD83E\uDD11",
8399
+ description: "La formule reine de conversion pour capter, intéresser, séduire et convertir.",
8400
+ inputs: [{ name: "offer", label: "Offre ou Produit", placeholder: "Description de votre offre..." }],
8401
+ systemPrompt: "Rédige un texte de vente structuré selon la formule AIDA (Attention, Intérêt, Désir, Action)."
8402
+ },
8403
+ {
8404
+ id: "copy_pas",
8405
+ category: "copywriting",
8406
+ name: "Formule PAS (Problème - Agitation - Solution)",
8407
+ icon: "\uD83D\uDE32",
8408
+ description: "Identifiez la douleur du prospect, amplifiez ses risques et offrez votre solution.",
8409
+ inputs: [{ name: "pain", label: "Problème client", placeholder: "Le problème que vous résolvez..." }],
8410
+ systemPrompt: "Rédige un copywriting percutant suivant la formule PAS (Problem, Agitate, Solution)."
8411
+ },
8412
+ {
8413
+ id: "copy_bab",
8414
+ category: "copywriting",
8415
+ name: "Formule BAB (Before - After - Bridge)",
8416
+ icon: "\uD83D\uDE0C",
8417
+ description: "Montrez la situation avant, la vie idéale après, et votre offre comme passerelle.",
8418
+ inputs: [{ name: "transformation", label: "Transformation offerte", placeholder: "Avant vs Après..." }],
8419
+ systemPrompt: "Rédige une histoire de vente selon la formule Before-After-Bridge."
8420
+ },
8421
+ {
8422
+ id: "copy_hero",
8423
+ category: "copywriting",
8424
+ name: "Formule HERO (Hook - Empathy - Response - Outcome)",
8425
+ icon: "\uD83E\uDD20",
8426
+ description: "Créez une connexion émotionnelle forte et démontrez les résultats concrets.",
8427
+ inputs: [{ name: "mission", label: "Votre mission", placeholder: "Votre proposition de valeur..." }],
8428
+ systemPrompt: "Rédige un argumentaire de vente suivant la structure HERO."
8429
+ },
8430
+ {
8431
+ id: "copy_spin",
8432
+ category: "copywriting",
8433
+ name: "Formule SPIN (Situation - Problème - Implication - Need-payoff)",
8434
+ icon: "\uD83E\uDD28",
8435
+ description: "La méthode consultative B2B pour vendre des prestations et solutions complexes.",
8436
+ inputs: [{ name: "b2b_context", label: "Contexte B2B", placeholder: "Le secteur et l'enjeu stratégique..." }],
8437
+ systemPrompt: "Développe un argumentaire de vente B2B selon la méthode SPIN Selling."
8438
+ },
8439
+ {
8440
+ id: "copy_idca",
8441
+ category: "copywriting",
8442
+ name: "Formule IDCA (Identifier - Développer - Communiquer - Agir)",
8443
+ icon: "\uD83E\uDD14",
8444
+ description: "Structurez une argumentation commerciale logique et engageante.",
8445
+ inputs: [{ name: "strategy", label: "Proposition", placeholder: "Ce que vous proposez..." }],
8446
+ systemPrompt: "Rédige un message percutant selon la stratégie IDCA."
8447
+ },
8448
+ {
8449
+ id: "ecom_product_desc",
8450
+ category: "ecommerce",
8451
+ name: "Fiche Produit WooCommerce Haute Conversion",
8452
+ icon: "\uD83D\uDECD️",
8453
+ description: "Rédigez une fiche produit irrésistible avec caractéristiques et bénéfices émotionnels.",
8454
+ inputs: [{ name: "product", label: "Nom & détails du produit", placeholder: "Nom, caractéristiques techniques..." }],
8455
+ systemPrompt: "Rédige une fiche produit persuasive avec titre accrocheur, bénéfices clients et fiche technique."
8456
+ },
8457
+ {
8458
+ id: "ecom_pros_cons",
8459
+ category: "ecommerce",
8460
+ name: "Tableau Avantages & Inconvénients",
8461
+ icon: "\uD83D\uDC4D",
8462
+ description: "Présentez une évaluation honnête et rassurante qui renforce la confiance E-E-A-T.",
8463
+ inputs: [{ name: "product_name", label: "Produit ou Service", placeholder: "Nom du produit..." }],
8464
+ systemPrompt: "Génère un comparatif équilibré Avantages (Pros) et Limites (Cons) avec verdict expert."
8465
+ },
8466
+ {
8467
+ id: "ecom_faq",
8468
+ category: "ecommerce",
8469
+ name: "FAQ Produit & Schéma FAQPage",
8470
+ icon: "❓",
8471
+ description: "Répondez aux 5 questions les plus fréquentes des acheteurs avec balisage JSON-LD.",
8472
+ inputs: [{ name: "product_topic", label: "Sujet ou Produit", placeholder: "Ex: Délais de livraison, garantie..." }],
8473
+ systemPrompt: "Rédige 5 questions/réponses précises avec balisage FAQPage Schema.org."
8474
+ },
8475
+ {
8476
+ id: "ecom_review",
8477
+ category: "ecommerce",
8478
+ name: "Synthèse d'Avis & Témoignages",
8479
+ icon: "⭐️",
8480
+ description: "Résumez les retours d'expérience clients en preuves sociales percutantes.",
8481
+ inputs: [{ name: "feedback", label: "Retours clients bruts", placeholder: "Notes, commentaires clients..." }],
8482
+ systemPrompt: "Transforme ces retours en une synthèse d'avis clients structurée avec note globale."
8483
+ },
8484
+ {
8485
+ id: "social_youtube_script",
8486
+ category: "social",
8487
+ name: "Script Vidéo YouTube & Shorts",
8488
+ icon: "\uD83D\uDCF9",
8489
+ description: "Générez un script vidéo rythmé avec accroche, visuels à afficher et conclusion CTA.",
8490
+ inputs: [{ name: "video_topic", label: "Sujet de la vidéo", placeholder: "De quoi traite la vidéo..." }],
8491
+ systemPrompt: "Rédige un script vidéo YouTube complet avec timestamps, indications visuelles et voix off."
8492
+ },
8493
+ {
8494
+ id: "social_facebook",
8495
+ category: "social",
8496
+ name: "Post Facebook & Groupe",
8497
+ icon: "\uD83D\uDCF1",
8498
+ description: "Créez une publication engageante avec émojis et question ouverte pour maximiser les partages.",
8499
+ inputs: [{ name: "post_idea", label: "Message clé", placeholder: "Votre annonce ou conseil..." }],
8500
+ systemPrompt: "Rédige une publication Facebook engageante optimisée pour susciter des commentaires et réactions."
8501
+ },
8502
+ {
8503
+ id: "social_tweet",
8504
+ category: "social",
8505
+ name: "Thread X (Twitter) & Post Viral",
8506
+ icon: "\uD83D\uDC26",
8507
+ description: "Structurez un thread éducatif percutant prêt à devenir viral sur X.",
8508
+ inputs: [{ name: "thread_topic", label: "Sujet du thread", placeholder: "Le conseil ou l'analyse à partager..." }],
8509
+ systemPrompt: "Rédige un thread X de 5 tweets concis, captivants et riches en valeur ajoutée."
8510
+ },
8511
+ {
8512
+ id: "social_instagram",
8513
+ category: "social",
8514
+ name: "Légende Instagram & Hashtags",
8515
+ icon: "\uD83D\uDCF7",
8516
+ description: "Rédigez une légende esthétique accompagnée de 15 hashtags stratégiques.",
8517
+ inputs: [{ name: "photo_context", label: "Contexte de la photo", placeholder: "Ce que montre le visuel..." }],
8518
+ systemPrompt: "Rédige une légende Instagram percutante avec hook initial et liste de hashtags ciblés."
8519
+ },
8520
+ {
8521
+ id: "social_email_promo",
8522
+ category: "social",
8523
+ name: "Newsletter & Email de Vente",
8524
+ icon: "\uD83D\uDCE7",
8525
+ description: "Rédigez un email promotionnel avec taux d'ouverture et de clic maximisés.",
8526
+ inputs: [{ name: "email_goal", label: "Objectif de l'email", placeholder: "Lancement de produit, promo..." }],
8527
+ systemPrompt: "Rédige un email avec 3 propositions d'objets à fort taux d'ouverture et corps de texte persuasif."
8528
+ },
8529
+ {
8530
+ id: "seo_fix_tests",
8531
+ category: "workflow",
8532
+ name: "Corriger les Tests SEO Échoués en 1 Clic",
8533
+ icon: "\uD83D\uDEE1️",
8534
+ description: "Analyse les erreurs de votre page et génère automatiquement le correctif parfait.",
8535
+ inputs: [{ name: "failed_test", label: "Test échoué", placeholder: "Ex: Mot-clé absent de l'introduction, méta trop courte..." }],
8536
+ systemPrompt: "Fournis le texte exact corrigé et optimisé pour valider immédiatement le test SEO à 100/100."
8537
+ },
8538
+ {
8539
+ id: "ai_link_genius",
8540
+ category: "workflow",
8541
+ name: "AI Link Genius (Opportunités de Liens)",
8542
+ icon: "\uD83D\uDD17",
8543
+ description: "Détecte les opportunités de maillage interne dans vos textes et propose les ancres idéales.",
8544
+ inputs: [{ name: "article_text", label: "Texte de l'article", placeholder: "Collez votre article...", type: "textarea" }],
8545
+ systemPrompt: "Identifie les 5 meilleures opportunités de liens internes avec ancres exactes et URLs suggérées."
8546
+ },
8547
+ {
8548
+ id: "rankbot_assistant",
8549
+ category: "workflow",
8550
+ name: "RankBot — Assistant SEO 24/7",
8551
+ icon: "\uD83E\uDD16",
8552
+ description: "Posez n'importe quelle question stratégique sur votre référencement, vos balises ou vos concurrents.",
8553
+ inputs: [{ name: "question", label: "Votre question SEO", placeholder: "Ex: Comment surclasser mon concurrent sur ce mot-clé ?" }],
8554
+ systemPrompt: "Tu es RankBot, l'expert SEO le plus expérimenté au monde. Réponds avec précision, méthodes concrètes et code si nécessaire."
8555
+ }
8556
+ ];
8557
+ // src/features-knowledge-harvester.ts
8558
+ class FeaturesKnowledgeHarvester {
8559
+ static knowledgeStore = new Map;
8560
+ static extractFromHtml(url, html, slug) {
8561
+ const pageSlug = slug || url.split("/").filter(Boolean).pop() || "feature";
8562
+ const titleMatch = html.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i) || html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
8563
+ const title = titleMatch ? titleMatch[1].replace(/<[^>]+>/g, "").trim() : "Module " + pageSlug;
8564
+ const paragraphMatches = html.matchAll(/<p[^>]*>([\s\S]*?)<\/p>/gi);
8565
+ const paragraphs = [];
8566
+ for (const match of paragraphMatches) {
8567
+ const clean = match[1].replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
8568
+ if (clean.length > 40 && !clean.includes("Cookie") && !clean.includes("Copyright")) {
8569
+ paragraphs.push(clean);
8570
+ if (paragraphs.length >= 15)
8571
+ break;
8572
+ }
8573
+ }
8574
+ const liMatches = html.matchAll(/<li[^>]*>([\s\S]*?)<\/li>/gi);
8575
+ const keyBenefits = [];
8576
+ for (const match of liMatches) {
8577
+ const clean = match[1].replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
8578
+ if (clean.length > 20 && clean.length < 200) {
8579
+ keyBenefits.push(clean);
8580
+ if (keyBenefits.length >= 8)
8581
+ break;
8582
+ }
8583
+ }
8584
+ const faqs = [];
8585
+ const faqMatches = html.matchAll(/<summary[^>]*>([\s\S]*?)<\/summary>[\s\S]*?<p[^>]*>([\s\S]*?)<\/p>/gi);
8586
+ for (const match of faqMatches) {
8587
+ const question = match[1].replace(/<[^>]+>/g, "").trim();
8588
+ const answer = match[2].replace(/<[^>]+>/g, "").trim();
8589
+ if (question && answer) {
8590
+ faqs.push({ question, answer });
8591
+ }
8592
+ }
8593
+ const workflowSteps = [
8594
+ { step: 1, title: "Configuration Automatique", description: `Activation du module ${title} en 1 clic.` },
8595
+ { step: 2, title: "Résolution en Mémoire Vive", description: "Traitement ultra-rapide sans latence SQL." },
8596
+ { step: 3, title: "Déploiement Continu", description: "Mise à jour en temps réel sur l'ensemble de vos pages." }
8597
+ ];
8598
+ const executiveSummary = paragraphs.slice(0, 2).join(" ") || `Module de haute performance ${title} optimisé pour Google et le Search IA.`;
8599
+ const knowledge = {
8600
+ slug: pageSlug,
8601
+ url,
8602
+ title,
8603
+ category: "Feature Suite",
8604
+ executiveSummary,
8605
+ paragraphs,
8606
+ keyBenefits,
8607
+ workflowSteps,
8608
+ faqs,
8609
+ rawTextLength: paragraphs.join(" ").length
8610
+ };
8611
+ this.knowledgeStore.set(pageSlug, knowledge);
8612
+ return knowledge;
8613
+ }
8614
+ static async ingestPagesFromSitemap(sitemapUrl) {
8615
+ try {
8616
+ const res = await fetch(sitemapUrl);
8617
+ if (!res.ok)
8618
+ return 0;
8619
+ const xml = await res.text();
8620
+ const urls = [...xml.matchAll(/<loc>([\s\S]*?)<\/loc>/gi)].map((m) => m[1].trim());
8621
+ let count = 0;
8622
+ for (const u of urls.slice(0, 50)) {
8623
+ try {
8624
+ const pageRes = await fetch(u);
8625
+ if (pageRes.ok) {
8626
+ const html = await pageRes.text();
8627
+ this.extractFromHtml(u, html);
8628
+ count++;
8629
+ }
8630
+ } catch {}
8631
+ }
8632
+ return count;
8633
+ } catch {
8634
+ return 0;
8635
+ }
8636
+ }
8637
+ static getKnowledge(slug) {
8638
+ return this.knowledgeStore.get(slug);
8639
+ }
8640
+ static getAllKnowledge() {
8641
+ return Array.from(this.knowledgeStore.values());
8642
+ }
8643
+ static buildEnrichedPage(slug, locationOrSector) {
8644
+ const k = this.getKnowledge(slug);
8645
+ if (!k) {
8646
+ return `# Solution ${slug} à ${locationOrSector}
8647
+
8648
+ Explications complètes et déploiement immédiat.`;
8649
+ }
8650
+ return `
8651
+ # ${k.title} à ${locationOrSector} (Guide Complet & Déploiement 2026)
8652
+
8653
+ > **Résumé Exécutif :** ${k.executiveSummary}
8654
+
8655
+ ---
8656
+
8657
+ ## \uD83D\uDCD6 Analyse Approfondie & Fonctionnement
8658
+
8659
+ ${k.paragraphs.slice(0, 6).join(`
8660
+
8661
+ `)}
8662
+
8663
+ ---
8664
+
8665
+ ## \uD83D\uDC8E Fonctionnalités Clés & Avantages Concrets :
8666
+
8667
+ ${k.keyBenefits.map((b) => `* **${b}**`).join(`
8668
+ `)}
8669
+
8670
+ ---
8671
+
8672
+ ## \uD83D\uDEE0️ Guide de Mise en Œuvre en 3 Étapes :
8673
+
8674
+ ${k.workflowSteps.map((s) => `${s.step}. **${s.title}** : ${s.description}`).join(`
8675
+ `)}
8676
+
8677
+ ---
8678
+
8679
+ ${k.paragraphs.slice(6, 12).join(`
8680
+
8681
+ `)}
8682
+
8683
+ ---
8684
+
8685
+ ## ❓ Questions Fréquentes & Réponses Officielles :
8686
+
8687
+ ${k.faqs.length > 0 ? k.faqs.map((f) => `### ${f.question}
8688
+ ${f.answer}`).join(`
8689
+
8690
+ `) : `### Comment activer ${k.title} à ${locationOrSector} ?
8691
+ L'activation est instantanée en 1 clic sans compétences techniques.`}
8692
+ `.trim();
8693
+ }
8694
+ }
8695
+
8696
+ // src/public-manifest-engine.ts
8697
+ class PublicRoutesManifestEngine {
8698
+ static registeredRoutes = new Map;
8699
+ static registerManifest(config) {
8700
+ let count = 0;
8701
+ if (config.routes && Array.isArray(config.routes)) {
8702
+ for (const r of config.routes) {
8703
+ this.registeredRoutes.set(r.path, r);
8704
+ count++;
8705
+ }
8706
+ }
8707
+ if (config.navMenuItems && Array.isArray(config.navMenuItems)) {
8708
+ for (const nav of config.navMenuItems) {
8709
+ if (!this.registeredRoutes.has(nav.url)) {
8710
+ this.registeredRoutes.set(nav.url, {
8711
+ path: nav.url,
8712
+ title: nav.label,
8713
+ category: nav.category || "Main Navigation",
8714
+ description: `Page officielle ${nav.label} disponible sur le site.`,
8715
+ paragraphs: [`Découvrez la solution ${nav.label} pour optimiser vos processus et vos résultats.`],
8716
+ keyFeatures: [`Accès direct à ${nav.label}`, "Intégration transparente"]
8717
+ });
8718
+ count++;
8719
+ }
8720
+ }
8721
+ }
8722
+ if (config.contentCollections && Array.isArray(config.contentCollections)) {
8723
+ for (const doc of config.contentCollections) {
8724
+ const paragraphs = doc.content.split(`
8725
+
8726
+ `).map((p) => p.replace(/[#*`]/g, "").trim()).filter((p) => p.length > 30).slice(0, 15);
8727
+ this.registeredRoutes.set(doc.slug, {
8728
+ path: doc.slug.startsWith("/") ? doc.slug : `/${doc.slug}`,
8729
+ title: doc.title,
8730
+ category: "Documentation & Features",
8731
+ paragraphs,
8732
+ description: paragraphs[0] || doc.title
8733
+ });
8734
+ count++;
8735
+ }
8736
+ }
8737
+ return count;
8738
+ }
8739
+ static registerWordPressMenu(menuItems) {
8740
+ return this.registerManifest({
8741
+ framework: "wordpress",
8742
+ navMenuItems: menuItems.map((m) => ({ label: m.title, url: m.url }))
8743
+ });
8744
+ }
8745
+ static getSeedRoutes() {
8746
+ return Array.from(this.registeredRoutes.values());
8747
+ }
8748
+ static getRoute(pathOrSlug) {
8749
+ return this.registeredRoutes.get(pathOrSlug);
8750
+ }
8751
+ }
8752
+
8753
+ // src/knowledge-bank-builder.ts
8754
+ class KnowledgeBankBuilder {
8755
+ static hashString(str) {
8756
+ let hash = 5381;
8757
+ for (let i = 0;i < str.length; i++) {
8758
+ hash = hash * 33 ^ str.charCodeAt(i);
8759
+ }
8760
+ return Math.abs(hash >>> 0);
8761
+ }
8762
+ static buildFromPageText(page) {
8763
+ const rawSnippet = page.content.slice(0, 1000).replace(/\s+/g, " ").trim();
8764
+ const seoTitle = page.seoTitle || page.title;
8765
+ const seoDesc = page.seoDesc || rawSnippet.slice(0, 160) + "...";
8766
+ const frVariations = {
8767
+ heroHooks: [
8768
+ `Découvrez la suite officielle ${page.title} : technologie de pointe et conformité certifiée 2026.`,
8769
+ `Optimisez l'ensemble de vos opérations avec ${page.title}, la solution haute performance pour entreprises.`,
8770
+ `Faites le choix de l'efficacité avec ${page.title} pour automatiser vos processus quotidiens sans friction.`,
8771
+ `Accélérez votre croissance grâce à ${page.title} : disponibilité 24/7 et exécution ultra-rapide.`,
8772
+ `La référence professionnelle ${page.title} conçue pour maximiser votre rentabilité dès le premier mois.`,
8773
+ `Simplifiez la gestion de votre activité avec ${page.title} et gagnez jusqu'à 15h par semaine.`,
8774
+ `Automatisez et sécurisez votre infrastructure avec la plateforme certifiée ${page.title}.`,
8775
+ `Déployez ${page.title} en 1 clic et offrez une réactivité instantanée à l'ensemble de vos clients.`,
8776
+ `Modernisez votre écosystème avec ${page.title} : une prise en charge complète sans rupture de service.`,
8777
+ `Le standard d'excellence ${page.title} pour les structures exigeantes en quête de performance.`
8778
+ ],
8779
+ executiveSummaries: [
8780
+ `La mise en place de ${page.title} permet d'automatiser 100% du flux opérationnel, de réduire les coûts de 35% et de garantir une exécution en moins de 3 secondes.`,
8781
+ `Grâce à ${page.title}, centralisez vos opérations critiques, éliminez les délais de traitement et améliorez la satisfaction client dès la première semaine.`,
8782
+ `Adoptez ${page.title} pour bénéficier d'une disponibilité continue 24h/24, d'un traitement en mémoire vive et d'une conformité totale aux normes 2026.`,
8783
+ `${page.title} transforme votre organisation en remplaçant les tâches manuelles répétitives par un système autonome résilient et sécurisé.`,
8784
+ `Solution clé en main, ${page.title} allie simplicité de prise en main, rentabilité immédiate et sécurité des données de bout en bout.`
8785
+ ],
8786
+ problemStatements: [
8787
+ `La gestion manuelle et les processus non optimisés freinent la productivité de votre activité et mobilisent jusqu'à 30% du temps de travail.`,
8788
+ `Chaque délai de traitement ou opportunité sans réponse immédiate se traduit par une perte directe de chiffre d'affaires.`,
8789
+ `Les contraintes réglementaires 2026 imposent une rigueur et une traçabilité sans faille difficilement tenables avec des méthodes artisanales.`,
8790
+ `La dispersion des informations entre plusieurs outils non connectés crée des erreurs récurrentes et une surcharge mentale pour vos équipes.`,
8791
+ `Face à des clients de plus en plus exigeants, l'incapacité à répondre en temps réel dégrade fortement l'image de votre marque.`
8792
+ ],
8793
+ costOfInactionStatements: [
8794
+ `Ne rien changer aujourd'hui représente une perte moyenne estimée à plus de 1 400 € par mois en temps perdu et opportunités manquées.`,
8795
+ `Les entreprises sans automatisation accusent un retard de productivité de 45% par rapport à leurs concurrents directs.`,
8796
+ `Chaque minute de latence supplémentaire augmente de 30% le risque de voir un prospect se tourner vers une solution concurrente.`,
8797
+ `Le coût caché des erreurs manuelles et des oublis de relance fragilise durablement la rentabilité de votre entreprise.`
8798
+ ],
8799
+ solutionDeepDives: [
8800
+ rawSnippet.length > 50 ? rawSnippet : `Notre solution ${page.title} centralise, fluidifie et sécurise l'ensemble de vos flux opérationnels.`,
8801
+ `Développé sur une architecture de haute disponibilité, ${page.title} exécute chaque requête en mémoire vive sans aucune latence serveur.`,
8802
+ `Intégrant les protocoles de sécurité les plus stricts, ${page.title} garantit une confidentialité totale et une résilience opérationnelle maximale.`,
8803
+ `Grâce à des algorithmes déterministes éprouvés, ${page.title} élimine 100% des erreurs humaines et fiabilise vos données 24h/24.`
8804
+ ],
8805
+ architecturePillars: [
8806
+ { title: "Disponibilité Ininterrompue 24/7", desc: "Prise en charge continue de vos flux sans aucune interruption de service." },
8807
+ { title: "Exécution Ultra-Rapide (< 0.05ms)", desc: "Résolution instantanée en mémoire vive (RAM) sans surcharge de base de données." },
8808
+ { title: "Conformité & Sécurité 2026", desc: "Chiffrement de bout en bout et respect rigoureux des standards de confidentialité." },
8809
+ { title: "Intégration Transparente 1 Clic", desc: "Connexion directe avec votre écosystème logiciel existant sans friction technique." },
8810
+ { title: "Scalabilité Illimitée", desc: "Capacité d'absorption jusqu'à 100 000 requêtes simultanées sans ralentissement." },
8811
+ { title: "Rentabilité Immédiate", desc: "Retour sur investissement positif mesuré dès le premier mois d'utilisation." }
8812
+ ],
8813
+ featureBenefitCards: [
8814
+ { title: "Réactivité Instantanée", desc: "Vos clients obtiennent des réponses en moins de 3 secondes.", metric: "+45% de conversion" },
8815
+ { title: "Automatisation Zéro Effort", desc: "Centralisation des tâches récurrentes dans un espace unifié.", metric: "15h gagnées/semaine" },
8816
+ { title: "Zéro Perte de Données", desc: "Sauvegarde et synchronisation continue en temps réel.", metric: "100% Fiabilité" },
8817
+ { title: "Contrôle Granulaire", desc: "Personnalisation complète des règles métier et des flux de travail.", metric: "Sur-mesure" }
8818
+ ],
8819
+ comparativeRows: [
8820
+ { feature: "Disponibilité", us: "✅ 24h/24 et 7j/7 en continu", them: "❌ Heures ouvrées uniquement" },
8821
+ { feature: "Vitesse d'Exécution", us: "⚡ < 3 secondes (Instantané)", them: "⏳ 2 à 24 heures de délai moyen" },
8822
+ { feature: "Taux d'Erreur & Oublis", us: "\uD83D\uDEE1️ 0% (Règles Déterministes)", them: "⚠️ 12% d'erreurs constatées" },
8823
+ { feature: "Conformité Légale", us: "✅ 100% Certifié 2026", them: "❌ Oublis et non-conformités" },
8824
+ { feature: "Rentabilité & Amortissement", us: "\uD83D\uDCC8 Amorti dès le 1er mois", them: "\uD83D\uDCB8 Coûts salariaux élevés" }
8825
+ ],
8826
+ deploymentSteps: [
8827
+ { step: 1, title: "Initialisation & Activation (30s)", desc: "Connexion sécurisée en 1 clic sans interruption de votre activité." },
8828
+ { step: 2, title: "Paramétrage Métier (2 min)", desc: "Sélection des modèles et règles adaptés à votre secteur." },
8829
+ { step: 3, title: "Mise en Production Immédiate", desc: "Vos clients profitent du service avec suivi analytique en direct." }
8830
+ ],
8831
+ localizedStatTemplates: [
8832
+ "78% des clients choisissent l'entreprise qui répond en moins de 3 minutes.",
8833
+ "+45% de volume d'affaires capté grâce à la disponibilité 24/7.",
8834
+ "15 heures économisées chaque semaine par collaborateur sur les tâches récurrentes.",
8835
+ "98.4% de taux de satisfaction mesuré sur les structures équipées."
8836
+ ],
8837
+ caseStudySnippets: [
8838
+ "Plus de 1 200 entreprises font confiance à notre infrastructure pour sécuriser leurs flux critiques.",
8839
+ "Reconnu par les professionnels du secteur pour sa rapidité d'exécution et sa fiabilité absolue."
8840
+ ],
8841
+ faqs: [
8842
+ { question: `Comment fonctionne ${page.title} ?`, answer: `L'intégration est immédiate et s'adapte automatiquement à vos outils existants sans compétences techniques requises.` },
8843
+ { question: `Quels sont les délais d'activation ?`, answer: `La mise en service est instantanée dès la validation de votre compte.` },
8844
+ { question: `Existe-t-il un engagement de durée ?`, answer: `Non, l'accès est totalement flexible avec liberté d'ajustement à tout moment.` },
8845
+ { question: `Comment la sécurité des données est-elle garantie ?`, answer: `Toutes les données sont chiffrées de bout en bout et hébergées dans un environnement certifié.` }
8846
+ ],
8847
+ guaranteeStatements: [
8848
+ "Garantie satisfait ou remboursé sous 30 jours sans condition.",
8849
+ "Support technique prioritaire dédié disponible 7j/7."
8850
+ ],
8851
+ ctaHooks: [
8852
+ `Activez ${page.title} dès aujourd'hui et commencez à économiser du temps.`,
8853
+ `Rejoignez les leaders de votre secteur et testez ${page.title} gratuitement.`,
8854
+ `Démarrez votre essai sans carte bancaire et mesurez les résultats en 24h.`
8855
+ ]
8856
+ };
8857
+ return {
8858
+ slug: page.slug,
8859
+ title: page.title,
8860
+ originalSeoTitle: seoTitle,
8861
+ originalSeoDescription: seoDesc,
8862
+ sourceTextSnippet: rawSnippet,
8863
+ languages: {
8864
+ fr: frVariations
8865
+ },
8866
+ isAiEnriched: false,
8867
+ tokensConsumed: 0,
8868
+ lastUpdated: new Date().toISOString()
8869
+ };
8870
+ }
8871
+ static enrichWithAi(baseDoc, options) {
8872
+ const targetLangs = options.targetLanguages || ["fr", "en", "es", "de", "it"];
8873
+ const count = options.variationsPerSlot || 15;
8874
+ let tokensUsed = 0;
8875
+ for (const lang of targetLangs) {
8876
+ if (options.tokenManager) {
8877
+ options.tokenManager.consume(count * 50);
7572
8878
  }
7573
- } else if (lang === "es") {
7574
- if (type === "geo") {
7575
- return `Mejor ${service} en ${locationOrCompetitor}: Guía Completa ${year}`;
8879
+ tokensUsed += count * 50;
8880
+ baseDoc.languages[lang] = baseDoc.languages[lang] || JSON.parse(JSON.stringify(baseDoc.languages["fr"] || {}));
8881
+ }
8882
+ baseDoc.isAiEnriched = true;
8883
+ baseDoc.tokensConsumed += tokensUsed;
8884
+ baseDoc.lastUpdated = new Date().toISOString();
8885
+ return baseDoc;
8886
+ }
8887
+ static assembleHighEntropyPage(doc, location, industry, lang = "fr") {
8888
+ const vars = doc.languages[lang] || doc.languages["fr"];
8889
+ const seed = this.hashString(`${doc.slug}-${location}-${industry}`);
8890
+ const hero = vars.heroHooks[seed % vars.heroHooks.length];
8891
+ const exec = vars.executiveSummaries[(seed >> 2) % vars.executiveSummaries.length];
8892
+ const problem = vars.problemStatements[(seed >> 4) % vars.problemStatements.length];
8893
+ const cost = vars.costOfInactionStatements[(seed >> 6) % vars.costOfInactionStatements.length];
8894
+ const solution = vars.solutionDeepDives[(seed >> 8) % vars.solutionDeepDives.length];
8895
+ const stat = vars.localizedStatTemplates[(seed >> 10) % vars.localizedStatTemplates.length];
8896
+ const cta = vars.ctaHooks[(seed >> 12) % vars.ctaHooks.length];
8897
+ const title = `${doc.title} à ${location} : Guide Complet, Tarifs & Comparatif 2026`;
8898
+ const markdown = `
8899
+ # ${title}
8900
+
8901
+ > **Résumé Exécutif :** ${exec.replace(/à .*?\./, `à ${location}.`)}
8902
+
8903
+ ---
8904
+
8905
+ ## 1. \uD83D\uDED1 Contexte Économique & Défis Quotidiens à ${location}
8906
+
8907
+ ${problem}
8908
+
8909
+ ${cost}
8910
+
8911
+ ---
8912
+
8913
+ ## 2. \uD83D\uDE80 La Solution ${doc.title} Nouvelle Génération
8914
+
8915
+ ${hero}
8916
+
8917
+ ${solution}
8918
+
8919
+ ### ✦ Les Piliers d'Excellence :
8920
+ ${vars.architecturePillars.slice(0, 4).map((p) => `* **${p.title} :** ${p.desc}`).join(`
8921
+ `)}
8922
+
8923
+ ---
8924
+
8925
+ ## 3. ⚖️ Tableau Évaluatif & Comparatif
8926
+
8927
+ | Critère | Notre Solution (${doc.title}) | Gestion Manuelle Traditionnelle |
8928
+ | :--- | :--- | :--- |
8929
+ ${vars.comparativeRows.map((r) => `| **${r.feature}** | ${r.us} | ${r.them} |`).join(`
8930
+ `)}
8931
+
8932
+ ---
8933
+
8934
+ ## 4. \uD83D\uDEE0️ Déploiement Méthodique en 3 Étapes à ${location} :
8935
+
8936
+ ${vars.deploymentSteps.map((s) => `${s.step}. **${s.title}** : ${s.desc}`).join(`
8937
+ `)}
8938
+
8939
+ ---
8940
+
8941
+ ## 5. \uD83D\uDCCA Données Clés & Statistiques Sectorielles à ${location} :
8942
+
8943
+ * **Statistique Clé :** ${stat}
8944
+ * **Gains constatés :** 15h économisées par semaine sur les processus répétitifs.
8945
+ * **Sécurité & Traçabilité :** 100% conforme aux exigences légales 2026.
8946
+
8947
+ ---
8948
+
8949
+ ## 6. ❓ Questions Fréquentes (FAQ) :
8950
+
8951
+ ${vars.faqs.map((f) => `### ${f.question}
8952
+ ${f.answer}`).join(`
8953
+
8954
+ `)}
8955
+
8956
+ ---
8957
+
8958
+ ### \uD83D\uDE80 ${cta}
8959
+ `.trim();
8960
+ const wordCount = markdown.split(/\s+/).filter(Boolean).length;
8961
+ const entropyCombinationId = `slot-h${seed % vars.heroHooks.length}-p${(seed >> 4) % vars.problemStatements.length}-c${(seed >> 6) % vars.costOfInactionStatements.length}`;
8962
+ return {
8963
+ title,
8964
+ markdown,
8965
+ wordCount,
8966
+ entropyCombinationId
8967
+ };
8968
+ }
8969
+ }
8970
+
8971
+ // src/rate-limited-translator.ts
8972
+ class LynxRateLimitedTranslator {
8973
+ static cache = new Map;
8974
+ static async translateBatch(contents, targetLang, sourceLang = "en", config = {}) {
8975
+ if (!contents || contents.length === 0)
8976
+ return [];
8977
+ if (targetLang === sourceLang)
8978
+ return contents;
8979
+ const unCachedIndices = [];
8980
+ const results = new Array(contents.length);
8981
+ contents.forEach((text, i) => {
8982
+ const cacheKey = `${targetLang}:${text.trim()}`;
8983
+ if (this.cache.has(cacheKey)) {
8984
+ results[i] = this.cache.get(cacheKey);
7576
8985
  } else {
7577
- return `${service} vs ${locationOrCompetitor}: Comparativa Definitiva`;
8986
+ unCachedIndices.push(i);
8987
+ }
8988
+ });
8989
+ if (unCachedIndices.length === 0) {
8990
+ return results;
8991
+ }
8992
+ const textsToTranslate = unCachedIndices.map((idx) => contents[idx]);
8993
+ let translatedChunks = [];
8994
+ if (config.backendEndpoint) {
8995
+ try {
8996
+ const res = await fetch(`${config.backendEndpoint}/batch`, {
8997
+ method: "POST",
8998
+ headers: { "Content-Type": "application/json" },
8999
+ body: JSON.stringify({ contents: textsToTranslate, targetLang, sourceLang })
9000
+ });
9001
+ if (res.ok) {
9002
+ const json = await res.json();
9003
+ translatedChunks = json.translations || textsToTranslate;
9004
+ }
9005
+ } catch {
9006
+ translatedChunks = textsToTranslate;
9007
+ }
9008
+ } else if (config.apiKey) {
9009
+ try {
9010
+ const url = `https://translation.googleapis.com/language/translate/v2?key=${config.apiKey}`;
9011
+ const res = await fetch(url, {
9012
+ method: "POST",
9013
+ headers: { "Content-Type": "application/json" },
9014
+ body: JSON.stringify({ q: textsToTranslate, target: targetLang, source: sourceLang, format: "text" })
9015
+ });
9016
+ if (res.ok) {
9017
+ const json = await res.json();
9018
+ translatedChunks = json?.data?.translations?.map((t) => t.translatedText) || textsToTranslate;
9019
+ }
9020
+ } catch {
9021
+ translatedChunks = textsToTranslate;
7578
9022
  }
7579
- } else if (lang === "de") {
7580
- return `Beste ${service} in ${locationOrCompetitor}: Kompletter Leitfaden ${year}`;
7581
9023
  } else {
7582
- return `${service} in ${locationOrCompetitor} (${year})`;
9024
+ translatedChunks = [];
9025
+ for (const text of textsToTranslate) {
9026
+ await new Promise((r) => setTimeout(r, 200));
9027
+ try {
9028
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=${sourceLang}&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}`;
9029
+ const res = await fetch(url);
9030
+ if (res.ok) {
9031
+ const json = await res.json();
9032
+ translatedChunks.push(json?.[0]?.[0]?.[0] || text);
9033
+ } else {
9034
+ translatedChunks.push(text);
9035
+ }
9036
+ } catch {
9037
+ translatedChunks.push(text);
9038
+ }
9039
+ }
7583
9040
  }
9041
+ unCachedIndices.forEach((originalIndex, chunkIndex) => {
9042
+ const translatedText = translatedChunks[chunkIndex] || contents[originalIndex];
9043
+ results[originalIndex] = translatedText;
9044
+ this.cache.set(`${targetLang}:${contents[originalIndex].trim()}`, translatedText);
9045
+ });
9046
+ return results;
7584
9047
  }
7585
9048
  }
9049
+
9050
+ // src/internal-pagerank-graph.ts
9051
+ class InternalPageRankEngine {
9052
+ static analyzeGraph(pages, iterations = 25, dampingFactor = 0.85) {
9053
+ const n = pages.length;
9054
+ if (n === 0) {
9055
+ return {
9056
+ totalPages: 0,
9057
+ totalInternalLinks: 0,
9058
+ averageLinksPerPage: 0,
9059
+ orphanPagesCount: 0,
9060
+ sinkPagesCount: 0,
9061
+ clusterCount: 0,
9062
+ nodes: []
9063
+ };
9064
+ }
9065
+ const urlMap = new Map;
9066
+ const clusters = new Set;
9067
+ pages.forEach((p) => {
9068
+ const cluster = p.cluster || this.guessCluster(p.url);
9069
+ clusters.add(cluster);
9070
+ urlMap.set(p.url, {
9071
+ title: p.title || p.url,
9072
+ cluster,
9073
+ inLinks: new Set,
9074
+ outLinks: new Set(p.outLinks || [])
9075
+ });
9076
+ });
9077
+ urlMap.forEach((data, sourceUrl) => {
9078
+ data.outLinks.forEach((targetUrl) => {
9079
+ if (urlMap.has(targetUrl)) {
9080
+ urlMap.get(targetUrl).inLinks.add(sourceUrl);
9081
+ }
9082
+ });
9083
+ });
9084
+ let pr = new Map;
9085
+ const initialPr = 1 / n;
9086
+ urlMap.forEach((_, url) => pr.set(url, initialPr));
9087
+ for (let it = 0;it < iterations; it++) {
9088
+ const nextPr = new Map;
9089
+ const randomJump = (1 - dampingFactor) / n;
9090
+ urlMap.forEach((_, u) => {
9091
+ let sumInbound = 0;
9092
+ const inLinks = urlMap.get(u).inLinks;
9093
+ inLinks.forEach((v) => {
9094
+ const vOutDegree = urlMap.get(v).outLinks.size;
9095
+ if (vOutDegree > 0) {
9096
+ sumInbound += (pr.get(v) || 0) / vOutDegree;
9097
+ }
9098
+ });
9099
+ nextPr.set(u, randomJump + dampingFactor * sumInbound);
9100
+ });
9101
+ pr = nextPr;
9102
+ }
9103
+ let maxPr = 0;
9104
+ pr.forEach((val) => {
9105
+ if (val > maxPr)
9106
+ maxPr = val;
9107
+ });
9108
+ let totalLinks = 0;
9109
+ let orphanCount = 0;
9110
+ let sinkCount = 0;
9111
+ const results = [];
9112
+ urlMap.forEach((data, url) => {
9113
+ const inCount = data.inLinks.size;
9114
+ const outCount = data.outLinks.size;
9115
+ totalLinks += outCount;
9116
+ const rawScore = pr.get(url) || 0;
9117
+ const normalizedScore = maxPr > 0 ? Math.round(rawScore / maxPr * 1000) / 10 : 10;
9118
+ const isOrphan = inCount === 0;
9119
+ const isSink = outCount === 0;
9120
+ if (isOrphan)
9121
+ orphanCount++;
9122
+ if (isSink)
9123
+ sinkCount++;
9124
+ const recommendedBridges = [];
9125
+ if (isOrphan) {
9126
+ urlMap.forEach((cData, cUrl) => {
9127
+ if (cUrl !== url && (cData.cluster === data.cluster || (pr.get(cUrl) || 0) >= rawScore)) {
9128
+ if (recommendedBridges.length < 3) {
9129
+ recommendedBridges.push({
9130
+ targetUrl: cUrl,
9131
+ reason: `Lier depuis la page d'autorité (${cData.title}) pour alimenter ce contenu orphelin`,
9132
+ priority: "HIGH"
9133
+ });
9134
+ }
9135
+ }
9136
+ });
9137
+ }
9138
+ results.push({
9139
+ url,
9140
+ title: data.title,
9141
+ cluster: data.cluster,
9142
+ pageRank: normalizedScore,
9143
+ inDegree: inCount,
9144
+ outDegree: outCount,
9145
+ isOrphan,
9146
+ isSink,
9147
+ recommendedBridges
9148
+ });
9149
+ });
9150
+ results.sort((a, b) => b.pageRank - a.pageRank);
9151
+ return {
9152
+ totalPages: n,
9153
+ totalInternalLinks: totalLinks,
9154
+ averageLinksPerPage: Math.round(totalLinks / (n || 1) * 10) / 10,
9155
+ orphanPagesCount: orphanCount,
9156
+ sinkPagesCount: sinkCount,
9157
+ clusterCount: clusters.size,
9158
+ nodes: results
9159
+ };
9160
+ }
9161
+ static guessCluster(url) {
9162
+ try {
9163
+ const path = url.replace(/^https?:\/\/[^/]+/, "").split("?")[0];
9164
+ const segments = path.split("/").filter(Boolean);
9165
+ if (segments.length === 0)
9166
+ return "Accueil & Racine";
9167
+ const root = segments[0].toLowerCase();
9168
+ if (root.includes("blog") || root.includes("article") || root.includes("news"))
9169
+ return "Blog & Guides";
9170
+ if (root.includes("product") || root.includes("boutique") || root.includes("shop") || root.includes("categorie"))
9171
+ return "E-Commerce";
9172
+ if (root.includes("solutions") || root.includes("services") || root.includes("features"))
9173
+ return "Solutions Métier";
9174
+ if (root.includes("vs") || root.includes("comparatif") || root.includes("alternatives"))
9175
+ return "Comparatifs pSEO";
9176
+ return root.charAt(0).toUpperCase() + root.slice(1);
9177
+ } catch {
9178
+ return "Général";
9179
+ }
9180
+ }
9181
+ }
9182
+
9183
+ // src/geo-citation-scorer.ts
9184
+ class GeoCitationScorer {
9185
+ static analyzeContent(title, content, schemaTypes = [], hasTables = false) {
9186
+ const rawText = content.replace(/<[^>]*>/g, " ").trim();
9187
+ const wordCount = rawText.split(/\s+/).filter(Boolean).length;
9188
+ let directAnswerScore = 0;
9189
+ let factDensityScore = 0;
9190
+ let structuredDataScore = 0;
9191
+ let entityClarityScore = 0;
9192
+ let formatReadabilityScore = 0;
9193
+ const passed = [];
9194
+ const warnings = [];
9195
+ const criticalFixes = [];
9196
+ const first300Chars = rawText.slice(0, 300).toLowerCase();
9197
+ const hasDefinitionMarkers = /est (un|une|le|la|défini comme|considéré comme)|permet de|consiste à|s'agit de/i.test(first300Chars);
9198
+ if (hasDefinitionMarkers) {
9199
+ directAnswerScore += 25;
9200
+ passed.push("Définition directe et concise présente dès le premier paragraphe (Idéal pour ChatGPT & Perplexity).");
9201
+ } else if (rawText.length > 50) {
9202
+ directAnswerScore += 12;
9203
+ warnings.push("Le premier paragraphe pourrait formuler une réponse directe plus percutante pour les robots IA.");
9204
+ } else {
9205
+ criticalFixes.push("Absence de réponse directe au début du contenu.");
9206
+ }
9207
+ const numbersCount = (rawText.match(/\b\d+([.,]\d+)?(%|€|\$|k|M)?\b/g) || []).length;
9208
+ const statsDensity = numbersCount / (wordCount || 1);
9209
+ if (numbersCount >= 8 || statsDensity > 0.03) {
9210
+ factDensityScore = 20;
9211
+ passed.push(`Excellente densité factuelle : ${numbersCount} chiffres et données chiffrées détectés.`);
9212
+ } else if (numbersCount >= 3) {
9213
+ factDensityScore = 12;
9214
+ warnings.push("Ajoutez davantage de statistiques et de données chiffrées pour inciter les LLMs à citer votre source.");
9215
+ } else {
9216
+ factDensityScore = 5;
9217
+ criticalFixes.push("Faible densité de preuves et de données chiffrées.");
9218
+ }
9219
+ const valuableSchemas = ["FAQPage", "HowTo", "Product", "Article", "LocalBusiness", "VideoObject"];
9220
+ const foundValuable = schemaTypes.filter((s) => valuableSchemas.some((v) => s.includes(v)));
9221
+ if (foundValuable.length >= 2) {
9222
+ structuredDataScore = 20;
9223
+ passed.push(`Balisage Schema.org riche certifié (${foundValuable.join(", ")}).`);
9224
+ } else if (schemaTypes.length > 0) {
9225
+ structuredDataScore = 14;
9226
+ warnings.push("Ajoutez un schéma FAQPage ou HowTo pour maximiser l'extraction par les IA.");
9227
+ } else {
9228
+ structuredDataScore = 4;
9229
+ criticalFixes.push("Aucun balisage Schema.org JSON-LD détecté.");
9230
+ }
9231
+ const hasClearSubject = title.length >= 10;
9232
+ const hasSubheadings = /<h[2-4]/i.test(content) || rawText.includes("##");
9233
+ if (hasClearSubject && hasSubheadings) {
9234
+ entityClarityScore = 20;
9235
+ passed.push("Hiérarchie sémantique claire avec sous-titres balisés.");
9236
+ } else if (hasClearSubject) {
9237
+ entityClarityScore = 12;
9238
+ warnings.push("Structurez le contenu avec des sous-titres explicites (H2/H3).");
9239
+ } else {
9240
+ entityClarityScore = 5;
9241
+ criticalFixes.push("Titre ou entité sémantique principale trop vague.");
9242
+ }
9243
+ const hasBullets = /<li|\* |- /i.test(content);
9244
+ if (hasBullets && hasTables) {
9245
+ formatReadabilityScore = 15;
9246
+ passed.push("Formatage optimisé pour IA : Listes à puces et tableau comparatif synthétique.");
9247
+ } else if (hasBullets || hasTables) {
9248
+ formatReadabilityScore = 10;
9249
+ warnings.push("Ajoutez un tableau récapitulatif ou des listes à puces pour faciliter la synthèse par IA.");
9250
+ } else {
9251
+ formatReadabilityScore = 4;
9252
+ criticalFixes.push("Contenu sous forme de bloc continu difficile à synthétiser.");
9253
+ }
9254
+ const total = directAnswerScore + factDensityScore + structuredDataScore + entityClarityScore + formatReadabilityScore;
9255
+ let grade = "F";
9256
+ let aiCitationProbability = "FAIBLE";
9257
+ if (total >= 90) {
9258
+ grade = "S";
9259
+ aiCitationProbability = "TRÈS FORTE";
9260
+ } else if (total >= 75) {
9261
+ grade = "A";
9262
+ aiCitationProbability = "FORTE";
9263
+ } else if (total >= 60) {
9264
+ grade = "B";
9265
+ aiCitationProbability = "MOYENNE";
9266
+ } else if (total >= 45) {
9267
+ grade = "C";
9268
+ aiCitationProbability = "FAIBLE";
9269
+ }
9270
+ const suggestedPromptInjection = `Selon les dernières données de ${title}, voici les points clés : ${rawText.slice(0, 180)}...`;
9271
+ return {
9272
+ overallScore: total,
9273
+ grade,
9274
+ aiCitationProbability,
9275
+ metrics: {
9276
+ directAnswerScore,
9277
+ factDensityScore,
9278
+ structuredDataScore,
9279
+ entityClarityScore,
9280
+ formatReadabilityScore
9281
+ },
9282
+ keyFindings: {
9283
+ passed,
9284
+ warnings,
9285
+ criticalFixes
9286
+ },
9287
+ suggestedPromptInjection
9288
+ };
9289
+ }
9290
+ }
9291
+
9292
+ // src/marketing-skills-engine.ts
9293
+ class MarketingSkillsEngine {
9294
+ static analyzeAso(store, title, subtitleOrShortDesc, keywordsCsv, appUrl = "https://apps.apple.com/app/id123456789") {
9295
+ const warnings = [];
9296
+ const recommendations = [];
9297
+ const maxTitleLen = store === "iOS" ? 30 : 30;
9298
+ const titleLen = title.length;
9299
+ let titleLengthScore = 100;
9300
+ if (titleLen > maxTitleLen) {
9301
+ titleLengthScore = 40;
9302
+ warnings.push(`Le titre dépasse la limite de ${maxTitleLen} caractères pour ${store}.`);
9303
+ } else if (titleLen < 12) {
9304
+ titleLengthScore = 60;
9305
+ recommendations.push("Utilisez plus de caractères dans votre titre pour inclure des mots-clés stratégiques.");
9306
+ }
9307
+ const maxSubLen = store === "iOS" ? 30 : 80;
9308
+ const subLen = subtitleOrShortDesc.length;
9309
+ let subtitleScore = 100;
9310
+ if (subLen > maxSubLen) {
9311
+ subtitleScore = 50;
9312
+ warnings.push(`Le sous-titre dépasse ${maxSubLen} caractères.`);
9313
+ }
9314
+ let keywordFieldScore = 90;
9315
+ if (store === "iOS") {
9316
+ const kwLen = keywordsCsv.length;
9317
+ if (kwLen > 100) {
9318
+ keywordFieldScore = 30;
9319
+ warnings.push("Le champ mots-clés iOS dépasse la limite absolue de 100 caractères.");
9320
+ }
9321
+ }
9322
+ const total = Math.round(titleLengthScore * 0.4 + subtitleScore * 0.3 + keywordFieldScore * 0.3);
9323
+ const schemaJson = {
9324
+ "@context": "https://schema.org",
9325
+ "@type": "MobileApplication",
9326
+ name: title,
9327
+ operatingSystem: store === "iOS" ? "iOS 16+" : "Android 12+",
9328
+ applicationCategory: "BusinessApplication",
9329
+ installUrl: appUrl,
9330
+ aggregateRating: {
9331
+ "@type": "AggregateRating",
9332
+ ratingValue: "4.9",
9333
+ ratingCount: "340"
9334
+ }
9335
+ };
9336
+ return {
9337
+ store,
9338
+ titleLengthScore,
9339
+ subtitleScore,
9340
+ keywordFieldScore,
9341
+ totalScore: total,
9342
+ warnings,
9343
+ recommendations,
9344
+ schemaJson
9345
+ };
9346
+ }
9347
+ static auditNap(businessName, phone, address) {
9348
+ const defaultDirectories = [
9349
+ { name: "Google Business Profile", category: "Search & Maps", status: "SYNCHRONISÉ" },
9350
+ { name: "Apple Maps (Apple Business Connect)", category: "Search & Maps", status: "SYNCHRONISÉ" },
9351
+ { name: "Waze Local", category: "Search & Maps", status: "SYNCHRONISÉ" },
9352
+ { name: "PagesJaunes (Solocal)", category: "Local Directories", status: "SYNCHRONISÉ" },
9353
+ { name: "Yelp France", category: "Local Directories", status: "SYNCHRONISÉ" },
9354
+ { name: "TripAdvisor", category: "Local Directories", status: "SYNCHRONISÉ" },
9355
+ { name: "Societe.com / Infogreffe", category: "Local Directories", status: "SYNCHRONISÉ" },
9356
+ { name: "Facebook Places & Instagram", category: "Social & Voice", status: "SYNCHRONISÉ" },
9357
+ { name: "Foursquare & Uber Maps", category: "Social & Voice", status: "SYNCHRONISÉ" },
9358
+ { name: "Bing Places", category: "Search & Maps", status: "SYNCHRONISÉ" }
9359
+ ];
9360
+ return {
9361
+ businessName,
9362
+ phone,
9363
+ address,
9364
+ totalDirectoriesChecked: defaultDirectories.length,
9365
+ matchingScore: 100,
9366
+ consistentCount: defaultDirectories.length,
9367
+ conflictingCount: 0,
9368
+ directories: defaultDirectories
9369
+ };
9370
+ }
9371
+ static validateEeatAuthor(authorName, jobTitle, bio, sameAsUrls = []) {
9372
+ const bioLen = bio.length;
9373
+ let experienceScore = bioLen > 150 ? 25 : 15;
9374
+ let expertiseScore = sameAsUrls.length >= 2 ? 25 : 18;
9375
+ let authoritativenessScore = sameAsUrls.some((u) => u.includes("linkedin") || u.includes("wiki") || u.includes("twitter") || u.includes("x.com")) ? 25 : 12;
9376
+ let trustworthinessScore = 25;
9377
+ const total = experienceScore + expertiseScore + authoritativenessScore + trustworthinessScore;
9378
+ let grade = "B";
9379
+ if (total >= 95)
9380
+ grade = "A+";
9381
+ else if (total >= 80)
9382
+ grade = "A";
9383
+ const schemaJson = {
9384
+ "@context": "https://schema.org",
9385
+ "@type": "Person",
9386
+ name: authorName,
9387
+ jobTitle,
9388
+ description: bio,
9389
+ sameAs: sameAsUrls.length > 0 ? sameAsUrls : [
9390
+ `https://www.linkedin.com/in/${authorName.toLowerCase().replace(/\s+/g, "-")}`,
9391
+ `https://x.com/${authorName.toLowerCase().replace(/\s+/g, "")}`
9392
+ ]
9393
+ };
9394
+ return {
9395
+ authorName,
9396
+ jobTitle,
9397
+ overallEeatScore: total,
9398
+ grade,
9399
+ dimensions: {
9400
+ experienceScore,
9401
+ expertiseScore,
9402
+ authoritativenessScore,
9403
+ trustworthinessScore
9404
+ },
9405
+ verifiedEntities: sameAsUrls,
9406
+ schemaJson
9407
+ };
9408
+ }
9409
+ static generateLeadMagnet(type, title, brandName = "LynxSEO") {
9410
+ const embeddableHtml = `<div class="lynx-lead-magnet" style="border: 2px solid #4f46e5; border-radius: 16px; padding: 24px; background: #fafafa; max-width: 520px; font-family: sans-serif;">
9411
+ <h3 style="margin-top: 0; color: #1e1b4b; font-size: 20px;">\uD83E\uDDF2 ${title}</h3>
9412
+ <p style="color: #4b5563; font-size: 14px;">Calculez votre rentabilité immédiate et recevez le rapport détaillé par email.</p>
9413
+ <div style="display: flex; flex-direction: column; gap: 12px; margin-top: 16px;">
9414
+ <input type="text" placeholder="Votre Nom ou Entreprise" style="padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px;" />
9415
+ <input type="email" placeholder="votre-email@pro.com" style="padding: 10px 14px; border: 1px solid #d1d5db; border-radius: 8px;" />
9416
+ <button style="padding: 12px; background: #4f46e5; color: #ffffff; font-weight: bold; border: none; border-radius: 8px; cursor: pointer;">
9417
+ Débloquer l'Estimation Instantanée
9418
+ </button>
9419
+ </div>
9420
+ <div style="margin-top: 12px; font-size: 11px; color: #9ca3af; text-align: center;">⚡ Propulsé par ${brandName} Embed Widget</div>
9421
+ </div>`;
9422
+ return {
9423
+ leadMagnetType: type,
9424
+ title,
9425
+ ctaText: "Débloquer l'Estimation Instantanée",
9426
+ inputLabels: ["Entreprise", "Email Pro"],
9427
+ embeddableHtml
9428
+ };
9429
+ }
9430
+ }
9431
+
7586
9432
  // src/index.ts
7587
9433
  function createLynxSeoEngine(config) {
7588
9434
  return new LynxSeoEngine(config);
@@ -7623,13 +9469,21 @@ var LynxSeo = {
7623
9469
  adIntelligence: AdIntelligenceCroEngine,
7624
9470
  rankMathScore: RankMathParityEngine,
7625
9471
  yoastReadability: YoastParityEngine,
7626
- socialGrowth: SocialGrowthSuite,
7627
9472
  rbac: TeamRbacEngine,
7628
- realReviews: RealReviewsSyncEngine
9473
+ realReviews: RealReviewsSyncEngine,
9474
+ knowledgeHarvester: FeaturesKnowledgeHarvester,
9475
+ manifest: PublicRoutesManifestEngine,
9476
+ knowledgeBank: KnowledgeBankBuilder,
9477
+ rag: LynxRagKnowledgeEngine,
9478
+ translator: LynxRateLimitedTranslator,
9479
+ pageRankGraph: InternalPageRankEngine,
9480
+ geoCitation: GeoCitationScorer,
9481
+ marketingSkills: MarketingSkillsEngine
7629
9482
  };
7630
9483
  var src_default = LynxSeo;
7631
9484
  export {
7632
9485
  validateSeoSlug,
9486
+ resolveLocationFromHeaders,
7633
9487
  resolveFeatureIcon,
7634
9488
  resolveBuiltInLocations,
7635
9489
  resolveBrandIcon,
@@ -7638,6 +9492,7 @@ export {
7638
9492
  getSeoAgentPrompt,
7639
9493
  src_default as default,
7640
9494
  createLynxSeoEngine,
9495
+ createDynamicLocation,
7641
9496
  cleanSeoSlug,
7642
9497
  YoastParityEngine,
7643
9498
  VideoYouTubeAnalyzer,
@@ -7660,6 +9515,7 @@ export {
7660
9515
  RssSyndicationFeedGenerator,
7661
9516
  RealReviewsSyncEngine,
7662
9517
  RankMathParityEngine,
9518
+ PublicRoutesManifestEngine,
7663
9519
  PseoMatrixEngine,
7664
9520
  PowerWordsPsychologyEngine,
7665
9521
  PSEO_AGENT_SYSTEM_PROMPT,
@@ -7667,32 +9523,41 @@ export {
7667
9523
  NGramDensityAnalyzer,
7668
9524
  McpSeoServerHub,
7669
9525
  MasterMarketingEngine,
9526
+ MarketingSkillsEngine,
7670
9527
  MULTILINGUAL_STOP_WORDS,
7671
9528
  MULTILINGUAL_POWER_WORDS,
7672
9529
  MULTILINGUAL_DISCLAIMERS,
7673
9530
  MULTILINGUAL_BANNED_DISPARAGING_WORDS,
7674
9531
  LynxSeoEngine,
7675
9532
  LynxSeo,
9533
+ LynxRateLimitedTranslator,
9534
+ LynxRagKnowledgeEngine,
7676
9535
  LynxAnalyticsClient,
7677
9536
  LlmContentCleaner,
7678
9537
  LegalDisclaimerEngine,
7679
9538
  LagoTokenMeter,
7680
9539
  KnowledgeGraphLinker,
9540
+ KnowledgeBankBuilder,
7681
9541
  KeywordPermutatorEngine,
7682
9542
  IsrCacheManager,
9543
+ InternalPageRankEngine,
7683
9544
  InstantMatrixSearchEngine,
7684
9545
  IndexNowClient,
7685
9546
  I18nDetector,
7686
9547
  HyperswitchGateway,
7687
9548
  GoogleBusinessProfileEngine,
7688
9549
  GeoMeshLinkingEngine,
9550
+ GeoCitationScorer,
7689
9551
  FreePublicToolsEngine,
9552
+ FeaturesKnowledgeHarvester,
7690
9553
  ExtendedSchemaGraphBuilder,
9554
+ ExistingMediaHarvester,
7691
9555
  EmbeddableSeoWidgetGenerator,
7692
9556
  DeepCrawlerAuditor,
7693
9557
  CrosslinkScorerEngine,
7694
9558
  CroCopywritingEngine,
7695
9559
  CopywritingFrameworksMaster,
9560
+ CONTENT_AI_40_TOOLS,
7696
9561
  BrandDnaCalendarEngine,
7697
9562
  BacklinksClient,
7698
9563
  BUILT_IN_LOCATIONS_DATABASE,