195 lines
6.5 KiB
Python
Executable File
195 lines
6.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
WEVIA DeepSeek Web — Navigateur headless ILLIMITÉ
|
|
Pas de token, pas d'API key — Playwright simule un navigateur
|
|
Port: 8901
|
|
"""
|
|
import json, os, time, threading, traceback
|
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
|
|
PORT = 8901
|
|
SESSION_DIR = '/opt/weval-l99/deepseek-session'
|
|
LOCK = threading.Lock()
|
|
|
|
browser = None
|
|
context = None
|
|
page = None
|
|
ready = False
|
|
last_error = ''
|
|
|
|
def init_browser():
|
|
global browser, context, page, ready, last_error
|
|
try:
|
|
from playwright.sync_api import sync_playwright
|
|
pw = sync_playwright().start()
|
|
browser = pw.chromium.launch(
|
|
headless=True,
|
|
args=['--no-sandbox', '--disable-gpu', '--disable-blink-features=AutomationControlled']
|
|
)
|
|
|
|
os.makedirs(SESSION_DIR, exist_ok=True)
|
|
state_file = os.path.join(SESSION_DIR, 'state.json')
|
|
|
|
ctx_args = {
|
|
'viewport': {'width': 1280, 'height': 900},
|
|
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
}
|
|
if os.path.exists(state_file):
|
|
ctx_args['storage_state'] = state_file
|
|
|
|
context = browser.new_context(**ctx_args)
|
|
page = context.new_page()
|
|
page.goto('https://chat.deepseek.com', timeout=20000, wait_until='domcontentloaded')
|
|
page.wait_for_timeout(3000)
|
|
|
|
# Check if we're on chat page (not login)
|
|
url = page.url
|
|
title = page.title()
|
|
has_textarea = page.locator('textarea').count() > 0
|
|
|
|
if has_textarea:
|
|
ready = True
|
|
context.storage_state(path=state_file)
|
|
last_error = ''
|
|
return True
|
|
else:
|
|
ready = False
|
|
last_error = f'No textarea found. URL={url} Title={title}'
|
|
return False
|
|
|
|
except Exception as e:
|
|
last_error = str(e)
|
|
ready = False
|
|
return False
|
|
|
|
def send_message(message, mode='instant'):
|
|
global page, context, ready, last_error
|
|
|
|
if not ready or not page:
|
|
return {"error": "Browser not ready", "detail": last_error}
|
|
|
|
with LOCK:
|
|
try:
|
|
t0 = time.time()
|
|
|
|
# Click New Chat
|
|
try:
|
|
new_btn = page.locator('div:has-text("New chat")').first
|
|
if new_btn.count() > 0:
|
|
new_btn.click()
|
|
page.wait_for_timeout(1000)
|
|
except:
|
|
pass
|
|
|
|
# Toggle DeepThink if needed
|
|
if mode == 'deepthink':
|
|
try:
|
|
dt = page.locator('text=DeepThink').first
|
|
if dt.count() > 0:
|
|
dt.click()
|
|
page.wait_for_timeout(500)
|
|
except:
|
|
pass
|
|
|
|
# Toggle Search if needed
|
|
if mode == 'search':
|
|
try:
|
|
sb = page.locator('text=Search').first
|
|
if sb.count() > 0:
|
|
sb.click()
|
|
page.wait_for_timeout(500)
|
|
except:
|
|
pass
|
|
|
|
# Type and send
|
|
textarea = page.locator('textarea').first
|
|
textarea.fill(message)
|
|
page.wait_for_timeout(300)
|
|
|
|
# Press Enter or click send
|
|
textarea.press('Enter')
|
|
page.wait_for_timeout(2000)
|
|
|
|
# Wait for response (poll until stable)
|
|
last_text = ''
|
|
stable = 0
|
|
timeout = 120 if mode == 'deepthink' else 60
|
|
|
|
while time.time() - t0 < timeout:
|
|
page.wait_for_timeout(2000)
|
|
|
|
# Try to get the last response
|
|
try:
|
|
msgs = page.locator('[class*="markdown"], [class*="message-content"], [class*="prose"]')
|
|
if msgs.count() > 0:
|
|
current = msgs.last.inner_text()
|
|
if len(current) > 3 and current == last_text:
|
|
stable += 1
|
|
if stable >= 3:
|
|
break
|
|
else:
|
|
stable = 0
|
|
last_text = current
|
|
except:
|
|
pass
|
|
|
|
# Save session
|
|
try:
|
|
context.storage_state(path=os.path.join(SESSION_DIR, 'state.json'))
|
|
except:
|
|
pass
|
|
|
|
latency = int((time.time() - t0) * 1000)
|
|
|
|
return {
|
|
"content": last_text if last_text else "No response captured",
|
|
"provider": "deepseek-web-unlimited",
|
|
"mode": mode,
|
|
"latency_ms": latency,
|
|
"cost": 0,
|
|
"unlimited": True
|
|
}
|
|
|
|
except Exception as e:
|
|
last_error = str(e)
|
|
return {"error": str(e)}
|
|
|
|
class Handler(BaseHTTPRequestHandler):
|
|
def do_POST(self):
|
|
length = int(self.headers.get('Content-Length', 0))
|
|
body = json.loads(self.rfile.read(length)) if length > 0 else {}
|
|
|
|
message = body.get('message', '')
|
|
mode = body.get('mode', 'instant')
|
|
|
|
if not message:
|
|
self.send_json({"error": "no message"})
|
|
return
|
|
|
|
result = send_message(message, mode)
|
|
self.send_json(result)
|
|
|
|
def do_GET(self):
|
|
if self.path == '/health':
|
|
self.send_json({"status": "ready" if ready else "not_ready", "error": last_error, "port": PORT})
|
|
elif self.path == '/init':
|
|
ok = init_browser()
|
|
self.send_json({"initialized": ok, "ready": ready, "error": last_error})
|
|
else:
|
|
self.send_json({"service": "WEVIA DeepSeek Web UNLIMITED", "modes": ["instant","deepthink","search"], "unlimited": True, "cost": 0, "no_token": True})
|
|
|
|
def send_json(self, data):
|
|
self.send_response(200)
|
|
self.send_header('Content-Type', 'application/json')
|
|
self.send_header('Access-Control-Allow-Origin', '*')
|
|
self.end_headers()
|
|
self.wfile.write(json.dumps(data, ensure_ascii=False).encode())
|
|
|
|
def log_message(self, *a): pass
|
|
|
|
if __name__ == '__main__':
|
|
print(f"WEVIA DeepSeek Web UNLIMITED :{PORT} — NO TOKEN NEEDED")
|
|
init_browser()
|
|
print(f"Ready: {ready} | Error: {last_error}")
|
|
HTTPServer(('127.0.0.1', PORT), Handler).serve_forever()
|