PPN1 commited on
Commit
166e4a6
Β·
verified Β·
1 Parent(s): 3942e76

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +80 -18
app.py CHANGED
@@ -2,6 +2,7 @@
2
  import os
3
  import io
4
  import json
 
5
  import traceback
6
  from typing import List
7
  from io import BytesIO
@@ -19,16 +20,17 @@ from google.cloud import vision_v1 as vision
19
  # ───── Load .env (locally) ────────────────────────────────────
20
  # In HF Spaces you'll set these as Secrets under Settings β†’ Variables & secrets
21
  load_dotenv()
22
- openai.api_key = os.getenv("OPENAI_API_KEY")
23
- gcv_api_key = os.getenv("GCV_API_KEY")
24
- proxycurl_api_key = os.getenv("PROXYCURL_API_KEY")
 
25
 
26
  if not openai.api_key:
27
  raise RuntimeError("Missing OPENAI_API_KEY")
28
  if not gcv_api_key:
29
  raise RuntimeError("Missing GCV_API_KEY")
30
- if not proxycurl_api_key:
31
- raise RuntimeError("Missing PROXYCURL_API_KEY")
32
 
33
  # ───── FastAPI setup ──────────────────────────────────────────
34
  app = FastAPI(title="Aliro Data Extraction API")
@@ -39,7 +41,7 @@ app.add_middleware(
39
  allow_headers=["*"],
40
  )
41
 
42
- # ───── A simple root so GET / won’t 404 ───────────────────────
43
  @app.get("/")
44
  def read_root():
45
  return {"message": "Aliro Data Extraction API – POST your files to /extract"}
@@ -94,18 +96,79 @@ def process_buffers(buffers: List[BytesIO]) -> List[str]:
94
 
95
  return results
96
 
97
- # ───── LinkedIn scrape via Proxycurl ─────────────────────────
98
  def scrape_linkedin(url: str) -> str:
99
  if not url:
100
  return ""
101
- resp = requests.get(
102
- "https://nubela.co/proxycurl/api/v2/linkedin",
103
- params={"linkedin_profile_url": url},
104
- headers={"Authorization": f"Bearer {proxycurl_api_key}"},
105
- timeout=10
106
- )
107
- resp.raise_for_status()
108
- return json.dumps(resp.json(), indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
  # ───── Summarize via OpenAI ─────────────────────────────────
111
  def make_summary(chunks: List[str]) -> str:
@@ -155,6 +218,5 @@ async def extract_endpoint(
155
 
156
  except requests.HTTPError as e:
157
  raise HTTPException(status_code=502, detail=f"LinkedIn scrape failed: {e}")
158
- except Exception:
159
- tb = traceback.format_exc()
160
- raise HTTPException(status_code=500, detail=f"Processing error:\n\n{tb}")
 
2
  import os
3
  import io
4
  import json
5
+ import time
6
  import traceback
7
  from typing import List
8
  from io import BytesIO
 
20
  # ───── Load .env (locally) ────────────────────────────────────
21
  # In HF Spaces you'll set these as Secrets under Settings β†’ Variables & secrets
22
  load_dotenv()
23
+ openai.api_key = os.getenv("OPENAI_API_KEY")
24
+ gcv_api_key = os.getenv("GCV_API_KEY")
25
+ brightdata_api_key = os.getenv("BRIGHTDATA_API_KEY")
26
+ brightdata_dataset_id = "gd_l1viktl72bvl7bjuj0"
27
 
28
  if not openai.api_key:
29
  raise RuntimeError("Missing OPENAI_API_KEY")
30
  if not gcv_api_key:
31
  raise RuntimeError("Missing GCV_API_KEY")
32
+ if not brightdata_api_key:
33
+ raise RuntimeError("Missing BRIGHTDATA_API_KEY")
34
 
35
  # ───── FastAPI setup ──────────────────────────────────────────
36
  app = FastAPI(title="Aliro Data Extraction API")
 
41
  allow_headers=["*"],
42
  )
43
 
44
+ # ───── A simple root so GET / won't 404 ───────────────────────
45
  @app.get("/")
46
  def read_root():
47
  return {"message": "Aliro Data Extraction API – POST your files to /extract"}
 
96
 
97
  return results
98
 
99
+ # ───── LinkedIn scrape via BrightData ─────────────────────────
100
  def scrape_linkedin(url: str) -> str:
101
  if not url:
102
  return ""
103
+
104
+ try:
105
+ # Step 1: Trigger data collection
106
+ trigger_url = "https://api.brightdata.com/datasets/v3/trigger"
107
+ headers = {
108
+ "Authorization": f"Bearer {brightdata_api_key}",
109
+ "Content-Type": "application/json",
110
+ }
111
+ params = {
112
+ "dataset_id": brightdata_dataset_id,
113
+ "include_errors": "true",
114
+ }
115
+
116
+ trigger_response = requests.post(
117
+ trigger_url,
118
+ headers=headers,
119
+ params=params,
120
+ json=[{"url": url}],
121
+ timeout=30
122
+ )
123
+
124
+ if not trigger_response.ok:
125
+ raise Exception(f"BrightData trigger failed: {trigger_response.status_code} - {trigger_response.text}")
126
+
127
+ trigger_data = trigger_response.json()
128
+ snapshot_id = trigger_data.get('snapshot_id')
129
+
130
+ if not snapshot_id:
131
+ raise Exception("No snapshot_id received from BrightData")
132
+
133
+ print(f"BrightData collection triggered, snapshot_id: {snapshot_id}")
134
+
135
+ # Step 2: Poll for completion (max 5 minutes)
136
+ max_attempts = 30
137
+ for attempt in range(max_attempts):
138
+ time.sleep(10) # Wait 10 seconds between checks
139
+
140
+ progress_url = f"https://api.brightdata.com/datasets/v3/progress/{snapshot_id}"
141
+ progress_response = requests.get(progress_url, headers=headers, timeout=30)
142
+
143
+ if progress_response.ok:
144
+ progress_data = progress_response.json()
145
+ status = progress_data.get('status')
146
+
147
+ print(f"Progress check {attempt + 1}: status = {status}")
148
+
149
+ if status == 'ready':
150
+ # Step 3: Fetch results
151
+ result_url = f"https://api.brightdata.com/datasets/v3/snapshot/{snapshot_id}"
152
+ result_params = {"format": "json"}
153
+ result_response = requests.get(result_url, headers=headers, params=result_params, timeout=30)
154
+
155
+ if result_response.ok:
156
+ linkedin_data = result_response.json()
157
+ return json.dumps(linkedin_data, indent=2)
158
+ else:
159
+ raise Exception(f"Failed to fetch results: {result_response.status_code} - {result_response.text}")
160
+
161
+ elif status == 'failed':
162
+ raise Exception("BrightData collection failed")
163
+
164
+ # Continue polling if status is 'running'
165
+ else:
166
+ print(f"Progress check failed: {progress_response.status_code}")
167
+
168
+ raise Exception("Timeout waiting for BrightData collection to complete")
169
+
170
+ except Exception as e:
171
+ raise Exception(f"LinkedIn scraping error: {str(e)}")
172
 
173
  # ───── Summarize via OpenAI ─────────────────────────────────
174
  def make_summary(chunks: List[str]) -> str:
 
218
 
219
  except requests.HTTPError as e:
220
  raise HTTPException(status_code=502, detail=f"LinkedIn scrape failed: {e}")
221
+ except Exception as e:
222
+ raise HTTPException(status_code=500, detail=f"Processing error: {str(e)}")