forked from lza6/perplexity-2api-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig_wizard.py
More file actions
283 lines (233 loc) · 11 KB
/
config_wizard.py
File metadata and controls
283 lines (233 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
import json
import os
import re
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
class ConfigWizard:
def __init__(self, root):
self.root = root
self.root.title("Perplexity-2API Smart Config Wizard v4.0 (All-in-One)")
self.root.geometry("800x650")
# Style settings
style = ttk.Style()
style.configure("Header.TLabel", font=("Segoe UI", 16, "bold"))
style.configure("TButton", font=("Segoe UI", 10))
style.configure("TLabel", font=("Segoe UI", 10))
# --- Header area ---
header_frame = ttk.Frame(root, padding="20 20 10 10")
header_frame.pack(fill=tk.X)
ttk.Label(header_frame, text="🔧 Perplexity-2API Config Console", style="Header.TLabel").pack(anchor=tk.W)
# --- Info area ---
info_frame = ttk.LabelFrame(root, text="ℹ️ Supported Data Formats", padding="15")
info_frame.pack(fill=tk.X, padx=20, pady=5)
info_text = (
"This tool can extract credentials from any of the following formats:\n"
"1. HAR file (JSON)\n"
"2. PowerShell script (Invoke-WebRequest)\n"
"3. cURL command\n"
"4. Any text snippet that contains Cookie"
)
ttk.Label(info_frame, text=info_text, justify=tk.LEFT).pack(anchor=tk.W)
# --- Tabs area ---
self.notebook = ttk.Notebook(root)
self.notebook.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# Tab 1: Paste text (recommended)
self.tab_paste = ttk.Frame(self.notebook, padding=15)
self.notebook.add(self.tab_paste, text="📋 Paste Any Content (Recommended)")
self.setup_paste_tab()
# Tab 2: Import file
self.tab_file = ttk.Frame(self.notebook, padding=15)
self.notebook.add(self.tab_file, text="📂 Import HAR File")
self.setup_file_tab()
# --- Bottom status area ---
self.status_frame = ttk.Frame(root, padding="20")
self.status_frame.pack(fill=tk.X)
self.status_label = ttk.Label(self.status_frame, text="Ready", foreground="#888")
self.status_label.pack(side=tk.LEFT)
self.write_btn = ttk.Button(self.status_frame, text="Write config to .env", command=self.write_to_env, state=tk.DISABLED)
self.write_btn.pack(side=tk.RIGHT)
# Data storage
self.extracted_cookie = None
self.extracted_ua = None
# .env path
self.env_path = ".env"
def setup_file_tab(self):
frame = ttk.Frame(self.tab_file)
frame.pack(fill=tk.X, pady=10)
ttk.Label(frame, text="Select HAR file:").pack(side=tk.LEFT, padx=(0, 10))
self.har_path_var = tk.StringVar()
ttk.Entry(frame, textvariable=self.har_path_var, width=50).pack(side=tk.LEFT, padx=(0, 10), fill=tk.X, expand=True)
ttk.Button(frame, text="Browse...", command=self.browse_har).pack(side=tk.LEFT)
def setup_paste_tab(self):
ttk.Label(self.tab_paste, text="Paste content here (Ctrl+V):").pack(anchor=tk.W, pady=(0, 5))
self.paste_text = scrolledtext.ScrolledText(self.tab_paste, height=10, font=("Consolas", 9))
self.paste_text.pack(fill=tk.BOTH, expand=True)
btn_frame = ttk.Frame(self.tab_paste)
btn_frame.pack(fill=tk.X)
ttk.Button(btn_frame, text="Smart Parse", command=self.parse_paste_content).pack(side=tk.RIGHT)
def browse_har(self):
filename = filedialog.askopenfilename(title="Select HAR file", filetypes=[("HTTP Archive", "*.har"), ("All Files", "*.*")])
if filename:
self.har_path_var.set(filename)
try:
with open(filename, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read() # Read as text directly
self.process_text_content(content)
except Exception as e:
messagebox.showerror("Error", f"Failed to read file: {str(e)}")
def parse_paste_content(self):
content = self.paste_text.get("1.0", tk.END).strip()
if not content:
messagebox.showwarning("Notice", "Please paste some content first")
return
self.process_text_content(content)
def process_text_content(self, content: str):
"""
All-in-one parsing logic: try JSON parsing first, then fall back to regex extraction
"""
self.status_label.config(text="Analyzing...", foreground="blue")
self.root.update()
cookie = None
ua = None
# 1. Try to parse as JSON (HAR format)
try:
data = json.loads(content)
cookie, ua = self.extract_from_json(data)
except Exception:
pass # Not JSON, continue with other methods
# 2. If JSON did not yield anything, try PowerShell format
if not cookie:
cookie, ua = self.extract_from_powershell(content)
# 3. If still nothing, try generic regex (key=value format)
if not cookie:
cookie = self.extract_from_regex(content)
# 4. Extract UA (if still missing)
if not ua:
ua = self.extract_ua_regex(content)
# 5. Result handling
if cookie:
# Clean up
cookie = cookie.strip().strip('"').strip("'")
ua = (ua or "").strip().strip('"').strip("'")
self.extracted_cookie = cookie
self.extracted_ua = ua
preview = cookie[:40] + "..." + cookie[-40:] if len(cookie) > 80 else cookie
self.status_label.config(text=f"✅ Extraction successful! (length: {len(cookie)})", foreground="green")
msg = (
f"Credentials extracted successfully!\n\n"
f"User-Agent: {ua[:30]}...\n"
f"Cookie: {preview}\n\n"
f"Click [Write Config] to save."
)
messagebox.showinfo("Parse Successful", msg)
self.write_btn.config(state=tk.NORMAL)
else:
self.status_label.config(text="❌ Failed to detect valid credentials", foreground="red")
messagebox.showerror(
"Parse Failed",
"Could not extract a valid Perplexity Cookie from the text.\n"
"Please make sure the content contains 'pplx.visitor-id' or 'session-token'."
)
def extract_from_json(self, data):
"""Recursively traverse JSON to find Cookie"""
candidates = []
ua_candidates = []
def walk(obj):
if isinstance(obj, dict):
for k, v in obj.items():
key_lower = str(k).lower()
if isinstance(v, str):
if 'cookie' in key_lower and 'pplx.visitor-id' in v:
candidates.append(v)
if 'user-agent' in key_lower:
ua_candidates.append(v)
elif isinstance(v, (dict, list)):
walk(v)
elif isinstance(obj, list):
for item in obj:
walk(item)
walk(data)
# Choose best Cookie
best_cookie = ""
for c in candidates:
if len(c) > len(best_cookie):
best_cookie = c
ua = ua_candidates[0] if ua_candidates else None
return best_cookie or None, ua
def extract_from_powershell(self, text):
"""Extract Cookie from PowerShell script"""
# Match $session.Cookies.Add((New-Object System.Net.Cookie("KEY", "VALUE", ...))
pattern = r'New-Object System\.Net\.Cookie\("([^"]+)",\s*"([^"]+)"'
matches = re.findall(pattern, text)
if not matches:
return None, None
cookie_parts = []
for key, value in matches:
cookie_parts.append(f"{key}={value}")
cookie = "; ".join(cookie_parts)
ua = self.extract_ua_regex(text)
return cookie, ua
def extract_from_regex(self, text):
"""Generic regex extraction"""
# Try to match the entire Cookie string (usually in cURL or raw header)
# Look for a long string that contains pplx.visitor-id
lines = text.splitlines()
for line in lines:
if "pplx.visitor-id" in line and "=" in line:
# Try to extract key=value; key=value format
# Simple heuristic: if the line has a Cookie: prefix, strip it
if "Cookie:" in line:
return line.split("Cookie:", 1)[1].strip()
# Otherwise, if the line looks like a cookie string
if ";" in line and "=" in line:
return line.strip()
return None
def extract_ua_regex(self, text):
"""Extract User-Agent"""
# Match User-Agent: ...
match = re.search(r'User-Agent["\']?\s*[:=]\s*["\']?([^"\']+)["\']?', text, re.IGNORECASE)
if match:
return match.group(1).strip()
# Match PowerShell $session.UserAgent = "..."
match = re.search(r'\$session\.UserAgent\s*=\s*"([^"]+)"', text)
if match:
return match.group(1).strip()
return None
def write_to_env(self):
if not self.extracted_cookie:
messagebox.showwarning("Notice", "No Cookie has been extracted yet")
return
cookie = self.extracted_cookie
ua = self.extracted_ua or "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.7499.147 Safari/537.36"
try:
if os.path.exists(self.env_path):
with open(self.env_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
else:
lines = []
new_lines = []
has_cookie = False
has_ua = False
for line in lines:
if line.startswith("PPLX_COOKIE="):
new_lines.append(f'PPLX_COOKIE="{cookie}"\n')
has_cookie = True
elif line.startswith("PPLX_USER_AGENT="):
new_lines.append(f'PPLX_USER_AGENT="{ua}"\n')
has_ua = True
else:
new_lines.append(line)
if not has_cookie:
new_lines.append(f'PPLX_COOKIE="{cookie}"\n')
if not has_ua:
new_lines.append(f'PPLX_USER_AGENT="{ua}"\n')
with open(self.env_path, 'w', encoding='utf-8') as f:
f.writelines(new_lines)
messagebox.showinfo("Write Successful", "✅ Config has been updated!\n\nPlease run the following command to restart the service:\n\ndocker-compose restart app")
self.root.destroy()
except Exception as e:
messagebox.showerror("Write Failed", f"Unable to write .env file: {str(e)}")
if __name__ == "__main__":
root = tk.Tk()
app = ConfigWizard(root)
root.mainloop()