From 7708e087863c0dfee12b208d3d2074da838d17f2 Mon Sep 17 00:00:00 2001 From: Aathithya Ananth <110254100+XDAathi@users.noreply.github.com> Date: Sun, 18 Jan 2026 06:05:16 -0500 Subject: [PATCH 1/2] linkedin search --- backend/linkedin_service.py | 21 ++++---- src/components/DetectiveBoard.tsx | 88 +++++++++++++++++++++++++++++++ src/components/SearchPanel.css | 64 ++++++++++++++++++++++ src/components/SearchPanel.tsx | 37 ++++++++++++- 4 files changed, 200 insertions(+), 10 deletions(-) diff --git a/backend/linkedin_service.py b/backend/linkedin_service.py index 70318f5..baf4ae9 100644 --- a/backend/linkedin_service.py +++ b/backend/linkedin_service.py @@ -6,8 +6,11 @@ async def scrape_user(username : str): # Initialize browser async with BrowserManager(headless=False) as browser: - # Load authenticated session - await browser.load_session("playwright/session.json") + # Load authenticated session if it exists + import os + session_path = os.path.join(os.path.dirname(__file__), "playwright", "session.json") + if os.path.exists(session_path): + await browser.load_session(session_path) # Create scraper scraper = PersonScraper(browser.page) @@ -58,7 +61,10 @@ async def scrape_user(username : str): async def scrape_company(company : str): async with BrowserManager(headless=False) as browser: - await browser.load_session("playwright/session.json") + import os + session_path = os.path.join(os.path.dirname(__file__), "playwright", "session.json") + if os.path.exists(session_path): + await browser.load_session(session_path) scraper = CompanyScraper(browser.page) company = await scraper.scrape(f"https://linkedin.com/company/{company}/") @@ -88,9 +94,6 @@ async def scrape_company(company : str): return json.dumps(returned_data) - -#response = asyncio.run(scrape_company("rogers-communications")) -#print(response) -#response = asyncio.run(scrape_user("dayuhechen")) -#print(response) -#asyncio.run(scrape_user("dayuhechen")) +response = asyncio.run(scrape_user("aathithy-aananth")) +print(response) +asyncio.run(scrape_user("aathithya-ananth")) diff --git a/src/components/DetectiveBoard.tsx b/src/components/DetectiveBoard.tsx index 16f4ec9..f8e9431 100644 --- a/src/components/DetectiveBoard.tsx +++ b/src/components/DetectiveBoard.tsx @@ -1150,6 +1150,7 @@ function AssetTracker() { export function DetectiveBoard() { const [editor, setEditor] = useState(null) const [isSearching, setIsSearching] = useState(false) + const [isLinkedInSearching, setIsLinkedInSearching] = useState(false) const [leadBranchingFactor, setLeadBranchingFactor] = useState(2) // Handle rope confirmation @@ -1481,6 +1482,91 @@ export function DetectiveBoard() { }; } + + const handleLinkedInSearch = useCallback(async (username: string) => { + if (!editor) return + + setIsLinkedInSearching(true) + + try { + // Call the LinkedIn API endpoint + const response = await fetch(`http://localhost:5000/api/linkedin_photo_pins/${username}`) + const data = await response.json() + + if (data.error) { + console.error('LinkedIn search error:', data.error) + alert(`Error: ${data.error}`) + return + } + + // Calculate base position for photo pins + const allShapes = editor.getCurrentPageShapes() + const existingPhotoPins = allShapes.filter((shape: any) => shape.type === 'photo-pin') + + let baseX = 300 + let baseY = 300 + + if (existingPhotoPins.length > 0) { + // Offset from the last photo pin + const lastPin = existingPhotoPins[existingPhotoPins.length - 1] + baseX = lastPin.x + 250 + baseY = lastPin.y + } + + const pinWidth = 200 + const pinHeight = 200 + const horizontalSpacing = 250 + + // Create photo pins for each logo + data.photo_pins.forEach((pin: any, index: number) => { + const pinX = baseX + (index * horizontalSpacing) + const pinY = baseY + + // Find non-colliding position + const position = findNonCollidingPosition( + editor, + pinX, + pinY, + pinWidth, + pinHeight, + 80 + ) + + editor.createShape({ + id: createShapeId(), + type: 'photo-pin', + x: position.x, + y: position.y, + props: { + w: pinWidth, + h: pinHeight, + imageUrl: pin.imageUrl, + caption: pin.caption, + }, + }) + }) + + // Optionally, create a note with profile info + if (data.profile && data.profile.name) { + editor.createShape({ + id: createShapeId(), + type: 'note-card', + x: baseX, + y: baseY - 150, + props: { + text: `${data.profile.name}\n${data.profile.location || ''}\n${data.profile.linkedin_url || ''}`, + }, + }) + } + + } catch (error) { + console.error('Error fetching LinkedIn data:', error) + alert('Failed to fetch LinkedIn data. Make sure the backend server is running.') + } finally { + setIsLinkedInSearching(false) + } + }, [editor]) + const handleImageUpload = useCallback(async (file: File | string) => { if (!editor) return @@ -1813,7 +1899,9 @@ export function DetectiveBoard() { {/* Lead Branching Factor Slider */}
void isSearching: boolean onTextSearch: (searchTerm: string) => void + onLinkedInSearch: (username: string) => void + isLinkedInSearching: boolean } -export function SearchPanel({ onImageUpload, isSearching, onTextSearch }: SearchPanelProps) { +export function SearchPanel({ onImageUpload, isSearching, onTextSearch, onLinkedInSearch, isLinkedInSearching }: SearchPanelProps) { const [dragActive, setDragActive] = useState(false) const [isExpanded, setIsExpanded] = useState(true) @@ -82,6 +84,39 @@ export function SearchPanel({ onImageUpload, isSearching, onTextSearch }: Search
+

+ LinkedIn Profile Search +

+
+
{ + e.preventDefault(); + const input = e.currentTarget.querySelector('input[name="linkedin-username"]') as HTMLInputElement; + if (input && input.value.trim()) { + onLinkedInSearch(input.value.trim()) + input.value = '' + } + }} + className="text-search-form" + > + + +
+
+
Date: Sun, 18 Jan 2026 07:17:18 -0500 Subject: [PATCH 2/2] merge --- backend/linkedin_service.py | 6 +++--- src/components/DetectiveBoard.tsx | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/linkedin_service.py b/backend/linkedin_service.py index baf4ae9..d4dc04b 100644 --- a/backend/linkedin_service.py +++ b/backend/linkedin_service.py @@ -94,6 +94,6 @@ async def scrape_company(company : str): return json.dumps(returned_data) -response = asyncio.run(scrape_user("aathithy-aananth")) -print(response) -asyncio.run(scrape_user("aathithya-ananth")) +#response = asyncio.run(scrape_user("aathithy-aananth")) +#print(response) +#asyncio.run(scrape_user("aathithya-ananth")) diff --git a/src/components/DetectiveBoard.tsx b/src/components/DetectiveBoard.tsx index df23e14..8a2a354 100644 --- a/src/components/DetectiveBoard.tsx +++ b/src/components/DetectiveBoard.tsx @@ -641,6 +641,12 @@ export function DetectiveBoard() { const mainNotePosition = {x:0, y:0} function handleTextUpload(inputstr : string) { + const noteCardWidth = 180 + const noteCardHeight = 180 + const viewport = editor.getViewportPageBounds() + const centerX = viewport.center.x - noteCardWidth / 2 + const centerY = viewport.center.y - noteCardHeight / 2 + if (!editor) return const original_id = createShapeId() editor.createShape({