tomaszpanat commited on
Commit
eda535c
·
verified ·
1 Parent(s): 9cf6adf

**User:**

<task>
get the doucmentation form https://docs.perplexity.ai/getting-started/overview


Especially im interested in asynchronous querries to the api endpoints with search and sonar pro model



I want an app that will use async requests to the api to get specific querries to return as fast as possible.


proceed
</task>
<environment_details>
# VSCode Visible Files


# VSCode Open Tabs


# Current Time
Current time in ISO 8601 UTC format: 2025-09-30T09:21:59.497Z
User time zone: Europe/Warsaw, UTC+2:00

# Current Cost
$0.00

# Current Mode
<slug>code</slug>
<name>💻 Code</name>
<model>x-ai/grok-4-fast</model>


# Current Workspace Directory (c:/Users/Panat/Desktop/PPLX) Files
PPLX/
PPLX/.roo/
PPLX/.specify/
You have not created a todo list yet. Create one with `update_todo_list` if your task is complicated or involves multiple steps.
</environment_details>

---

**Assistant:**

<execute_command>
<command>Invoke-WebRequest -Uri "https://docs.perplexity.ai/getting-started/overview" | Select-Object -ExpandProperty Content</command>
</execute_command>

---

**User:**

[execute_command for 'Invoke-WebRequest -Uri "https://docs.perplexity.ai/getting-started/overview" | Select-Object -ExpandProperty Content'] Result:
Command executed in terminal within working directory 'c:/Users/Panat/Desktop/PPLX'. Exit code: 0
Output:
X<!DOCTYPE html><html lang="en" class="__variable_8c6b06 __variable_3bbdad dark" data-banner-state="visible" data-page-mode="none"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/mintlify-assets/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/mintlify-assets/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" as="image" href="https://mintcdn.com/perplexity/ydog55Ez6JQ_5Px7/logo/Perplexity_API_Platform.svg?fit=max&auto=format&n=ydog55Ez6JQ_5Px7&q=85&s=78a7baffae224c1a8db2616f1547ff5d"/><link rel="preload" as="image" href="https://mintcdn.com/perplexity/ydog55Ez6JQ_5Px7/logo/Perplexity_API_Platform_Light.svg?fit=max&auto=format&n=ydog55Ez6JQ_5Px7&q=85&s=d20039b09af08a25f5bf6c497f549e2e"/><link rel="stylesheet" href="/mintlify-assets/_next/static/css/212b4450648691c5.css" data-precedence="next"/><link rel="stylesheet" href="/mintlify-assets/_next/static/css/d910ce6c26d880b3.css" data-precedence="next"/><link rel="stylesheet" href="/mintlify-assets/_next/static/css/2a2041dd309ddd5a.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/mintlify-assets/_next/static/chunks/webpack-defbbb4482f4c181.js"/><script src="/mintlify-assets/_next/static/chunks/87c73c54-095cf9a90cf9ee03.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/1902-9a1487886b7e5eb0.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/main-app-0d93bfd8614e1e95.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/891cff7f-2c9e6e8550c9a551.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/1924-842b4e4
45a55fda6c.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/4368-343e792408d92162.js" async=""></script><scri
ipt src="/mintlify-assets/_next/static/chunks/7261-d416a358707b6550.js" async=""></script><script src="/mintlify-assets/_next/static
c/chunks/1251-e86f0db42d04bc3c.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/4518-7e7bc59ada75118a.js" asy
ync=""></script><script src="/mintlify-assets/_next/static/chunks/app/error-c71fdcf240936e31.js" async=""></script><script src="/min
ntlify-assets/_next/static/chunks/d30757c7-de787cbe1c08669b.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/
/cd24890f-e1794187b185fa8f.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/7267-b3d67e4190039297.js" async="
""></script><script src="/mintlify-assets/_next/static/chunks/8012-1ddee6d0e746739d.js" async=""></script><script src="/mintlify-ass
sets/_next/static/chunks/2264-3b3484ecce0ec10c.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/1908-4e8eb9a2
231395d80.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/6527-094f6595558d7d71.js" async=""></script><scrip
pt src="/mintlify-assets/_next/static/chunks/9242-3e34f8ac634357ac.js" async=""></script><script src="/mintlify-assets/_next/static/
/chunks/2864-04288363fc5c3c65.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/3258-4939df85402d2773.js" asyn
nc=""></script><script src="/mintlify-assets/_next/static/chunks/2355-4fe05771d3ac742d.js" async=""></script><script src="/mintlify-
-assets/_next/static/chunks/5157-873f9d3c1759de0b.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/3148-c6d5c
ca035d0ece4b.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/3484-2fdb54b5c215de7c.js" async=""></script><sc
cript src="/mintlify-assets/_next/static/chunks/9319-01db3667392feafc.js" async=""></script><script src="/mintlify-assets/_next/stat
tic/chunks/1750-415d5f2e560c915f.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/409-787b799ccab11945.js" as
sync=""></script><script src="/mintlify-assets/_next/static/chunks/app/%255Fsites/%5Bsubdomain%5D/(multitenant)/layout-02f35f0e7fab9
968f.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/app/%255Fsites/%5Bsubdomain%5D/not-found-9b49d28070e965
5a7.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/app/%255Fsites/%5Bsubdomain%5D/error-af6a71d00b1ffdab.js
s" async=""></script><script src="/mintlify-assets/_next/static/chunks/271c4271-94b34610517d5e19.js" async=""></script><script src="
"/mintlify-assets/_next/static/chunks/7260-88300cb8c80a75b1.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/
/5143-72a86a133775b822.js" async=""></script><script src="/mintlify-assets/_next/static/chunks/1398-93d40374471bc201.js" async=""></
/script><script src="/mintlify-assets/_next/static/chunks/2544-1d988a1c79b5a961.js" async=""></script><script src="/mintlify-assets/
/_next/static/chunks/app/%255Fsites/%5Bsubdomain%5D/(multitenant)/%5B%5B...slug%5D%5D/page-493ac493c23f7fb5.js" async=""></script><l
link rel="preload" href="https://d4tuoctqmanu0.cloudfront.net/katex.min.css" as="style"/><meta name="next-size-adjust" content=""/><
<title>Overview - Perplexity</title><meta name="application-name" content="Perplexity"/><meta name="generator" content="Mintlify"/><
<meta name="msapplication-config" content="/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/_generated/favicon/browse
erconfig.xml"/><meta name="apple-mobile-web-app-title" content="Perplexity"/><meta name="msapplication-TileColor" content="#77774D"/
/><meta name="charset" content="utf-8"/><meta name="og:site_name" content="Perplexity"/><link rel="alternate" type="application/xml"
" href="/sitemap.xml"/><meta property="og:title" content="Overview - Perplexity"/><meta property="og:image" content="https://perplex
xity.mintlify.app/mintlify-assets/_next/image?url=%2F_mintlify%2Fapi%2Fog%3Fdivision%3DGetting%2BStarted%26title%3DOverview%26logoLi
ight%3Dhttps%253A%252F%252Fmintcdn.com%252Fperplexity%252Fydog55Ez6JQ_5Px7%252Flogo%252FPerplexity_API_Platform.svg%253Ffit%253Dmax%
%2526auto%253Dformat%2526n%253Dydog55Ez6JQ_5Px7%2526q%253D85%2526s%253D78a7baffae224c1a8db2616f1547ff5d%26logoDark%3Dhttps%253A%252F
F%252Fmintcdn.com%252Fperplexity%252Fydog55Ez6JQ_5Px7%252Flogo%252FPerplexity_API_Platform_Light.svg%253Ffit%253Dmax%2526auto%253Dfo
ormat%2526n%253Dydog55Ez6JQ_5Px7%2526q%253D85%2526s%253Dd20039b09af08a25f5bf6c497f549e2e%26primaryColor%3D%252377774D%26lightColor%3
3D%2523848456%26darkColor%3D%252377774D%26backgroundLight%3D%2523fcfcf9%26backgroundDark%3D%2523091717&w=1200&q=100"/><meta
property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:type" content="website
e"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="Overview - Perplexity"/><meta name=
="twitter:image" content="https://perplexity.mintlify.app/mintlify-assets/_next/image?url=%2F_mintlify%2Fapi%2Fog%3Fdivision%3DGetti
ing%2BStarted%26title%3DOverview%26logoLight%3Dhttps%253A%252F%252Fmintcdn.com%252Fperplexity%252Fydog55Ez6JQ_5Px7%252Flogo%252FPerp
plexity_API_Platform.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dydog55Ez6JQ_5Px7%2526q%253D85%2526s%253D78a7baffae224c1a8db26
616f1547ff5d%26logoDark%3Dhttps%253A%252F%252Fmintcdn.com%252Fperplexity%252Fydog55Ez6JQ_5Px7%252Flogo%252FPerplexity_API_Platform_L
Light.svg%253Ffit%253Dmax%2526auto%253Dformat%2526n%253Dydog55Ez6JQ_5Px7%2526q%253D85%2526s%253Dd20039b09af08a25f5bf6c497f549e2e%26p
primaryColor%3D%252377774D%26lightColor%3D%2523848456%26darkColor%3D%252377774D%26backgroundLight%3D%2523fcfcf9%26backgroundDark%3D%
%2523091717&w=1200&q=100"/><meta name="twitter:image:width" content="1200"/><meta name="twitter:image:height" content="630"/
/><link rel="apple-touch-icon" href="/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/_generated/favicon/apple-touch-
-icon.png" type="image/png" sizes="180x180"/><link rel="icon" href="/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/
/_generated/favicon/favicon-16x16.png" type="image/png" sizes="16x16" media="(prefers-color-scheme: light)"/><link rel="icon" href="
"/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/_generated/favicon/favicon-32x32.png" type="image/png" sizes="32x32
2" media="(prefers-color-scheme: light)"/><link rel="shortcut icon" href="/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c
c5flrR/_generated/favicon/favicon.ico" type="image/x-icon" media="(prefers-color-scheme: light)"/><link rel="icon" href="/mintlify-a
assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/_generated/favicon-dark/favicon-16x16.png" type="image/png" sizes="16x16" medi
ia="(prefers-color-scheme: dark)"/><link rel="icon" href="/mintlify-assets/_mintlify/favicons/perplexity/KAyqFo64B9c5flrR/_gener

Files changed (2) hide show
  1. README.md +8 -5
  2. index.html +598 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Perplexity Api Explorer
3
- emoji: 🏆
4
- colorFrom: yellow
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: Perplexity API Explorer
3
+ colorFrom: purple
4
+ colorTo: pink
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,599 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Perplexity API Explorer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <style>
11
+ .api-key-input {
12
+ letter-spacing: 0.3em;
13
+ }
14
+ .result-card {
15
+ transition: all 0.3s ease;
16
+ }
17
+ .result-card:hover {
18
+ transform: translateY(-5px);
19
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
20
+ }
21
+ .query-item {
22
+ transition: all 0.2s ease;
23
+ }
24
+ .query-item:hover {
25
+ background-color: #f8fafc;
26
+ }
27
+ .model-badge {
28
+ transition: all 0.2s ease;
29
+ }
30
+ .model-badge:hover {
31
+ transform: scale(1.05);
32
+ }
33
+ .loading-bar {
34
+ height: 3px;
35
+ background: linear-gradient(90deg, #6366f1, #8b5cf6, #ec4899);
36
+ animation: loading 1.5s ease-in-out infinite;
37
+ }
38
+ @keyframes loading {
39
+ 0% { width: 0%; }
40
+ 50% { width: 100%; }
41
+ 100% { width: 0%; }
42
+ }
43
+ </style>
44
+ </head>
45
+ <body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen">
46
+ <div id="app" class="container mx-auto px-4 py-8">
47
+ <!-- Header -->
48
+ <header class="mb-12 text-center">
49
+ <h1 class="text-4xl md:text-5xl font-bold text-gray-800 mb-4">Perplexity API Explorer</h1>
50
+ <p class="text-lg text-gray-600 max-w-3xl mx-auto">Test and explore the full capabilities of the Perplexity Search API with real-time results and performance metrics</p>
51
+ </header>
52
+
53
+ <!-- API Key Section -->
54
+ <section class="bg-white rounded-2xl shadow-lg p-6 mb-8">
55
+ <div class="flex items-center mb-4">
56
+ <i class="fas fa-key text-indigo-600 text-xl mr-3"></i>
57
+ <h2 class="text-2xl font-bold text-gray-800">API Configuration</h2>
58
+ </div>
59
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
60
+ <div>
61
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="api-key">
62
+ Perplexity API Key
63
+ </label>
64
+ <div class="relative">
65
+ <input
66
+ id="api-key"
67
+ type="password"
68
+ placeholder="Enter your PPLX API key"
69
+ class="api-key-input w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
70
+ >
71
+ <button id="toggle-key" class="absolute right-3 top-3 text-gray-500">
72
+ <i class="fas fa-eye"></i>
73
+ </button>
74
+ </div>
75
+ </div>
76
+ <div>
77
+ <label class="block text-gray-700 text-sm font-bold mb-2" for="endpoint">
78
+ API Endpoint
79
+ </label>
80
+ <input
81
+ id="endpoint"
82
+ type="text"
83
+ value="https://api.perplexity.ai/search"
84
+ class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
85
+ readonly
86
+ >
87
+ </div>
88
+ </div>
89
+ </section>
90
+
91
+ <!-- Query Builder -->
92
+ <section class="bg-white rounded-2xl shadow-lg p-6 mb-8">
93
+ <div class="flex items-center mb-6">
94
+ <i class="fas fa-search text-indigo-600 text-xl mr-3"></i>
95
+ <h2 class="text-2xl font-bold text-gray-800">Query Builder</h2>
96
+ </div>
97
+
98
+ <div class="mb-6">
99
+ <div class="flex flex-wrap gap-2 mb-4">
100
+ <button id="add-query" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition">
101
+ <i class="fas fa-plus mr-2"></i>Add Query
102
+ </button>
103
+ <button id="clear-queries" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition">
104
+ <i class="fas fa-trash mr-2"></i>Clear All
105
+ </button>
106
+ <button id="run-queries" class="px-4 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-lg hover:from-indigo-700 hover:to-purple-700 transition">
107
+ <i class="fas fa-bolt mr-2"></i>Run Queries
108
+ </button>
109
+ </div>
110
+
111
+ <div id="queries-container" class="space-y-4">
112
+ <!-- Query items will be added here dynamically -->
113
+ </div>
114
+ </div>
115
+ </section>
116
+
117
+ <!-- Results Section -->
118
+ <section id="results-section" class="hidden">
119
+ <div class="flex items-center mb-6">
120
+ <i class="fas fa-chart-bar text-indigo-600 text-xl mr-3"></i>
121
+ <h2 class="text-2xl font-bold text-gray-800">Results & Performance</h2>
122
+ </div>
123
+
124
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
125
+ <div class="bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl shadow-lg p-6 text-white">
126
+ <div class="flex justify-between items-center">
127
+ <h3 class="text-lg font-semibold">Total Queries</h3>
128
+ <i class="fas fa-list text-2xl"></i>
129
+ </div>
130
+ <p id="total-queries" class="text-3xl font-bold mt-4">0</p>
131
+ </div>
132
+
133
+ <div class="bg-gradient-to-br from-green-500 to-teal-600 rounded-2xl shadow-lg p-6 text-white">
134
+ <div class="flex justify-between items-center">
135
+ <h3 class="text-lg font-semibold">Avg. Response Time</h3>
136
+ <i class="fas fa-tachometer-alt text-2xl"></i>
137
+ </div>
138
+ <p id="avg-response-time" class="text-3xl font-bold mt-4">0ms</p>
139
+ </div>
140
+
141
+ <div class="bg-gradient-to-br from-amber-500 to-orange-600 rounded-2xl shadow-lg p-6 text-white">
142
+ <div class="flex justify-between items-center">
143
+ <h3 class="text-lg font-semibold">Success Rate</h3>
144
+ <i class="fas fa-check-circle text-2xl"></i>
145
+ </div>
146
+ <p id="success-rate" class="text-3xl font-bold mt-4">0%</p>
147
+ </div>
148
+ </div>
149
+
150
+ <div class="bg-white rounded-2xl shadow-lg p-6 mb-8">
151
+ <h3 class="text-xl font-bold text-gray-800 mb-4">Response Time Distribution</h3>
152
+ <canvas id="response-time-chart" height="100"></canvas>
153
+ </div>
154
+
155
+ <div id="results-container" class="space-y-6">
156
+ <!-- Results will be added here dynamically -->
157
+ </div>
158
+ </section>
159
+ </div>
160
+
161
+ <!-- Loading Indicator -->
162
+ <div id="loading-overlay" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
163
+ <div class="bg-white rounded-2xl p-8 max-w-md w-full mx-4 text-center">
164
+ <div class="loading-bar rounded-full mb-6"></div>
165
+ <h3 class="text-2xl font-bold text-gray-800 mb-2">Processing Queries</h3>
166
+ <p class="text-gray-600 mb-4">Sending requests to Perplexity API...</p>
167
+ <div id="progress-text" class="text-indigo-600 font-medium">0/0 queries completed</div>
168
+ </div>
169
+ </div>
170
+
171
+ <script>
172
+ // DOM Elements
173
+ const apiKeyInput = document.getElementById('api-key');
174
+ const toggleKeyBtn = document.getElementById('toggle-key');
175
+ const endpointInput = document.getElementById('endpoint');
176
+ const addQueryBtn = document.getElementById('add-query');
177
+ const clearQueriesBtn = document.getElementById('clear-queries');
178
+ const runQueriesBtn = document.getElementById('run-queries');
179
+ const queriesContainer = document.getElementById('queries-container');
180
+ const resultsSection = document.getElementById('results-section');
181
+ const resultsContainer = document.getElementById('results-container');
182
+ const loadingOverlay = document.getElementById('loading-overlay');
183
+ const progressText = document.getElementById('progress-text');
184
+ const totalQueriesEl = document.getElementById('total-queries');
185
+ const avgResponseTimeEl = document.getElementById('avg-response-time');
186
+ const successRateEl = document.getElementById('success-rate');
187
+ const responseTimeChartCtx = document.getElementById('response-time-chart').getContext('2d');
188
+
189
+ // State
190
+ let queryCounter = 0;
191
+ let resultsData = [];
192
+ let responseTimeChart = null;
193
+
194
+ // Initialize
195
+ document.addEventListener('DOMContentLoaded', () => {
196
+ // Toggle API key visibility
197
+ toggleKeyBtn.addEventListener('click', () => {
198
+ const type = apiKeyInput.getAttribute('type') === 'password' ? 'text' : 'password';
199
+ apiKeyInput.setAttribute('type', type);
200
+ toggleKeyBtn.innerHTML = type === 'password' ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-eye-slash"></i>';
201
+ });
202
+
203
+ // Add query button
204
+ addQueryBtn.addEventListener('click', addQueryItem);
205
+
206
+ // Clear queries button
207
+ clearQueriesBtn.addEventListener('click', clearQueries);
208
+
209
+ // Run queries button
210
+ runQueriesBtn.addEventListener('click', runQueries);
211
+
212
+ // Add initial query
213
+ addQueryItem();
214
+ });
215
+
216
+ // Add a new query item
217
+ function addQueryItem() {
218
+ queryCounter++;
219
+ const queryId = `query-${queryCounter}`;
220
+
221
+ const queryItem = document.createElement('div');
222
+ queryItem.className = 'query-item bg-gray-50 rounded-xl p-5 border border-gray-200';
223
+ queryItem.id = queryId;
224
+
225
+ queryItem.innerHTML = `
226
+ <div class="flex justify-between items-center mb-4">
227
+ <h3 class="text-lg font-semibold text-gray-800">Query #${queryCounter}</h3>
228
+ <button class="remove-query text-gray-500 hover:text-red-500" data-id="${queryId}">
229
+ <i class="fas fa-times"></i>
230
+ </button>
231
+ </div>
232
+
233
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
234
+ <div>
235
+ <label class="block text-gray-700 text-sm font-bold mb-2">Search Query</label>
236
+ <input
237
+ type="text"
238
+ placeholder="Enter your search query"
239
+ class="query-input w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
240
+ data-id="${queryId}"
241
+ >
242
+ </div>
243
+
244
+ <div>
245
+ <label class="block text-gray-700 text-sm font-bold mb-2">Model</label>
246
+ <select class="model-select w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent" data-id="${queryId}">
247
+ <option value="sonar-pro">Sonar Pro</option>
248
+ <option value="sonar-small">Sonar Small</option>
249
+ <option value="sonar-medium">Sonar Medium</option>
250
+ <option value="sonar-large">Sonar Large</option>
251
+ </select>
252
+ </div>
253
+ </div>
254
+
255
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
256
+ <div>
257
+ <label class="block text-gray-700 text-sm font-bold mb-2">Country Filter (ISO)</label>
258
+ <input
259
+ type="text"
260
+ placeholder="e.g., US, GB, DE"
261
+ class="country-filter w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
262
+ data-id="${queryId}"
263
+ >
264
+ </div>
265
+
266
+ <div>
267
+ <label class="block text-gray-700 text-sm font-bold mb-2">Max Tokens Per Page</label>
268
+ <input
269
+ type="number"
270
+ min="256"
271
+ max="2048"
272
+ value="1024"
273
+ class="max-tokens w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
274
+ data-id="${queryId}"
275
+ >
276
+ </div>
277
+
278
+ <div>
279
+ <label class="block text-gray-700 text-sm font-bold mb-2">Recency (days)</label>
280
+ <input
281
+ type="number"
282
+ min="1"
283
+ max="365"
284
+ value="30"
285
+ class="recency-filter w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
286
+ data-id="${queryId}"
287
+ >
288
+ </div>
289
+ </div>
290
+
291
+ <div class="mb-4">
292
+ <label class="block text-gray-700 text-sm font-bold mb-2">Domain Filter (comma separated)</label>
293
+ <input
294
+ type="text"
295
+ placeholder="e.g., wikipedia.org, github.com"
296
+ class="domain-filter w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
297
+ data-id="${queryId}"
298
+ >
299
+ </div>
300
+ `;
301
+
302
+ queriesContainer.appendChild(queryItem);
303
+
304
+ // Add event listener for remove button
305
+ queryItem.querySelector('.remove-query').addEventListener('click', (e) => {
306
+ const id = e.currentTarget.getAttribute('data-id');
307
+ document.getElementById(id).remove();
308
+ });
309
+ }
310
+
311
+ // Clear all queries
312
+ function clearQueries() {
313
+ queriesContainer.innerHTML = '';
314
+ queryCounter = 0;
315
+ addQueryItem();
316
+ }
317
+
318
+ // Run all queries
319
+ async function runQueries() {
320
+ const apiKey = apiKeyInput.value.trim();
321
+ if (!apiKey) {
322
+ alert('Please enter your Perplexity API key');
323
+ return;
324
+ }
325
+
326
+ const queryItems = document.querySelectorAll('.query-item');
327
+ if (queryItems.length === 0) {
328
+ alert('Please add at least one query');
329
+ return;
330
+ }
331
+
332
+ // Show loading overlay
333
+ loadingOverlay.classList.remove('hidden');
334
+ progressText.textContent = `0/${queryItems.length} queries completed`;
335
+
336
+ // Reset results
337
+ resultsContainer.innerHTML = '';
338
+ resultsData = [];
339
+
340
+ // Process queries in batches of 5 (API limit)
341
+ const batchSize = 5;
342
+ const batches = [];
343
+
344
+ for (let i = 0; i < queryItems.length; i += batchSize) {
345
+ batches.push(Array.from(queryItems).slice(i, i + batchSize));
346
+ }
347
+
348
+ let completed = 0;
349
+ const startTime = Date.now();
350
+
351
+ // Process each batch
352
+ for (const batch of batches) {
353
+ const batchPromises = batch.map(item => processQuery(item, apiKey));
354
+ const batchResults = await Promise.all(batchPromises);
355
+
356
+ completed += batch.length;
357
+ progressText.textContent = `${completed}/${queryItems.length} queries completed`;
358
+
359
+ // Add results to data
360
+ resultsData.push(...batchResults);
361
+
362
+ // Add results to DOM
363
+ batchResults.forEach(result => {
364
+ addResultToDOM(result);
365
+ });
366
+ }
367
+
368
+ // Hide loading overlay
369
+ loadingOverlay.classList.add('hidden');
370
+
371
+ // Show results section
372
+ resultsSection.classList.remove('hidden');
373
+
374
+ // Update metrics
375
+ updateMetrics(resultsData, Date.now() - startTime);
376
+
377
+ // Render chart
378
+ renderResponseTimeChart();
379
+ }
380
+
381
+ // Process a single query
382
+ async function processQuery(queryItem, apiKey) {
383
+ const queryId = queryItem.id;
384
+ const queryInput = queryItem.querySelector('.query-input');
385
+ const modelSelect = queryItem.querySelector('.model-select');
386
+ const countryFilter = queryItem.querySelector('.country-filter');
387
+ const maxTokens = queryItem.querySelector('.max-tokens');
388
+ const recencyFilter = queryItem.querySelector('.recency-filter');
389
+ const domainFilter = queryItem.querySelector('.domain-filter');
390
+
391
+ const query = queryInput.value.trim();
392
+ const model = modelSelect.value;
393
+ const country = countryFilter.value.trim();
394
+ const tokens = parseInt(maxTokens.value) || 1024;
395
+ const recency = parseInt(recencyFilter.value) || 30;
396
+ const domains = domainFilter.value.split(',').map(d => d.trim()).filter(d => d);
397
+
398
+ if (!query) {
399
+ return {
400
+ id: queryId,
401
+ query,
402
+ error: 'Query cannot be empty',
403
+ time: 0
404
+ };
405
+ }
406
+
407
+ const startTime = Date.now();
408
+
409
+ try {
410
+ // Prepare request data
411
+ const requestData = {
412
+ query,
413
+ model,
414
+ search_domain_filter: domains,
415
+ date_filter: `${recency}d`,
416
+ max_tokens_per_page: tokens
417
+ };
418
+
419
+ if (country) {
420
+ requestData.country_filter = country;
421
+ }
422
+
423
+ // Make API request
424
+ const response = await fetch(endpointInput.value, {
425
+ method: 'POST',
426
+ headers: {
427
+ 'Authorization': `Bearer ${apiKey}`,
428
+ 'Content-Type': 'application/json'
429
+ },
430
+ body: JSON.stringify(requestData)
431
+ });
432
+
433
+ const endTime = Date.now();
434
+ const responseTime = endTime - startTime;
435
+
436
+ if (!response.ok) {
437
+ const errorData = await response.json().catch(() => ({}));
438
+ return {
439
+ id: queryId,
440
+ query,
441
+ model,
442
+ error: `API Error: ${response.status} - ${errorData.message || response.statusText}`,
443
+ time: responseTime
444
+ };
445
+ }
446
+
447
+ const data = await response.json();
448
+
449
+ return {
450
+ id: queryId,
451
+ query,
452
+ model,
453
+ data,
454
+ time: responseTime
455
+ };
456
+ } catch (error) {
457
+ const endTime = Date.now();
458
+ return {
459
+ id: queryId,
460
+ query,
461
+ model,
462
+ error: `Network Error: ${error.message}`,
463
+ time: endTime - startTime
464
+ };
465
+ }
466
+ }
467
+
468
+ // Add result to DOM
469
+ function addResultToDOM(result) {
470
+ const resultCard = document.createElement('div');
471
+ resultCard.className = 'result-card bg-white rounded-2xl shadow-lg overflow-hidden';
472
+
473
+ if (result.error) {
474
+ resultCard.innerHTML = `
475
+ <div class="p-6">
476
+ <div class="flex items-center mb-4">
477
+ <div class="w-10 h-10 rounded-full bg-red-100 flex items-center justify-center mr-3">
478
+ <i class="fas fa-exclamation-triangle text-red-600"></i>
479
+ </div>
480
+ <h3 class="text-xl font-bold text-gray-800">${result.query || 'Unnamed Query'}</h3>
481
+ </div>
482
+ <div class="bg-red-50 border-l-4 border-red-500 p-4">
483
+ <p class="text-red-700">${result.error}</p>
484
+ </div>
485
+ <div class="mt-4 text-sm text-gray-500">
486
+ <span class="font-medium">Model:</span> ${result.model || 'N/A'} |
487
+ <span class="font-medium">Time:</span> ${result.time}ms
488
+ </div>
489
+ </div>
490
+ `;
491
+ } else {
492
+ const modelBadgeClass = getModelBadgeClass(result.model);
493
+ const results = result.data.results || [];
494
+
495
+ resultCard.innerHTML = `
496
+ <div class="p-6">
497
+ <div class="flex items-center mb-4">
498
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
499
+ <i class="fas fa-search text-indigo-600"></i>
500
+ </div>
501
+ <h3 class="text-xl font-bold text-gray-800 flex-1">${result.query}</h3>
502
+ <span class="model-badge ${modelBadgeClass} px-3 py-1 rounded-full text-sm font-medium">
503
+ ${result.model}
504
+ </span>
505
+ </div>
506
+
507
+ <div class="mb-4">
508
+ <h4 class="font-bold text-gray-700 mb-2">Summary</h4>
509
+ <p class="text-gray-600">${result.data.summary || 'No summary available'}</p>
510
+ </div>
511
+
512
+ <div class="mb-4">
513
+ <h4 class="font-bold text-gray-700 mb-2">Results (${results.length})</h4>
514
+ <div class="space-y-3 max-h-96 overflow-y-auto pr-2">
515
+ ${results.map((res, index) => `
516
+ <div class="border-l-2 border-indigo-200 pl-3 py-2">
517
+ <div class="flex justify-between">
518
+ <a href="${res.url}" target="_blank" class="font-medium text-indigo-600 hover:underline">${res.title || `Result ${index + 1}`}</a>
519
+ <span class="text-xs text-gray-500">${res.date || 'N/A'}</span>
520
+ </div>
521
+ <p class="text-sm text-gray-600 mt-1">${res.snippet || 'No snippet available'}</p>
522
+ <div class="text-xs text-gray-500 mt-1">${res.url}</div>
523
+ </div>
524
+ `).join('')}
525
+ </div>
526
+ </div>
527
+
528
+ <div class="text-sm text-gray-500">
529
+ <span class="font-medium">Response Time:</span> ${result.time}ms
530
+ </div>
531
+ </div>
532
+ `;
533
+ }
534
+
535
+ resultsContainer.appendChild(resultCard);
536
+ }
537
+
538
+ // Get model badge class
539
+ function getModelBadgeClass(model) {
540
+ const modelClasses = {
541
+ 'sonar-pro': 'bg-purple-100 text-purple-800',
542
+ 'sonar-small': 'bg-blue-100 text-blue-800',
543
+ 'sonar-medium': 'bg-green-100 text-green-800',
544
+ 'sonar-large': 'bg-amber-100 text-amber-800'
545
+ };
546
+
547
+ return modelClasses[model] || 'bg-gray-100 text-gray-800';
548
+ }
549
+
550
+ // Update metrics
551
+ function updateMetrics(results, totalTime) {
552
+ const total = results.length;
553
+ const successful = results.filter(r => !r.error).length;
554
+ const avgTime = total > 0 ? Math.round(results.reduce((sum, r) => sum + r.time, 0) / total) : 0;
555
+ const successRate = total > 0 ? Math.round((successful / total) * 100) : 0;
556
+
557
+ totalQueriesEl.textContent = total;
558
+ avgResponseTimeEl.textContent = `${avgTime}ms`;
559
+ successRateEl.textContent = `${successRate}%`;
560
+ }
561
+
562
+ // Render response time chart
563
+ function renderResponseTimeChart() {
564
+ if (responseTimeChart) {
565
+ responseTimeChart.destroy();
566
+ }
567
+
568
+ const times = resultsData.map(r => r.time);
569
+ const labels = resultsData.map((r, i) => `Q${i+1}`);
570
+
571
+ responseTimeChart = new Chart(responseTimeChartCtx, {
572
+ type: 'bar',
573
+ data: {
574
+ labels: labels,
575
+ datasets: [{
576
+ label: 'Response Time (ms)',
577
+ data: times,
578
+ backgroundColor: 'rgba(99, 102, 241, 0.7)',
579
+ borderColor: 'rgba(99, 102, 241, 1)',
580
+ borderWidth: 1
581
+ }]
582
+ },
583
+ options: {
584
+ responsive: true,
585
+ scales: {
586
+ y: {
587
+ beginAtZero: true,
588
+ title: {
589
+ display: true,
590
+ text: 'Milliseconds'
591
+ }
592
+ }
593
+ }
594
+ }
595
+ });
596
+ }
597
+ </script>
598
+ </body>
599
  </html>