virtual-assistant / utils.py
Navy
scarping update
b720cc9
from bs4 import BeautifulSoup
from pathlib import Path
from fpdf import FPDF
from urllib.parse import urlparse
import openai
import time
import os
import logging
# ---------------- OPENAI ----------------
def init_openai(api_key: str):
openai.api_key = api_key
def clean_text_with_openai(raw_text: str) -> str:
"""
Bersihkan teks menggunakan OpenAI terbaru
- Hilangkan navigasi, footer, duplikasi
- Rangkum untuk customer service
- Pertahankan semua informasi penting, termasuk link website
"""
prompt = f"""
Tolong bersihkan dan ringkas teks berikut agar menjadi relevan untuk customer service:
- Hilangkan navigasi, footer, menu, iklan, dan duplikasi
- Pertahankan semua informasi penting, termasuk URL/link website, email, dan kontak resmi
- Rangkum secara rapi per section dengan judul yang jelas
- Hasil akhir tetap mudah dibaca dan lengkap untuk menjawab pertanyaan pengguna
Teks mentah:
{raw_text}
"""
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": (
"Kamu adalah asisten yang merapikan teks website agar siap digunakan dalam RAG chatbot berbasis FAISS.\n"
"Instruksi:\n"
"- Pisahkan konten menjadi bagian-bagian logis: Produk, Layanan, Testimoni, Kontak, Informasi Perusahaan, dsb.\n"
"- Hapus elemen navigasi, menu, footer, iklan, dan duplikasi.\n"
"- Jangan menghapus URL/link, email, atau informasi kontak resmi.\n"
"- Format teks supaya mudah dicari oleh vector database: paragraf pendek, bullet point untuk list, judul section.\n"
"- Jangan menambahkan opini, komentar, atau promosi tambahan.\n"
"- Tetap pertahankan semua informasi penting agar chatbot bisa menjawab pertanyaan pengguna dengan akurat.\n"
"- Output harus bersih, ringkas, lengkap, dan siap diindeks untuk retrieval."
)
},
{"role": "user", "content": prompt}
],
temperature=0
)
cleaned_text = response.choices[0].message.content.strip()
return cleaned_text
# ---------------- LOGGING ----------------
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
# ---------------- SELENIUM ----------------
def init_driver(headless=True):
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium import webdriver
options = Options()
if headless:
options.add_argument("--headless=new")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
options.binary_location = "/usr/bin/chromium" # path Chromium di HF Spaces
service = Service("/usr/bin/chromedriver") # pastikan path benar
driver = webdriver.Chrome(service=service, options=options)
logging.info("WebDriver berhasil diinisialisasi")
return driver
def init_driver_local(headless=True):
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
if headless:
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(options=options)
return driver
def fetch_page_text(driver, url: str) -> str:
logging.info("Mengambil halaman: %s", url)
driver.get(url)
time.sleep(2) # beri waktu agar JS selesai render
soup = BeautifulSoup(driver.page_source, "html.parser")
main_content = soup.find("main") or soup
text = main_content.get_text(separator="\n", strip=True)
logging.info("Halaman berhasil diambil (%d karakter)", len(text))
return text
# ---------------- PDF ----------------
def save_to_pdf(text: str, output_file: Path):
logging.info("Menyimpan teks ke PDF: %s", output_file)
pdf = FPDF()
pdf.set_auto_page_break(auto=True, margin=15)
pdf.add_page()
pdf.set_font("Arial", size=12)
for line in text.split("\n"):
if len(line) > 120:
chunks = [line[i:i+120] for i in range(0, len(line), 120)]
for chunk in chunks:
pdf.multi_cell(0, 6, chunk)
else:
pdf.multi_cell(0, 6, line)
pdf.ln(1)
pdf.output(str(output_file))
logging.info("PDF berhasil disimpan: %s", output_file)
def url_to_filename(url: str, folder: Path) -> Path:
parsed = urlparse(url)
path_safe = parsed.path.strip("/").replace("/", "_")
if path_safe:
safe_name = f"{parsed.netloc.replace('.', '_')}_{path_safe}.pdf"
else:
safe_name = f"{parsed.netloc.replace('.', '_')}.pdf"
output_file = folder / safe_name
logging.info("Nama file PDF untuk URL '%s': %s", url, output_file)
return output_file