CIM Generator OpenAI v4 | 360 Biz Brokers
CIM Generator — New CIM
0
Sections Filled
16
Total Fields
0%
Completeness
Quick Start
📄
Cover Info
Name, price, key metrics
✍️
Executive Summary
AI can write this for you
💰
Financials
Revenue, SDE, EBITDA
📸
Upload Photos
Logos & business photos
🤖 AI Connection

The upload and AI writing tools require a working WordPress REST proxy endpoint. If your site returns 404, paste the current proxy URL below and click Save.

📥 Step 1 — Download & Send Intake Form to Seller

Download the 360 Biz Brokers Listing Intake Form. Send it to your seller to complete. Once returned, upload it in Step 2 below and AI will auto-populate all CIM fields.

English Version
Full listing intake • 4 pages • All CIM sections
Spanish Version / Versión en Español
Formulario completo • 4 páginas • Todas las secciones
💡 Tip: Save as PDF from your browser's Print dialog (File → Print → Save as PDF) before emailing to the seller.
⚡ Step 2 — Upload Completed Intake & Auto-Fill CIM

Upload a listing intake form, seller questionnaire, or any business document. AI will read it and automatically populate all CIM fields.

📋
Drop your listing intake form here
Supports PDF, Word (.docx), JPG, PNG — seller questionnaires, intake sheets, listing agreements
Browse Files
Choose CIM Template
CONFIDENTIAL
Business Name
Presented by 360 Biz Brokers
Gold & Black ★
CONFIDENTIAL
Business Name
Investment Overview
Navy Professional
CONFIDENTIAL
Business Name
Presented by Broker
Forest Green
CONFIDENTIAL
Business Name
Luxury Brief
Burgundy Luxury
Cover Page Information
Know the Listing Broker
✨ AI:
Executive Summary
✨ AI:
Business Overview
Investment Highlights
Location & Market Overview
Products & Services
Operations & Staff
Facilities & Lease
Financial Summary & Recasted Earnings
Financial Metric Year 1 Year 2 Year 3 (Latest)
Gross Revenue
Cost of Goods Sold
Gross Profit
Total Operating Expenses
Net SDE / Owner Benefit
📊 Financial Documents — AI Auto-Extract

Upload tax returns, P&Ls, or spreadsheets. AI will read the numbers and auto-populate the financial table above. You can upload up to 3 documents (one per year).

Year 1 Document
📂
Tax Return / P&L
Year 1
Year 2 Document
📂
Tax Return / P&L
Year 2
Year 3 (Latest)
📂
Tax Return / P&L
Year 3 / Latest
Supports PDF, Word, Excel/CSV, JPG/PNG · Tax returns, P&Ls, QuickBooks exports
Competition & Industry Analysis
Growth Opportunities
Reason for Sale & Transition Support
Asset List (Included in Sale)
ITEM DESCRIPTION QTY FAIR MKT VALUE
Confidentiality Disclaimer
Logos & Key Images
📎
Badge / Award
📎
Broker Photo
Business Photos
📎
Cover Photo
📎
Photo 2
📎
Photo 3
📎
Photo 4
📎
Photo 5
📎
Photo 6
CIM Preview — use Print to save as PDF
`); printWin.document.close(); printWin.onload = () => { setTimeout(() => { printWin.focus(); printWin.print(); }, 700); }; } function buildCIM() { const t=ST.tpl; const tc={ 1:{bg:'#111111',ac:'#C9A84C',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Anton',sans-serif"}, 2:{bg:'#1a2744',ac:'#4a90d9',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Playfair Display',serif"}, 3:{bg:'#1b3a2d',ac:'#5cb87a',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Montserrat',sans-serif"}, 4:{bg:'#2d0a1e',ac:'#b8436e',tx:'white',sb:'rgba(255,255,255,0.5)',tf:"'Playfair Display',serif"}, }[t]; const bn=g('f-biz-name')||'Business Name'; const bt=g('f-biz-type'); const ap=g('f-asking-price'); const rv=g('f-revenue'); const sd=g('f-sde'); const lc=g('f-location'); const yr=g('f-years'); const bk=g('f-brokerage')||'360 Biz Brokers'; const brn=g('f-broker-name'); function tp(text) { if(!text) return ''; return text.split('\n').filter(l=>l.trim()).map(l=>`

${l.trim()}

`).join(''); } function tb(text) { if(!text) return ''; return `
    ${text.split('\n').filter(l=>l.trim()).map(l=>`
  • ${l.trim().replace(/^[-•*▸]\s*/,'')}
  • `).join('')}
`; } function sec(label, title, body) { if(!body||!body.trim()) return ''; return `
${label?`
${label}
`:''}
${title}
${body}
`; } // Cover meta const metaItems=[['Industry',bt],['Asking Price',ap],['Annual Revenue',rv],['SDE / Owner Benefit',sd],['Location',lc],['Years Established',yr?(yr+' Years'):'']].filter(([,v])=>v); const coverMeta=metaItems.length?`
${metaItems.map(([k,v])=>`
${k}
${v}
`).join('')}
`:''; const brokerLogoHtml=im('broker-logo')?``:`
${bk}
`; const bizLogoHtml=im('biz-logo')?``:''; const coverPhotoHtml=im('cover-photo')?`
`:''; const badgeHtml=im('broker-badge')?``:''; const brokerPhotoHtml=im('broker-photo')?``:`
👤
`; // KPI grid const kpis=[[ap,'Asking Price'],[rv,'Annual Revenue'],[sd,'SDE / Owner Benefit'],[yr?yr+' Yrs':'','Years Established']].filter(([v])=>v); const kpiHtml=kpis.length?`
${kpis.map(([v,l])=>`
${l}
${v}
`).join('')}
`:''; // Financial table const finRows=[['Gross Revenue','f-rev'],['Cost of Goods Sold','f-cogs'],['Gross Profit','f-gp'],['Total Operating Expenses','f-opex'],['Net SDE / Owner Benefit','f-sde']]; const hasFinData=['f-rev1','f-rev2','f-rev3','f-sde1','f-sde2','f-sde3'].some(id=>g(id)); const finTable=hasFinData?`${finRows.map(([lbl,px],i)=>{const last=i===finRows.length-1;const r1=g(px+'1'),r2=g(px+'2'),r3=g(px+'3');return``}).join('')}
Financial MetricYear 1Year 2Year 3 (Latest)
${lbl}${r1||'—'}${r2||'—'}${r3||'—'}
`:''; // Assets const assetRows=Array.from(document.querySelectorAll('#asset-rows > div')).map(r=>{const inp=r.querySelectorAll('input');return inp.length>=3?[inp[0].value,inp[1].value,inp[2].value]:null;}).filter(r=>r&&r[0]); const assetTable=assetRows.length?`${assetRows.map(([d,q,f])=>``).join('')}
Asset DescriptionQtyFMV
${d}${q||'1'}${f||'—'}
`:''; // Gallery const gphotos=['p2','p3','p4','p5','p6'].map(k=>im(k)).filter(Boolean); const gallery=gphotos.length?`
${gphotos.slice(0,6).map(s=>``).join('')}
`:''; // Financial body const finBody=[ kpiHtml,finTable, g('f-recast')?`
${tp(g('f-recast'))}
`:'', [g('f-valuation')&&`Valuation: ${g('f-valuation')}`,g('f-deal')&&`Deal Structure: ${g('f-deal')}`].filter(Boolean).join('
'), ].filter(Boolean).join(''); // Broker bio const brokerBio=(g('f-broker-bio')||g('f-broker-fullname'))?`
Your Listing Broker
Know Your Broker
${brokerPhotoHtml}
${g('f-broker-fullname')||brn}
${g('f-broker-title')||'Principal Broker'}
${g('f-broker-phone')?`
📞 ${g('f-broker-phone')}
`:''} ${g('f-broker-email')?`
✉️ ${g('f-broker-email')}
`:''} ${g('f-broker-website')?`
🌐 ${g('f-broker-website')}
`:''} ${g('f-broker-bio')?`
${g('f-broker-bio')}
`:''} ${badgeHtml}
`:''; // Info rows helper function infoRow(items) { const filled=items.filter(([,v])=>v); if(!filled.length) return ''; return `
${filled.map(([k,v])=>`${k}: ${v}`).join('  ·  ')}
`; } return `
${brokerLogoHtml}${bizLogoHtml}
Confidential Information Memorandum
${bn}
${bt?`
${bt}
`:''}
${coverMeta}
Presented exclusively by ${bk}${brn?' | '+brn:''}
Strictly Confidential
© ${new Date().getFullYear()} ${bk}
${coverPhotoHtml} ${brokerBio} ${sec('','Executive Summary',tp(g('f-exec')))} ${(g('f-biz-desc')||g('f-biz-history'))?sec('The Opportunity','Business Overview',[tp(g('f-biz-desc')),g('f-biz-history')?`
${tp(g('f-biz-history'))}
`:'',infoRow([['Legal',g('f-legal')],['Ownership',g('f-ownership')],['Hours',g('f-hours')]]),g('f-customers')?`
Customer Demographics:
${g('f-customers')}
`:'' ].filter(Boolean).join('')):''} ${g('f-highlights')?sec('Why Buy','Investment Highlights',tb(g('f-highlights'))):''} ${gallery} ${(g('f-loc-desc')||g('f-demand'))?sec('Market','Location & Market Overview',[lc?`
Area: ${lc}
`:'',tp(g('f-loc-desc')),g('f-demand')?`
Nearby Demand Drivers:
${tp(g('f-demand'))}
`:'' ].filter(Boolean).join('')):''} ${(g('f-products')||g('f-rev-mix'))?sec('Offerings','Products & Services',[tp(g('f-products')),g('f-rev-mix')?`
Revenue Mix: ${g('f-rev-mix')}
`:'' ].filter(Boolean).join('')):''} ${(g('f-ops')||g('f-employees'))?sec('How It Runs','Operations & Staff',[infoRow([['Team',g('f-employees')],['Owner Role',g('f-owner-role')],['Key Staff',g('f-mgmt')]]),tp(g('f-ops')),g('f-staff')?`
${tp(g('f-staff'))}
`:'' ].filter(Boolean).join('')):''} ${(g('f-facilities')||g('f-sqft')||g('f-rent'))?sec('The Space','Facilities & Lease',[infoRow([['Size',g('f-sqft')],['Monthly Rent',g('f-rent')],['Lease Exp.',g('f-lease-exp')]]),tp(g('f-facilities'))].filter(Boolean).join('')):''} ${finBody?sec('Performance','Financial Summary & Recasted Earnings',finBody):''} ${(g('f-competition')||g('f-industry')||g('f-reviews'))?sec('The Market','Competition & Industry Analysis',[g('f-competition')?`

Competitive Landscape

${tp(g('f-competition'))}`:'',g('f-industry')?`

Industry Analysis

${tp(g('f-industry'))}`:'',g('f-reviews')?`

Public Reputation

${tp(g('f-reviews'))}`:''].filter(Boolean).join('')):''} ${g('f-growth')?sec('The Upside','Growth Opportunities',tb(g('f-growth'))):''} ${(g('f-reason')||g('f-transition'))?sec('Next Steps','Reason for Sale & Transition',[g('f-reason')?`
Reason for Sale:
${tp(g('f-reason'))}
`:'',g('f-transition')?`
Transition Support:
${tp(g('f-transition'))}
`:'' ].filter(Boolean).join('')):''} ${(assetTable||g('f-asset-notes'))?sec('Included Assets','Asset List',[assetTable,g('f-asset-notes')?tp(g('f-asset-notes')):'' ].filter(Boolean).join('')):''} ${g('f-disclaimer')?`
Confidentiality Disclaimer
${tp(g('f-disclaimer'))}
${g('f-appendix')?`
${tp(g('f-appendix'))}
`:''}
`:''}
${bk} · Strictly Confidential
Generated ${new Date().toLocaleDateString('en-US',{month:'long',day:'numeric',year:'numeric'})}
`; } // ── INTAKE FORM DOWNLOAD ── function downloadIntakeForm(lang) { const isES = lang === 'es'; const L = { title: isES ? 'Formulario de Listado — Cuestionario del Vendedor' : 'Business Listing Intake Form — Seller Questionnaire', confidential: isES ? 'CONFIDENCIAL' : 'CONFIDENTIAL', tagline: isES ? 'Complete este formulario y devuélvalo a su corredor. Toda información será mantenida estrictamente confidencial.' : 'Please complete this form and return it to your broker. All information will be kept strictly confidential.', broker_label: isES ? 'Corredor Asignado' : 'Assigned Broker', date_label: isES ? 'Fecha' : 'Date', s1: isES ? 'SECCIÓN 1 — INFORMACIÓN GENERAL DEL NEGOCIO' : 'SECTION 1 — GENERAL BUSINESS INFORMATION', s2: isES ? 'SECCIÓN 2 — FINANZAS' : 'SECTION 2 — FINANCIALS', s3: isES ? 'SECCIÓN 3 — OPERACIONES Y PERSONAL' : 'SECTION 3 — OPERATIONS & STAFF', s4: isES ? 'SECCIÓN 4 — INSTALACIONES Y ARRENDAMIENTO' : 'SECTION 4 — FACILITIES & LEASE', s5: isES ? 'SECCIÓN 5 — PRODUCTOS Y SERVICIOS' : 'SECTION 5 — PRODUCTS & SERVICES', s6: isES ? 'SECCIÓN 6 — ACTIVOS INCLUIDOS EN LA VENTA' : 'SECTION 6 — ASSETS INCLUDED IN SALE', s7: isES ? 'SECCIÓN 7 — RAZÓN DE VENTA Y TRANSICIÓN' : 'SECTION 7 — REASON FOR SALE & TRANSITION', s8: isES ? 'SECCIÓN 8 — INFORMACIÓN ADICIONAL' : 'SECTION 8 — ADDITIONAL INFORMATION', disclaimer: isES ? 'Este formulario es estrictamente confidencial y está destinado únicamente para uso interno de 360 Biz Brokers. La información proporcionada se utilizará exclusivamente para la preparación del Memorando de Información Confidencial (CIM).' : 'This form is strictly confidential and intended solely for internal use by 360 Biz Brokers. Information provided will be used exclusively for preparation of the Confidential Information Memorandum (CIM).', fields: isES ? { biz_name: 'Nombre Legal del Negocio', dba: 'Nombre Comercial (DBA)', biz_type: 'Tipo de Negocio / Industria', founded: 'Año de Fundación', years: 'Años en Operación', address: 'Dirección Completa', city_state: 'Ciudad, Estado, Código Postal', phone: 'Teléfono del Negocio', website: 'Sitio Web', legal_structure: 'Estructura Legal (LLC, Corp, etc.)', ein: 'EIN / Número de Identificación Fiscal', owner_name: 'Nombre del Propietario', owner_phone: 'Teléfono del Propietario', owner_email: 'Correo del Propietario', asking_price: 'Precio Pedido', price_rationale: 'Justificación del Precio', rev_yr1: 'Ingresos Brutos — Año 1 ($)', rev_yr2: 'Ingresos Brutos — Año 2 ($)', rev_yr3: 'Ingresos Brutos — Año 3 / Más Reciente ($)', cogs_yr3: 'Costo de Ventas — Año 3 ($)', opex_yr3: 'Gastos Operativos Totales — Año 3 ($)', owner_salary: 'Salario del Propietario Incluido en Gastos ($)', sde: 'SDE / Beneficio Neto del Propietario ($)', addbacks: 'Gastos Adicionales (add-backs) y Gastos Personales', taxes_current: '¿Impuestos al Día?', employees_ft: 'Empleados de Tiempo Completo', employees_pt: 'Empleados de Tiempo Parcial', owner_hours: 'Horas del Propietario por Semana', owner_role: 'Rol del Propietario en el Negocio', key_staff: 'Personal Clave y Sus Roles', staff_staying: '¿El Personal Clave Continuará?', systems: 'Sistemas / Software / POS Utilizados', suppliers: 'Proveedores Principales', sqft: 'Metros Cuadrados del Local', rent: 'Renta Mensual ($)', lease_exp: 'Vencimiento del Arrendamiento', lease_options: 'Opciones de Renovación del Arrendamiento', parking: 'Estacionamiento Disponible', landlord: 'Relación con el Arrendador', real_estate: '¿Se Incluye Bienes Raíces?', products_desc: 'Descripción de Productos y/o Servicios', revenue_mix: 'Mezcla de Ingresos (% por línea de producto/servicio)', customers: 'Perfil del Cliente Principal', contracts: 'Contratos o Clientes Recurrentes', ffe_desc: 'Describa el FF&E Incluido (muebles, equipos, accesorios)', inventory: 'Valor Estimado del Inventario ($)', vehicles: 'Vehículos Incluidos', ip: 'Propiedad Intelectual (marcas, patentes, dominio web)', reason: 'Razón para Vender', timeline: 'Línea de Tiempo Deseada para Cerrar', training: 'Capacitación / Soporte de Transición Ofrecido', seller_financing: '¿Considera Financiamiento del Vendedor?', competition: 'Principales Competidores', advantages: 'Ventajas Competitivas', growth: 'Oportunidades de Crecimiento', risks: 'Riesgos o Desafíos a Revelar', pending_legal: 'Litigios Pendientes o Problemas Legales', licenses: 'Licencias y Permisos Requeridos', other: 'Información Adicional que el Comprador Debe Conocer' } : { biz_name: 'Legal Business Name', dba: 'Trade Name / DBA', biz_type: 'Business Type / Industry', founded: 'Year Founded', years: 'Years in Operation', address: 'Full Business Address', city_state: 'City, State, Zip Code', phone: 'Business Phone', website: 'Website', legal_structure: 'Legal Structure (LLC, Corp, etc.)', ein: 'EIN / Federal Tax ID', owner_name: 'Owner Full Name', owner_phone: 'Owner Phone', owner_email: 'Owner Email', asking_price: 'Asking Price', price_rationale: 'Basis for Asking Price', rev_yr1: 'Gross Revenue — Year 1 ($)', rev_yr2: 'Gross Revenue — Year 2 ($)', rev_yr3: 'Gross Revenue — Year 3 / Most Recent ($)', cogs_yr3: 'Cost of Goods Sold — Year 3 ($)', opex_yr3: 'Total Operating Expenses — Year 3 ($)', owner_salary: 'Owner Salary Included in Expenses ($)', sde: 'SDE / Net Owner Benefit ($)', addbacks: 'Add-Back Items & Personal Expenses Run Through Business', taxes_current: 'Are Business Taxes Current?', employees_ft: 'Full-Time Employees', employees_pt: 'Part-Time Employees', owner_hours: 'Owner Hours Per Week', owner_role: 'Owner\'s Role in the Business', key_staff: 'Key Staff Members & Their Roles', staff_staying: 'Will Key Staff Stay Post-Sale?', systems: 'Systems / Software / POS Used', suppliers: 'Major Suppliers / Vendors', sqft: 'Total Square Footage', rent: 'Monthly Rent ($)', lease_exp: 'Lease Expiration Date', lease_options: 'Lease Renewal Options', parking: 'Parking Available', landlord: 'Landlord Relationship', real_estate: 'Is Real Estate Included in Sale?', products_desc: 'Description of Products and/or Services Offered', revenue_mix: 'Revenue Mix (% breakdown by product/service line)', customers: 'Primary Customer Profile / Demographics', contracts: 'Recurring Contracts or Key Accounts', ffe_desc: 'Describe FF&E Included (furniture, fixtures, equipment)', inventory: 'Estimated Inventory Value at Time of Sale ($)', vehicles: 'Vehicles Included', ip: 'Intellectual Property (trademarks, patents, website domain)', reason: 'Reason for Selling', timeline: 'Desired Closing Timeline', training: 'Training / Transition Support Offered', seller_financing: 'Open to Seller Financing?', competition: 'Primary Competitors', advantages: 'Key Competitive Advantages', growth: 'Untapped Growth Opportunities', risks: 'Known Risks or Challenges to Disclose', pending_legal: 'Pending Litigation or Legal Issues', licenses: 'Licenses & Permits Required to Operate', other: 'Any Other Information a Buyer Should Know' } }; const F = L.fields; function row(label, lines=1, hint='') { const h = lines === 1 ? `
` : `
`; return `
${label}${hint?` — ${hint}`:''}
${h}
`; } function section(num, title, body) { return `
${title}
${body}
`; } function twoCol(f1, f2, lines=1) { return `
${row(f1,lines)}${row(f2,lines)}
`; } function threeCol(f1, f2, f3) { return `
${row(f1)}${row(f2)}${row(f3)}
`; } const html = ` ${L.title} — 360 Biz Brokers
360 Biz Brokers — Listing Intake Form Preview
360 BIZ BROKERS
360bizbrokers.com · (954) 325-2625 · val@360bizbrokers.com
${L.confidential}
${L.title}
${L.tagline}
${L.broker_label}
${L.date_label}
${section(1, L.s1, ` ${twoCol(F.biz_name, F.dba)} ${twoCol(F.biz_type, F.legal_structure)} ${threeCol(F.founded, F.years, F.ein)} ${row(F.address)} ${twoCol(F.city_state, F.phone)} ${twoCol(F.website, '')}
${threeCol(F.owner_name, F.owner_phone, F.owner_email)} ${twoCol(F.asking_price, F.price_rationale)}
`)} ${section(2, L.s2, ` ${threeCol(F.rev_yr1, F.rev_yr2, F.rev_yr3)} ${threeCol(F.cogs_yr3, F.opex_yr3, F.owner_salary)} ${twoCol(F.sde, F.taxes_current)} ${row(F.addbacks, 3, isES?'Describa cada partida y monto':'Describe each item and amount')} `)} ${section(3, L.s3, ` ${threeCol(F.employees_ft, F.employees_pt, F.owner_hours)} ${row(F.owner_role, 2)} ${row(F.key_staff, 3, isES?'Nombre, cargo, salario, años en la empresa':'Name, title, salary, years with company')} ${twoCol(F.staff_staying, F.systems)} ${row(F.suppliers, 2)} `)} ${section(4, L.s4, ` ${threeCol(F.sqft, F.rent, F.lease_exp)} ${twoCol(F.lease_options, F.parking)} ${twoCol(F.landlord, F.real_estate)} `)} ${section(5, L.s5, ` ${row(F.products_desc, 4)} ${row(F.revenue_mix, 2, isES?'ej. 60% comidas, 25% catering':'e.g. 60% dine-in, 25% catering')} ${row(F.customers, 2)} ${row(F.contracts, 2)} `)} ${section(6, L.s6, ` ${row(F.ffe_desc, 4, isES?'Liste los equipos más importantes y su estado':'List major equipment items and condition')} ${threeCol(F.inventory, F.vehicles, F.ip)} `)} ${section(7, L.s7, ` ${row(F.reason, 3)} ${twoCol(F.timeline, F.seller_financing)} ${row(F.training, 3)} `)} ${section(8, L.s8, ` ${row(F.competition, 2)} ${row(F.advantages, 2)} ${row(F.growth, 3)} ${row(F.risks, 2)} ${twoCol(F.pending_legal, F.licenses)} ${row(F.other, 3)} `)}
${isES?'Firma del Propietario':'Owner Signature'}
${isES?'Nombre impreso y fecha':'Printed name and date'}
${isES?'Firma del Corredor':'Broker Signature'}
${isES?'Nombre impreso y fecha':'Printed name and date'}
360 Biz Brokers — A DBA of Florida 360 Realty, LLC · ${isES?'Todos los derechos reservados':'All rights reserved'} © ${new Date().getFullYear()}
${L.confidential}
${L.disclaimer}
`; // Open in new window and trigger print const win = window.open('', '_blank'); win.document.write(html); win.document.close(); // Small delay so fonts load before print dialog win.onload = () => setTimeout(() => win.focus(), 400); } // ── INTAKE EXTRACTION ── let intakeFileData = null; let intakeFileType = null; let intakeFileName = null; function handleIntakeUpload(input) { const file = input.files[0]; if (!file) return; intakeFileName = file.name; const sizeMB = (file.size / 1024 / 1024).toFixed(1); // Show preview bar document.getElementById('intake-preview-bar').style.display = 'flex'; document.getElementById('intake-filename').textContent = file.name; document.getElementById('intake-filesize').textContent = sizeMB + ' MB · ' + (file.type || 'document'); // Detect file type const ext = file.name.split('.').pop().toLowerCase(); const isImage = file.type.startsWith('image/'); const mimeMap = { pdf: 'application/pdf', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', doc: 'application/msword', txt: 'text/plain', csv: 'text/csv' }; intakeFileType = isImage ? file.type : (file.type || mimeMap[ext] || 'application/octet-stream'); const reader = new FileReader(); reader.onload = (e) => { intakeFileData = e.target.result.split(',')[1]; }; reader.readAsDataURL(file); // Style the drop zone const dz = document.getElementById('intake-drop-zone'); dz.style.borderColor = 'var(--gold)'; dz.style.background = 'rgba(201,168,76,0.06)'; } function clearIntake() { intakeFileData = null; intakeFileType = null; intakeFileName = null; document.getElementById('intake-file-input').value = ''; document.getElementById('intake-preview-bar').style.display = 'none'; document.getElementById('intake-status').style.display = 'none'; const dz = document.getElementById('intake-drop-zone'); dz.style.borderColor = 'var(--gold-light)'; dz.style.background = 'rgba(201,168,76,0.04)'; } async function runIntakeExtraction() { if (!intakeFileData) { toast('No file loaded','err'); return; } const statusEl = document.getElementById('intake-status'); statusEl.style.display = 'block'; statusEl.innerHTML = '
AI is reading your intake document and extracting data… this may take 15–30 seconds.
'; const systemPrompt = `You are an expert business broker assistant. You will be given a listing intake form, seller questionnaire, or business document. Extract all available information and return it as a single valid JSON object with these exact keys (use empty string "" if not found): { "f-biz-name": "", "f-biz-type": "", "f-asking-price": "", "f-revenue": "", "f-sde": "", "f-location": "", "f-years": "", "f-brokerage": "", "f-broker-name": "", "f-broker-fullname": "", "f-broker-title": "", "f-broker-phone": "", "f-broker-email": "", "f-broker-website": "", "f-broker-bio": "", "f-exec": "", "f-biz-desc": "", "f-biz-history": "", "f-legal": "", "f-ownership": "", "f-hours": "", "f-customers": "", "f-advantages": "", "f-address": "", "f-neighborhood": "", "f-loc-desc": "", "f-demand": "", "f-products": "", "f-rev-mix": "", "f-employees": "", "f-owner-role": "", "f-ops": "", "f-staff": "", "f-sqft": "", "f-rent": "", "f-lease-exp": "", "f-facilities": "", "f-rev1": "", "f-rev2": "", "f-rev3": "", "f-cogs1": "", "f-cogs2": "", "f-cogs3": "", "f-gp1": "", "f-gp2": "", "f-gp3": "", "f-opex1": "", "f-opex2": "", "f-opex3": "", "f-sde1": "", "f-sde2": "", "f-sde3": "", "f-recast": "", "f-valuation": "", "f-deal": "", "f-competition": "", "f-industry": "", "f-growth": "", "f-reason": "", "f-transition": "", "f-asset-notes": "", "f-highlights": "", "f-appendix": "" } Rules: - Return ONLY the raw JSON object. No markdown, no backticks, no explanation. - For financial fields (f-rev1/2/3, f-sde1/2/3, etc.) use the most recently labeled years available. - For f-highlights and f-growth, format as one item per line. - For f-legal, use one of: LLC, S-Corp, C-Corp, Sole Proprietorship, Partnership — or leave blank. - For f-ownership, use one of: Single Owner, Partnership, Family-Owned, Absentee-Owned — or leave blank. - For f-mgmt, use one of: Yes all key staff staying, Most key staff staying, Varies, Unknown — or leave blank. - Be comprehensive — extract every piece of information available in the document.`; try { // Determine media type and build message content let msgContent; if (intakeFileType && intakeFileType.startsWith('image/')) { msgContent = [ { type: 'image', source: { type: 'base64', media_type: intakeFileType, data: intakeFileData } }, { type: 'text', text: 'Extract all business listing information from this intake form image and return as JSON.' } ]; } else { msgContent = [ { type: 'document', source: { type: 'base64', media_type: intakeFileType || 'application/octet-stream', filename: intakeFileName || 'uploaded-document', data: intakeFileData } }, { type: 'text', text: 'Extract all business listing information from this uploaded document and return as JSON.' } ]; } const payload = { model: AI_MODEL, max_tokens: 2000, system: systemPrompt, messages: [{ role: 'user', content: msgContent }] }; const data = await callProxyAI(payload); const rawText = parseProxyResponse(data); const extracted = extractJsonObject(rawText); // Count fields populated let filled = 0; Object.entries(extracted).forEach(([k, v]) => { if (v && v.toString().trim()) { const el = document.getElementById(k); if (el) { el.value = v; filled++; } } }); updateTopbar(); updateProgress(); saveData(); statusEl.innerHTML = `
✅ Extraction complete — ${filled} fields populated from "${intakeFileName}". Review each section and use AI Assist to refine any content.
`; toast(`✅ ${filled} fields auto-filled from intake!`); // Highlight the drop zone const dz = document.getElementById('intake-drop-zone'); dz.style.borderColor = '#16a34a'; dz.style.background = 'rgba(34,197,94,0.04)'; } catch(err) { console.error('Intake extraction error:', err); statusEl.innerHTML = `
❌ Extraction failed: ${err.message}
`; } } // ── FINANCIAL DOCUMENT EXTRACTION ── const finDocs = { 1: null, 2: null, 3: null }; const finDocTypes = { 1: null, 2: null, 3: null }; const finDocNames = { 1: null, 2: null, 3: null }; const FIN_ICONS = { pdf: '📄', docx: '📝', doc: '📝', xlsx: '📊', xls: '📊', csv: '📊', jpg: '🖼️', jpeg: '🖼️', png: '🖼️', tiff: '🖼️', tif: '🖼️' }; function handleFinDoc(input, yearNum) { const file = input.files[0]; if (!file) return; const ext = file.name.split('.').pop().toLowerCase(); finDocNames[yearNum] = file.name; const zone = document.getElementById('fin-zone-' + yearNum); const iconEl = document.getElementById('fin-icon-' + yearNum); const labelEl = document.getElementById('fin-label-' + yearNum); const nameEl = document.getElementById('fin-doc-name-' + yearNum); zone.style.borderColor = 'var(--gold)'; zone.style.background = 'rgba(201,168,76,0.06)'; iconEl.textContent = FIN_ICONS[ext] || '📄'; labelEl.innerHTML = '' + file.name.substring(0,22) + (file.name.length>22?'…':'') + ''; nameEl.textContent = (file.size/1024).toFixed(0) + ' KB'; nameEl.style.display = 'block'; const isWord = ext === 'docx' || ext === 'doc'; const isImg = file.type.startsWith('image/'); finDocTypes[yearNum] = isWord ? 'docx' : (ext === 'pdf' ? 'application/pdf' : (isImg ? file.type : (ext === 'csv' || ext === 'xlsx' || ext === 'xls' ? 'spreadsheet' : 'application/pdf'))); const reader = new FileReader(); if (isWord || ext === 'xlsx' || ext === 'xls' || ext === 'csv') { reader.onload = (e) => { const bytes = new Uint8Array(e.target.result); let bin = ''; bytes.forEach(b => bin += String.fromCharCode(b)); finDocs[yearNum] = btoa(bin); updateFinImgPreviews(); }; reader.readAsArrayBuffer(file); } else { reader.onload = (e) => { finDocs[yearNum] = e.target.result.split(',')[1]; finDocTypes[yearNum] = isImg ? file.type : 'application/pdf'; updateFinImgPreviews(); }; reader.readAsDataURL(file); } } function updateFinImgPreviews() { const previewSection = document.getElementById('fin-img-previews'); const grid = document.getElementById('fin-img-grid'); const hasAny = Object.values(finDocNames).some(n => n); if (!hasAny) { previewSection.style.display = 'none'; return; } previewSection.style.display = 'block'; grid.innerHTML = ''; [1, 2, 3].forEach(yr => { if (!finDocNames[yr]) return; const ext = finDocNames[yr].split('.').pop().toLowerCase(); const isImg = ['jpg','jpeg','png','tiff','tif','gif','webp'].includes(ext); const cell = document.createElement('div'); cell.style.cssText = 'border:1px solid var(--g200);border-radius:var(--r);overflow:hidden;background:var(--g50)'; if (isImg && finDocs[yr]) { // Show actual image preview cell.innerHTML = '' + '
Year ' + yr + ' — ' + finDocNames[yr].substring(0,20) + '
'; } else { // Show a styled doc tile const icon = FIN_ICONS[ext] || '📄'; cell.innerHTML = '
' + '
' + icon + '
' + '
' + finDocNames[yr].substring(0,22) + (finDocNames[yr].length>22?'…':'') + '
' + '
' + '
Year ' + yr + (yr===3?' (Latest)':'') + '
'; } grid.appendChild(cell); }); } function clearFinDocs() { [1,2,3].forEach(yr => { finDocs[yr]=null; finDocTypes[yr]=null; finDocNames[yr]=null; const inp = document.getElementById('fin-file-'+yr); if (inp) inp.value=''; const zone = document.getElementById('fin-zone-'+yr); if (zone) { zone.style.borderColor='var(--g200)'; zone.style.background='var(--g50)'; } const icon = document.getElementById('fin-icon-'+yr); if (icon) icon.textContent='📂'; const lbl = document.getElementById('fin-label-'+yr); if (lbl) lbl.innerHTML = 'Tax Return / P&L
Year ' + yr + (yr===3?' / Latest':''); const nm = document.getElementById('fin-doc-name-'+yr); if (nm) nm.style.display='none'; }); document.getElementById('fin-img-previews').style.display='none'; document.getElementById('fin-extract-status').style.display='none'; } async function runFinExtraction() { const hasAny = Object.values(finDocs).some(d => d); if (!hasAny) { toast('Upload at least one financial document first','err'); return; } const statusEl = document.getElementById('fin-extract-status'); statusEl.style.display='block'; statusEl.innerHTML='
AI is reading your financial documents and extracting numbers… this may take 20–40 seconds.
'; const finSysPrompt = `You are an expert business broker and CPA assistant. You will be given one or more financial documents (tax returns, P&Ls, income statements, spreadsheets). Extract the key financial figures for each year and return ONLY a valid JSON object with these exact keys. Use empty string "" if not found. Format all dollar amounts with $ and commas (e.g. "$485,000"). { "f-rev1": "", "f-rev2": "", "f-rev3": "", "f-cogs1": "", "f-cogs2": "", "f-cogs3": "", "f-gp1": "", "f-gp2": "", "f-gp3": "", "f-opex1": "", "f-opex2": "", "f-opex3": "", "f-sde1": "", "f-sde2": "", "f-sde3": "", "f-recast": "", "f-valuation": "", "year1_label": "", "year2_label": "", "year3_label": "" } Rules: - year1_label/year2_label/year3_label should be the actual year (e.g. "2022", "2023", "2024"). - f-rev = Gross Revenue / Total Sales / Total Income - f-cogs = Cost of Goods Sold / Cost of Sales / Direct Costs - f-gp = Gross Profit (Revenue minus COGS) - f-opex = Total Operating Expenses (excluding COGS) - f-sde = Seller's Discretionary Earnings / Net Income + owner compensation + depreciation + amortization + other add-backs - f-recast = Summarize any add-back items found (owner salary, personal expenses, depreciation, one-time items) - For multiple documents assign year numbers based on the document's tax year or date - Return ONLY raw JSON, no markdown, no explanation`; try { // Build message content with all uploaded docs const msgContent = []; const yearLabels = ['first','second','third']; [1,2,3].forEach((yr, i) => { if (!finDocs[yr]) return; const ft = finDocTypes[yr] || 'application/pdf'; const isImg = ft.startsWith('image/'); if (isImg) { msgContent.push({ type:'image', source:{ type:'base64', media_type:ft, data:finDocs[yr] } }); } else { msgContent.push({ type:'document', source:{ type:'base64', media_type:ft || 'application/octet-stream', filename:finDocNames[yr] || ('financial-year-' + yr), data:finDocs[yr] } }); } msgContent.push({ type:'text', text:'The ' + yearLabels[i] + ' document above corresponds to Year ' + yr + '.' }); }); msgContent.push({ type:'text', text:'Extract all financial figures from these documents and return as JSON.' }); const payload = { model:AI_MODEL, max_tokens:1500, system:finSysPrompt, messages:[{ role:'user', content:msgContent }] }; const data = await callProxyAI(payload); const rawText = parseProxyResponse(data); const extracted = extractJsonObject(rawText); const finFields = ['f-rev1','f-rev2','f-rev3','f-cogs1','f-cogs2','f-cogs3','f-gp1','f-gp2','f-gp3','f-opex1','f-opex2','f-opex3','f-sde1','f-sde2','f-sde3','f-recast','f-valuation']; let filled = 0; finFields.forEach(k => { if (extracted[k] && extracted[k].trim()) { const el = document.getElementById(k); if (el) { el.value = extracted[k]; filled++; } } }); // Update year column headers if we got labels const headers = document.querySelectorAll('#panel-s-financials table thead th'); if (headers.length >= 4) { if (extracted.year1_label) headers[1].textContent = extracted.year1_label; if (extracted.year2_label) headers[2].textContent = extracted.year2_label; if (extracted.year3_label) headers[3].textContent = extracted.year3_label + ' (Latest)'; } updateProgress(); saveData(); statusEl.innerHTML='
✅ Extracted ' + filled + ' financial values from ' + Object.values(finDocNames).filter(Boolean).length + ' document(s). Review the table above and adjust any figures as needed.
'; toast('✅ ' + filled + ' financial fields populated!'); } catch(err) { console.error(err); statusEl.innerHTML='
❌ Extraction failed: ' + err.message + '
'; } } // Drag-and-drop support for intake zone document.addEventListener('DOMContentLoaded', () => { const dz = document.getElementById('intake-drop-zone'); if (!dz) return; dz.addEventListener('dragover', e => { e.preventDefault(); dz.style.borderColor='var(--gold)'; dz.style.background='rgba(201,168,76,0.1)'; }); dz.addEventListener('dragleave', () => { dz.style.borderColor='var(--gold-light)'; dz.style.background='rgba(201,168,76,0.04)'; }); dz.addEventListener('drop', e => { e.preventDefault(); const file = e.dataTransfer.files[0]; if (file) { const inp = document.getElementById('intake-file-input'); // Create a DataTransfer to assign file const dt = new DataTransfer(); dt.items.add(file); inp.files = dt.files; handleIntakeUpload(inp); } }); }); // Spin animation for intake loader const spinStyle = document.createElement('style'); spinStyle.textContent = '@keyframes spin{to{transform:rotate(360deg)}}'; document.head.appendChild(spinStyle); // INIT initAiProxySettings(); loadData(); updateProgress(); setInterval(saveData,120000);