Changed from user specific, to open for everyone
This commit is contained in:
@@ -72,6 +72,54 @@ def detect_browser_from_profile(profile_path: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def find_firefox_profile() -> str | None:
|
||||
"""Auto-detect Firefox profile directory cross-platform."""
|
||||
import sys
|
||||
home = os.path.expanduser("~")
|
||||
candidates = []
|
||||
|
||||
if sys.platform == "win32":
|
||||
appdata = os.environ.get("APPDATA", "")
|
||||
if appdata:
|
||||
profiles_dir = os.path.join(appdata, "Mozilla", "Firefox", "Profiles")
|
||||
else:
|
||||
profiles_dir = os.path.join(home, "AppData", "Roaming", "Mozilla", "Firefox", "Profiles")
|
||||
elif sys.platform == "darwin":
|
||||
profiles_dir = os.path.join(home, "Library", "Application Support", "Firefox", "Profiles")
|
||||
else:
|
||||
profiles_dir = os.path.join(home, ".mozilla", "firefox")
|
||||
|
||||
if os.path.isdir(profiles_dir):
|
||||
for entry in os.listdir(profiles_dir):
|
||||
full = os.path.join(profiles_dir, entry)
|
||||
if os.path.isdir(full) and (".default" in entry.lower() or ".dev-edition" in entry.lower()):
|
||||
candidates.append(full)
|
||||
candidates.sort(key=lambda p: "default-release" in p.lower(), reverse=True)
|
||||
if candidates:
|
||||
logger.info("Auto-detected Firefox profile: %s", candidates[0])
|
||||
return candidates[0]
|
||||
return None
|
||||
|
||||
|
||||
def find_chrome_profile() -> str | None:
|
||||
"""Auto-detect Chrome/Chromium profile directory cross-platform."""
|
||||
import sys
|
||||
home = os.path.expanduser("~")
|
||||
|
||||
if sys.platform == "win32":
|
||||
base = os.path.join(os.environ.get("LOCALAPPDATA", ""), "Google", "Chrome", "User Data")
|
||||
elif sys.platform == "darwin":
|
||||
base = os.path.join(home, "Library", "Application Support", "Google", "Chrome")
|
||||
else:
|
||||
base = os.path.join(home, ".config", "google-chrome")
|
||||
|
||||
default_profile = os.path.join(base, "Default")
|
||||
if os.path.isdir(default_profile):
|
||||
logger.info("Auto-detected Chrome profile: %s", default_profile)
|
||||
return default_profile
|
||||
return None
|
||||
|
||||
|
||||
def copy_firefox_profile(src_path: str) -> str:
|
||||
"""Copy essential Firefox profile files to a temp dir for Playwright."""
|
||||
essential = ['cookies.sqlite', 'webappsstore.sqlite', 'permissions.sqlite']
|
||||
@@ -745,12 +793,27 @@ def cleanup_chrome():
|
||||
async def scrape_facebook(profile_path: str | None = None, force: bool = False) -> dict:
|
||||
"""Dispatcher — Firefox primary, browser-use Agent fallback."""
|
||||
effective_path = profile_path or FX_PROFILE
|
||||
|
||||
# Auto-detect Firefox profile if none provided
|
||||
if not effective_path:
|
||||
detected = find_firefox_profile()
|
||||
if detected:
|
||||
effective_path = detected
|
||||
os.environ["FX_PROFILE"] = detected
|
||||
|
||||
browser_type = detect_browser_from_profile(effective_path)
|
||||
|
||||
if not browser_type and CHROME_PROFILE:
|
||||
browser_type = detect_browser_from_profile(CHROME_PROFILE)
|
||||
effective_path = CHROME_PROFILE
|
||||
|
||||
# Auto-detect Chrome profile if still nothing
|
||||
if not browser_type:
|
||||
detected_chrome = find_chrome_profile()
|
||||
if detected_chrome:
|
||||
effective_path = detected_chrome
|
||||
browser_type = 'chromium'
|
||||
|
||||
logger.info("Detected browser: %s (profile: %s)", browser_type or "none", effective_path)
|
||||
|
||||
# Firefox primary (raw Playwright, stealth)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
fastapi>=0.115.0
|
||||
uvicorn>=0.34.0
|
||||
playwright>=1.49.0
|
||||
browser-use>=0.1.0
|
||||
langchain-ollama>=0.2.0
|
||||
+5
-4
@@ -5,13 +5,14 @@
|
||||
"scripts": {
|
||||
"dev": "npm run dev:precheck & npm run dev:ollama & npm run dev:start",
|
||||
"dev:signaling": "node signaling-server.mjs",
|
||||
"dev:open": "powershell -NoProfile -Command \"Start-Sleep 8; Start-Process 'http://localhost:3001/splash'\"",
|
||||
"dev:open": "node scripts/open-browser.mjs",
|
||||
"dev:start": "concurrently -n AI,BROWSE,SIGNAL,NEXT,OPEN -c cyan,magenta,yellow,green,white \"npm run dev:rust\" \"npm run dev:browser-use\" \"npm run dev:signaling\" \"npm run dev:next\" \"npm run dev:open\"",
|
||||
"dev:next": "next dev -p 3006",
|
||||
"dev:precheck": "powershell -NoProfile -Command \"Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -in 3001,3006,3007,3008 } | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force -ErrorAction SilentlyContinue; Write-Host ('Freed port '+$_.LocalPort) }\"",
|
||||
"dev:ollama": "powershell -NoProfile -Command \"$ollama = if (Get-Command ollama -ErrorAction SilentlyContinue) { 'ollama' } else { Join-Path $env:LOCALAPPDATA 'Programs\\Ollama\\ollama.exe' }; if (-not (Get-Process ollama -ErrorAction SilentlyContinue)) { Start-Process $ollama -ArgumentList 'serve' -WindowStyle Hidden; Start-Sleep 3 }; exit 0\"",
|
||||
"dev:precheck": "node scripts/precheck.mjs",
|
||||
"dev:ollama": "node scripts/ensure-ollama.mjs",
|
||||
"dev:rust": "node ai-server/index.mjs",
|
||||
"dev:browser-use": "set FX_PROFILE=C:\\Users\\USER-PC\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\h8p11vlj.default-release && cd browser-use-service && python main.py",
|
||||
"dev:browser-use": "cd browser-use-service && node ../scripts/run-python.mjs main.py",
|
||||
"setup": "node scripts/setup.mjs",
|
||||
"build": "next build",
|
||||
"start": "next start -p 3006",
|
||||
"lint": "eslint"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { execSync, spawn } from "node:child_process"
|
||||
import { platform } from "node:os"
|
||||
|
||||
function isRunning() {
|
||||
try {
|
||||
if (platform() === "win32") {
|
||||
execSync('tasklist /FI "IMAGENAME eq ollama.exe" 2>nul | findstr ollama', { stdio: "pipe", timeout: 3000 })
|
||||
} else {
|
||||
execSync('pgrep -x ollama', { stdio: "pipe", timeout: 3000 })
|
||||
}
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function findOllama() {
|
||||
if (platform() === "win32") {
|
||||
try {
|
||||
return execSync("where ollama", { encoding: "utf8", timeout: 3000 }).trim().split("\n")[0]
|
||||
} catch {}
|
||||
const local = `${process.env.LOCALAPPDATA}\\Programs\\Ollama\\ollama.exe`
|
||||
const programFiles = `${process.env.PROGRAMFILES}\\Ollama\\ollama.exe`
|
||||
if (local) try { execSync(`"${local}" --version`, { stdio: "ignore", timeout: 2000 }); return local } catch {}
|
||||
if (programFiles) try { execSync(`"${programFiles}" --version`, { stdio: "ignore", timeout: 2000 }); return programFiles } catch {}
|
||||
} else {
|
||||
try { return execSync("which ollama", { encoding: "utf8", timeout: 3000 }).trim() } catch {}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
if (!isRunning()) {
|
||||
const bin = findOllama()
|
||||
if (!bin) {
|
||||
console.error("Ollama not found. Install from https://ollama.com")
|
||||
process.exit(1)
|
||||
}
|
||||
console.log("Starting Ollama...")
|
||||
if (platform() === "win32") {
|
||||
spawn(bin, ["serve"], { stdio: "ignore", detached: true, windowsHide: true }).unref()
|
||||
} else {
|
||||
spawn(bin, ["serve"], { stdio: "ignore", detached: true }).unref()
|
||||
}
|
||||
execSync("sleep 3", { stdio: "ignore", timeout: 5000 })
|
||||
} else {
|
||||
console.log("Ollama already running")
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { execSync } from "node:child_process"
|
||||
import { platform } from "node:os"
|
||||
|
||||
const url = process.argv[2] || "http://localhost:3001/splash"
|
||||
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
|
||||
|
||||
async function main() {
|
||||
await sleep(8000)
|
||||
try {
|
||||
if (platform() === "win32") {
|
||||
execSync(`start "" "${url}"`, { stdio: "ignore", timeout: 5000 })
|
||||
} else if (platform() === "darwin") {
|
||||
execSync(`open "${url}"`, { stdio: "ignore", timeout: 5000 })
|
||||
} else {
|
||||
execSync(`xdg-open "${url}"`, { stdio: "ignore", timeout: 5000 })
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to open browser:", e.message)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,30 @@
|
||||
import { execSync } from "node:child_process"
|
||||
import { platform } from "node:os"
|
||||
|
||||
const PORTS = [3001, 3006, 3007, 3008]
|
||||
|
||||
if (platform() === "win32") {
|
||||
for (const port of PORTS) {
|
||||
try {
|
||||
const out = execSync(`netstat -ano | findstr "LISTENING" | findstr ":${port} "`, { encoding: "utf8", timeout: 5000 })
|
||||
const lines = out.trim().split("\n").filter(Boolean)
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split(/\s+/)
|
||||
const pid = parts[parts.length - 1]
|
||||
if (pid) {
|
||||
try { execSync(`taskkill /F /PID ${pid}`, { stdio: "ignore", timeout: 3000 }); console.log(`Freed port ${port} (PID ${pid})`) } catch {}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
} else {
|
||||
for (const port of PORTS) {
|
||||
try {
|
||||
const pid = execSync(`lsof -ti:${port} 2>/dev/null`, { encoding: "utf8", timeout: 5000 }).trim()
|
||||
if (pid) {
|
||||
execSync(`kill -9 ${pid}`, { stdio: "ignore", timeout: 3000 })
|
||||
console.log(`Freed port ${port} (PID ${pid})`)
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { execSync, spawn } from "node:child_process"
|
||||
import { platform } from "node:os"
|
||||
|
||||
function detectPython() {
|
||||
const candidates = platform() === "win32" ? ["python", "python3"] : ["python3", "python"]
|
||||
for (const cmd of candidates) {
|
||||
try {
|
||||
const out = execSync(platform() === "win32" ? `where ${cmd}` : `which ${cmd}`, { encoding: "utf8", timeout: 5000 })
|
||||
const path = out.trim().split("\n")[0].replace(/\r$/, "")
|
||||
if (path) return path
|
||||
} catch {}
|
||||
}
|
||||
console.error("Python not found. Install Python 3 from https://python.org")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const PYTHON = detectPython()
|
||||
const script = process.argv[2]
|
||||
const args = process.argv.slice(3)
|
||||
|
||||
if (!script) {
|
||||
console.error("Usage: node run-python.mjs <script> [args...]")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const proc = spawn(PYTHON, [script, ...args], { stdio: "inherit" })
|
||||
proc.on("exit", (code) => process.exit(code ?? 1))
|
||||
@@ -0,0 +1,69 @@
|
||||
import { execSync } from "node:child_process"
|
||||
import { existsSync, copyFileSync } from "node:fs"
|
||||
import { platform } from "node:os"
|
||||
|
||||
const SEP = platform() === "win32" ? "&" : ";"
|
||||
|
||||
function detectPython() {
|
||||
const candidates = platform() === "win32" ? ["python", "python3"] : ["python3", "python"]
|
||||
for (const cmd of candidates) {
|
||||
try {
|
||||
execSync(`${cmd} --version`, { stdio: "pipe", timeout: 5000 })
|
||||
return cmd
|
||||
} catch {}
|
||||
}
|
||||
console.error("Python not found. Install Python 3 from https://python.org")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
function detectPip(python) {
|
||||
const candidates = platform() === "win32" ? ["pip", "pip3"] : ["pip3", "pip"]
|
||||
for (const cmd of candidates) {
|
||||
try {
|
||||
execSync(`${cmd} --version`, { stdio: "pipe", timeout: 5000 })
|
||||
return cmd
|
||||
} catch {}
|
||||
}
|
||||
return `${python} -m pip`
|
||||
}
|
||||
|
||||
const PY = detectPython()
|
||||
const PIP = detectPip(PY)
|
||||
|
||||
function run(cmd, label) {
|
||||
console.log(`\n── ${label} ──`)
|
||||
try {
|
||||
execSync(cmd, { stdio: "inherit", timeout: 120000 })
|
||||
} catch (e) {
|
||||
console.error(` ✗ Failed: ${e.message}`)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
console.log("=== CoastIT CRM Setup ===\n")
|
||||
|
||||
// 1. Node dependencies
|
||||
run("npm install", "Installing Node.js dependencies")
|
||||
|
||||
// 2. Python dependencies
|
||||
run(`cd browser-use-service ${SEP} ${PIP} install -r requirements.txt`, "Installing Python dependencies")
|
||||
|
||||
// 3. Playwright browsers
|
||||
run(`${PY} -m playwright install firefox chromium`, "Installing Playwright browsers")
|
||||
|
||||
// 4. .env file
|
||||
if (!existsSync(".env.local")) {
|
||||
console.log("\n── Creating .env.local ──")
|
||||
copyFileSync(".env.example", ".env.local")
|
||||
console.log(" ✓ Created .env.local from .env.example — edit it with your settings")
|
||||
} else {
|
||||
console.log("\n── .env.local already exists, skipping ──")
|
||||
}
|
||||
|
||||
// 5. Ollama model
|
||||
console.log("\n── Next steps ──")
|
||||
console.log(" 1. Make sure PostgreSQL is running with database 'crm'")
|
||||
console.log(" 2. Pull the Ollama model: ollama pull dolphin-llama3:8b")
|
||||
console.log(" 3. Edit .env.local with your settings")
|
||||
console.log(" 4. Run: npm run dev")
|
||||
console.log("\n=== Setup complete! ===")
|
||||
Reference in New Issue
Block a user