| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| const API_BASE = 'http://localhost:8001/api'; |
| const API_ENDPOINTS = { |
| |
| jobs: `${API_BASE}/jobs`, |
| jobResults: (jobId) => `${API_BASE}/jobs/${jobId}/results`, |
| jobStatus: (jobId) => `${API_BASE}/jobs/${jobId}`, |
| |
| |
| keywords: (jobId) => `${API_BASE}/jobs/${jobId}/keywords`, |
| |
| |
| tavilySearch: `${API_BASE}/tavily/search`, |
| |
| |
| competitorIntel: `${API_BASE}/competitor/intelligence`, |
| |
| |
| health: `${API_BASE}/health`, |
| |
| |
| auth: { |
| login: `${API_BASE}/auth/login`, |
| register: `${API_BASE}/auth/register`, |
| me: `${API_BASE}/users/me`, |
| } |
| }; |
|
|
| |
| function getAuthToken() { |
| return localStorage.getItem('token') || null; |
| } |
|
|
| function setAuthToken(token) { |
| localStorage.setItem('token', token); |
| } |
|
|
| |
| 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; |
| } |
| } |
|
|
| |
| |
| |
|
|
| async function runSmartScanWithAPI(businessName) { |
| console.log('π Starting Smart Scan for:', businessName); |
| |
| try { |
| |
| console.log('π‘ Checking API health...'); |
| const health = await apiRequest(API_ENDPOINTS.health); |
| console.log('β API Health:', health); |
| |
| |
| 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); |
| |
| |
| 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); |
| |
| |
| 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); |
| |
| |
| 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; |
| |
| return Math.min(100, results.length * 15); |
| } |
|
|
| |
| |
| |
|
|
| async function submitAuditForm(formData) { |
| console.log('π Submitting Audit Form:', formData); |
| |
| try { |
| |
| 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); |
| |
| |
| console.log('β³ Waiting for analysis to complete...'); |
| const analysisResult = await pollJobCompletion(jobId); |
| console.log('β Analysis Complete:', analysisResult); |
| |
| |
| 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(); |
| }); |
| } |
|
|
| |
| |
| |
|
|
| async function loadDashboardData() { |
| console.log('π Loading Dashboard Data...'); |
| |
| try { |
| |
| const jobsResponse = await apiRequest(API_ENDPOINTS.jobs); |
| const jobs = jobsResponse.jobs || []; |
| console.log('β Jobs Loaded:', jobs.length); |
| |
| |
| 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); |
| |
| |
| const results = await apiRequest(API_ENDPOINTS.jobResults(latestJob.id)); |
| console.log('β Job Results:', results); |
| |
| |
| 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; |
| } |
| } |
|
|
| |
| |
| |
|
|
| 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; |
| } |
| } |
|
|
| |
| |
| |
|
|
| async function testAllConnections() { |
| console.log('π Testing All API Connections...'); |
| |
| const results = { |
| timestamp: new Date().toISOString(), |
| endpoints: {} |
| }; |
| |
| |
| 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); |
| } |
| |
| |
| 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); |
| } |
| } |
| |
| |
| 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; |
| } |
|
|
| |
| |
| |
|
|
| window.MahrakAPI = { |
| runSmartScanWithAPI, |
| submitAuditForm, |
| loadDashboardData, |
| getCompetitorIntelligence, |
| testAllConnections, |
| apiRequest, |
| getAuthToken, |
| setAuthToken, |
| API_ENDPOINTS |
| }; |
|
|
| console.log('β Mahrak API Integration Loaded'); |
|
|