feat: universal zero-hallucination dynamic web scraper engine & instant tag edit mode

This commit is contained in:
2026-08-08 07:04:42 +03:00
parent 5994e91ef9
commit a8d52b8601
3 changed files with 285 additions and 146 deletions
+75 -11
View File
@@ -4,13 +4,15 @@ import { Globe, Bot, Sparkles, CheckCircle2, ShieldCheck, Tag, X, Loader2, Datab
import confetti from 'canvas-confetti';
export const CompanyScannerModal = () => {
const { isCompanyScannerOpen, setIsCompanyScannerOpen, userProfile, scanCompanyWebsite } = useApp();
const { isCompanyScannerOpen, setIsCompanyScannerOpen, userProfile, scanCompanyWebsite, updateCompanyCapabilities } = useApp();
const [urlInput, setUrlInput] = useState(userProfile.website || 'https://www.tanriverdimedikal.com.tr');
const [isScanning, setIsScanning] = useState(false);
const [scanStep, setScanStep] = useState(0);
const [scanSuccess, setScanSuccess] = useState(false);
const [newProductInput, setNewProductInput] = useState('');
if (!isCompanyScannerOpen) return null;
const handleStartScan = async (e) => {
@@ -21,8 +23,8 @@ export const CompanyScannerModal = () => {
setScanSuccess(false);
setScanStep(1);
setTimeout(() => setScanStep(2), 800);
setTimeout(() => setScanStep(3), 1600);
setTimeout(() => setScanStep(2), 600);
setTimeout(() => setScanStep(3), 1200);
const capabilities = await scanCompanyWebsite(urlInput);
setIsScanning(false);
@@ -34,8 +36,28 @@ export const CompanyScannerModal = () => {
const handleRemoveSector = (indexToRemove) => {
if (!caps?.extractedSectors) return;
const updatedSectors = caps.extractedSectors.filter((_, idx) => idx !== indexToRemove);
scanCompanyWebsite(userProfile.website || urlInput);
const updated = caps.extractedSectors.filter((_, idx) => idx !== indexToRemove);
updateCompanyCapabilities({ extractedSectors: updated });
};
const handleRemoveProduct = (indexToRemove) => {
if (!caps?.extractedProducts) return;
const updated = caps.extractedProducts.filter((_, idx) => idx !== indexToRemove);
updateCompanyCapabilities({ extractedProducts: updated });
};
const handleRemoveCert = (indexToRemove) => {
if (!caps?.extractedCertifications) return;
const updated = caps.extractedCertifications.filter((_, idx) => idx !== indexToRemove);
updateCompanyCapabilities({ extractedCertifications: updated });
};
const handleAddCustomProduct = (e) => {
e.preventDefault();
if (!newProductInput.trim() || !caps) return;
const updated = [...(caps.extractedProducts || []), newProductInput.trim()];
updateCompanyCapabilities({ extractedProducts: updated });
setNewProductInput('');
};
return (
@@ -163,27 +185,62 @@ export const CompanyScannerModal = () => {
</span>
<div className="space-y-1.5">
{caps.extractedSectors?.map((s, i) => (
<div key={i} className="flex items-center justify-between text-xs font-bold text-blue-900 bg-blue-100/70 border border-blue-200 px-2.5 py-1.5 rounded-lg">
<div key={i} className="flex items-center justify-between text-xs font-bold text-blue-900 bg-blue-100/70 border border-blue-200 px-2.5 py-1.5 rounded-lg group">
<span>{s}</span>
<span className="text-[10px] text-blue-600 bg-white px-1.5 py-0.5 rounded-md font-semibold">Doğrulandı</span>
<button
type="button"
onClick={() => handleRemoveSector(i)}
className="text-blue-400 hover:text-red-600 transition-colors p-0.5"
title="Sektörü Kaldır"
>
<X className="w-3.5 h-3.5" />
</button>
</div>
))}
</div>
</div>
{/* Products */}
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 space-y-2 md:col-span-2">
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 space-y-3 md:col-span-2">
<span className="font-bold text-xs text-slate-800 uppercase tracking-wider flex items-center gap-1.5 justify-between">
<span className="flex items-center gap-1.5">
<Bot className="w-3.5 h-3.5 text-emerald-600" /> Detaylı Ürün & Hizmet Kataloğu ({caps.extractedProducts?.length || 0})
</span>
<span className="text-[10px] text-emerald-700 font-semibold">Sayfadan Ayıklanan Detaylı Kalemler</span>
</span>
{/* Add Custom Item Form */}
<form onSubmit={handleAddCustomProduct} className="flex gap-2">
<input
type="text"
value={newProductInput}
onChange={(e) => setNewProductInput(e.target.value)}
placeholder="+ Yeni Ürün / İhale Kalemi Ekle..."
className="flex-1 bg-white border border-slate-300 rounded-lg px-3 py-1.5 text-xs text-slate-900 font-semibold focus:ring-2 focus:ring-emerald-500"
/>
<button
type="submit"
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold px-3 py-1.5 rounded-lg text-xs transition-colors shrink-0"
>
Ekle
</button>
</form>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-1.5">
{caps.extractedProducts?.map((p, i) => (
<div key={i} className="text-xs font-semibold text-slate-700 bg-white border border-slate-200 p-2 rounded-lg flex items-start gap-1.5">
<span className="shrink-0 text-emerald-600 font-bold">📦</span>
<span className="line-clamp-2">{p}</span>
<div key={i} className="text-xs font-semibold text-slate-700 bg-white border border-slate-200 p-2 rounded-lg flex items-start justify-between gap-1.5 group">
<div className="flex items-start gap-1.5">
<span className="shrink-0 text-emerald-600 font-bold">📦</span>
<span className="line-clamp-2">{p}</span>
</div>
<button
type="button"
onClick={() => handleRemoveProduct(i)}
className="text-slate-300 hover:text-red-600 transition-colors p-0.5 shrink-0"
title="Ürünü Kaldır"
>
<X className="w-3.5 h-3.5" />
</button>
</div>
))}
</div>
@@ -200,6 +257,13 @@ export const CompanyScannerModal = () => {
{caps.extractedCertifications?.map((c, i) => (
<span key={i} className="text-xs font-semibold text-purple-900 bg-purple-100/70 border border-purple-200 px-3 py-1 rounded-lg flex items-center gap-1.5">
📜 {c}
<button
type="button"
onClick={() => handleRemoveCert(i)}
className="text-purple-400 hover:text-red-600 transition-colors"
>
<X className="w-3 h-3" />
</button>
</span>
))}
</div>