Smart Copilot for ERP systems using RAG (Retrieval-Augmented Generation)

Luis Avilan
CODE AUTHOR
Posts: 22
 2 weeks 6 days ago #662 by Luis Avilan
Luis Avilan created the code: Smart Copilot for ERP systems using RAG (Retrieval-Augmented Generation)

This is a complete, ready-to-run example in PowerBuilder that implements a Smart Copilot for ERP systems using RAG (Retrieval-Augmented Generation) techniques. The project allows you to map windows, read PDFs, and perform semantic queries using Artificial Intelligence.

The Smart Copilot operates under two main approaches (these can be used independently or combined):

  • Semantic ERP Mapping: Analyzes the source code of the windows and uses AI to understand their purpose, creating a smart catalog of functionalities.
  • Document Knowledge Base (PDFs): Indexes system manuals and documents to answer complex questions based on the actual content.

The visual core: w_copiloto_inteligente

The main window (w_copiloto_inteligente) centralizes all user interaction with the AI. Its key features include:

  • Target Selection (.pbt): Allows the user to indicate the path to the ERP project's PBT file for automated analysis.
  • Smart ERP Mapping: Through the indexing button, it traverses all the project's PBLs, extracting controls and visible text from each object to generate a unified JSON catalog.
  • PDF Upload: Allows selecting PDF files (manuals, policies, guides) to be processed and indexed in the copilot's document database using Python and PowerShell.
  • Copilot Querying: Provides an interface where the user can ask questions in natural language. The system prioritizes searching the indexed PDFs, and if it cannot find the answer, it falls back to the semantic ERP catalog to suggest the appropriate screen.
  • Integrated Visualization: Uses a native WebBrowser control (Chromium-based) to display the results, the mapping progress, and the AI responses in HTML format with a modern, aesthetic, and user-friendly design.

The semantic engine: n_cst_diccionario_ai

The non-visual object n_cst_diccionario_ai is the brain behind the PowerBuilder code analysis. Its technical responsibilities are:

  • Source Code Analysis (uf_indexar_y_guardar): Reads the PBT, dynamically locates the PBLs, and extracts the source code of each window using LibraryExport, optimizing the read with StreamMode.
  • Attribute Extraction (of_extraer_atributos_visibles): Parses the extracted code to identify titles, button texts, static labels, and relevant control names, omitting non-visible internal code.
  • AI Profiling (uf_analisis_semantico_ia): Connects to an LLM (such as Ollama or Cloud APIs) sending the window's source code so the AI can deduce its real purpose, generate a possible menu path, and propose colloquial ("human") expressions that a user would use to search for that screen.
  • Local Search Engine (uf_filtrar_catalogo and of_score_busqueda): Implements a powerful scoring algorithm that normalizes the user's question (removing accents, special characters, and normalizing spaces) and compares it against the JSON catalog. It assigns scores for exact, partial matches, or minor typos (tolerant search), returning the top 5 most relevant windows to the user blazingly fast.

PDF Handling with Python

The system features a specialized engine for interacting with PDF documents, orchestrated from PowerBuilder but executed via independent scripts. The workflow is as follows:

  • Mass Selection and Upload: Using asynchronous PowerShell commands (select_pdfs.ps1), the system allows the user to search for and select multiple documents simultaneously.
  • Indexing (pdf_index): Each document is processed by a Python executable or script that extracts the text from the PDF and generates a vector index in the results folder (outputs\pdf_copiloto\biblioteca).
  • Smart Querying (pdf_query): When asking a question, if there are PDFs in the library, PowerBuilder invokes Python, passing the query and connection details to the local LLM (Ollama). Python performs a semantic search, formulates the answer, and saves it to an HTML file (respuesta_pdf.html).
  • Visualization: The HTML result is instantly loaded into the WebBrowser control, applying UI adjustments through additional utilities to ensure comfortable reading.

A look at select_pdfs.ps1

This script uses native Windows Forms libraries from PowerShell to invoke the standard file selection dialog. Its goal is to neatly solve multiple file selection. Here is the code:


param([string]$Out, [string]$InitialDir = "")
$ErrorActionPreference = "Stop"
Add-Type -AssemblyName System.Windows.Forms

$dlg = New-Object System.Windows.Forms.OpenFileDialog
$dlg.Title = "Seleccionar manuales PDF"
$dlg.Filter = "Archivos PDF (*.pdf)|*.pdf|Todos (*.*)|*.*"
$dlg.Multiselect = $true # Habilita selección múltiple

if ($InitialDir -ne "" -and (Test-Path -LiteralPath $InitialDir)) {
$dlg.InitialDirectory = $InitialDir
}

$result = $dlg.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
# Guarda un listado con las rutas en un archivo de texto temporal
[System.IO.File]::WriteAllLines($Out, $dlg.FileNames, [System.Text.Encoding]::Default)
exit 0
}
exit 1

Instead of returning the information through the console output (which sometimes presents buffer issues or weird character encoding problems), the script writes the list of paths directly to a temporary text file (passed as the $Out parameter) that PowerBuilder then processes line by line seamlessly.

The documentary brain: pdf_query.py

This Python script is in charge of processing the semantic search and communicating with the AI model. Unlike complex solutions that require dedicated vector databases, this implementation uses a lightweight and straightforward approach based on fragment scoring over local JSON files. Here is an excerpt of its core logic:


def select_context(indexes, question, max_chars=6000, top_chunks=8):
question_terms = terms(question)
scored = []

# 1. Puntuación de fragmentos (chunks) leídos de los PDFs
for index_data, index_dir in indexes:
for chunk in index_data.get("chunks", []):
score = score_chunk(chunk, question_terms)
if score > 0:
scored.append((score, chunk, index_data, index_dir))

scored.sort(key=lambda item: item[0], reverse=True)

# 2. Construcción del contexto que se enviará a la IA
parts, refs, total = [], [], 0
for _, chunk, index_data, index_dir in scored[:top_chunks]:
text = chunk.get("text", "").strip()
page = int(chunk.get("page", 0))
block = f"[Documento: {title} | Pagina {page}]\n{text}"
parts.append(block)
total += len(block)
if total > max_chars: break

return "\n\n---\n\n".join(parts), refs

def call_ollama(url, model, question, context):
prompt = f"Eres un asistente experto... \nContexto:\n{context}\nPregunta:\n{question}"
payload = {
"model": model,
"stream": False,
"messages": [{"role": "user", "content": prompt}],
"options": {"temperature": 0.1} # Baja temperatura para evitar alucinaciones
}
# Llamada nativa vía HTTP, sin depender de librerías externas pesadas
request = urllib.request.Request(url, data=json.dumps(payload).encode("utf-8"))
with urllib.request.urlopen(request) as response:
return json.loads(response.read())["message"]["content"]

Once the LLM's response is obtained, the script generates a complete HTML file (respuesta_pdf.html) that includes the formatted answer and thumbnails of the referenced manual pages (even with a zoom viewer integrated in pure JavaScript). PowerBuilder simply loads this generated HTML into its WebBrowser control, achieving a professional and dynamic result with very little code.

Architecture and Performance

The system delegates indexing and complex PDF queries to Python, interacting with PowerBuilder frictionlessly. For the internal semantic engine, HTTP queries to the LLM are made using the HttpClient object, and JSON responses are parsed with JSONParser. Thanks to this segmentation, a perfect balance is achieved between Python's power for AI processing and PowerBuilder's robustness for business logic and UI.

How to test it

Before running the demo, make sure you meet the following prerequisites so the PDF reading engine works properly (since the Python source code is provided for lightweight distribution):


# 1. Install Python (3.9 or higher) and make sure to add it to the Windows PATH.
# 2. Open a terminal and run the following command to install the PDF reading engine:
pip install pymupdf
# 3. Install Ollama and make sure it is running in the background.

Once installed, open the workspace in the PowerBuilder 2025 IDE, compile, and run. Select a .pbt file from any existing project and click "Smart ERP Mapping". Once the catalog is finished, try asking everyday questions like "Where can I register a new sales invoice?". You can also upload a system PDF and make specific queries about its policies.

This message has an attachment file.
Please log in or register to see it.

Please Log in or Create an account to join the conversation.