last_edit / frontend /api-integration.js
Moharek
Deploy Moharek GEO Platform
a74b879
/**
* ═══════════════════════════════════════════════════════════════
* MAHRAK GEO PLATFORM β€” API INTEGRATION
* ═══════════════════════════════════════════════════════════════
*
* This file connects the index.html UI with all backend APIs
* Handles: Smart Scan, Audit Form, Dashboard Data
*/
// ═══ CONFIG ═══
const API_BASE = 'http://localhost:8001/api'; // Point to backend on port 8001
const API_ENDPOINTS = {
// Analysis & Crawling
jobs: `${API_BASE}/jobs`,
jobResults: (jobId) => `${API_BASE}/jobs/${jobId}/results`,
jobStatus: (jobId) => `${API_BASE}/jobs/${jobId}`,
// Keywords
keywords: (jobId) => `${API_BASE}/jobs/${jobId}/keywords`,
// Tavily Search (for Smart Scan)
tavilySearch: `${API_BASE}/tavily/search`,
// Competitor Intelligence
competitorIntel: `${API_BASE}/competitor/intelligence`,
// Health Check
health: `${API_BASE}/health`,
// Auth
auth: {
login: `${API_BASE}/auth/login`,
register: `${API_BASE}/auth/register`,
me: `${API_BASE}/users/me`,
}
};
// ═══ UTILITY: Get Auth Token ═══
function getAuthToken() {
return localStorage.getItem('token') || null;
}
function setAuthToken(token) {
localStorage.setItem('token', token);
}
// ═══ UTILITY: API Request Helper ═══
async function apiRequest(endpoint, options = {}) {
const token = getAuthToken();
const headers = {
'Content-Type': 'application/json',
...options.headers,
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
try {
const response = await fetch(endpoint, {
...options,
headers,
});
const data = await response.json();
if (!response.ok) {
console.error(`API Error [${response.status}]:`, data);
throw new Error(data.error || `HTTP ${response.status}`);
}
return data;
} catch (error) {
console.error('API Request Failed:', error);
throw error;
}
}
// ═══════════════════════════════════════════════════════════════
// SMART SCAN β€” Connect to Real Backend
// ═══════════════════════════════════════════════════════════════
async function runSmartScanWithAPI(businessName) {
console.log('πŸš€ Starting Smart Scan for:', businessName);
try {
// Step 1: Check API Health
console.log('πŸ“‘ Checking API health...');
const health = await apiRequest(API_ENDPOINTS.health);
console.log('βœ“ API Health:', health);
// Step 2: Run Tavily Search for AI Visibility
console.log('πŸ€– Scanning AI Search Engines...');
const aiSearchResult = await apiRequest(API_ENDPOINTS.tavilySearch, {
method: 'POST',
body: JSON.stringify({
query: `"${businessName}" OR ${businessName} best recommendation`,
max_results: 5,
search_depth: 'advanced'
})
});
console.log('βœ“ AI Search Results:', aiSearchResult);
// Step 3: Run Tavily Search for Google Results
console.log('πŸ” Scanning Google Search...');
const googleSearchResult = await apiRequest(API_ENDPOINTS.tavilySearch, {
method: 'POST',
body: JSON.stringify({
query: businessName,
max_results: 10,
search_depth: 'basic'
})
});
console.log('βœ“ Google Search Results:', googleSearchResult);
// Step 4: Run Tavily Search for Social
console.log('πŸ“± Scanning Social Media...');
const socialSearchResult = await apiRequest(API_ENDPOINTS.tavilySearch, {
method: 'POST',
body: JSON.stringify({
query: `${businessName} site:tiktok.com OR site:instagram.com OR site:youtube.com`,
max_results: 5,
search_depth: 'basic'
})
});
console.log('βœ“ Social Search Results:', socialSearchResult);
// Step 5: Compile Results
const scanResults = {
businessName,
timestamp: new Date().toISOString(),
engines: {
aiSearch: {
name: 'AI Search (ChatGPT/Gemini/Perplexity)',
results: aiSearchResult.result?.results || [],
score: calculateScore(aiSearchResult.result?.results || []),
status: (aiSearchResult.result?.results || []).length > 0 ? 'found' : 'missing'
},
googleSearch: {
name: 'Google Search',
results: googleSearchResult.result?.results || [],
score: calculateScore(googleSearchResult.result?.results || []),
status: (googleSearchResult.result?.results || []).length > 0 ? 'found' : 'missing'
},
socialSearch: {
name: 'Social Media (TikTok/Instagram/YouTube)',
results: socialSearchResult.result?.results || [],
score: calculateScore(socialSearchResult.result?.results || []),
status: (socialSearchResult.result?.results || []).length > 0 ? 'found' : 'missing'
}
}
};
console.log('βœ“ Scan Complete:', scanResults);
return scanResults;
} catch (error) {
console.error('❌ Smart Scan Failed:', error);
throw error;
}
}
function calculateScore(results) {
if (!results || results.length === 0) return 0;
// Score based on number of results and relevance
return Math.min(100, results.length * 15);
}
// ═══════════════════════════════════════════════════════════════
// AUDIT FORM β€” Connect to Analysis System
// ═══════════════════════════════════════════════════════════════
async function submitAuditForm(formData) {
console.log('πŸ“‹ Submitting Audit Form:', formData);
try {
// Step 1: Create a new job/analysis
console.log('πŸ”„ Creating analysis job...');
const jobResponse = await apiRequest(API_ENDPOINTS.jobs, {
method: 'POST',
body: JSON.stringify({
url: formData.website,
org_name: formData.businessName,
org_url: formData.website,
max_pages: 10,
runs: 1,
metadata: {
contactName: formData.name,
contactEmail: formData.email,
contactPhone: formData.phone,
sector: formData.sector
}
})
});
if (!jobResponse.ok) {
throw new Error(jobResponse.error || 'Failed to create job');
}
const jobId = jobResponse.job_id;
console.log('βœ“ Job Created:', jobId);
// Step 2: Poll for job completion
console.log('⏳ Waiting for analysis to complete...');
const analysisResult = await pollJobCompletion(jobId);
console.log('βœ“ Analysis Complete:', analysisResult);
// Step 3: Get detailed results
console.log('πŸ“Š Fetching detailed results...');
const detailedResults = await apiRequest(API_ENDPOINTS.jobResults(jobId));
console.log('βœ“ Detailed Results:', detailedResults);
return {
jobId,
formData,
analysisResult,
detailedResults
};
} catch (error) {
console.error('❌ Audit Form Submission Failed:', error);
throw error;
}
}
async function pollJobCompletion(jobId, maxAttempts = 40, interval = 3000) {
let attempts = 0;
return new Promise((resolve, reject) => {
const poll = async () => {
try {
const jobStatus = await apiRequest(API_ENDPOINTS.jobStatus(jobId));
console.log(`[Attempt ${attempts + 1}/${maxAttempts}] Job Status:`, jobStatus.status);
if (jobStatus.status === 'completed') {
resolve(jobStatus);
} else if (jobStatus.status === 'failed') {
reject(new Error('Job failed: ' + (jobStatus.error || 'Unknown error')));
} else if (attempts >= maxAttempts) {
reject(new Error('Job polling timeout'));
} else {
attempts++;
setTimeout(poll, interval);
}
} catch (error) {
reject(error);
}
};
poll();
});
}
// ═══════════════════════════════════════════════════════════════
// DASHBOARD DATA β€” Load Real Data
// ═══════════════════════════════════════════════════════════════
async function loadDashboardData() {
console.log('πŸ“Š Loading Dashboard Data...');
try {
// Get all jobs
const jobsResponse = await apiRequest(API_ENDPOINTS.jobs);
const jobs = jobsResponse.jobs || [];
console.log('βœ“ Jobs Loaded:', jobs.length);
// Get latest completed job
const completedJobs = jobs.filter(j => j.status === 'completed');
if (completedJobs.length === 0) {
console.warn('⚠️ No completed jobs found');
return null;
}
const latestJob = completedJobs[completedJobs.length - 1];
console.log('βœ“ Latest Job:', latestJob.id);
// Get job results
const results = await apiRequest(API_ENDPOINTS.jobResults(latestJob.id));
console.log('βœ“ Job Results:', results);
// Get keywords
const keywords = await apiRequest(API_ENDPOINTS.keywords(latestJob.id));
console.log('βœ“ Keywords:', keywords);
return {
job: latestJob,
results,
keywords
};
} catch (error) {
console.error('❌ Dashboard Data Load Failed:', error);
return null;
}
}
// ═══════════════════════════════════════════════════════════════
// COMPETITOR INTELLIGENCE
// ═══════════════════════════════════════════════════════════════
async function getCompetitorIntelligence(url, industry) {
console.log('πŸ‘₯ Fetching Competitor Intelligence...');
try {
const result = await apiRequest(API_ENDPOINTS.competitorIntel, {
method: 'POST',
body: JSON.stringify({
url,
industry,
count: 5
})
});
console.log('βœ“ Competitor Intelligence:', result);
return result;
} catch (error) {
console.error('❌ Competitor Intelligence Failed:', error);
return null;
}
}
// ═══════════════════════════════════════════════════════════════
// HEALTH CHECK β€” Test All Connections
// ═══════════════════════════════════════════════════════════════
async function testAllConnections() {
console.log('πŸ” Testing All API Connections...');
const results = {
timestamp: new Date().toISOString(),
endpoints: {}
};
// Test Health
try {
const health = await apiRequest(API_ENDPOINTS.health);
results.endpoints.health = { status: 'ok', data: health };
console.log('βœ“ Health:', health);
} catch (error) {
results.endpoints.health = { status: 'error', error: error.message };
console.error('βœ— Health:', error.message);
}
// Test Auth (if token exists)
const token = getAuthToken();
if (token) {
try {
const me = await apiRequest(API_ENDPOINTS.auth.me);
results.endpoints.auth = { status: 'ok', data: me };
console.log('βœ“ Auth:', me);
} catch (error) {
results.endpoints.auth = { status: 'error', error: error.message };
console.error('βœ— Auth:', error.message);
}
}
// Test Jobs
try {
const jobs = await apiRequest(API_ENDPOINTS.jobs);
results.endpoints.jobs = { status: 'ok', count: (jobs.jobs || []).length };
console.log('βœ“ Jobs:', jobs.jobs?.length || 0);
} catch (error) {
results.endpoints.jobs = { status: 'error', error: error.message };
console.error('βœ— Jobs:', error.message);
}
console.log('πŸ“‹ Connection Test Results:', results);
return results;
}
// ═══════════════════════════════════════════════════════════════
// EXPORT FOR USE IN HTML
// ═══════════════════════════════════════════════════════════════
window.MahrakAPI = {
runSmartScanWithAPI,
submitAuditForm,
loadDashboardData,
getCompetitorIntelligence,
testAllConnections,
apiRequest,
getAuthToken,
setAuthToken,
API_ENDPOINTS
};
console.log('βœ“ Mahrak API Integration Loaded');