|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Advanced AI Content Analyzer & Humanizer</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<style> |
|
|
.gradient-bg { |
|
|
background: linear-gradient(135deg, #6e8efb 0%, #a777e3 100%); |
|
|
} |
|
|
.analyzer-bg { |
|
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
|
|
} |
|
|
.humanizer-bg { |
|
|
background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%); |
|
|
} |
|
|
.textarea-container { |
|
|
position: relative; |
|
|
} |
|
|
.word-count { |
|
|
position: absolute; |
|
|
bottom: 10px; |
|
|
right: 15px; |
|
|
font-size: 0.8rem; |
|
|
color: #6b7280; |
|
|
background-color: rgba(255, 255, 255, 0.7); |
|
|
padding: 2px 6px; |
|
|
border-radius: 10px; |
|
|
} |
|
|
.pulse { |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
@keyframes pulse { |
|
|
0% { opacity: 0.6; } |
|
|
50% { opacity: 1; } |
|
|
100% { opacity: 0.6; } |
|
|
} |
|
|
.progress-bar { |
|
|
height: 10px; |
|
|
border-radius: 5px; |
|
|
background-color: #e5e7eb; |
|
|
overflow: hidden; |
|
|
} |
|
|
.progress-fill { |
|
|
height: 100%; |
|
|
border-radius: 5px; |
|
|
transition: width 0.5s ease; |
|
|
} |
|
|
.tab { |
|
|
cursor: pointer; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.tab.active { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
|
|
} |
|
|
.metric-card { |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.metric-card:hover { |
|
|
transform: translateY(-3px); |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
.highlight-ai { |
|
|
background-color: rgba(255, 0, 0, 0.1); |
|
|
border-bottom: 2px dashed red; |
|
|
} |
|
|
.highlight-human { |
|
|
background-color: rgba(0, 255, 0, 0.1); |
|
|
border-bottom: 2px dashed green; |
|
|
} |
|
|
.highlight-neutral { |
|
|
background-color: rgba(255, 255, 0, 0.1); |
|
|
border-bottom: 2px dashed orange; |
|
|
} |
|
|
.analysis-tag { |
|
|
display: inline-block; |
|
|
padding: 2px 8px; |
|
|
border-radius: 12px; |
|
|
font-size: 0.75rem; |
|
|
font-weight: 600; |
|
|
margin-right: 4px; |
|
|
margin-bottom: 4px; |
|
|
} |
|
|
.tag-ai { |
|
|
background-color: #fee2e2; |
|
|
color: #b91c1c; |
|
|
} |
|
|
.tag-human { |
|
|
background-color: #dcfce7; |
|
|
color: #166534; |
|
|
} |
|
|
.tag-neutral { |
|
|
background-color: #fef3c7; |
|
|
color: #92400e; |
|
|
} |
|
|
.tag-warning { |
|
|
background-color: #fef3c7; |
|
|
color: #92400e; |
|
|
} |
|
|
.tag-danger { |
|
|
background-color: #fee2e2; |
|
|
color: #b91c1c; |
|
|
} |
|
|
.tag-success { |
|
|
background-color: #dcfce7; |
|
|
color: #166534; |
|
|
} |
|
|
.sentence-complexity { |
|
|
height: 4px; |
|
|
border-radius: 2px; |
|
|
margin-top: 2px; |
|
|
} |
|
|
.tooltip { |
|
|
position: relative; |
|
|
display: inline-block; |
|
|
} |
|
|
.tooltip .tooltiptext { |
|
|
visibility: hidden; |
|
|
width: 200px; |
|
|
background-color: #555; |
|
|
color: #fff; |
|
|
text-align: center; |
|
|
border-radius: 6px; |
|
|
padding: 5px; |
|
|
position: absolute; |
|
|
z-index: 1; |
|
|
bottom: 125%; |
|
|
left: 50%; |
|
|
margin-left: -100px; |
|
|
opacity: 0; |
|
|
transition: opacity 0.3s; |
|
|
} |
|
|
.tooltip:hover .tooltiptext { |
|
|
visibility: visible; |
|
|
opacity: 1; |
|
|
} |
|
|
.settings-panel { |
|
|
transition: all 0.3s ease; |
|
|
max-height: 0; |
|
|
overflow: hidden; |
|
|
} |
|
|
.settings-panel.open { |
|
|
max-height: 500px; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="min-h-screen bg-gray-50 p-4"> |
|
|
<div class="max-w-6xl mx-auto"> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg mb-6 overflow-hidden"> |
|
|
<div class="gradient-bg px-4 py-3 flex justify-between items-center cursor-pointer" id="settingsToggle"> |
|
|
<h2 class="text-lg font-semibold text-white"> |
|
|
<i class="fas fa-cog mr-2"></i> API Settings |
|
|
</h2> |
|
|
<i class="fas fa-chevron-down text-white transition-transform duration-300" id="settingsIcon"></i> |
|
|
</div> |
|
|
<div class="settings-panel" id="settingsPanel"> |
|
|
<div class="p-4"> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">DeepSeek API Key</label> |
|
|
<input |
|
|
type="password" |
|
|
id="apiKeyInput" |
|
|
class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-blue-500" |
|
|
placeholder="Enter your DeepSeek API key"> |
|
|
<p class="text-xs text-gray-500 mt-1">Your API key is stored locally in your browser and never sent to our servers.</p> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">API Endpoint</label> |
|
|
<input |
|
|
type="text" |
|
|
id="apiEndpointInput" |
|
|
class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-blue-500" |
|
|
value="https://api.deepseek.com/v1" |
|
|
placeholder="https://api.deepseek.com/v1"> |
|
|
</div> |
|
|
<div class="flex justify-between items-center"> |
|
|
<div> |
|
|
<label class="inline-flex items-center"> |
|
|
<input type="checkbox" id="saveSettingsCheckbox" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50" checked> |
|
|
<span class="ml-2 text-sm text-gray-700">Remember settings</span> |
|
|
</label> |
|
|
</div> |
|
|
<button |
|
|
id="saveSettingsBtn" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-md shadow-sm"> |
|
|
Save Settings |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="text-center mb-8"> |
|
|
<h1 class="text-3xl font-bold text-gray-800 mb-2">Advanced AI Content Analyzer & Humanizer</h1> |
|
|
<p class="text-gray-600">Comprehensive analysis of AI-generated content with detailed metrics and humanization</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="flex justify-center mb-6"> |
|
|
<div class="inline-flex rounded-lg bg-white shadow"> |
|
|
<div id="analyzerTab" class="tab analyzer-bg text-white font-medium py-2 px-6 rounded-l-lg active"> |
|
|
<i class="fas fa-chart-bar mr-2"></i>Analyzer |
|
|
</div> |
|
|
<div id="humanizerTab" class="tab humanizer-bg text-white font-medium py-2 px-6 rounded-r-lg"> |
|
|
<i class="fas fa-user mr-2"></i>Humanizer |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="analyzerPanel" class="grid grid-cols-1 lg:grid-cols-2 gap-6"> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="analyzer-bg px-4 py-3"> |
|
|
<h2 class="text-lg font-semibold text-white"> |
|
|
<i class="fas fa-keyboard mr-2"></i> AI Text Input |
|
|
</h2> |
|
|
</div> |
|
|
<div class="p-4 textarea-container"> |
|
|
<textarea |
|
|
id="aiInput" |
|
|
class="w-full h-64 p-4 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-300 resize-none" |
|
|
placeholder="Paste your AI-generated text here..."></textarea> |
|
|
<div id="inputWordCount" class="word-count">0 words</div> |
|
|
</div> |
|
|
<div class="px-4 pb-4"> |
|
|
<button |
|
|
id="analyzeBtn" |
|
|
class="w-full analyzer-bg hover:opacity-90 text-white font-bold py-3 px-6 rounded-lg shadow-lg transform transition-all duration-200 hover:scale-[1.01] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"> |
|
|
<i class="fas fa-search mr-2"></i> Analyze Content |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="analyzer-bg px-4 py-3"> |
|
|
<h2 class="text-lg font-semibold text-white"> |
|
|
<i class="fas fa-chart-pie mr-2"></i> Analysis Results |
|
|
</h2> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<div id="analysisPlaceholder" class="h-64 flex flex-col items-center justify-center text-gray-400"> |
|
|
<i class="fas fa-chart-bar text-4xl mb-4"></i> |
|
|
<p>Your analysis results will appear here</p> |
|
|
</div> |
|
|
|
|
|
<div id="analysisResults" class="hidden"> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
|
|
<div class="metric-card bg-white p-4 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<h3 class="font-semibold text-gray-700 mb-2 flex items-center"> |
|
|
<i class="fas fa-robot text-red-500 mr-2"></i> AI Detection Score |
|
|
</h3> |
|
|
<div class="flex items-center mb-1"> |
|
|
<div class="w-full progress-bar"> |
|
|
<div id="aiScoreBar" class="progress-fill bg-red-500" style="width: 0%"></div> |
|
|
</div> |
|
|
<span id="aiScoreText" class="ml-3 font-bold text-gray-700">0%</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-500">Higher score indicates more detectable AI patterns</p> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-4 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<h3 class="font-semibold text-gray-700 mb-2 flex items-center"> |
|
|
<i class="fas fa-user text-green-500 mr-2"></i> Human Likeness Score |
|
|
</h3> |
|
|
<div class="flex items-center mb-1"> |
|
|
<div class="w-full progress-bar"> |
|
|
<div id="humanScoreBar" class="progress-fill bg-green-500" style="width: 0%"></div> |
|
|
</div> |
|
|
<span id="humanScoreText" class="ml-3 font-bold text-gray-700">0%</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-500">Higher score indicates more human-like qualities</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h3 class="font-semibold text-gray-700 mb-3 flex items-center"> |
|
|
<i class="fas fa-tachometer-alt text-blue-500 mr-2"></i> Detailed Metrics |
|
|
</h3> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3"> |
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Perplexity Score</h4> |
|
|
<p id="perplexityScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Measures unpredictability of word choices. Higher values are more human-like.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="perplexityBar" class="progress-fill bg-blue-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Burstiness Score</h4> |
|
|
<p id="burstinessScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Measures variation in sentence structure. Higher values are more human-like.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="burstinessBar" class="progress-fill bg-purple-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Formality Index</h4> |
|
|
<p id="formalityScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Measures use of formal language. Higher values may indicate AI.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="formalityBar" class="progress-fill bg-yellow-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Passive Voice</h4> |
|
|
<p id="passiveScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Percentage of passive voice constructions. Higher values may indicate AI.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="passiveBar" class="progress-fill bg-orange-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Sentence Variation</h4> |
|
|
<p id="sentenceVarScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Measures diversity in sentence length and structure. Higher is better.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="sentenceVarBar" class="progress-fill bg-teal-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="metric-card bg-white p-3 rounded-lg border border-gray-200 shadow-sm"> |
|
|
<div class="flex justify-between items-start"> |
|
|
<div> |
|
|
<h4 class="text-sm font-medium text-gray-600">Personalization</h4> |
|
|
<p id="personalScore" class="text-lg font-bold">--</p> |
|
|
</div> |
|
|
<div class="tooltip"> |
|
|
<i class="fas fa-info-circle text-gray-400"></i> |
|
|
<span class="tooltiptext">Measures use of personal pronouns and anecdotes. Higher is better.</span> |
|
|
</div> |
|
|
</div> |
|
|
<div class="progress-bar mt-2"> |
|
|
<div id="personalBar" class="progress-fill bg-pink-500" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h3 class="font-semibold text-gray-700 mb-3 flex items-center"> |
|
|
<i class="fas fa-search text-blue-500 mr-2"></i> Text Analysis |
|
|
</h3> |
|
|
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200 max-h-60 overflow-y-auto"> |
|
|
<div id="analyzedText" class="whitespace-pre-wrap"></div> |
|
|
</div> |
|
|
<div class="mt-2 flex flex-wrap"> |
|
|
<span class="text-xs mr-3"><span class="inline-block w-3 h-3 bg-red-100 border border-red-300 mr-1"></span> AI-like patterns</span> |
|
|
<span class="text-xs mr-3"><span class="inline-block w-3 h-3 bg-green-100 border border-green-300 mr-1"></span> Human-like patterns</span> |
|
|
<span class="text-xs"><span class="inline-block w-3 h-3 bg-yellow-100 border border-yellow-300 mr-1"></span> Neutral/Uncertain</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-4"> |
|
|
<h3 class="font-semibold text-gray-700 mb-3 flex items-center"> |
|
|
<i class="fas fa-lightbulb text-blue-500 mr-2"></i> Key Findings |
|
|
</h3> |
|
|
<div id="keyFindings" class="space-y-2"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-4"> |
|
|
<h3 class="font-semibold text-gray-700 mb-2 flex items-center"> |
|
|
<i class="fas fa-exclamation-triangle text-orange-500 mr-2"></i> Common AI Patterns Detected |
|
|
</h3> |
|
|
<div id="aiPatterns" class="flex flex-wrap"> |
|
|
|
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-6 pt-4 border-t border-gray-200"> |
|
|
<button |
|
|
id="proceedToHumanizeBtn" |
|
|
class="w-full humanizer-bg hover:opacity-90 text-white font-bold py-3 px-6 rounded-lg shadow-lg transform transition-all duration-200 hover:scale-[1.01] focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-opacity-50"> |
|
|
<i class="fas fa-magic mr-2"></i> Humanize This Content |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="humanizerPanel" class="hidden grid grid-cols-1 lg:grid-cols-2 gap-6"> |
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="humanizer-bg px-4 py-3"> |
|
|
<h2 class="text-lg font-semibold text-white"> |
|
|
<i class="fas fa-keyboard mr-2"></i> Text to Humanize |
|
|
</h2> |
|
|
</div> |
|
|
<div class="p-4 textarea-container"> |
|
|
<textarea |
|
|
id="humanizerInput" |
|
|
class="w-full h-64 p-4 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-300 resize-none" |
|
|
placeholder="Text to humanize will appear here..."></textarea> |
|
|
<div id="humanizerWordCount" class="word-count">0 words</div> |
|
|
</div> |
|
|
<div class="px-4 pb-4"> |
|
|
<div class="grid grid-cols-2 gap-3 mb-3"> |
|
|
<div> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Humanization Level</label> |
|
|
<select id="humanizeLevel" class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-purple-500"> |
|
|
<option value="light">Light (subtle changes)</option> |
|
|
<option value="medium" selected>Medium (balanced)</option> |
|
|
<option value="heavy">Heavy (complete rewrite)</option> |
|
|
</select> |
|
|
</div> |
|
|
<div> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Target Tone</label> |
|
|
<select id="targetTone" class="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:ring-2 focus:ring-purple-500"> |
|
|
<option value="neutral">Neutral</option> |
|
|
<option value="casual">Casual</option> |
|
|
<option value="professional">Professional</option> |
|
|
<option value="friendly">Friendly</option> |
|
|
<option value="academic">Academic</option> |
|
|
</select> |
|
|
</div> |
|
|
</div> |
|
|
<button |
|
|
id="humanizeBtn" |
|
|
class="w-full humanizer-bg hover:opacity-90 text-white font-bold py-3 px-6 rounded-lg shadow-lg transform transition-all duration-200 hover:scale-[1.01] focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-opacity-50"> |
|
|
<i class="fas fa-magic mr-2"></i> Humanize Text |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
<div class="humanizer-bg px-4 py-3"> |
|
|
<h2 class="text-lg font-semibold text-white"> |
|
|
<i class="fas fa-user mr-2"></i> Humanized Output |
|
|
</h2> |
|
|
</div> |
|
|
<div class="p-4 textarea-container"> |
|
|
<textarea |
|
|
id="humanOutput" |
|
|
class="w-full h-64 p-4 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-300 resize-none bg-gray-50" |
|
|
placeholder="Your humanized text will appear here..." |
|
|
readonly></textarea> |
|
|
<div id="outputWordCount" class="word-count">0 words</div> |
|
|
</div> |
|
|
<div class="px-4 pb-4 grid grid-cols-2 gap-3"> |
|
|
<button |
|
|
id="copyBtn" |
|
|
class="bg-gray-700 hover:bg-gray-800 text-white font-bold py-3 px-6 rounded-lg shadow-lg transform transition-all duration-200 hover:scale-[1.01] focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-opacity-50"> |
|
|
<i class="fas fa-copy mr-2"></i> Copy |
|
|
</button> |
|
|
<button |
|
|
id="analyzeAgainBtn" |
|
|
class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg shadow-lg transform transition-all duration-200 hover:scale-[1.01] focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50"> |
|
|
<i class="fas fa-redo mr-2"></i> Re-analyze |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mt-4 text-center"> |
|
|
<div id="analyzerLoading" class="hidden"> |
|
|
<div class="inline-flex items-center analyzer-bg text-white py-2 px-4 rounded-full"> |
|
|
<div class="pulse"> |
|
|
<i class="fas fa-spinner fa-spin mr-2"></i> |
|
|
</div> |
|
|
<span>Analyzing content with advanced metrics...</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="humanizerLoading" class="hidden"> |
|
|
<div class="inline-flex items-center humanizer-bg text-white py-2 px-4 rounded-full"> |
|
|
<div class="pulse"> |
|
|
<i class="fas fa-spinner fa-spin mr-2"></i> |
|
|
</div> |
|
|
<span>Humanizing content (this may take a moment)...</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="errorMessage" class="mt-2 hidden"> |
|
|
<div class="inline-flex items-center bg-red-100 border border-red-400 text-red-700 px-3 py-2 rounded"> |
|
|
<i class="fas fa-exclamation-circle mr-2"></i> |
|
|
<span id="errorText">Something went wrong. Please try again.</span> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const aiInput = document.getElementById('aiInput'); |
|
|
const humanizerInput = document.getElementById('humanizerInput'); |
|
|
const humanOutput = document.getElementById('humanOutput'); |
|
|
const analyzeBtn = document.getElementById('analyzeBtn'); |
|
|
const proceedToHumanizeBtn = document.getElementById('proceedToHumanizeBtn'); |
|
|
const humanizeBtn = document.getElementById('humanizeBtn'); |
|
|
const copyBtn = document.getElementById('copyBtn'); |
|
|
const analyzeAgainBtn = document.getElementById('analyzeAgainBtn'); |
|
|
const analyzerLoading = document.getElementById('analyzerLoading'); |
|
|
const humanizerLoading = document.getElementById('humanizerLoading'); |
|
|
const errorMessage = document.getElementById('errorMessage'); |
|
|
const inputWordCount = document.getElementById('inputWordCount'); |
|
|
const humanizerWordCount = document.getElementById('humanizerWordCount'); |
|
|
const outputWordCount = document.getElementById('outputWordCount'); |
|
|
const analysisPlaceholder = document.getElementById('analysisPlaceholder'); |
|
|
const analysisResults = document.getElementById('analysisResults'); |
|
|
const aiScoreBar = document.getElementById('aiScoreBar'); |
|
|
const aiScoreText = document.getElementById('aiScoreText'); |
|
|
const humanScoreBar = document.getElementById('humanScoreBar'); |
|
|
const humanScoreText = document.getElementById('humanScoreText'); |
|
|
const keyFindings = document.getElementById('keyFindings'); |
|
|
const aiPatterns = document.getElementById('aiPatterns'); |
|
|
const analyzedText = document.getElementById('analyzedText'); |
|
|
const analyzerTab = document.getElementById('analyzerTab'); |
|
|
const humanizerTab = document.getElementById('humanizerTab'); |
|
|
const analyzerPanel = document.getElementById('analyzerPanel'); |
|
|
const humanizerPanel = document.getElementById('humanizerPanel'); |
|
|
const perplexityScore = document.getElementById('perplexityScore'); |
|
|
const perplexityBar = document.getElementById('perplexityBar'); |
|
|
const burstinessScore = document.getElementById('burstinessScore'); |
|
|
const burstinessBar = document.getElementById('burstinessBar'); |
|
|
const formalityScore = document.getElementById('formalityScore'); |
|
|
const formalityBar = document.getElementById('formalityBar'); |
|
|
const passiveScore = document.getElementById('passiveScore'); |
|
|
const passiveBar = document.getElementById('passiveBar'); |
|
|
const sentenceVarScore = document.getElementById('sentenceVarScore'); |
|
|
const sentenceVarBar = document.getElementById('sentenceVarBar'); |
|
|
const personalScore = document.getElementById('personalScore'); |
|
|
const personalBar = document.getElementById('personalBar'); |
|
|
const humanizeLevel = document.getElementById('humanizeLevel'); |
|
|
const targetTone = document.getElementById('targetTone'); |
|
|
const settingsToggle = document.getElementById('settingsToggle'); |
|
|
const settingsPanel = document.getElementById('settingsPanel'); |
|
|
const settingsIcon = document.getElementById('settingsIcon'); |
|
|
const apiKeyInput = document.getElementById('apiKeyInput'); |
|
|
const apiEndpointInput = document.getElementById('apiEndpointInput'); |
|
|
const saveSettingsCheckbox = document.getElementById('saveSettingsCheckbox'); |
|
|
const saveSettingsBtn = document.getElementById('saveSettingsBtn'); |
|
|
|
|
|
|
|
|
settingsToggle.addEventListener('click', function() { |
|
|
settingsPanel.classList.toggle('open'); |
|
|
settingsIcon.classList.toggle('rotate-180'); |
|
|
}); |
|
|
|
|
|
|
|
|
function loadSettings() { |
|
|
const savedSettings = localStorage.getItem('deepseekSettings'); |
|
|
if (savedSettings) { |
|
|
const settings = JSON.parse(savedSettings); |
|
|
apiKeyInput.value = settings.apiKey || ''; |
|
|
apiEndpointInput.value = settings.apiEndpoint || 'https://api.deepseek.com/v1'; |
|
|
saveSettingsCheckbox.checked = settings.saveSettings !== false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
saveSettingsBtn.addEventListener('click', function() { |
|
|
const settings = { |
|
|
apiKey: apiKeyInput.value, |
|
|
apiEndpoint: apiEndpointInput.value, |
|
|
saveSettings: saveSettingsCheckbox.checked |
|
|
}; |
|
|
|
|
|
if (saveSettingsCheckbox.checked) { |
|
|
localStorage.setItem('deepseekSettings', JSON.stringify(settings)); |
|
|
} else { |
|
|
localStorage.removeItem('deepseekSettings'); |
|
|
} |
|
|
|
|
|
showSuccess("Settings saved successfully!"); |
|
|
}); |
|
|
|
|
|
|
|
|
loadSettings(); |
|
|
|
|
|
|
|
|
analyzerTab.addEventListener('click', function() { |
|
|
analyzerTab.classList.add('active'); |
|
|
humanizerTab.classList.remove('active'); |
|
|
analyzerPanel.classList.remove('hidden'); |
|
|
humanizerPanel.classList.add('hidden'); |
|
|
}); |
|
|
|
|
|
humanizerTab.addEventListener('click', function() { |
|
|
if (humanizerInput.value.trim() === '') { |
|
|
showError("Please analyze content first before humanizing"); |
|
|
return; |
|
|
} |
|
|
humanizerTab.classList.add('active'); |
|
|
analyzerTab.classList.remove('active'); |
|
|
analyzerPanel.classList.add('hidden'); |
|
|
humanizerPanel.classList.remove('hidden'); |
|
|
}); |
|
|
|
|
|
|
|
|
aiInput.addEventListener('input', function() { |
|
|
const text = aiInput.value.trim(); |
|
|
const words = text ? text.split(/\s+/).length : 0; |
|
|
inputWordCount.textContent = `${words} words`; |
|
|
}); |
|
|
|
|
|
humanizerInput.addEventListener('input', function() { |
|
|
const text = humanizerInput.value.trim(); |
|
|
const words = text ? text.split(/\s+/).length : 0; |
|
|
humanizerWordCount.textContent = `${words} words`; |
|
|
}); |
|
|
|
|
|
|
|
|
analyzeBtn.addEventListener('click', async function() { |
|
|
const inputText = aiInput.value.trim(); |
|
|
|
|
|
if (!inputText) { |
|
|
showError("Please enter some text to analyze."); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
analyzerLoading.classList.remove('hidden'); |
|
|
errorMessage.classList.add('hidden'); |
|
|
analyzeBtn.disabled = true; |
|
|
analyzeBtn.classList.add('opacity-75'); |
|
|
|
|
|
try { |
|
|
|
|
|
const analysis = await simulateComprehensiveAnalysis(inputText); |
|
|
|
|
|
|
|
|
displayAnalysisResults(analysis); |
|
|
|
|
|
|
|
|
humanizerInput.value = inputText; |
|
|
const words = inputText ? inputText.split(/\s+/).length : 0; |
|
|
humanizerWordCount.textContent = `${words} words`; |
|
|
|
|
|
} catch (error) { |
|
|
console.error("Error:", error); |
|
|
showError("Failed to analyze text. Please try again later."); |
|
|
} finally { |
|
|
analyzerLoading.classList.add('hidden'); |
|
|
analyzeBtn.disabled = false; |
|
|
analyzeBtn.classList.remove('opacity-75'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
proceedToHumanizeBtn.addEventListener('click', function() { |
|
|
humanizerTab.click(); |
|
|
}); |
|
|
|
|
|
|
|
|
humanizeBtn.addEventListener('click', async function() { |
|
|
const inputText = humanizerInput.value.trim(); |
|
|
const level = humanizeLevel.value; |
|
|
const tone = targetTone.value; |
|
|
|
|
|
if (!inputText) { |
|
|
showError("Please enter some text to humanize."); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const apiKey = apiKeyInput.value.trim(); |
|
|
if (!apiKey) { |
|
|
showError("Please enter your DeepSeek API key in the settings panel."); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
humanizerLoading.classList.remove('hidden'); |
|
|
errorMessage.classList.add('hidden'); |
|
|
humanizeBtn.disabled = true; |
|
|
humanizeBtn.classList.add('opacity-75'); |
|
|
|
|
|
try { |
|
|
|
|
|
const humanizedText = await callDeepSeekApi(inputText, level, tone, apiKey); |
|
|
|
|
|
if (humanizedText) { |
|
|
humanOutput.value = humanizedText; |
|
|
|
|
|
|
|
|
const words = humanizedText ? humanizedText.split(/\s+/).length : 0; |
|
|
outputWordCount.textContent = `${words} words`; |
|
|
} else { |
|
|
showError("Failed to humanize text. No response from API."); |
|
|
} |
|
|
|
|
|
} catch (error) { |
|
|
console.error("Error:", error); |
|
|
showError("Failed to humanize text. Please check your API key and try again."); |
|
|
} finally { |
|
|
humanizerLoading.classList.add('hidden'); |
|
|
humanizeBtn.disabled = false; |
|
|
humanizeBtn.classList.remove('opacity-75'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
copyBtn.addEventListener('click', function() { |
|
|
if (humanOutput.value) { |
|
|
humanOutput.select(); |
|
|
document.execCommand('copy'); |
|
|
|
|
|
|
|
|
const tooltip = document.createElement('div'); |
|
|
tooltip.className = 'fixed bg-gray-800 text-white px-3 py-1 rounded text-sm'; |
|
|
tooltip.textContent = 'Copied!'; |
|
|
tooltip.style.top = (event.pageY - 40) + 'px'; |
|
|
tooltip.style.left = (event.pageX - 30) + 'px'; |
|
|
document.body.appendChild(tooltip); |
|
|
|
|
|
setTimeout(() => { |
|
|
document.body.removeChild(tooltip); |
|
|
}, 1000); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
analyzeAgainBtn.addEventListener('click', function() { |
|
|
if (humanOutput.value.trim()) { |
|
|
aiInput.value = humanOutput.value; |
|
|
humanizerInput.value = humanOutput.value; |
|
|
const words = humanOutput.value ? humanOutput.value.split(/\s+/).length : 0; |
|
|
inputWordCount.textContent = `${words} words`; |
|
|
humanizerWordCount.textContent = `${words} words`; |
|
|
analyzerTab.click(); |
|
|
analyzeBtn.click(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
async function callDeepSeekApi(text, level, tone, apiKey) { |
|
|
const endpoint = apiEndpointInput.value.trim() || 'https://api.deepseek.com/v1'; |
|
|
|
|
|
|
|
|
let prompt = `Please humanize the following text to make it sound more natural and less like AI-generated content. `; |
|
|
|
|
|
if (level === 'light') { |
|
|
prompt += `Make subtle changes only, keeping most of the original structure intact. `; |
|
|
} else if (level === 'medium') { |
|
|
prompt += `Make balanced changes, improving flow and naturalness while preserving the core meaning. `; |
|
|
} else if (level === 'heavy') { |
|
|
prompt += `Completely rewrite the text to make it sound entirely human-written, using more varied sentence structures and natural phrasing. `; |
|
|
} |
|
|
|
|
|
if (tone === 'casual') { |
|
|
prompt += `Use a casual, conversational tone. `; |
|
|
} else if (tone === 'professional') { |
|
|
prompt += `Use a professional, formal tone. `; |
|
|
} else if (tone === 'friendly') { |
|
|
prompt += `Use a friendly, approachable tone. `; |
|
|
} else if (tone === 'academic') { |
|
|
prompt += `Use an academic, scholarly tone. `; |
|
|
} else { |
|
|
prompt += `Use a neutral tone. `; |
|
|
} |
|
|
|
|
|
prompt += `Here's the text to humanize:\n\n${text}`; |
|
|
|
|
|
const requestBody = { |
|
|
model: "deepseek-chat", |
|
|
messages: [ |
|
|
{ |
|
|
role: "user", |
|
|
content: prompt |
|
|
} |
|
|
], |
|
|
temperature: 0.7, |
|
|
max_tokens: 2000 |
|
|
}; |
|
|
|
|
|
const response = await fetch(`${endpoint}/chat/completions`, { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Content-Type': 'application/json', |
|
|
'Authorization': `Bearer ${apiKey}` |
|
|
}, |
|
|
body: JSON.stringify(requestBody) |
|
|
}); |
|
|
|
|
|
if (!response.ok) { |
|
|
const errorData = await response.json(); |
|
|
throw new Error(errorData.error?.message || 'API request failed'); |
|
|
} |
|
|
|
|
|
const data = await response.json(); |
|
|
return data.choices?.[0]?.message?.content || ''; |
|
|
} |
|
|
|
|
|
|
|
|
function displayAnalysisResults(analysis) { |
|
|
analysisPlaceholder.classList.add('hidden'); |
|
|
analysisResults.classList.remove('hidden'); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
aiScoreBar.style.width = `${analysis.aiScore}%`; |
|
|
humanScoreBar.style.width = `${analysis.humanScore}%`; |
|
|
aiScoreText.textContent = `${analysis.aiScore}%`; |
|
|
humanScoreText.textContent = `${analysis.humanScore}%`; |
|
|
|
|
|
|
|
|
perplexityScore.textContent = analysis.perplexity; |
|
|
perplexityBar.style.width = `${analysis.perplexity}%`; |
|
|
burstinessScore.textContent = analysis.burstiness; |
|
|
burstinessBar.style.width = `${analysis.burstiness}%`; |
|
|
formalityScore.textContent = analysis.formality; |
|
|
formalityBar.style.width = `${analysis.formality}%`; |
|
|
passiveScore.textContent = `${analysis.passiveVoice}%`; |
|
|
passiveBar.style.width = `${analysis.passiveVoice}%`; |
|
|
sentenceVarScore.textContent = analysis.sentenceVariation; |
|
|
sentenceVarBar.style.width = `${analysis.sentenceVariation}%`; |
|
|
personalScore.textContent = analysis.personalization; |
|
|
personalBar.style.width = `${analysis.personalization}%`; |
|
|
}, 100); |
|
|
|
|
|
|
|
|
keyFindings.innerHTML = ''; |
|
|
analysis.findings.forEach(finding => { |
|
|
const div = document.createElement('div'); |
|
|
div.className = 'flex items-start'; |
|
|
div.innerHTML = ` |
|
|
<div class="flex-shrink-0 mt-1 mr-2"> |
|
|
<i class="fas ${finding.severity === 'high' ? 'fa-exclamation-circle text-red-500' : finding.severity === 'medium' ? 'fa-info-circle text-yellow-500' : 'fa-check-circle text-green-500'}"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="text-gray-700">${finding.text}</p> |
|
|
${finding.suggestion ? `<p class="text-sm text-gray-500 mt-1">${finding.suggestion}</p>` : ''} |
|
|
</div> |
|
|
`; |
|
|
keyFindings.appendChild(div); |
|
|
}); |
|
|
|
|
|
|
|
|
aiPatterns.innerHTML = ''; |
|
|
analysis.patterns.forEach(pattern => { |
|
|
const span = document.createElement('span'); |
|
|
span.className = `analysis-tag ${pattern.type === 'ai' ? 'tag-ai' : pattern.type === 'human' ? 'tag-human' : 'tag-neutral'}`; |
|
|
span.textContent = pattern.text; |
|
|
aiPatterns.appendChild(span); |
|
|
}); |
|
|
|
|
|
|
|
|
analyzedText.innerHTML = ''; |
|
|
const textSegments = analysis.textSegments; |
|
|
|
|
|
textSegments.forEach(segment => { |
|
|
const span = document.createElement('span'); |
|
|
span.className = segment.class; |
|
|
span.textContent = segment.text; |
|
|
|
|
|
if (segment.tooltip) { |
|
|
span.classList.add('tooltip'); |
|
|
const tooltipSpan = document.createElement('span'); |
|
|
tooltipSpan.className = 'tooltiptext'; |
|
|
tooltipSpan.textContent = segment.tooltip; |
|
|
span.appendChild(tooltipSpan); |
|
|
} |
|
|
|
|
|
analyzedText.appendChild(span); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function simulateComprehensiveAnalysis(text) { |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 2000)); |
|
|
|
|
|
|
|
|
const wordCount = text.split(/\s+/).length; |
|
|
const sentenceCount = text.split(/[.!?]+/).filter(s => s.trim().length > 0).length; |
|
|
const avgSentenceLength = wordCount / sentenceCount; |
|
|
const aiKeywords = ['artificial intelligence', 'machine learning', 'algorithm', 'neural network', 'AI model', 'deep learning', 'language model']; |
|
|
const formalWords = ['utilize', 'commence', 'terminate', 'optimal', 'endeavor', 'ascertain', 'ameliorate', 'furthermore', 'moreover', 'however']; |
|
|
const passiveVoiceRegex = /\b(am|is|are|was|were|be|being|been)\s+[a-z]+\b/gi; |
|
|
|
|
|
|
|
|
let aiScore = 0; |
|
|
let patterns = []; |
|
|
let textSegments = []; |
|
|
let findings = []; |
|
|
|
|
|
|
|
|
aiKeywords.forEach(keyword => { |
|
|
const regex = new RegExp(keyword, 'gi'); |
|
|
const matches = text.match(regex); |
|
|
if (matches) { |
|
|
aiScore += matches.length * 5; |
|
|
patterns.push({ type: 'ai', text: `AI keyword: ${keyword}` }); |
|
|
|
|
|
|
|
|
let lastIndex = 0; |
|
|
let match; |
|
|
while ((match = regex.exec(text)) !== null) { |
|
|
|
|
|
if (match.index > lastIndex) { |
|
|
textSegments.push({ |
|
|
text: text.substring(lastIndex, match.index), |
|
|
class: '' |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
textSegments.push({ |
|
|
text: match[0], |
|
|
class: 'highlight-ai', |
|
|
tooltip: `AI-related keyword detected` |
|
|
}); |
|
|
|
|
|
lastIndex = regex.lastIndex; |
|
|
} |
|
|
|
|
|
|
|
|
if (lastIndex < text.length) { |
|
|
textSegments.push({ |
|
|
text: text.substring(lastIndex), |
|
|
class: '' |
|
|
}); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
let formalWordCount = 0; |
|
|
formalWords.forEach(word => { |
|
|
const regex = new RegExp(`\\b${word}\\b`, 'gi'); |
|
|
const matches = text.match(regex); |
|
|
if (matches) { |
|
|
formalWordCount += matches.length; |
|
|
patterns.push({ type: 'ai', text: `Formal word: ${word}` }); |
|
|
} |
|
|
}); |
|
|
|
|
|
if (formalWordCount > 0) { |
|
|
aiScore += Math.min(30, formalWordCount * 3); |
|
|
findings.push({ |
|
|
text: `Found ${formalWordCount} overly formal word${formalWordCount > 1 ? 's' : ''} (e.g., ${formalWords.find(w => text.toLowerCase().includes(w)) || 'utilize'})`, |
|
|
severity: 'medium', |
|
|
suggestion: 'Consider replacing with more natural alternatives' |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const passiveMatches = text.match(passiveVoiceRegex) || []; |
|
|
const passiveVoicePercentage = Math.round((passiveMatches.length / sentenceCount) * 100); |
|
|
if (passiveVoicePercentage > 20) { |
|
|
aiScore += Math.min(20, (passiveVoicePercentage - 20)); |
|
|
findings.push({ |
|
|
text: `High passive voice usage (${passiveVoicePercentage}% of sentences)`, |
|
|
severity: 'medium', |
|
|
suggestion: 'Try to use more active voice constructions' |
|
|
}); |
|
|
patterns.push({ type: 'ai', text: `Passive voice overuse` }); |
|
|
} |
|
|
|
|
|
|
|
|
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0); |
|
|
const sentenceLengths = sentences.map(s => s.split(/\s+/).length); |
|
|
const lengthVariation = calculateVariation(sentenceLengths); |
|
|
|
|
|
if (lengthVariation < 0.4) { |
|
|
aiScore += 15; |
|
|
findings.push({ |
|
|
text: 'Low sentence length variation detected', |
|
|
severity: 'medium', |
|
|
suggestion: 'Try mixing short, medium and long sentences' |
|
|
}); |
|
|
patterns.push({ type: 'ai', text: `Uniform sentence length` }); |
|
|
} |
|
|
|
|
|
|
|
|
const phraseRepetition = checkPhraseRepetition(text); |
|
|
if (phraseRepetition.count > 0) { |
|
|
aiScore += Math.min(20, phraseRepetition.count * 5); |
|
|
findings.push({ |
|
|
text: `Repetitive phrasing detected (e.g., "${phraseRepetition.example}")`, |
|
|
severity: 'high', |
|
|
suggestion: 'Try to vary your phrasing and word choice' |
|
|
}); |
|
|
patterns.push({ type: 'ai', text: `Repetitive phrasing` }); |
|
|
} |
|
|
|
|
|
|
|
|
const personalPronouns = (text.match(/\b(I|me|my|mine|we|us|our|ours)\b/gi) || []).length; |
|
|
const personalizationScore = Math.min(100, Math.round((personalPronouns / wordCount) * 10000)); |
|
|
|
|
|
if (personalizationScore < 5) { |
|
|
aiScore += 10; |
|
|
findings.push({ |
|
|
text: 'Lack of personal pronouns or subjective perspective', |
|
|
severity: 'low', |
|
|
suggestion: 'Consider adding personal perspective where appropriate' |
|
|
}); |
|
|
patterns.push({ type: 'ai', text: `Lacks personalization` }); |
|
|
} |
|
|
|
|
|
|
|
|
const vaguePhrases = ['many ways', 'various aspects', 'numerous factors', 'multiple benefits', 'revolutionizing', 'transformative impact']; |
|
|
let vagueCount = 0; |
|
|
vaguePhrases.forEach(phrase => { |
|
|
if (text.toLowerCase().includes(phrase)) { |
|
|
vagueCount++; |
|
|
} |
|
|
}); |
|
|
|
|
|
if (vagueCount > 0) { |
|
|
aiScore += Math.min(15, vagueCount * 3); |
|
|
findings.push({ |
|
|
text: `Found ${vagueCount} vague generalization${vagueCount > 1 ? 's' : ''}`, |
|
|
severity: 'medium', |
|
|
suggestion: 'Try to be more specific with examples or data' |
|
|
}); |
|
|
patterns.push({ type: 'ai', text: `Vague generalizations` }); |
|
|
} |
|
|
|
|
|
|
|
|
const grammarErrors = (text.match(/\b(ain't|gonna|wanna|gotta|kinda|sorta)\b/gi) || []).length; |
|
|
if (grammarErrors === 0 && wordCount > 100) { |
|
|
aiScore += 5; |
|
|
findings.push({ |
|
|
text: 'No colloquialisms or informal grammar detected', |
|
|
severity: 'low', |
|
|
suggestion: 'In casual contexts, some informal language can sound more natural' |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
aiScore = Math.min(100, Math.max(0, aiScore)); |
|
|
|
|
|
|
|
|
const humanScore = Math.min(100, Math.max(0, 100 - aiScore + (Math.random() * 20 - 10))); |
|
|
|
|
|
|
|
|
const perplexity = Math.min(100, Math.max(0, |
|
|
70 - (aiScore * 0.6) + (Math.random() * 20 - 10) |
|
|
)); |
|
|
|
|
|
|
|
|
const burstiness = Math.min(100, Math.max(0, |
|
|
60 - (aiScore * 0.5) + (Math.random() * 20 - 10) |
|
|
)); |
|
|
|
|
|
|
|
|
const formality = Math.min(100, Math.max(0, |
|
|
20 + (aiScore * 0.4) + (Math.random() * 10 - 5) |
|
|
)); |
|
|
|
|
|
|
|
|
const sentenceVariation = Math.min(100, Math.max(0, |
|
|
40 + (lengthVariation * 60) + (Math.random() * 10 - 5) |
|
|
)); |
|
|
|
|
|
|
|
|
if (humanScore > 70) { |
|
|
findings.unshift({ |
|
|
text: 'Content shows strong human-like qualities', |
|
|
severity: 'low' |
|
|
}); |
|
|
patterns.push({ type: 'human', text: `Human-like qualities` }); |
|
|
} |
|
|
|
|
|
if (personalizationScore > 10) { |
|
|
findings.unshift({ |
|
|
text: 'Contains personal perspective or subjective elements', |
|
|
severity: 'low' |
|
|
}); |
|
|
patterns.push({ type: 'human', text: `Personal perspective` }); |
|
|
} |
|
|
|
|
|
if (lengthVariation > 0.6) { |
|
|
findings.unshift({ |
|
|
text: 'Good variation in sentence length and structure', |
|
|
severity: 'low' |
|
|
}); |
|
|
patterns.push({ type: 'human', text: `Sentence variation` }); |
|
|
} |
|
|
|
|
|
return { |
|
|
aiScore: Math.round(aiScore), |
|
|
humanScore: Math.round(humanScore), |
|
|
perplexity: Math.round(perplexity), |
|
|
burstiness: Math.round(burstiness), |
|
|
formality: Math.round(formality), |
|
|
passiveVoice: passiveVoicePercentage, |
|
|
sentenceVariation: Math.round(sentenceVariation), |
|
|
personalization: personalizationScore, |
|
|
findings: findings, |
|
|
patterns: patterns, |
|
|
textSegments: textSegments.length > 0 ? textSegments : [{ text: text, class: '' }] |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
function calculateVariation(values) { |
|
|
if (values.length < 2) return 0; |
|
|
const mean = values.reduce((a, b) => a + b) / values.length; |
|
|
const variance = values.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / values.length; |
|
|
const stdDev = Math.sqrt(variance); |
|
|
return stdDev / mean; |
|
|
} |
|
|
|
|
|
|
|
|
function checkPhraseRepetition(text) { |
|
|
const phrases = [ |
|
|
'it is important to note', |
|
|
'in conclusion', |
|
|
'as a result', |
|
|
'in other words', |
|
|
'on the other hand', |
|
|
'in addition', |
|
|
'for example', |
|
|
'this means that', |
|
|
'it should be noted', |
|
|
'as mentioned earlier' |
|
|
]; |
|
|
|
|
|
let maxCount = 0; |
|
|
let maxPhrase = ''; |
|
|
|
|
|
phrases.forEach(phrase => { |
|
|
const regex = new RegExp(phrase, 'gi'); |
|
|
const matches = text.match(regex) || []; |
|
|
if (matches.length > maxCount) { |
|
|
maxCount = matches.length; |
|
|
maxPhrase = phrase; |
|
|
} |
|
|
}); |
|
|
|
|
|
return { count: maxCount, example: maxPhrase }; |
|
|
} |
|
|
|
|
|
function showError(message) { |
|
|
errorText.textContent = message; |
|
|
errorMessage.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
function showSuccess(message) { |
|
|
const successDiv = document.createElement('div'); |
|
|
successDiv.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-md shadow-lg flex items-center'; |
|
|
successDiv.innerHTML = ` |
|
|
<i class="fas fa-check-circle mr-2"></i> |
|
|
<span>${message}</span> |
|
|
`; |
|
|
document.body.appendChild(successDiv); |
|
|
|
|
|
setTimeout(() => { |
|
|
document.body.removeChild(successDiv); |
|
|
}, 3000); |
|
|
} |
|
|
}); |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=sqibhe/humanizer" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |