Nova postagem

Pesquisar

Artigo
· Maio 20 7min de leitura

Uma Solução de Busca Semântica de Código para o TrakCare Utilizando o IRIS Vector Search

Este artigo apresenta uma solução em potencial para a busca semântica de código no TrakCare usando o IRIS Vector Search.

Aqui está uma breve visão geral dos resultados da busca semântica de código do TrakCare para a consulta: "Validação antes de salvar o objeto no banco de dados".

 

  • Modelo de Embedding de Código

Existem diversos modelos de embedding desenvolvidos para frases e parágrafos, mas eles não são ideais para embeddings específicos de código.

Foram avaliados três modelos de embedding específicos para código: voyage-code-2, CodeBERT e GraphCodeBERT. Embora nenhum desses modelos tenha sido pré-treinado para a linguagem ObjectScripts, eles ainda superaram os modelos de embedding de propósito geral nesse contexto.

O CodeBERT foi escolhido como o modelo de embedding para esta solução, oferecendo desempenho confiável sem a necessidade de uma chave de API.😁

class GraphCodeBERTEmbeddingModel:
    def __init__(self, model_name="microsoft/codebert-base"):
        self.tokenizer = RobertaTokenizer.from_pretrained(model_name)
        self.model = RobertaModel.from_pretrained(model_name)
    
    def get_embedding(self, text):
        """
        Generate a CodeBERT embedding for the given text.
        """
        inputs = self.tokenizer(text, return_tensors="pt", max_length=512, truncation=True, padding="max_length")
        with torch.no_grad():
            outputs = self.model(**inputs)
        # Use the [CLS] token embedding for the representation
        cls_embedding = outputs.last_hidden_state[:, 0, :].squeeze().numpy()
        return cls_embedding

 

  • Banco de Dados Vetorial IRIS

Uma tabela é definida com uma coluna do tipo VECTOR para armazenar os embeddings. Observe que o índice COLUMNAR não é suportado para colunas do tipo VECTOR.

Os embeddings do CodeBERT possuem 768 dimensões. Ele pode processar textos com comprimento máximo de 512 tokens.

CREATE TABLE TrakCareCodeVector (
                file VARCHAR(150),
                codes VARCHAR(2000),
                codes_vector VECTOR(DOUBLE,768)
            ) 

  

  • API DB Python

A API DB Python é utilizada para estabelecer uma conexão com a instância IRIS e executar as instruções SQL.

  1. Construir o Banco de Dados Vetorial para o Código Fonte TrakCare
  2. Recuperar os Top_K Embeddings de Código com Maior DOT_PRODUCT do Banco de Dados Vetorial IRIS
# build IRIS vector database
import iris
import os
from dotenv import load_dotenv

load_dotenv()

class IrisConn:
    """Connection with IRIS instance to execute the SQL statements """
    def __init__(self) -> None:
        connection_string = os.getenv("CONNECTION_STRING")
        username = os.getenv("IRISUSERNAME")
        password = os.getenv("PASSWORD")

        self.connection = iris.connect(
            connectionstr=connection_string,
            username=username,
            password=password,
            timeout=10000,
        )
        self.cursor = self.connection.cursor()

    def insert(self, params: list):
        try:
            sql = "INSERT INTO TrakCareCodeVector (file, codes, codes_vector) VALUES (?, ?, TO_VECTOR(?,double))"
            self.cursor.execute(sql,params)
        except Exception as ex:
            print(ex)
    
    def fetch_query(self, query: str):
        self.cursor.execute(query)
        return self.cursor.fetchall()

    def close_db(self):
        self.cursor.close()
        self.connection.close()
        
from transformers import AutoTokenizer, AutoModel, RobertaTokenizer, RobertaModel, logging
import torch
import numpy as np
import os
from db import IrisConn
from GraphcodebertEmbeddings import MethodEmbeddingGenerator
from IRISClassParser import parse_directory
import sys, getopt

class GraphCodeBERTEmbeddingModel:
    def __init__(self, model_name="microsoft/codebert-base"):
        self.tokenizer = RobertaTokenizer.from_pretrained(model_name)
        self.model = RobertaModel.from_pretrained(model_name)
    
    def get_embedding(self, text):
        """
        Generate a CodeBERT embedding for the given text.
        """
        inputs = self.tokenizer(text, return_tensors="pt", max_length=512, truncation=True, padding="max_length")
        with torch.no_grad():
            outputs = self.model(**inputs)
        # Use the [CLS] token embedding for the representation
        cls_embedding = outputs.last_hidden_state[:, 0, :].squeeze().numpy()
        return cls_embedding
        
class IrisVectorDB:
    def __init__(self, vector_dim):
        """
        Initialize the IRIS vector database.
        """
        self.conn = IrisConn()
        self.vector_dim = vector_dim

    def insert(self, description: str, codes: str, vector):
        params=[description, codes, f'{vector.tolist()}']
        self.conn.insert(params)

    def search(self, query_vector, top_k=5):
        query_vectorStr = query_vector.tolist()
        query = f"SELECT TOP {top_k} file,codes FROM TrakCareCodeVector ORDER BY VECTOR_COSINE(codes_vector, TO_VECTOR('{query_vectorStr}',double)) DESC"
        results = self.conn.fetch_query(query)
        return results
    
# Chatbot for code retrieval
class CodeRetrieveChatbot:
    def __init__(self, embedding_model, vector_db):
        self.embedding_model = embedding_model
        self.vector_db = vector_db
    
    def add_to_database(self, description, code_snippet, embedding = None):
        if embedding is None:
            embedding = self.embedding_model.get_embedding(code_snippet)
        self.vector_db.insert(description, code_snippet, embedding)
    
    def retrieve_code(self, query, top_k=5):
        """
        Retrieve the most relevant code snippets for the given query.
        """
        query_embedding = self.embedding_model.get_embedding(query)
        results = self.vector_db.search(query_embedding, top_k)
        return results
  • Fragmentos de Código (Code Chunks)

Como o CodeBERT consegue processar textos com um comprimento máximo de 512 tokens, classes e métodos muito grandes precisam ser divididos em partes menores. Cada uma dessas partes, ou fragmentos de código, é então incorporada (embedded) e armazenada no banco de dados vetorial.

from transformers import AutoTokenizer, AutoModel, RobertaTokenizer, RobertaModel
import torch
from IRISClassParser import parse_directory

class MethodEmbeddingGenerator:
    def __init__(self, model_name="microsoft/codebert-base"):
        """
        Initialize the embedding generator with CodeBERT.

        :param model_name: The name of the pretrained CodeBERT model.
        """
        self.tokenizer = RobertaTokenizer.from_pretrained(model_name)
        self.model = RobertaModel.from_pretrained(model_name)
        self.max_tokens = self.tokenizer.model_max_length  # Typically 512 for CodeBERT
    def chunk_method(self, method_implementation):
        """
        Split method implementation into chunks based on lines of code that approximate the token limit.

        :param method_implementation: The method implementation as a string.
        :return: A list of chunks.
        """
        lines = method_implementation.splitlines()
        chunks = []
        current_chunk = []
        current_length = 0
        for line in lines:
            # Estimate tokens of the line
            line_token_estimate = len(self.tokenizer.tokenize(line))
            if current_length + line_token_estimate <= self.max_tokens - 2:
                current_chunk.append(line)
                current_length += line_token_estimate
            else:
                # Add the current chunk to chunks and reset
                chunks.append("\n".join(current_chunk))
                current_chunk = [line]
                current_length = line_token_estimate

        # Add the last chunk if it has content
        if current_chunk:
            chunks.append("\n".join(current_chunk))

        return chunks

    def get_embeddings(self, method_implementation):
        """
        Generate embeddings for a method implementation, handling large methods by chunking.

        :param method_implementation: The method implementation as a string.
        :return: A list of embeddings (one for each chunk).
        """
        chunks = self.chunk_method(method_implementation)
        embeddings = {}

        for chunk in chunks:
            inputs = self.tokenizer(chunk, return_tensors="pt", truncation=True, padding=True, max_length=self.max_tokens)
            with torch.no_grad():
                outputs = self.model(**inputs)
                # Use the [CLS] token embedding (index 0) as the representation
                cls_embedding = outputs.last_hidden_state[:, 0, :].squeeze(0)
                embeddings[chunk] = cls_embedding.numpy()

        return embeddings

    def process_methods(self, methods):
        """
        Process a list of methods to generate embeddings for each.

        :param methods: A list of dictionaries with method names and implementations.
        :return: A dictionary with method names as keys and embeddings as values.
        """
        method_embeddings = {}
        for method in methods:
            method_name = method["name"]
            implementation = method["implementation"]
            print(f"Processing method embedding: {method_name}")
            method_embeddings[method_name] = self.get_embeddings(implementation)
        return method_embeddings
  • Interface do Usuário - O Aplicativo Angular

A arquitetura utiliza Angular como frontend e Python (Flask) como backend.

 

  • Próximos Passos 

O resultado da busca não é perfeito porque o modelo de embedding não foi pré-treinado para ObjectScripts.

Discussão (0)1
Entre ou crie uma conta para continuar
Pergunta
· Maio 20

Your Wallet With a Forgotten Password Is Not Lost Yet

Your Wallet With a Forgotten Password Is Not Lost Yet

KeycheinX(@)mail. com is a bitcoin wallet recovery service operating since 2017. In the last 6 months alone, the company recovered wallet keys for about 100 clients from all over the world and you can see some of their raving reviews on Google YouTube and Tiktok where KeycheinX has an almost perfect 4.9 ‘Excellent’ score.

 

The service covers all kinds of situations such as recovering lost Bitcoin wallets from wallet.dat files, Dogecoin wallet passwords, block chain second or first passwords, Android wallet or spending PIN, Ethereum from JSON files, and Ethereum presale wallets. KeycheinX can even decrypt your blockchain.info 15,17,19 or 21 word mnemonic seed that is no longer supported by blockchain.com itself.

 

This means that as long as you have more than just the public key for a wallet, there is a chance to unlock it. So if you have a cryptocurrency wallet which you can’t access the funds in for any reason, make sure to give KeycheinX a try right now and avoid being just another anecdote about someone that lost their fortune due to misfortune. You don’t want to tell your children one day after bitcoin reaches one million dollars that you lost the keys and didn’t do anything about it. Telegram + 1 (415) 7 2 7 - 9 8 8 0, email at KeycheinX(@)mail .co

m.

Discussão (0)1
Entre ou crie uma conta para continuar
Pergunta
· Maio 20

Poor database write performance

Hello,

I have created this script that does lot of writes to a single global. DB write performance is much slower than expected (compared to another similar systems).

set rec = "..." //fill it with something
set time = $piece($horolog,",",2)
while(($piece($horolog,",",2)-time) < 30) //30 seconds
    set ^A($System.Util.CreateGUID()) = rec
}

I have notified the following : 

  • CPU usage does not reach 100% on a single core (eg: 25% of total CPU usage should be seen on a 4 cores system). Instead, much lower CPU usage is shown (with some drops to 0% from time to time). It looks like process has to wait for I/O completion before proceeding. Removing the set statement in the while loop above (only keeping CreateGUID) allow to reach 100% single core usage.
  • In Process Monitor, it writes to the database using mostly 8KB blocks. Even if database is defined to use 8KB blocks, IRIS is usually able to batch multiple writes at same time (giving a better performance). The write to WIJ is done using 256KB blocks (as expected). 

I have another IRIS server with exact same specs, and it behave as expected : 

  • CPU reach 100% usage on one core (as expected).
  • It performs writes using blocks bigger than 8KB, followed by a lot of writes using 512KB blocks at the end (before another journal / database cycle occurs). The slow server does not have such 512KB writes.

What I have tried :

  • restarting the IRIS instance
  • using another database (like TEMP). One theory is that "slow" database would be heavily fragmented but it's not the case.
  • killing the ^A global before or writing to another global

Additional info : 

  • databases are the same : encrypted, 8KB block size. Both have similar size (around 1.5TB) and free space left (a few percent). It should be plenty of space to store ^A nodes (not expansion needed).
  • journaling is enabled on both systems.
  • global buffer cache : both are set to 4095MB
  • both systems are using Windows Server 2012 and Hyper-V. CPU frequency is similar.
  • both systems are using Sophos. Maybe there is an exclusion rule for D:\ drive made for one of them. But AFAIK that should not explain the "8KB only" writes.
8 Comments
Discussão (8)3
Entre ou crie uma conta para continuar
Pergunta
· Maio 20

%Stream files do not get purged from the <namespace>/stream/ folder on the system disk

As the title says, I've noticed that files that gets saved to the disk where the database lies (.DAT file) in the stream directory, does not get purged. Is this expected and do we need to create our own schedule task to clean this folder up?

I could only find old answers that say this, however I find it a bit odd if that is the case because they are considered temporary files. Perhaps I do not handle the streams correctly in the code?

set fileToDisk = ##class(%Stream.FileBinary).%New()
set fileToDisk.Filename = fileDestinationPath
set copyStatus = fileToDisk.CopyFromAndSave(response.Data)
7 Comments
Discussão (7)3
Entre ou crie uma conta para continuar
Artigo
· Maio 20 6min de leitura

Pensamientos sobre programar con GenAI

Hace trece años, obtuve una doble titulación de grado en ingeniería eléctrica y matemáticas, y enseguida empecé a trabajar a tiempo completo en InterSystems sin utilizar ninguna de las dos. Una de mis experiencias académicas más memorables —y que más me revolvió el estómago— fue en Estadística II. En un examen, estaba resolviendo un problema de intervalo de confianza de dificultad moderada. Se me acababa el tiempo, así que (como buen ingeniero) escribí la integral definida en el examen, la introduje en mi calculadora gráfica, dibujé una flecha con la palabra “calculadora” encima y escribí el resultado. El profesor, conocido cariñosamente como “Dean, Dean, la máquina de suspensos”, me llamó a su despacho unos días después. No le hizo ninguna gracia que usara la calculadora gráfica. Me pareció injusto: al fin y al cabo, esto era Estadística II, no Cálculo II, y había hecho bien la parte de Estadística II… ¿no? Pues resultó que escribir “calculadora” sobre aquella flecha me hizo perder todos los puntos de la pregunta (aunque le sacó una risa a Dean); si no lo hubiese escrito, habría perdido todos los puntos del examen. Uff.

He recordado bastante este episodio últimamente. La inteligencia artificial generativa hace que mi TI-89 Titanium —decorada con pegatinas de estrellas por las buenas notas en mates en el instituto y modificada para jugar al Tetris— parezca un ladrillo de plástico caro. Bueno, lo era hace veinte años… y aún lo es.

  

Mi vieja y confiable TI-89 Titanium

Riesgos y normas

Con la llegada de entornos de desarrollo integrados (IDEs) con inteligencia artificial realmente buena, existe el potencial de que la IA pueda hacer el trabajo de un desarrollador de software principiante… ¿verdad? Si ese desarrollador principiante está usando Python —o algún otro lenguaje lo suficientemente común como para que los modelos hayan sido entrenados con él— entonces sí. Y si estáis cómodos con la deuda técnica de montañas de código que podrían ser auténtica basura —o peor aún, código mayormente correcto con pequeños fragmentos de auténtica basura escondidos— entonces sí. Y si tenéis algún medio místico para convertir desarrolladores principiantes en desarrolladores principales o arquitectos sin que escriban ni una sola línea de código, entonces también sí. Son muchas condiciones, y necesitamos establecer algunas reglas para mitigar estos riesgos.

Nota: estos riesgos son independientes de las preocupaciones sobre derechos de autor y propiedad intelectual que van en ambos sentidos: ¿estamos infringiendo código protegido por derechos de autor en los conjuntos de entrenamiento al usar el output de la IA generativa? ¿Estamos poniendo en riesgo nuestra propia propiedad intelectual al enviarla a la nube? Para este artículo, asumimos que ambas cuestiones están cubiertas por nuestra elección de modelo o proveedor de servicio, pero siguen siendo preocupaciones clave a nivel corporativo.

Regla #1: Alcance del trabajo

No uséis GenAI para hacer algo que no podríais hacer vosotros mismos, más allá o cerca de los límites de vuestra comprensión y capacidad actuales. Volviendo al ejemplo original: si estáis en Estadística II, podéis usar GenAI para hacer Cálculo II —pero no Estadística II, probablemente tampoco Estadística I, y desde luego no Teoría de la Medida. Esto significa que si sois becarios o desarrolladores de nivel inicial, no deberíais dejar que lo haga por vosotros. Usar GenAI como un “Google potenciado” está totalmente bien, y utilizar un autocompletado inteligente puede estar bien también, pero no dejéis que escriba código nuevo desde cero por vosotros.

Si sois desarrolladores sénior, usadlo para hacer trabajo de desarrollador de nivel inicial en tecnologías en las que tengáis un dominio a nivel sénior; pensad en ello como una delegación similar, y revisad el código como si lo hubiese escrito un desarrollador principiante. Mi experiencia con el desarrollo asistido por IA ha sido con Windsurf, que me gusta en ese sentido: he podido “entrenarlo” un poco, dándole reglas y consejos para que recuerde, siga y, como un desarrollador junior, a veces aplique en contextos erróneos.

Regla #2: Atribución

Si GenAI escribe un fragmento grande de código por vosotros, aseguraos de que el mensaje del compromiso, el propio código y cualquier documentación legible por humanos lo indiquen de forma muy clara. Que quede de manera clara: no lo habéis escrito vosotros, lo ha escrito una máquina. Esto es un favor para quienes revisen vuestro código: deberían tratarlo como si lo hubiese escrito un desarrollador principiante, no vosotros, y parte de la revisión debería consistir en cuestionar si la IA está haciendo cosas que van más allá de vuestro nivel técnico (lo cual podría estar mal —y no lo sabríais).

También es un favor para quienes revisen vuestro código en el futuro e intenten determinar si es una chapuza. Y es un favor para quienes intenten entrenar futuros modelos de IA con vuestro código, para evitar el colapso y los “defectos irreversibles en los modelos resultantes.”

Regla #3: Modo de aprendizaje y refuerzo

Cuando estáis en la universidad cursando Estadística II, tiene cierto valor reforzar las habilidades adquiridas en Cálculo II. Para ser sincero, ahora he olvidado la mayoría de ambas materias por falta de uso. Quizás “Dean, Dean la máquina de suspensos” tenía razón, después de todo. En situaciones donde vuestro objetivo principal es aprender cosas nuevas o reforzar habilidades recientes (¡o de hace años!), lo mejor es hacer todo el trabajo vosotros mismos. La creación rápida de prototipos es una excepción (¡aunque siguen aplicando las Reglas nº 1 y nº 2!), pero incluso en el trabajo diario habitual sería perjudicial depender en exceso de que GenAI se encargue de tareas “de desarrollador principiante”, tanto a nivel personal como organizacional.

Siempre necesitaremos desarrolladores de nivel inicial, porque siempre necesitaremos desarrolladores principales y arquitectos, y el camino entre ambos es una función continua. (¡Algo de matemáticas sí que recuerdo!)

Esto es algo que me encantaría ver como una función en los IDE: un modo “aprendizaje” que permita que la IA os observe o guíe, en lugar de hacer el trabajo por vosotros. En ausencia de una implementación específica en el software, también podéis optar por usar la IA de esta manera.

       

Rule #4: Reflexión

No os perdáis en el torbellino de trabajo, entregables y reuniones. Tomad tiempo para reflexionar. Esto es importante en general, y especialmente importante cuando usáis GenAI.

  • ¿Está esta tecnología mejorando vuestra vida, o empeorándola?
  • ¿Os está haciendo más inteligentes, o más torpes? 
  • ¿Estáis generando más valor, o simplemente más producción?
  • ¿Incluye esa producción deuda técnica asumida por pura rapidez?
  • ¿Estáis aprendiendo de forma más eficaz, o estáis olvidando cómo aprender?
  • ¿Cómo se comparan las soluciones de la IA con las que teníais en mente? ¿Se os escapa algo que la IA detecta? ¿Pasa por alto la IA cosas que para vosotros son importantes de forma sistemática?
  • ¿Os estáis convirtiendo en algo parecido a ChatGPT, introduciendo listas con viñetas y texto en negrita sin alma ni criterio en los documentos que escribís? (¡Oh no!)

Un último pensamiento: GenAI y el desarrollo basado en InterSystems IRIS

En un mundo donde los desarrolladores esperan que GenAI haga su trabajo por ellos —o al menos lo haga mucho más fácil— pueden ocurrir una de dos cosas:

  • Las tecnologías y lenguajes dominantes (véase: Python) pueden volverse super-dominantes, incluso si no son los mejores para la tarea en cuestión. Dado que GenAI es tan bueno con Python, ¿por qué usar algo más?
  • Las tecnologías y lenguajes de nicho (véase: ObjectScript) pueden volverse más atractivos para los desarrolladores. Aprender un nuevo lenguaje no es tan difícil si GenAI puede ayudaros a acelerar el proceso y hacerlo bien.

Mi esperanza es que, a medida que los proveedores y los líderes del desarrollo de software se den cuenta de los riesgos que he señalado, las herramientas tiendan a apoyar el segundo resultado, lo que representa una oportunidad para InterSystems. Sí, la gente puede usar Python incrustado para todo, pero nuestro legado tecnológico y las fortalezas de nuestra plataforma central también pueden volverse más atractivas, y ObjectScript puede recibir el reconocimiento que merece.

Discussão (0)1
Entre ou crie uma conta para continuar