perplexity-webui-scraper 0.3.4__tar.gz → 0.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/PKG-INFO +97 -7
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/README.md +92 -6
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/pyproject.toml +11 -1
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/__init__.py +5 -14
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/cli/get_perplexity_session_token.py +24 -8
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/config.py +65 -0
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/constants.py +30 -10
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/core.py +223 -21
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/enums.py +147 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/exceptions.py +126 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/http.py +533 -0
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/limits.py +12 -4
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/logging.py +278 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/mcp/__init__.py +20 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/mcp/__main__.py +11 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/mcp/server.py +166 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/models.py +109 -0
- perplexity_webui_scraper-0.3.6/src/perplexity_webui_scraper/resilience.py +181 -0
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/types.py +15 -5
- perplexity_webui_scraper-0.3.4/src/perplexity_webui_scraper/config.py +0 -36
- perplexity_webui_scraper-0.3.4/src/perplexity_webui_scraper/enums.py +0 -75
- perplexity_webui_scraper-0.3.4/src/perplexity_webui_scraper/exceptions.py +0 -50
- perplexity_webui_scraper-0.3.4/src/perplexity_webui_scraper/http.py +0 -197
- perplexity_webui_scraper-0.3.4/src/perplexity_webui_scraper/models.py +0 -73
- {perplexity_webui_scraper-0.3.4 → perplexity_webui_scraper-0.3.6}/src/perplexity_webui_scraper/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: perplexity-webui-scraper
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Python scraper to extract AI responses from Perplexity's web interface.
|
|
5
5
|
Keywords: perplexity,ai,scraper,webui,api,client
|
|
6
6
|
Author: henrique-coder
|
|
@@ -20,14 +20,18 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
22
|
Requires-Dist: curl-cffi>=0.14.0
|
|
23
|
+
Requires-Dist: loguru>=0.7.3
|
|
23
24
|
Requires-Dist: orjson>=3.11.5
|
|
24
25
|
Requires-Dist: pydantic>=2.12.5
|
|
26
|
+
Requires-Dist: tenacity>=9.1.2
|
|
27
|
+
Requires-Dist: fastmcp>=2.14.2 ; extra == 'mcp'
|
|
25
28
|
Requires-Python: >=3.10
|
|
26
29
|
Project-URL: Changelog, https://github.com/henrique-coder/perplexity-webui-scraper/releases
|
|
27
30
|
Project-URL: Documentation, https://github.com/henrique-coder/perplexity-webui-scraper#readme
|
|
28
31
|
Project-URL: Homepage, https://github.com/henrique-coder/perplexity-webui-scraper
|
|
29
32
|
Project-URL: Issues, https://github.com/henrique-coder/perplexity-webui-scraper/issues
|
|
30
33
|
Project-URL: Repository, https://github.com/henrique-coder/perplexity-webui-scraper.git
|
|
34
|
+
Provides-Extra: mcp
|
|
31
35
|
Description-Content-Type: text/markdown
|
|
32
36
|
|
|
33
37
|
<div align="center">
|
|
@@ -47,7 +51,8 @@ Python scraper to extract AI responses from [Perplexity's](https://www.perplexit
|
|
|
47
51
|
## Installation
|
|
48
52
|
|
|
49
53
|
```bash
|
|
50
|
-
uv pip install perplexity-webui-scraper
|
|
54
|
+
uv pip install perplexity-webui-scraper # from PyPI (stable)
|
|
55
|
+
uv pip install git+https://github.com/henrique-coder/perplexity-webui-scraper.git@dev # from GitHub (development)
|
|
51
56
|
```
|
|
52
57
|
|
|
53
58
|
## Requirements
|
|
@@ -197,18 +202,103 @@ conversation.ask("Latest AI research", files=["paper.pdf"])
|
|
|
197
202
|
| `timezone` | `None` | Timezone |
|
|
198
203
|
| `coordinates` | `None` | Location (lat/lng) |
|
|
199
204
|
|
|
200
|
-
##
|
|
205
|
+
## Exceptions
|
|
201
206
|
|
|
202
|
-
|
|
207
|
+
The library provides specific exception types for better error handling:
|
|
208
|
+
|
|
209
|
+
| Exception | Description |
|
|
210
|
+
| ---------------------------------- | ------------------------------------------------------------ |
|
|
211
|
+
| `PerplexityError` | Base exception for all library errors |
|
|
212
|
+
| `AuthenticationError` | Session token is invalid or expired (HTTP 403) |
|
|
213
|
+
| `RateLimitError` | Rate limit exceeded (HTTP 429) |
|
|
214
|
+
| `FileUploadError` | File upload failed |
|
|
215
|
+
| `FileValidationError` | File validation failed (size, type, etc.) |
|
|
216
|
+
| `ResearchClarifyingQuestionsError` | Research mode is asking clarifying questions (not supported) |
|
|
217
|
+
| `ResponseParsingError` | API response could not be parsed |
|
|
218
|
+
| `StreamingError` | Error during streaming response |
|
|
219
|
+
|
|
220
|
+
### Handling Research Mode Clarifying Questions
|
|
221
|
+
|
|
222
|
+
When using Research mode (`Models.RESEARCH`), the API may ask clarifying questions before providing an answer. Since programmatic interaction is not supported, the library raises a `ResearchClarifyingQuestionsError` with the questions:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from perplexity_webui_scraper import (
|
|
226
|
+
Perplexity,
|
|
227
|
+
ResearchClarifyingQuestionsError,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
conversation.ask("Research this topic", model=Models.RESEARCH)
|
|
232
|
+
except ResearchClarifyingQuestionsError as error:
|
|
233
|
+
print("The AI needs clarification:")
|
|
234
|
+
for question in error.questions:
|
|
235
|
+
print(f" - {question}")
|
|
236
|
+
# Consider rephrasing your query to be more specific
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## MCP Server (Model Context Protocol)
|
|
240
|
+
|
|
241
|
+
The library includes an MCP server that allows AI assistants (like Claude) to search using Perplexity AI directly.
|
|
242
|
+
|
|
243
|
+
### Installation
|
|
203
244
|
|
|
204
245
|
```bash
|
|
205
|
-
|
|
246
|
+
uv pip install perplexity-webui-scraper[mcp]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Running the Server
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# Set your session token
|
|
253
|
+
export PERPLEXITY_SESSION_TOKEN="your_token_here" # For Linux/Mac
|
|
254
|
+
set PERPLEXITY_SESSION_TOKEN="your_token_here" # For Windows
|
|
255
|
+
|
|
256
|
+
# Run with FastMCP
|
|
257
|
+
uv run fastmcp run src/perplexity_webui_scraper/mcp/server.py
|
|
258
|
+
|
|
259
|
+
# Or test with the dev inspector
|
|
260
|
+
uv run fastmcp dev src/perplexity_webui_scraper/mcp/server.py
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Claude Desktop Configuration
|
|
264
|
+
|
|
265
|
+
Add to `~/.config/claude/claude_desktop_config.json`:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"mcpServers": {
|
|
270
|
+
"perplexity": {
|
|
271
|
+
"command": "uv",
|
|
272
|
+
"args": [
|
|
273
|
+
"run",
|
|
274
|
+
"fastmcp",
|
|
275
|
+
"run",
|
|
276
|
+
"path/to/perplexity_webui_scraper/mcp/server.py"
|
|
277
|
+
],
|
|
278
|
+
"env": {
|
|
279
|
+
"PERPLEXITY_SESSION_TOKEN": "your_token_here"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
206
284
|
```
|
|
207
285
|
|
|
208
|
-
|
|
286
|
+
### Available Tool
|
|
287
|
+
|
|
288
|
+
| Tool | Description |
|
|
289
|
+
| ---------------- | --------------------------------------------------------------------------- |
|
|
290
|
+
| `perplexity_ask` | Ask questions and get AI-generated answers with real-time data from the web |
|
|
291
|
+
|
|
292
|
+
**Parameters:**
|
|
293
|
+
|
|
294
|
+
| Parameter | Type | Default | Description |
|
|
295
|
+
| -------------- | ----- | -------- | ------------------------------------------------------------- |
|
|
296
|
+
| `query` | `str` | - | Question to ask (required) |
|
|
297
|
+
| `model` | `str` | `"best"` | AI model (`best`, `research`, `gpt52`, `claude_sonnet`, etc.) |
|
|
298
|
+
| `source_focus` | `str` | `"web"` | Source type (`web`, `academic`, `social`, `finance`, `all`) |
|
|
209
299
|
|
|
210
300
|
## Disclaimer
|
|
211
301
|
|
|
212
|
-
This is an **unofficial** library. It uses internal APIs that may change without notice. Use at your own risk.
|
|
302
|
+
This is an **unofficial** library. It uses internal APIs that may change without notice. Use at your own risk.
|
|
213
303
|
|
|
214
304
|
By using this library, you agree to Perplexity AI's Terms of Service.
|
|
@@ -15,7 +15,8 @@ Python scraper to extract AI responses from [Perplexity's](https://www.perplexit
|
|
|
15
15
|
## Installation
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
uv pip install perplexity-webui-scraper
|
|
18
|
+
uv pip install perplexity-webui-scraper # from PyPI (stable)
|
|
19
|
+
uv pip install git+https://github.com/henrique-coder/perplexity-webui-scraper.git@dev # from GitHub (development)
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
## Requirements
|
|
@@ -165,18 +166,103 @@ conversation.ask("Latest AI research", files=["paper.pdf"])
|
|
|
165
166
|
| `timezone` | `None` | Timezone |
|
|
166
167
|
| `coordinates` | `None` | Location (lat/lng) |
|
|
167
168
|
|
|
168
|
-
##
|
|
169
|
+
## Exceptions
|
|
169
170
|
|
|
170
|
-
|
|
171
|
+
The library provides specific exception types for better error handling:
|
|
172
|
+
|
|
173
|
+
| Exception | Description |
|
|
174
|
+
| ---------------------------------- | ------------------------------------------------------------ |
|
|
175
|
+
| `PerplexityError` | Base exception for all library errors |
|
|
176
|
+
| `AuthenticationError` | Session token is invalid or expired (HTTP 403) |
|
|
177
|
+
| `RateLimitError` | Rate limit exceeded (HTTP 429) |
|
|
178
|
+
| `FileUploadError` | File upload failed |
|
|
179
|
+
| `FileValidationError` | File validation failed (size, type, etc.) |
|
|
180
|
+
| `ResearchClarifyingQuestionsError` | Research mode is asking clarifying questions (not supported) |
|
|
181
|
+
| `ResponseParsingError` | API response could not be parsed |
|
|
182
|
+
| `StreamingError` | Error during streaming response |
|
|
183
|
+
|
|
184
|
+
### Handling Research Mode Clarifying Questions
|
|
185
|
+
|
|
186
|
+
When using Research mode (`Models.RESEARCH`), the API may ask clarifying questions before providing an answer. Since programmatic interaction is not supported, the library raises a `ResearchClarifyingQuestionsError` with the questions:
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from perplexity_webui_scraper import (
|
|
190
|
+
Perplexity,
|
|
191
|
+
ResearchClarifyingQuestionsError,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
try:
|
|
195
|
+
conversation.ask("Research this topic", model=Models.RESEARCH)
|
|
196
|
+
except ResearchClarifyingQuestionsError as error:
|
|
197
|
+
print("The AI needs clarification:")
|
|
198
|
+
for question in error.questions:
|
|
199
|
+
print(f" - {question}")
|
|
200
|
+
# Consider rephrasing your query to be more specific
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## MCP Server (Model Context Protocol)
|
|
204
|
+
|
|
205
|
+
The library includes an MCP server that allows AI assistants (like Claude) to search using Perplexity AI directly.
|
|
206
|
+
|
|
207
|
+
### Installation
|
|
171
208
|
|
|
172
209
|
```bash
|
|
173
|
-
|
|
210
|
+
uv pip install perplexity-webui-scraper[mcp]
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Running the Server
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Set your session token
|
|
217
|
+
export PERPLEXITY_SESSION_TOKEN="your_token_here" # For Linux/Mac
|
|
218
|
+
set PERPLEXITY_SESSION_TOKEN="your_token_here" # For Windows
|
|
219
|
+
|
|
220
|
+
# Run with FastMCP
|
|
221
|
+
uv run fastmcp run src/perplexity_webui_scraper/mcp/server.py
|
|
222
|
+
|
|
223
|
+
# Or test with the dev inspector
|
|
224
|
+
uv run fastmcp dev src/perplexity_webui_scraper/mcp/server.py
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Claude Desktop Configuration
|
|
228
|
+
|
|
229
|
+
Add to `~/.config/claude/claude_desktop_config.json`:
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"mcpServers": {
|
|
234
|
+
"perplexity": {
|
|
235
|
+
"command": "uv",
|
|
236
|
+
"args": [
|
|
237
|
+
"run",
|
|
238
|
+
"fastmcp",
|
|
239
|
+
"run",
|
|
240
|
+
"path/to/perplexity_webui_scraper/mcp/server.py"
|
|
241
|
+
],
|
|
242
|
+
"env": {
|
|
243
|
+
"PERPLEXITY_SESSION_TOKEN": "your_token_here"
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
174
248
|
```
|
|
175
249
|
|
|
176
|
-
|
|
250
|
+
### Available Tool
|
|
251
|
+
|
|
252
|
+
| Tool | Description |
|
|
253
|
+
| ---------------- | --------------------------------------------------------------------------- |
|
|
254
|
+
| `perplexity_ask` | Ask questions and get AI-generated answers with real-time data from the web |
|
|
255
|
+
|
|
256
|
+
**Parameters:**
|
|
257
|
+
|
|
258
|
+
| Parameter | Type | Default | Description |
|
|
259
|
+
| -------------- | ----- | -------- | ------------------------------------------------------------- |
|
|
260
|
+
| `query` | `str` | - | Question to ask (required) |
|
|
261
|
+
| `model` | `str` | `"best"` | AI model (`best`, `research`, `gpt52`, `claude_sonnet`, etc.) |
|
|
262
|
+
| `source_focus` | `str` | `"web"` | Source type (`web`, `academic`, `social`, `finance`, `all`) |
|
|
177
263
|
|
|
178
264
|
## Disclaimer
|
|
179
265
|
|
|
180
|
-
This is an **unofficial** library. It uses internal APIs that may change without notice. Use at your own risk.
|
|
266
|
+
This is an **unofficial** library. It uses internal APIs that may change without notice. Use at your own risk.
|
|
181
267
|
|
|
182
268
|
By using this library, you agree to Perplexity AI's Terms of Service.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "perplexity-webui-scraper"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.6"
|
|
4
4
|
description = "Python scraper to extract AI responses from Perplexity's web interface."
|
|
5
5
|
authors = [{ name = "henrique-coder", email = "henriquemoreira10fk@gmail.com" }]
|
|
6
6
|
license = "MIT"
|
|
@@ -24,8 +24,10 @@ classifiers = [
|
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
26
|
"curl-cffi>=0.14.0",
|
|
27
|
+
"loguru>=0.7.3",
|
|
27
28
|
"orjson>=3.11.5",
|
|
28
29
|
"pydantic>=2.12.5",
|
|
30
|
+
"tenacity>=9.1.2",
|
|
29
31
|
]
|
|
30
32
|
|
|
31
33
|
[dependency-groups]
|
|
@@ -33,16 +35,23 @@ dev = [
|
|
|
33
35
|
"beautifulsoup4>=4.14.3",
|
|
34
36
|
"jsbeautifier>=1.15.4",
|
|
35
37
|
"lxml>=6.0.2",
|
|
38
|
+
"prek>=0.2.25",
|
|
36
39
|
"python-dotenv>=1.2.1",
|
|
37
40
|
"rich>=14.2.0",
|
|
38
41
|
]
|
|
39
42
|
lint = [
|
|
40
43
|
"ruff>=0.14.10",
|
|
44
|
+
"ty>=0.0.9",
|
|
41
45
|
]
|
|
42
46
|
tests = [
|
|
43
47
|
"pytest>=9.0.2",
|
|
44
48
|
]
|
|
45
49
|
|
|
50
|
+
[project.optional-dependencies]
|
|
51
|
+
mcp = [
|
|
52
|
+
"fastmcp>=2.14.2",
|
|
53
|
+
]
|
|
54
|
+
|
|
46
55
|
[project.urls]
|
|
47
56
|
Homepage = "https://github.com/henrique-coder/perplexity-webui-scraper"
|
|
48
57
|
Documentation = "https://github.com/henrique-coder/perplexity-webui-scraper#readme"
|
|
@@ -103,6 +112,7 @@ skip-magic-trailing-comma = false # Preserve trailing commas as formatting hin
|
|
|
103
112
|
|
|
104
113
|
[project.scripts]
|
|
105
114
|
get-perplexity-session-token = "perplexity_webui_scraper.cli.get_perplexity_session_token:get_token"
|
|
115
|
+
perplexity-webui-scraper-mcp = "perplexity_webui_scraper.mcp:run_server"
|
|
106
116
|
|
|
107
117
|
[build-system]
|
|
108
118
|
requires = ["uv_build"]
|
|
@@ -1,36 +1,27 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Extract AI responses from Perplexity's web interface.
|
|
3
|
+
"""
|
|
2
4
|
|
|
3
5
|
from importlib import metadata
|
|
4
6
|
|
|
5
7
|
from .config import ClientConfig, ConversationConfig
|
|
6
8
|
from .core import Conversation, Perplexity
|
|
7
|
-
from .enums import CitationMode, SearchFocus, SourceFocus, TimeRange
|
|
8
|
-
from .exceptions import (
|
|
9
|
-
AuthenticationError,
|
|
10
|
-
FileUploadError,
|
|
11
|
-
FileValidationError,
|
|
12
|
-
PerplexityError,
|
|
13
|
-
RateLimitError,
|
|
14
|
-
)
|
|
9
|
+
from .enums import CitationMode, LogLevel, SearchFocus, SourceFocus, TimeRange
|
|
15
10
|
from .models import Model, Models
|
|
16
11
|
from .types import Coordinates, Response, SearchResultItem
|
|
17
12
|
|
|
18
13
|
|
|
19
14
|
__version__: str = metadata.version("perplexity-webui-scraper")
|
|
20
15
|
__all__: list[str] = [
|
|
21
|
-
"AuthenticationError",
|
|
22
16
|
"CitationMode",
|
|
23
17
|
"ClientConfig",
|
|
24
18
|
"Conversation",
|
|
25
19
|
"ConversationConfig",
|
|
26
20
|
"Coordinates",
|
|
27
|
-
"
|
|
28
|
-
"FileValidationError",
|
|
21
|
+
"LogLevel",
|
|
29
22
|
"Model",
|
|
30
23
|
"Models",
|
|
31
24
|
"Perplexity",
|
|
32
|
-
"PerplexityError",
|
|
33
|
-
"RateLimitError",
|
|
34
25
|
"Response",
|
|
35
26
|
"SearchFocus",
|
|
36
27
|
"SearchResultItem",
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
CLI utility for secure Perplexity authentication and session extraction.
|
|
3
|
+
"""
|
|
2
4
|
|
|
3
5
|
from __future__ import annotations
|
|
4
6
|
|
|
@@ -57,7 +59,9 @@ def update_env(token: str) -> bool:
|
|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
def _initialize_session() -> tuple[Session, str]:
|
|
60
|
-
"""
|
|
62
|
+
"""
|
|
63
|
+
Initialize session and obtain CSRF token.
|
|
64
|
+
"""
|
|
61
65
|
|
|
62
66
|
session = Session(impersonate="chrome", headers={"Referer": BASE_URL, "Origin": BASE_URL})
|
|
63
67
|
|
|
@@ -73,7 +77,9 @@ def _initialize_session() -> tuple[Session, str]:
|
|
|
73
77
|
|
|
74
78
|
|
|
75
79
|
def _request_verification_code(session: Session, csrf: str, email: str) -> None:
|
|
76
|
-
"""
|
|
80
|
+
"""
|
|
81
|
+
Send verification code to user's email.
|
|
82
|
+
"""
|
|
77
83
|
|
|
78
84
|
with console.status("[bold green]Sending verification code...", spinner="dots"):
|
|
79
85
|
r = session.post(
|
|
@@ -92,7 +98,9 @@ def _request_verification_code(session: Session, csrf: str, email: str) -> None:
|
|
|
92
98
|
|
|
93
99
|
|
|
94
100
|
def _validate_and_get_redirect_url(session: Session, email: str, user_input: str) -> str:
|
|
95
|
-
"""
|
|
101
|
+
"""
|
|
102
|
+
Validate user input (OTP or magic link) and return redirect URL.
|
|
103
|
+
"""
|
|
96
104
|
|
|
97
105
|
with console.status("[bold green]Validating...", spinner="dots"):
|
|
98
106
|
if user_input.startswith("http"):
|
|
@@ -120,7 +128,9 @@ def _validate_and_get_redirect_url(session: Session, email: str, user_input: str
|
|
|
120
128
|
|
|
121
129
|
|
|
122
130
|
def _extract_session_token(session: Session, redirect_url: str) -> str:
|
|
123
|
-
"""
|
|
131
|
+
"""
|
|
132
|
+
Extract session token from cookies after authentication.
|
|
133
|
+
"""
|
|
124
134
|
|
|
125
135
|
session.get(redirect_url)
|
|
126
136
|
token = session.cookies.get("__Secure-next-auth.session-token")
|
|
@@ -132,7 +142,9 @@ def _extract_session_token(session: Session, redirect_url: str) -> str:
|
|
|
132
142
|
|
|
133
143
|
|
|
134
144
|
def _display_and_save_token(token: str) -> None:
|
|
135
|
-
"""
|
|
145
|
+
"""
|
|
146
|
+
Display token and optionally save to .env file.
|
|
147
|
+
"""
|
|
136
148
|
|
|
137
149
|
console.print("\n[bold green]✅ Token generated successfully![/bold green]")
|
|
138
150
|
console.print(f"\n[bold white]Your session token:[/bold white]\n[green]{token}[/green]\n")
|
|
@@ -147,7 +159,9 @@ def _display_and_save_token(token: str) -> None:
|
|
|
147
159
|
|
|
148
160
|
|
|
149
161
|
def _show_header() -> None:
|
|
150
|
-
"""
|
|
162
|
+
"""
|
|
163
|
+
Display welcome header.
|
|
164
|
+
"""
|
|
151
165
|
|
|
152
166
|
console.print(
|
|
153
167
|
Panel(
|
|
@@ -161,7 +175,9 @@ def _show_header() -> None:
|
|
|
161
175
|
|
|
162
176
|
|
|
163
177
|
def _show_exit_message() -> None:
|
|
164
|
-
"""
|
|
178
|
+
"""
|
|
179
|
+
Display security note and wait for user to exit.
|
|
180
|
+
"""
|
|
165
181
|
|
|
166
182
|
console.print("\n[bold yellow]⚠️ Security Note:[/bold yellow]")
|
|
167
183
|
console.print("Press [bold white]ENTER[/bold white] to clear screen and exit.")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration classes.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from .enums import CitationMode, LogLevel, SearchFocus, SourceFocus, TimeRange
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
from .models import Model
|
|
17
|
+
from .types import Coordinates
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(slots=True)
|
|
21
|
+
class ConversationConfig:
|
|
22
|
+
"""
|
|
23
|
+
Default settings for a conversation. Can be overridden per message.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
model: Model | None = None
|
|
27
|
+
citation_mode: CitationMode = CitationMode.CLEAN
|
|
28
|
+
save_to_library: bool = False
|
|
29
|
+
search_focus: SearchFocus = SearchFocus.WEB
|
|
30
|
+
source_focus: SourceFocus | list[SourceFocus] = SourceFocus.WEB
|
|
31
|
+
time_range: TimeRange = TimeRange.ALL
|
|
32
|
+
language: str = "en-US"
|
|
33
|
+
timezone: str | None = None
|
|
34
|
+
coordinates: Coordinates | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True, slots=True)
|
|
38
|
+
class ClientConfig:
|
|
39
|
+
"""
|
|
40
|
+
HTTP client settings.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
timeout: Request timeout in seconds.
|
|
44
|
+
impersonate: Browser to impersonate (e.g., "chrome", "edge", "safari").
|
|
45
|
+
max_retries: Maximum retry attempts for failed requests.
|
|
46
|
+
retry_base_delay: Initial delay in seconds before first retry.
|
|
47
|
+
retry_max_delay: Maximum delay between retries.
|
|
48
|
+
retry_jitter: Random jitter factor (0-1) to add to delays.
|
|
49
|
+
requests_per_second: Rate limit for requests (0 to disable).
|
|
50
|
+
rotate_fingerprint: Whether to rotate browser fingerprint on retries.
|
|
51
|
+
logging_level: Logging verbosity level. Default is DISABLED.
|
|
52
|
+
log_file: Optional file path for persistent logging. If set, logs go to file only.
|
|
53
|
+
If None, logs go to console. All logs are appended.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
timeout: int = 3600
|
|
57
|
+
impersonate: str = "chrome"
|
|
58
|
+
max_retries: int = 3
|
|
59
|
+
retry_base_delay: float = 1.0
|
|
60
|
+
retry_max_delay: float = 60.0
|
|
61
|
+
retry_jitter: float = 0.5
|
|
62
|
+
requests_per_second: float = 0.5
|
|
63
|
+
rotate_fingerprint: bool = True
|
|
64
|
+
logging_level: LogLevel = LogLevel.DISABLED
|
|
65
|
+
log_file: str | Path | None = None
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Constants and values for the Perplexity internal API and HTTP interactions.
|
|
3
|
+
"""
|
|
2
4
|
|
|
3
5
|
from __future__ import annotations
|
|
4
6
|
|
|
@@ -8,20 +10,30 @@ from typing import Final
|
|
|
8
10
|
|
|
9
11
|
# API Configuration
|
|
10
12
|
API_VERSION: Final[str] = "2.18"
|
|
11
|
-
"""
|
|
13
|
+
"""
|
|
14
|
+
Current API version used by Perplexity WebUI.
|
|
15
|
+
"""
|
|
12
16
|
|
|
13
17
|
API_BASE_URL: Final[str] = "https://www.perplexity.ai"
|
|
14
|
-
"""
|
|
18
|
+
"""
|
|
19
|
+
Base URL for all API requests.
|
|
20
|
+
"""
|
|
15
21
|
|
|
16
22
|
# API Endpoints
|
|
17
23
|
ENDPOINT_ASK: Final[str] = "/rest/sse/perplexity_ask"
|
|
18
|
-
"""
|
|
24
|
+
"""
|
|
25
|
+
SSE endpoint for sending prompts.
|
|
26
|
+
"""
|
|
19
27
|
|
|
20
28
|
ENDPOINT_SEARCH_INIT: Final[str] = "/search/new"
|
|
21
|
-
"""
|
|
29
|
+
"""
|
|
30
|
+
Endpoint to initialize a search session.
|
|
31
|
+
"""
|
|
22
32
|
|
|
23
33
|
ENDPOINT_UPLOAD: Final[str] = "/rest/uploads/batch_create_upload_urls"
|
|
24
|
-
"""
|
|
34
|
+
"""
|
|
35
|
+
Endpoint for file upload URL generation.
|
|
36
|
+
"""
|
|
25
37
|
|
|
26
38
|
# API Fixed Parameters
|
|
27
39
|
SEND_BACK_TEXT: Final[bool] = True
|
|
@@ -33,10 +45,14 @@ False = API sends delta chunks only (accumulate mode).
|
|
|
33
45
|
"""
|
|
34
46
|
|
|
35
47
|
USE_SCHEMATIZED_API: Final[bool] = False
|
|
36
|
-
"""
|
|
48
|
+
"""
|
|
49
|
+
Whether to use the schematized API format.
|
|
50
|
+
"""
|
|
37
51
|
|
|
38
52
|
PROMPT_SOURCE: Final[str] = "user"
|
|
39
|
-
"""
|
|
53
|
+
"""
|
|
54
|
+
Source identifier for prompts.
|
|
55
|
+
"""
|
|
40
56
|
|
|
41
57
|
# Regex Patterns (Pre-compiled for performance in streaming parsing)
|
|
42
58
|
CITATION_PATTERN: Final[Pattern[str]] = compile(r"\[(\d{1,2})\]")
|
|
@@ -47,7 +63,9 @@ Uses word boundary to avoid matching things like [123].
|
|
|
47
63
|
"""
|
|
48
64
|
|
|
49
65
|
JSON_OBJECT_PATTERN: Final[Pattern[str]] = compile(r"^\{.*\}$")
|
|
50
|
-
"""
|
|
66
|
+
"""
|
|
67
|
+
Pattern to detect JSON object strings.
|
|
68
|
+
"""
|
|
51
69
|
|
|
52
70
|
# HTTP Headers
|
|
53
71
|
DEFAULT_HEADERS: Final[dict[str, str]] = {
|
|
@@ -61,4 +79,6 @@ Referer and Origin are added dynamically based on BASE_URL.
|
|
|
61
79
|
"""
|
|
62
80
|
|
|
63
81
|
SESSION_COOKIE_NAME: Final[str] = "__Secure-next-auth.session-token"
|
|
64
|
-
"""
|
|
82
|
+
"""
|
|
83
|
+
Name of the session cookie used for authentication.
|
|
84
|
+
"""
|