Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/lessons/tools/browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ read_url("https://gptme.org/docs/getting-started.html")
search("latest developments in LLM agents", "perplexity")
```

**Note**: Perplexity search requires either:
- `PERPLEXITY_API_KEY` - Direct access to Perplexity API
- `OPENROUTER_API_KEY` - Uses Perplexity via OpenRouter (model: `perplexity/sonar-pro`)

If both keys are available, PERPLEXITY_API_KEY takes precedence.

### Taking Screenshots
```python
# Screenshot and view
Expand Down
51 changes: 41 additions & 10 deletions gptme/tools/_browser_perplexity.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,49 @@ def search_perplexity(query: str) -> str:
"Error: OpenAI package not installed. Install with: pip install openai"
)

# Get API key
# Get API key - try Perplexity first, then OpenRouter
api_key = os.getenv("PERPLEXITY_API_KEY")
use_openrouter = False

if not api_key:
# Try config file
config_path = Path.home() / ".config" / "gptme" / "config.toml"
config_env = {}
if config_path.exists():
with open(config_path) as f:
config = tomlkit.load(f)
api_key = config.get("env", {}).get("PERPLEXITY_API_KEY")
config_env = config.get("env", {})

# Try Perplexity key from config
api_key = config_env.get("PERPLEXITY_API_KEY")

if not api_key:
# Try OpenRouter as fallback
api_key = os.getenv("OPENROUTER_API_KEY") or config_env.get(
"OPENROUTER_API_KEY"
)
if api_key:
use_openrouter = True

if not api_key:
return "Error: Perplexity API key not found. Set PERPLEXITY_API_KEY environment variable or add it to ~/.config/gptme/config.toml"
return "Error: No API key found. Set PERPLEXITY_API_KEY or OPENROUTER_API_KEY environment variable or add it to ~/.config/gptme/config.toml"

# Create client and search
client = OpenAI(
api_key=api_key,
base_url="https://api.perplexity.ai",
)
if use_openrouter:
client = OpenAI(
api_key=api_key,
base_url="https://openrouter.ai/api/v1",
)
model = "perplexity/sonar-pro"
else:
client = OpenAI(
api_key=api_key,
base_url="https://api.perplexity.ai",
)
model = "sonar-pro"

response = client.chat.completions.create(
model="sonar-pro",
model=model,
messages=[
{
"role": "system",
Expand All @@ -79,17 +101,26 @@ def search_perplexity(query: str) -> str:


def has_perplexity_key() -> bool:
"""Check if Perplexity API key is available."""
"""Check if Perplexity or OpenRouter API key is available."""
# Check for Perplexity key
if os.getenv("PERPLEXITY_API_KEY"):
return True

# Check for OpenRouter key (can be used for Perplexity search)
if os.getenv("OPENROUTER_API_KEY"):
return True

# Try config file
config_path = Path.home() / ".config" / "gptme" / "config.toml"
if config_path.exists():
try:
with open(config_path) as f:
config = tomlkit.load(f)
return bool(config.get("env", {}).get("PERPLEXITY_API_KEY"))
env_config = config.get("env", {})
return bool(
env_config.get("PERPLEXITY_API_KEY")
or env_config.get("OPENROUTER_API_KEY")
)
except Exception:
pass

Expand Down
2 changes: 1 addition & 1 deletion gptme/tools/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def search(query: str, engine: EngineType = "google") -> str:
if has_perplexity:
return search_perplexity(query) # type: ignore
else:
return "Error: Perplexity search not available. Set PERPLEXITY_API_KEY environment variable or add it to ~/.config/gptme/config.toml"
return "Error: Perplexity search not available. Set PERPLEXITY_API_KEY or OPENROUTER_API_KEY environment variable or add it to ~/.config/gptme/config.toml"
elif browser == "playwright":
return search_playwright(query, engine)
elif browser == "lynx":
Expand Down
30 changes: 30 additions & 0 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,33 @@ def test_read_url_arxiv_pdf():
# TODO: test that we can read it
# url = "https://arxiv.org/pdf/2410.12361v2"
pass


@pytest.mark.slow
def test_search_perplexity(monkeypatch):
"""Test Perplexity search with both API types."""
import os

# Skip if no API keys available
has_perplexity = os.getenv("PERPLEXITY_API_KEY") is not None
has_openrouter = os.getenv("OPENROUTER_API_KEY") is not None

if not (has_perplexity or has_openrouter):
pytest.skip("No PERPLEXITY_API_KEY or OPENROUTER_API_KEY available")

# Test the search works
results = search("what is gptme", "perplexity")
assert results, "Should get results from Perplexity"
assert (
"error" not in results.lower() or "Error" not in results
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion using 'or' may not reliably catch error messages. Replace 'or' with 'and' (or check just one case using lower-case) so that the test properly fails when an error is present.

Suggested change
"error" not in results.lower() or "Error" not in results
"error" not in results.lower()

), f"Got error: {results}"
Comment on lines +66 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: logical error in assertion - using or instead of and means the assertion passes if either condition is true, which is incorrect

Suggested change
assert (
"error" not in results.lower() or "Error" not in results
), f"Got error: {results}"
assert "error" not in results.lower(), f"Got error: {results}"
Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/test_browser.py
Line: 66:68

Comment:
**logic:** logical error in assertion - using `or` instead of `and` means the assertion passes if either condition is true, which is incorrect

```suggestion
    assert "error" not in results.lower(), f"Got error: {results}"
```

How can I resolve this? If you propose a fix, please make it concise.


# If we have OpenRouter key, test that it works too
if has_openrouter and not has_perplexity:
# Clear Perplexity key to force OpenRouter usage
monkeypatch.delenv("PERPLEXITY_API_KEY", raising=False)
results2 = search("what is gptme", "perplexity")
assert results2, "Should get results from OpenRouter"
assert (
"error" not in results2.lower() or "Error" not in results2
), f"Got error: {results2}"
Comment on lines +76 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: same logical error - using or instead of and

Suggested change
assert (
"error" not in results2.lower() or "Error" not in results2
), f"Got error: {results2}"
assert "error" not in results2.lower(), f"Got error: {results2}"
Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/test_browser.py
Line: 76:78

Comment:
**logic:** same logical error - using `or` instead of `and` 

```suggestion
    assert "error" not in results2.lower(), f"Got error: {results2}"
```

How can I resolve this? If you propose a fix, please make it concise.

Loading