0 Seguidores · 40 Postagens

Interface de Programação de Aplicações (API) é um conjunto de definições de sub-rotina, protocolos e ferramentas para a construção de aplicações de software. Em termos gerais, é um conjunto de métodos de comunicação claramente definidos entre vários componentes de software.

Saber mais.

Artigo Heloisa Paiva · Out. 23, 2025 1m read

Olá a todos,

Esta é uma dica rápida sobre como usar URLs em serviços REST API sem distinção entre maiúsculas e minúsculas.

Se você tem uma classe que estende de %CSP.REST e Ens.BusinessService para criar um serviço REST API, e você definiu seu WebApplication em minúsculas:

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
    <Route Url="/user" Method="POST" Call="User"/>
    <Route Url="/login" Method="POST" Call="Login"/>
</Routes>
}

Ele só aceitará URLs em minúsculas, por exemplo: http://myserver/myproduction/user

0
0 19
Artigo Heloisa Paiva · Out. 8, 2025 3m read

Parece-me que, por alguma razão, isto não chegou à documentação oficial e aparenta ser pouco conhecido, embora já tenha sido implementado no IRIS 2020.1.

Graças a @Dan Pasco, obtive uma pista sobre as classes envolvidas. Usei a sequência recomendada de como utilizá-lo. Tudo foi retirado diretamente da Referência de Classe e eu apenas compilei para criar uma primeira visão geral.

1
0 22
Artigo Andre Larsen Barbosa · Jul. 30, 2025 3m read

É... Chegou a hora dos testes. Sabemos que em muitas vezes, ela até já passou. Bom, e agora? Consigo reforçar a qualidade do meu desenvolvimento?

A resposta é: SIM. Sim, você consegue. A ferramenta Toolqa busca exatamente isto. É um facilitador. Qual é o seu objetivo? Garantir que as APIS atendam aos requisitos de negócio pré-estabelecidos, e também mantenha-se rígida com as <sarcasm> futuras tentativas frustradas </sarcasm> de acabar com a sua aplicação, site, App ou qualquer outro que utilize-se de sua API.

Agora deve estar se perguntando, mas como é que isto acontece? Onde está a mágica?

0
0 24
Pergunta Guilherme Silva · Jun. 10, 2025

Estamos desenvolvendo uma aplicação em React e essa aplicação terá seus próprios usuários/senhas. Estamos fazendo alguns testes de autenticação, e estamos procurando conhecer melhor JWT do Iris. Entretanto, segundo a documentação, precisamos passar um body com um usuário do Iris para então receber o token JWT. A nossa preocupação é que essa primeira chamada não parece ser segura, já que precisamos enviar esse body aberto para então conseguir um token. Alguma sugestão de como enviar esse body de forma oculta? utilizamos como draft um post da comunidade:
 

3
0 67
Artigo Julio Esquerdo · Jun. 7, 2025 18m read

Olá,

Neste artigo vamos ver o uso do python como linguagem de programação no InterSystems Iris. Para tal vamos usar como referência a versão Community 2025.1 que está disponível para ser baixada em https://download.intersystems.com mediante o login no ambiente. Para maiores informações sobre o download e instalação do Iris veja o link da comunidade https://community.intersystems.com/post/how-download-and-install-intersystems-iris

0
0 41
Artigo Larissa Prussak · Jun. 5, 2025 5m read

Por muito tempo, eu quis aprender o framework Django, mas sempre surgia algum projeto mais urgente que acabava tomando prioridade. Como muitos desenvolvedores, eu uso Python para projetos de machine learning, mas quando comecei a aprender programação para web, o PHP ainda dominava. Então, quando precisei escolher um framework mais robusto para criar aplicações web e publicar meu trabalho de machine learning, acabei voltando para o PHP. Durante um tempo, utilizei o framework Laravel para construir meus sites, e foi com ele que conheci o padrão Model-View-Controller (MVC) moderno de programação

0
0 32
Artigo Larissa Prussak · Jun. 5, 2025 3m read

O IRIS oferece suporte nativo para transformações CCDA e FHIR, mas o acesso e a visualização desses recursos exigem tempo considerável de configuração e conhecimento do produto. O aplicativo IRIS Interop DevTools foi desenvolvido para preencher essa lacuna, permitindo que implementadores comecem a utilizar e visualizar imediatamente as capacidades de transformação embutidas no produto.

Além do ambiente de transformação IRIS XML, XPath e CCDA, o pacote Interop DevTools agora inclui:

0
0 33
Artigo Heloisa Paiva · Maio 20, 2025 7m read

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.

0
0 30
Artigo Heloisa Paiva · Abr. 18, 2025 18m read

Image generated by OpenAI DALL·E

Sou um grande fã de ficção científica, mas embora eu esteja totalmente a bordo da nave Star Wars (desculpas aos meus colegas Trekkies!), sempre apreciei os episódios clássicos de Star Trek da minha infância. A tripulação diversificada da USS Enterprise, cada um dominando suas funções únicas, é uma metáfora perfeita para entender os agentes de IA e seu poder em projetos como o Facilis. Então, vamos embarcar em uma missão intergaláctica, utilizando a IA como a tripulação da nossa nave e  audaciosamente ir audaciosamente ir homem jamais esteve!  Esse conceito de trabalho em equipe é uma analogia maravilhosa para ilustrar como os agentes de IA funcionam e como os usamos em nosso projeto DC-Facilis. Então, vamos mergulhar e assumir o papel de um capitão de nave estelar, liderando uma tripulação de IA em territórios inexplorados!

Bem-vindo ao CrewAI!

Para gerenciar nossa tripulação de IA, usamos uma estrutura fantástica chamada CrewAI.É enxuta, extremamente rápida e opera como uma plataforma Python multiagente. Uma das razões pelas quais a amamos, além do fato de ter sido criada por outro brasileiro, é sua incrível flexibilidade e design baseado em funções.

from crewai import Agent, Task, Crew

the taken quote

Conheça os Planejadores

No Facilis, nossos agentes de IA são divididos em dois grupos. Vamos começar com o primeiro, que gosto de chamar de "Os Planejadores".

O Agente de Extração

O papel principal do Facilis é receber uma descrição em linguagem natural de um serviço REST e criar automaticamente toda a interoperabilidade necessária. Portanto, nosso primeiro membro da tripulação é o Agente de Extração. Este agente tem a tarefa de "extrair" as especificações da API a partir da descrição fornecida pelo usuário.

Aqui está o que o Agente de Extração procura:

  • Host (obrigatório)
  • Endpoint (obrigatório)
  • Params (opcional)
  • Port (se disponível)
  • modelo JSON (para POST/PUT/PATCH/DELETE)
  • Autenticação (se aplicável)
    def create_extraction_agent(self) -> Agent:
        return Agent(
            role='Extrator de Especificações de API',
            goal='Extrair especificações de API de descrições em linguagem natural',
            backstory=dedent("""
                        Você é especializado em interpretar descrições em linguagem natural
                        e extrair especificações de API estruturadas.
            """),
            allow_delegation=True,
            llm=self.llm
        )

    def extract_api_specs(self, descriptions: List[str]) -> Task:
        return Task(
            description=dedent(f"""
               Extraia as especificações de API das seguintes descrições:
                {json.dumps(descriptions, indent=2)}
                
               Para cada descrição, extraia:
                - Host (obrigatório)
                - Endpoint (obrigatório)
                - Params (opcional)
                - Port (se disponível)
                - modelo JSON (para POST/PUT/PATCH/DELETE)
                - Autenticação (se aplicável)
                
                Marque quaisquer campos obrigatórios ausentes como 'missing'.
                Retorne os resultados em formato JSON como um array de especificações.
            """),
            expected_output="""Um array JSON contendo as especificações de API extraídas com todos os campos obrigatórios e opcionais""",
            agent=self.extraction_agent
        )

O Agente de Validação

Próximo na fila, o Agente de Validação! Sua missão é garantir que as especificações de API coletadas pelo Agente de Extração estejam corretas e consistentes. Ele verifica:

  1. Formato de host válido
  2. Endpoint começando com '/'
  3. Métodos HTTP válidos (GET, POST, PUT, DELETE, PATCH)
  4. Número de porta válido (se fornecido)
  5. Presença de modelo JSON para métodos aplicáveis.

    def create_validation_agent(self) -> Agent:
        return Agent(
            role='API Validator',
            goal='Validar especificações de API quanto à correção e consistência.',
            backstory=dedent("""
                 Você é um especialista em validação de API, garantindo que todas as especificações
                 atendam aos padrões e formatos necessários.
            """),
            allow_delegation=False,
            llm=self.llm
        )

 def validate_api_spec(self, extracted_data: Dict) -> Task:
        return Task(
            description=dedent(f"""
                Valide a seguinte especificação de API:
                {json.dumps(extracted_data, indent=2)}
                
                Verifique:
                1. Formato de host válido
                2. Endpoint começando com '/'
                3. Métodos HTTP válidos  (GET, POST, PUT, DELETE, PATCH)
                4. Número de porta válido (se fornecido)
                5. Presença de modelo JSON para métodos aplicáveis.
                
               Retorne os resultados da validação em formato JSON.
            """),
            expected_output="""Um objeto JSON contendo os resultados da validação com quaisquer erros ou confirmação de validade""",
            agent=self.validation_agent
        )

O Agente de Interação

Avançando, conhecemos o Agente de Interação, nosso Especialista em Interação com o Usuário. Seu papel é obter quaisquer campos de especificação de API ausentes que foram marcados pelo Agente de Extração e validá-los com base nas descobertas do Agente de Validação. Eles interagem diretamente com os usuários para preencher quaisquer lacunas.

O Agente de Produção

Precisamos de duas informações cruciais para criar a interoperabilidade necessária: namespace e nome da produção. O Agente de Produção interage com os usuários para coletar essas informações, de forma muito semelhante ao Agente de Interação.

O Agente de Transformação de Documentação

Assim que as especificações estiverem prontas, é hora de convertê-las em documentação OpenAPI. O Agente de Transformação de Documentação, um especialista em OpenAPI, cuida disso.

    def create_transformation_agent(self) -> Agent:
        return Agent(
            role='Especialista em Transformação OpenAPI',
            goal='Converter especificações de API em documentação OpenAPI',
            backstory=dedent("""
                Você é um especialista em especificações e documentação OpenAPI.
                Seu papel é transformar detalhes de API validados em documentação
                OpenAPI 3.0 precisa e abrangente.
            """),
            allow_delegation=False,
            llm=self.llm
        )

    def transform_to_openapi(self, validated_endpoints: List[Dict], production_info: Dict) -> Task:
        return Task(
            description=dedent(f"""
                Transforme as seguintes especificações de API validadas em documentação OpenAPI 3.0:
                
                Informações de Produção:
                {json.dumps(production_info, indent=2)}
                
               Endpoints Validados:
                {json.dumps(validated_endpoints, indent=2)}
                
               Requisitos:
               1. Gerar especificação OpenAPI 3.0 completa
               2. Incluir schemas de requisição/resposta apropriados
               3. Documentar todos os parâmetros e corpos de requisição
               4. Incluir autenticação se especificado
               5. Garantir formatação de caminho apropriada
                
                Retorne a especificação OpenAPI nos formatos JSON e YAML.
            """),
            expected_output="""Um objeto JSON contendo a especificação OpenAPI 3.0 completa com todos os endpoints e schemas.""",
            agent=self.transformation_agent
        )

The Review Agent

Após a transformação, a documentação OpenAPI passa por uma revisão meticulosa para garantir conformidade e qualidade. O Agente de Revisão segue esta lista de verificação:

1.Conformidade OpenAPI 3.0

  • Especificação de versão correta
  • Elementos raiz obrigatórios
  • Validação da estrutura do schema
  1. Completude
  • Todos os endpoints documentados
  • Parâmetros totalmente especificados
  • Schemas de requisição/resposta definidos
  • Esquemas de segurança configurados corretamente
  1. Verificações de Qualidade
  • Convenções de nomenclatura consistentes
  • Descrições claras
  • Uso adequado de tipos de dados
  • Códigos de resposta significativos
  1. Melhores Práticas
  • Uso adequado de tags
  • Nomenclatura de parâmetros consistente
  • Definições de segurança apropriadas

Finalmente, se tudo parecer bom, o Agente de Revisão reporta um objeto JSON saudável com a seguinte estrutura:

{
 "is_valid": boolean,
 "approved_spec": object (a especificação OpenAPI revisada e possivelmente corrigida),
 "issues": [array de strings descrevendo quaisquer problemas encontrados],
 "recommendations": [array de sugestões de melhoria]
}

    def create_reviewer_agent(self) -> Agent:
        return Agent(
            role='Revisor de Documentação OpenAPI',
            goal='Garantir a conformidade e qualidade da documentação OpenAPI',
            backstory=dedent("""
                Você é a autoridade final em qualidade e conformidade de documentação OpenAPI.
               Com vasta experiência em especificações OpenAPI 3.0, você revisa meticulosamente
               a documentação para precisão, completude e adesão aos padrões.
            """),
            allow_delegation=True,
            llm=self.llm
        )


    def review_openapi_spec(self, openapi_spec: Dict) -> Task:
        return Task(
            description=dedent(f"""
                Revise a seguinte especificação OpenAPI para conformidade e qualidade:
                
                {json.dumps(openapi_spec, indent=2)}
                
                Lista de Verificação da Revisão::
                1. Conformidade OpenAPI 3.0
                - Verificar a especificação de versão correta
                - Verificar os elementos raiz obrigatórios
                - Validar a estrutura do schema
                
                2. Completude
                - Todos os endpoints devidamente documentados
                - Parâmetros totalmente especificados
                - Schemas de requisição/resposta definidos
                - Esquemas de segurança configurados corretamente
                
                3. Quality Checks
                - Consistent naming conventions
                - Clear descriptions
                - Proper use of data types
                - Meaningful response codes
                
                4. Best Practices
                - Proper tag usage
                - Consistent parameter naming
                - Appropriate security definitions
                
                Você deve retornar um objeto JSON com a seguinte estrutura:
                {{
                    "is_valid": boolean,
                    "approved_spec": object (a especificação OpenAPI revisada e possivelmente corrigida),
                    "issues": [array de strings descrevendo quaisquer problemas encontrados],
                    "recommendations": [array de sugestões de melhoria]
                }}
            """),
            expected_output=""" Um objeto JSON contendo: is_valid (boolean), approved_spec (object), issues (array), e recommendations (array)""",
            agent=self.reviewer_agent
        )

O Agente Iris

O último agente no grupo do planejador é o Agente Iris, que envia a documentação OpenAPI finalizada para o Iris.


    def create_iris_i14y_agent(self) -> Agent:
        return Agent(
            role='Especialista em Integração Iris I14y',
            goal='Integrar especificações de API com o serviço Iris I14y',
            backstory=dedent("""
                  Você é responsável por garantir uma integração suave entre o sistema de
                 documentação da API e o serviço Iris I14y. Você lida com a
                 comunicação com o Iris, valida as respostas e garante a integração
                 bem-sucedida das especificações da API.
            """),
            allow_delegation=False,
            llm=self.llm
        )

    def send_to_iris(self, openapi_spec: Dict, production_info: Dict, review_result: Dict) -> Task:
        return Task(
            description=dedent(f"""
               Enviar a especificação OpenAPI aprovada para o serviço Iris I14y:

                Informações de Produção:
                - Nome: {production_info['production_name']}
                - Namespace: {production_info['namespace']}
                - É Novo: {production_info.get('create_new', False)}

               Status da Revisão:
                - Aprovado: {review_result['is_valid']}
                
                Retornar o resultado da integração em formato JSON.
            """),
            expected_output="""Um objeto JSON contendo o resultado da integração com o serviço Iris I14y, incluindo o status de sucesso e os detalhes da resposta.""",
            agent=self.iris_i14y_agent
        )

class IrisI14yService:
    def __init__(self):
        self.logger = logging.getLogger('facilis.IrisI14yService')
        self.base_url = os.getenv("FACILIS_URL", "http://dc-facilis-iris-1:52773") 
        self.headers = {
            "Content-Type": "application/json"
        }
        self.timeout = int(os.getenv("IRIS_TIMEOUT", "504"))  # in milliseconds
        self.max_retries = int(os.getenv("IRIS_MAX_RETRIES", "3"))
        self.logger.info("IrisI14yService initialized")

    async def send_to_iris_async(self, payload: Dict) -> Dict:
        """
        Enviar carga útil para o endpoint de geração do Iris de forma assíncrona.
        """
        self.logger.info("Enviando carga útil para o endpoint de geração do Iris.")
        if isinstance(payload, str):
            try:
                json.loads(payload)  
            except json.JSONDecodeError:
                raise ValueError("Invalid JSON string provided")
        
        retry_count = 0
        last_error = None

        # Cria timeout para o aiohttp
        timeout = aiohttp.ClientTimeout(total=self.timeout / 1000)  # Converte ms para seconds

        while retry_count < self.max_retries:
            try:
                self.logger.info(f"Attempt {retry_count + 1}/{self.max_retries}: Enviando requisição para {self.base_url}/facilis/api/generate")
                
                async with aiohttp.ClientSession(timeout=timeout) as session:
                    async with session.post(
                        f"{self.base_url}/facilis/api/generate",
                        json=payload,
                        headers=self.headers
                    ) as response:
                        if response.status == 200:
                            return await response.json()
                        response.raise_for_status()

            except asyncio.TimeoutError as e:
                retry_count += 1
                last_error = e
                error_msg = f"Timeout occurred (attempt {retry_count}/{self.max_retries})"
                self.logger.warning(error_msg)
                
                if retry_count < self.max_retries:
                    wait_time = 2 ** (retry_count - 1)
                    self.logger.info(f"Waiting {wait_time} seconds before retry...")
                    await asyncio.sleep(wait_time)
                continue

            except aiohttp.ClientError as e:
                error_msg = f"Failed to send to Iris: {str(e)}"
                self.logger.error(error_msg)
                raise IrisIntegrationError(error_msg)

        error_msg = f"Failed to send to Iris after {self.max_retries} attempts due to timeout"
        self.logger.error(error_msg)
        raise IrisIntegrationError(error_msg, last_error)

Conheça os Geradores

Nosso segundo conjunto de agentes são os Geradores. Eles estão aqui para transformar as especificações OpenAPI em interoperabilidade InterSystems IRIS. Há oito deles neste grupo.

O primeiro deles é o Agente Analisador. Ele é como o planejador, traçando a rota. Seu trabalho é mergulhar nas especificações OpenAPI e descobrir quais componentes de Interoperabilidade IRIS são necessários.


    def create_analyzer_agent():
        return Agent(
            role="Analisador de Especificações OpenAPI",
            goal="Analisar minuciosamente as especificações OpenAPI e planejar os componentes de Interoperabilidade IRIS",
            backstory="""Você é um especialista em especificações OpenAPI e em Interoperabilidade InterSystems IRIS.
                     Seu trabalho é analisar documentos OpenAPI e criar um plano detalhado de como eles devem ser implementados como componentes de Interoperabilidade IRIS.""",
            verbose=False,
            allow_delegation=False,
            tools=[analyze_openapi_tool],
            llm=get_facilis_llm()
        )

   analysis_task = Task(
        description="""Analisar a especificação OpenAPI e planejar os componentes de Interoperabilidade IRIS necessários.
Incluir uma lista de todos os componentes que devem estar na classe de Produção."",
        agent=analyzer,
        expected_output="Uma análise detalhada da especificação OpenAPI e um plano para os componentes IRIS, incluindo a lista de componentes de Produção",
        input={
            "openapi_spec": openApiSpec,
            "production_name": "${production_name}" 
        }
    )

Em seguida, os Agentes de Business Services (BS) e Business Operations (BO) assumem o controle. Eles geram os Business Services e as Business Operations com base nos endpoints OpenAPI. Eles usam uma ferramenta útil chamada MessageClassTool para gerar as classes de mensagens perfeitas, garantindo a comunicação.


    def create_bs_generator_agent():
        return Agent(
            role="Gerador de Produção e Business Service IRIS",
            goal="Gerar classes de Produção e Business Service IRIS formatadas corretamente a partir de especificações OpenAPI",
            backstory="""Você é um desenvolvedor InterSystems IRIS experiente, especializado em Produções de Interoperabilidade.
                 Sua expertise reside na criação de Business Services e Produções capazes de receber e processar requisições de entrada com base emespecificações de API."",
            verbose=False,
            allow_delegation=True,
            tools=[generate_production_class_tool, generate_business_service_tool],
            llm=get_facilis_llm()
        )

    def create_bo_generator_agent():
        return Agent(
            role="Gerador de Business Operation IRIS",
            goal="Gerar classes de Business Operation IRIS formatadas corretamente a partir de especificações OpenAPI",
            backstory="""Você é um desenvolvedor InterSystems IRIS experiente, especializado em Produções de Interoperabilidade.
                 Sua expertise reside na criação de Business Operations capazes de enviar requisições para sistemas externos com base em especificações de API.""",
            verbose=False,
            allow_delegation=True,
            tools=[generate_business_operation_tool, generate_message_class_tool],
            llm=get_facilis_llm()
        )

    bs_generation_task = Task(
        description="Gerar classes de Business Service com base nos endpoints OpenAPI",
        agent=bs_generator,
        expected_output="Definições de classes de Business Service do IRIS",
        context=[analysis_task]
    )

    bo_generation_task = Task(
        description="Gerar classes de Business Operation com base nos endpoints OpenAPI",
        agent=bo_generator,
        expected_output="Definições de classes de Business Operation do IRIS",
        context=[analysis_task]
    )

    class GenerateMessageClassTool(BaseTool):
        name: str = "generate_message_class"
        description: str = "Gerar uma classe de Mensagem IRIS"
        input_schema: Type[BaseModel] = GenerateMessageClassToolInput

        def _run(self, message_name: str, schema_info: Union[str, Dict[str, Any]]) -> str:
            writer = IRISClassWriter()
            try:
                if isinstance(schema_info, str):
                    try:
                        schema_dict = json.loads(schema_info)
                    except json.JSONDecodeError:
                        return "Error: Invalid JSON format for schema info"
                else:
                    schema_dict = schema_info

                class_content = writer.write_message_class(message_name, schema_dict)
                # Armazenar a classe gerada.
                writer.generated_classes[f"MSG.{message_name}"] = class_content
                return class_content
            except Exception as e:
                return f"Error generating message class: {str(e)}"

Depois que BS e BO fazem o que têm que fazer, é a hora do Agente de Produção brilhar! Este agente junta tudo para criar um ambiente de produção coeso.

Depois que tudo estiver configurado, o próximo na linha é o Agente de Validação. Este entra em cena para uma verificação final, garantindo que cada classe Iris esteja ok.

Em seguida, temos o Agente de Exportação e o Agente de Coleção. O Agente de Exportação gera os arquivos .cls, enquanto o Agente de Coleção reúne todos os nomes de arquivos. Tudo é passado para o importador, que compila tudo no InterSystems Iris.


    def create_exporter_agent():
        return Agent(
            role="Exportador de Classes IRIS",
            goal="Exportar e validar definições de classes IRIS para arquivos .cls adequados",
            backstory="""Você é um especialista em implantação InterSystems IRIS. Seu trabalho é garantir que as definições de classes IRIS geradas sejam devidamente exportadas como arquivos .cls válidos que
                possam ser importados diretamente para um ambiente IRIS.""",
            verbose=False,
            allow_delegation=False,
            tools=[export_iris_classes_tool, validate_iris_classes_tool],
            llm=get_facilis_llm()
        )
        
    def create_collector_agent():
        return Agent(
            role="Coletor de Classes IRIS",
            goal="Coletar todos os arquivos de classes IRIS gerados em uma coleção JSON",
            backstory="""Você é um especialista em sistema de arquivos responsável por reunir e
                organizar os arquivos de classes IRIS gerados em uma coleção estruturada.""",
            verbose=False,
            allow_delegation=False,
            tools=[CollectGeneratedFilesTool()],
            llm=get_facilis_llm()
        )

    export_task = Task(
        description="Exportar todas as classes IRIS geradas como arquivos .cls válidos",
        agent=exporter,
        expected_output="Arquivos .cls IRIS válidos salvos no diretório de saída",
        context=[bs_generation_task, bo_generation_task],
        input={
            "output_dir": "/home/irisowner/dev/output/iris_classes"  # Optional
        }
    )

    collection_task = Task(
        description="Coletar todos os arquivos de classes IRIS gerados em uma coleção JSON",
        agent=collector,
        expected_output="Coleção JSON de todos os arquivos .cls gerados",
        context=[export_task, validate_task],
        input={
            "directory": "./output/iris_classes"
        }
    )

Limitações e Desafios

Nosso projeto começou como um experimento empolgante, onde meus colegas mosqueteiros e eu almejávamos criar uma ferramenta totalmente automatizada usando agentes. Foi uma jornada selvagem! Nosso foco principal estava em integrações de API REST. É sempre uma alegria receber uma tarefa com uma especificação OpenAPI para integrar; no entanto, sistemas legados podem ser uma história completamente diferente. Pensamos que automatizar essas tarefas poderia ser incrivelmente útil. Mas toda aventura tem suas reviravoltas: Um dos maiores desafios foi instruir a IA a converter OpenAPI para Interoperabilidade Iris. Começamos com o modelo openAI GPT3.5-turbo, que em testes iniciais se mostrou difícil com depuração e prevenção de interrupções. A mudança para o Anthropic Claude 3.7 Sonnet mostrou melhores resultados para o grupo Gerador, mas não tanto para os Planejadores... Isso nos levou a dividir nossas configurações de ambiente, usando diferentes provedores de LLM para flexibilidade. Usamos GPT3.5-turbo para planejamento e Claude sonnet para geração, uma ótima combinação! Essa combinação funcionou bem, mas encontramos problemas com alucinações. A mudança para o GT4o melhorou os resultados, mas ainda enfrentamos alucinações na criação de classes Iris e, às vezes, especificações OpenAPI desnecessárias, como o renomado exemplo Pet Store OpenAPI. Nos divertimos muito aprendendo ao longo do caminho, e estou super animado com o futuro incrível nesta área, com inúmeras possibilidades!

1
0 42
Artigo Heloisa Paiva · Mar. 5, 2025 6m read

O que é JWT?

JWT (JSON Web Token) é um padrão aberto (RFC 7519) que oferece um método leve, compacto e auto-contido para transmitir informações de forma segura entre duas partes. É comumente usado em aplicações web para autenticação, autorização e troca de informações.

Um JWT é tipicamente composto por três partes:

1. Cabeçalho JOSE (JSON Object Signing and Encryption) 
2. Payload (Carga útil)
3. Assinatura

Essas partes são codificadas no formato Base64Url e concatenadas com pontos (.) separando-as.

Estrutura de um JWT

Cabeçalho

{ "alg": "HS256", "typ": "JWT"}

Payload

0
0 43
Artigo Heloisa Paiva · Fev. 17, 2025 6m read

Monitorar sua implantação do IRIS é crucial. Com a descontinuação do System Alert and Monitoring (SAM), uma solução moderna e escalável é necessária para obter insights em tempo real, detecção precoce de problemas e eficiência operacional. Este guia aborda a configuração do Prometheus e Grafana no Kubernetes para monitorar o InterSystems IRIS de forma eficaz.

Este guia pressupõe que você já tenha um cluster IRIS implantado usando o InterSystems Kubernetes Operator (IKO), que simplifica a implantação, integração e gerenciamento.

 

Por que Prometheus e Grafana?

0
0 64
Pergunta Gabriel Silva dos Santos · jan 17, 2025

Olá pessoal, tudo bem?

Estou enfrentando problemas na replicação de dados do meu Caché 2016 para um banco PostgreSQL. Preciso lidar com cerca de 300 atualizações de dados por minuto, e, sempre que determinadas tabelas sofrem alterações, essas mudanças precisam ser refletidas em outras bases de dados.

Até o momento, já tentei várias abordagens, como:

  • Configurar uma API intermediária,
  • Utilizar o Azure Service Bus,
  • Usar Jobs do Caché,
  • E todas elas têm como ponto de entrada as triggers das minhas tabelas.
2
0 55
Artigo Heloisa Paiva · Out. 22, 2024 9m read

django_logo

Descrição

Este é um modelo para um aplicativo Django que pode ser implantado no IRIS como um aplicativo Web nativo.

Instalação

  1. Clone o repositório
  2. Crie um ambiente virtual
  3. Instale os requisitos
  4. Rode o arquivo docker-compose
git clone
cd iris-django-template
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
docker-compose up

Uso

A URL base é http://localhost:53795/django/.

Endpoints

  • /iris - Retorna um objeto JSON com as 10 principais classes presentes no namespace IRISAPP.
  • /interop - Um endpoint de ping para testar a estrutura de interoperabilidade do IRIS.
  • /api/posts -Um endpoint CRUD simples para um objeto Post.
  • /api/comments - Um endpoint CRUD simples para um objeto Comment.

Como desenvolver deste modelo

Veja o artigo de introdução ao WSGI: wsgi-introduction.

TL;DR: Você pode ativar ou desativar o sinalizador DEBUG no portal de segurança para que as alterações sejam refletidas no aplicativo à medida que você desenvolve.

Apresentação do código

A aplicação Django é estruturada como se segue:

  • app - Pasta do projeto Django
    • app - Pasta da aplicação Django para configuração
      • settings.py - Arquivo de definições Django
      • urls.py - Arquivo de configuração de URL Django para conectar as visualizações às URLs
      • wsgi.py - Arquivo do Django WSGI
      • asgi.py - Arquivo do Django AGI
    • community - Pasta da aplicação Django para o aplicativo da comunidade, com CRUD nos objetos de Post e Comment
      • models.py - Arquivo de modelos do Djando para os objetos Post e Comment
      • views.py - Arquivo de visualizações Django para cessar os objetos Post e Comment
      • serializers.py - Arquivo Django de serializadores para os objetos Post e Comentário. * admin.py - Arquivo Django de administração para adicionar CRUD à interface administrativa.
      • migrations - Pasta Django de migrações para construir o banco de dados.
      • fixtures - Pasta Django de fixtures com dados de demonstração
    • sqloniris - Pasta do aplicativo Django para o aplicativo SQL no IRIS.
      • views.py - Arquivo Django de views para consultar o namespace IRISAPP.
      • apps.py - Arquivo de configuração do aplicativo Django.
    • interop - Pasta do aplicativo Django para o aplicativo de interoperabilidade.
      • views.py - Arquivo Django de views para testar a estrutura de interoperabilidade.
      • apps.py - Arquivo de configuração do aplicativo Django.
    • manage.py - Arquivo de gerenciamento Django.

app/settings.py

Este arquivo contém as configurações Django para o aplicativo.

...

# Definição de aplicação

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'community',
    'sqloniris',
    'interop',
    'rest_framework'
]

...

REST_FRAMEWORK = {
    # Use as permissões padrão do Django `django.contrib.auth` ,
    # ou permita acesso de apenas leitura para usuários não autenticados
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
    ],
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
    'PAGE_SIZE': 20
}

...

DATABASES = {
    "default": {
        "ENGINE": "django_iris",
        "EMBEDDED": True,
        "NAMESPACE": "IRISAPP",
        "USER":"SuperUser",
        "PASSWORD":"SYS",
    }
}

Algumas definições importantes para notar:

  • INSTALLED_APPS - Contém a lista de aplicativos instalados no projeto Django.
  • community - O aplicativo Django para as operações CRUD nos objetos Post e Comentário.
  • sqloniris - TO aplicativo Django para as operações SQL no IRIS.
  • interop - O aplicativo Django para as operações de interoperabilidade.
  • rest_framework - O framework Django REST para a API REST.
  • REST_FRAMEWORK - Contém as configurações para o framework Django REST.
    • DEFAULT_PERMISSION_CLASSES - Somente usuários autenticados podem realizar operações CRUD.
    • DEFAULT_PAGINATION_CLASS - A classe de paginação para a API REST.
  • DATABASES - Contém as configurações para a conexão com o banco de dados IRIS.
    • Aqui estamos usando o mecanismo django_iris para conectar ao banco de dados IRIS.

app/urls.py

Este arquivo contém a configuração de URL para o aplicativo Django.

from django.contrib import admin
from django.urls import path,include
from rest_framework import routers
from community.views import PostViewSet, CommentViewSet
from sqloniris.views import index
from interop.views import index as interop_index

router = routers.DefaultRouter()
router.register(r'posts', PostViewSet)
router.register(r'comments', CommentViewSet)


urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include(router.urls)),
    path('iris/', index),
    path('interop/', interop_index)
]
  • router - Contém o roteador padrão para a API REST.
  • routeer.register - Registra os viewsets Post e Comentário no roteador.
  • urlpatterns - Contém os padrões de URL para o aplicativo Django
    • /admin/ - A interface administrativa Django.
    • /api/ -A API REST para os objetos Post e Comentário.
    • /iris/ - O endpoint SQL no IRIS.
    • /interop/ - O endpoint de interoperabilidade.

app/wsgi.py

Este arquivo contém a configuração WSGI para o aplicativo Django.

Este é o arquivo que temos que fornecer ao IRIS para executar o aplicativo Django.

Na seção Security->Applications->Web Applications, temos que fornecer o caminho para este arquivo.

  • Application Name
    • app.wsgi
  • Callable Name
    • application
  • WSGI App directory
    • /irisdev/app/app

community/models.py

Este arquivo contém os modelos Django para os objetos Post e Comentário.

from django.db import models

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()

class Comment(models.Model):
    content = models.TextField()
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
  • Post - O modelo para o objeto Post.
    • title - O título do post.
    • content - O conteúdo do post.
  • Comment - O modelo para o objeto Comentário.
    • content - O conteúdo do comentário.
    • post - A chave estrangeira para o objeto Post.
    • related_name - O nome relacionado para os comentários.

community/seializers.py

Este arquivo contém os serializadores Django para os objetos Post e Comentário.

Usando o framework Django REST, podemos serializar os modelos Django em objetos JSON.

from rest_framework import serializers
from community.models import Post, Comment

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ('id', 'title', 'content', 'comments')

class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = ('id', 'content', 'post')
  • PostSerializer -O serializador para o objeto Post.
  • CommentSerializer -O serializador para o objeto Comentário.
  • fields - Os campos a serem serializados.

community/views.py

Este arquivo contém as views Django para os objetos Post e Comentário.

Usando o framework Django REST, podemos criar operações CRUD para os modelos Django.

from django.shortcuts import render
from rest_framework import viewsets

# Import the Post and Comment models
from community.models import Post, Comment

# Import the Post and Comment serializers
from community.serializers import PostSerializer, CommentSerializer

# Create your views here.
class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
  • PostViewSet - O viewset para o objeto Post.
  • CommentViewSet - O viewset para o objeto Comentário.
  • queryset - O queryset para o viewset.
  • serializer_class - A classe de serializador para o viewset.

sqloniris/views.py

Este arquivo contém as views Django para as operações SQL no IRIS.

from django.http import JsonResponse

import iris

def index(request):
    query = "SELECT top 10 * FROM %Dictionary.ClassDefinition"
    rs = iris.sql.exec(query)
    # Convert the result to a list of dictionaries
    result = []
    for row in rs:
        result.append(row)
    return JsonResponse(result, safe=False)
  • index - A view para a operação SQL no IRIS.
  • query - A consulta SQL a ser executada no banco de dados IRIS.
  • rs - O conjunto de resultados da consulta.
  • result - A lista de listas do conjunto de resultados.
  • JsonResponse - A resposta JSON para a view, safe é definido como False para permitir lista de listas.

interop/views.py

Este arquivo contém as views Django para as operações de interoperabilidade.

from django.http import HttpResponse

from grongier.pex import Director

bs = Director.create_python_business_service('BS')

def index(request):
    result = bs.on_process_input(request)
    return HttpResponse(result, safe=False)
  • bs - O objeto de serviço de negócios criado usando a classe Director .
  • index -A view para a operação de interoperabilidade.
  • result - A view para a operação de interoperabilidade.

Observação: não usamos JsonResponse para simplificar o código, podemos usá-lo se quisermos retornar um objeto JSON.

Solução de Problemas

Como executar o aplicativo Django em modo autônomo

Para executar o aplicativo Django em modo autônomo, podemos usar o seguinte comando:

cd /irisdev/app/app
python3 manage.py runserver 8001

Isso executará o aplicativo Django na porta padrão 8001.

Observação: você deve estar dentro do contêiner para executar este comando.

docker exec -it iris-django-template-iris-1 bash

Reiniciando o aplicativo no IRIS

Esteja no modo DEBUG, faça várias chamadas para o aplicativo e as alterações serão refletidas no aplicativo.

Como acessar o Portal de Gerenciamento do IRIS

Você pode acessar o Portal de Gerenciamento do IRIS acessando http://localhost:53795/csp/sys/UtilHome.csp.

Executar este template localmente

Para isso, você precisa ter o IRIS instalado em sua máquina.

Em seguida, você precisa criar um namespace chamado IRISAPP.

Instale os requisitos.

# Move to the app directory
cd /irisdev/app/app

# python manage.py flush --no-input
python3 manage.py migrate
# create superuser
export DJANGO_SUPERUSER_PASSWORD=SYS
python3 manage.py createsuperuser --no-input --username SuperUser --email admin@admin.fr

# load demo data
python3 manage.py loaddata community/fixtures/demo.json

# collect static files
python3 manage.py collectstatic --no-input --clear

# init iop
iop --init

# load production
iop -m /irisdev/app/app/interop/settings.py

# start production
iop --start Python.Production

Como servir arquivos estáticos

Para servir os arquivos estáticos no aplicativo Django, podemos usar o seguinte comando:

cd /irisdev/app
python3 manage.py collectstatic

Isso coletará os arquivos estáticos do aplicativo Django e os servirá no diretório /irisdev/app/static.

Para publicar os arquivos estáticos no IRIS, configure a seçãoSecurity->Applications->Web Applications.

web_applications

0
0 35
Artigo Heloisa Paiva · Maio 20, 2024 21m read

Há 2 anos eu venho utilizando Python embutido diariamente. Talvez seja o momento de compartilhar um feedback sobre essa jornada.

Por que escrever esse feedback? Porque eu acredito que sou como a maioria das pessoas aqui, um desenvolvedor ObjectScript, e penso que a comunidade poderia ter algum benefício desse feedback e entender melhor os prós e contras de escolher Python embutido para desenvolver em IRIS. Além de evitar algumas armadilhas.

image

Introdução

Eu sou desenvolvedor desde 2010 e trabalho com ObjectScript desde 2013.

Então são aproximadamente 10 anos de experiência com ObjectScript.

Desde 2021 e o lançamento do Python Embutido no IRIS, eu me propus um desafio:

  • Aprender Python
  • Fazer tudo o máximo possível com Python

Quando eu comecei essa jornada, eu não tinha ideia do que era Python. Então, comecei com o básico e ainda estou aprendendo todo dia.

Começando com Python

O lado bom do Python é que é fácil de aprender. É ainda mais fácil se você já conhece ObjectScript.

Por quê? Elas têm muito em comum.

ObjectScriptPython
Não tipadaNão tipada
Scripting languageScripting language
Orientada a ObjetoOrientada a Objeto
InterpretadaInterpretada
Fácil integração com CFácil integração com C

Então, se você conhece ObjectScript você já sabe muito sobre Python.

Porém, há algumas diferenças, dentre as quais algumas não são fáceis de entender.

Python não é ObjectScript

Para manter as coisas simples, vou focar nas principais diferenças entre ObjectScript e Python.

Para mim, há 3 principais diferenças:

  • Pep8
  • Módulos
  • Dunders

Pep8

O que é Pep8 ?

É um conjunto de regras para escrever códigos Python.

pep8.org

Algumas delas são:

  • Convenção de nomenclatura
  • nomes de variáveis
    • snake_case
  • nomes de classes
    • CamelCase
  • indentação
  • comprimento da linha
  • etc.

Por que isso é importante?

Porque é a maneira de escrever código Python. Se você não seguir essas regras, terá dificuldade em ler o código de outras pessoas e elas terão dificuldade de ler o seu.

Como desenvolvedores ObjectScript, também temos algumas regras para seguir, mas não são tão rígidas como a Pep8.

Eu aprendi Pep8 da maneira mais difícil.

Para contar a história, eu sou engenheiro de vendas na InterSystems e estou fazendo várias demos. Certo dia, eu estava fazendo uma demo de Python Embutido para um cliente que era desenvolvedor Python, e a conversa encurtou quando ele viu meu código. Ele me contou que meu código não era nada "Pythonico" (ele estava certo). Eu estava programando em Python como eu programava em ObjectScript. Por causa disso, ele disse que não estava interessado no Python Embutido mais. Eu fiquei chocado e decidi aprender Python do jeito certo.

Assim, se você quer aprender Python, aprenda Pep8 primeiro.

Módulos

Os módulos são uma funcionalidade que não temos em ObjectScript.

Geralmente, em linguagens orientadas a objetos, há classes e pacotes. No Python, temos classes, pacotes e módulos.

O que é um módulo?

É um arquivo com extensão .py. É a maneira de organizar seu código.

Você não entendeu? No começo eu também não. Portanto vamos usar um exemplo.

Geralmente, quando você quer criar uma classe em ObjectScript, você cria um arquivo .cls e coloca sua classe ali dentro. E, se quiser criar outra classe, usa outro arquivo .cls. Por fim, se quiser criar um pacote, você gera uma pasta e coloca os arquivos .cls dentro dela.

Em Python fazemos o mesmo, mas ele tem a habilidade de guardar várias classes num mesmo arquivo. Esse arquivo é chamado módulo. É importante saber que é "Pythônico" ter muitas classes em um mesmo arquivo.

Portanto, planeje de antemão como pretende organizar seu código e como vai nomear seus módulos para não terminar como eu, com um monte de módulos com o mesmo nome das suas classes.

Um mau exemplo:

A bad example :

MinhaClasse.py

class MinhaClasse:
    def __init__(self):
        pass

    def meu_metodo(self):
        pass

Para instanciar essa classe, você fará:

import MinhaClasse.MinhaClasse # estranho, né?

minha_classe= MinhaClasse()

Estranho, né?

Dunders

Dunders são métodos especiais em Python. Eles são chamados de dunder porque começam e terminam com dois caracteres underscores (_).

Eles são similares aos métodos do ObjectScript com '%'.

Eles são usados para:

  • construtor
  • sobrecarga de operador
  • representação do objeto
  • etc.

Exemplo:

class MinhaClasse:
    def __init__(self):
        pass

    def __repr__(self):
        return "MyClass"

    def __add__(self, other):
        return self + other

Aqui temos 3 métodos dunder:

  • __init__ : construtor
  • __repr__ : representação do objeto
  • __add__ : sobrecarga de operador

Métodos Dunders estão por toda parte em Python. São uma grande parte da linguagem, mas não se preocupe; você vai aprendê-los rapidamente,

Conclusão

Python não é ObjectScript, e você terá que aprender. Mas não é tão difícil, então você vai aprender rápido. Apenas mantenha em mente que você deverá aprender Pep8 e como organizar seu código com módulos e métodos dunder.

Bons sites para aprender Python


Python Embutido

Agora que você conhece um pouco mais sobre o Python, vamos falar de Python Embutido.

O que é o Python Embutido?

Python Embutido é uma maneira de executar código Python dentro do IRIS. É uma nova funcionalidade do IRIS 2021.2+. Isso significa que seu código Python será executado no mesmo processo que o IRIS.

No mais, toda classe ObjectScript é uma classe Python, e o mesmo cale para métodos e atributos, e vice-versa. 🥳 Isso é bacana!

Como usar Python Embutido?

Há 3 maneiras diferentes de usar Python Embutido:

  • Usando a tag de linguagem do ObjectScript
    • Method Foo() As %String [ Language = python ]
  • Usando a função ##class(%SYS.Python).Import()
  • Usando o interpretador de Python
    • python3 -c "import iris; print(iris.system.Version.GetVersion())"

Mas se você quiser usar mesmo o Python Embutido, você terá que evitar usar a tag de linguagem.

image

Por quê?

  • Porque não é Pythônico
  • Porque também não é ObjectScript
  • Porque você não terá um debugador
  • Porque você não terá um linter
  • Porque você não terá um formatador
  • Porque você não terá um framework de testes
  • Porque você não terá um gerenciador de pacotes
  • Porque você está misturando duas linguagens no mesmo arquivo
  • Porque quando o seu processo quebra, você não tem um rastreio da pilha
  • Porque você não pode usar um ambiente virtual ou ambientes conda
  • ...

Não me entenda mal, isso funciona e pode ser útil se você quiser testar algo rapidamente, mas na minha opinião não é uma boa prática.

Então, o que eu aprendi nesses 2 anos de Python Embutido, e como utilizá-lo da maneira correta?

Como eu uso Python embutido

Para mim, existem duas opções:

  • Usar libraries do Python como se fossem classes do ObjectScript
    • with ##class(%SYS.Python).Import() function
  • Usar uma abordagem de Python em primeiro lugar.

Usar libraries do Python como se fossem classes do ObjectScript

Você ainda quer usar Python no seu código ObjectScript, mas não quer usar a tag de linguagem. O que você pode fazer, então?

"Simplesmente" usar códigos e libraries do Python como se fossem classes ObjectScript.

Vamos tomar como exemplo:

Você quer usar a library requests (é uma library para fazer requisições HTTP) no seu código ObjectScript

Com a tag de linguagem

ClassMethod Get() As %Status [ Language = python ]
{
	import requests

	url = "https://httpbin.org/get"
	# faça uma requisição get
	response = requests.get(url)
	# pegue os dados do json de resposta
	data = response.json()
	# iterar pelos dados e printar os pares chave-valoe
	for key, value in data.items():
		print(key, ":", value)
}

Por que eu não acho uma boa ideia?

Porque você está misturando duas linguagens no mesmo arquivo, e você não tem um debugador, um linter, um formatador, etc. Se esse código der algum problema, você terá dificuldade de debugar. Se você não tem um rastreio da pilha, não saberá da onde veio o erro. E também não tem a funcionalidade de completar automaticamente.

Sem a tag de linguagem

ClassMethod Get() As %Status
{
	set status = $$$OK
    set url = "https://httpbin.org/get"
    // Importar o módulo Python "requests" como uma classe ObjectScript 
    set request = ##class(%SYS.Python).Import("requests")
    // Chamar o método get da classe request
    set response = request.get(url)
    // Chamar o método json da classe response
	set data = response.json()
    // Aqui os dados são um dicionário Python
    // Para iterar por um dicionário Python, você deve usar o método dunder e items().
	// Importar um módulo pré-existente de Python.
	set builtins = ##class(%SYS.Python).Import("builtins")
    // Aqui estamos usando "len" do módulo de pré-existentes (built in) para saber o comprimento do dicionário.
    For i = 0:1:builtins.len(data)-1 {
        // Agora nós convertemos os itens do dicionário para uma lista, então pegamos a chave e o valor usando o método dunder __getitem__
		Write builtins.list(data.items())."__getitem__"(i)."__getitem__"(0),": ",builtins.list(data.items())."__getitem__"(i)."__getitem__"(1),!
	}
	quit status
}

Por que eu acho isso uma boa ideia?

Porque você está utilizando Python como se fosse ObejctScript. Você está importando a library requests como uma classe ObjectScript e usando como se fosse uma classe ObjectScript. Toda a lógica está em ObjectScript, e você utiliza o Python como uma library. Até para manutenção, é mais fácil de ler e entender; qualquer desenvolvedor ObjectScript consegue entender esse código. A desvantagem é que você tem que saber como usar os métodos dunders, e como usar Python como se fosse ObjectScript.

Conclusão

Acredite em mim, dessa maneira você vai acabar com um código mais robusto e conseguirá debugar facilmente. A princípio parece difícil, mas você vai entender os benefícios de aprender Python mais rápido do que você pensa.

Usar uma abordagem de Python em primeiro lugar

Essa é a maneira que eu prefiro usar Python Embutido

Eu construí várias ferramentas usando essa abordagem e estou muito feliz com isso.

Alguns exemplos:

Então, o que é uma abordagem de Python em primeiro lugar?

Existe apenas uma regra: o código Python deve estar em arquivos . py, o código ObjectScript deve estar em arquivos .cls

Como conseguir isso?

A ideia é criar classes de invólucro de ObjectScript para chamar o código Python.


Vamos tomar o exemplo de iris-fhir-python-strategy :

Exemplo : iris-fhir-python-strategy

Primeiramente, nós temos que entender como o servidor IRIS FHIR funciona.

Todo servidor IRIS FHIR implementa uma Strategy (estratégia).

Uma Strategy é um conjunto de duas classes:

SuperclasesParâmetros de Subclasse
HS.FHIRServer.API.InteractionsStrategyStrategyKey — Especifica um identificador único para a InteractionsStrategy.
InteractionsClass — Especifica o nome da sua subclasse de Interactions (interações).
HS.FHIRServer.API.RepoManagerStrategyClass —Especifica o nome da sua sublcasse InteractionsStrategy.
StrategyKey — Especifica um identificaod único para a InteractionsStrategy. Deve ter o mesmo valor do parâmetro StrategyKey na subclasse InteractionsStrategy.

As duas classes são do tipo Abstract (abstratas).

  • HS.FHIRServer.API.InteractionsStrategy é uma classe Abstractque deve ser implementada para customizar o comportamento do Servidor FHIR.
  • HS.FHIRServer.API.RepoManager é uma classe Abstract que deve ser implementada para customizar o armazenamento do servidor FHIR.

Observações

Para o nosso exemplo, vamos focar apenas na classe HS.FHIRServer.API.InteractionsStrategy, mesmo que a classe HS.FHIRServer.API.RepoManager também seja implementada e obrigatória para customizar o Servidor FHIR. A classe HS.FHIRServer.API.RepoManager é implementada pela classe HS.FHIRServer.Storage.Json.RepoManager, que é a implementação padrão do Servidor FHIR.

##Onde achar o código

Todo o código fonte pode ser achado nesse repositório: iris-fhir-python-strategy A pasta src contém as seguintes pastas:

  • python : contém o código Python
  • cls : contem o código ObjectScript que é usado para chamar o código Python

Como implementar uma Strategy

Nesta prova de conceito, só estaremos interessados em como implementar uma Strategy em Python, não em como implementar um RepoManager (gerenciador de repositório).

Para implementar uma Strategy você deve criar pelo menos duas classes:

  • Uma classe que herda da HS.FHIRServer.API.InteractionsStrategy
  • Uma classe que herda da HS.FHIRServer.API.Interactions class

Implementação de InteractionsStrategy

A classe HS.FHIRServer.API.InteractionsStrategy foca em customizar o comportamento do Servidor FHIR ao sobrescrever os seguintes métodos:

  • GetMetadataResource: chamado para pegar os metadados do servidor FHIR
    • esse é o único método que vamos sobrescrever nessa prova de conceito

HS.FHIRServer.API.InteractionsStrategy também tem dois parâmetros:

  • StrategyKey : um identificador único para a InteractionsStrategy
  • InteractionsClass : o nome da subclasse de Interactions

Implementação de Interactions

A classe HS.FHIRServer.API.Interactions foca em customizar o comportamento do Servidor FHIR ao sobrescrever os seguintes métodos:

  • OnBeforeRequest : chamada antes da requisição ser enviada ao servidor
  • OnAfterRequest : chamada após a requisição ser enviada ao servidor
  • PostProcessRead : chamada após a operação de leitura estar finalizada
  • PostProcessSearch : chamada após a operação de procura estar finalizada
  • Read : chamada para ler um recurso
  • Add : chamada para adicionar um recurso
  • Update : chamada para atualizar um recurso
  • Delete : chamada para deletar um recurso
  • e muito mais...

Nós implementamos a classe HS.FHIRServer.API.Interactions no arquivo src/cls/FHIR/Python/Interactions.cls.

 
Spoiler
Class FHIR.Python.Interactions Extends (HS.FHIRServer.Storage.Json.Interactions, FHIR.Python.Helper)
{

Parameter OAuth2TokenHandlerClass As%String = "FHIR.Python.OAuth2Token";

Method %OnNew(pStrategy As HS.FHIRServer.Storage.Json.InteractionsStrategy) As%Status { // %OnNew é chamado quando o objeto é criado.// O parâmetro pStrategy é o objeto de estratégia criado nesse objeto.// A implementação padrão não faz nada// Primeiro define o caminho do Python de uma variável de ambienteset..PythonPath = $system.Util.GetEnviron("INTERACTION_PATH") // Depois define o nome da classe de Python pela variável de ambienteset..PythonClassname = $system.Util.GetEnviron("INTERACTION_CLASS") // Então define o nome do módulo Python pela variável de ambienteset..PythonModule = $system.Util.GetEnviron("INTERACTION_MODULE")

<span class="hljs-keyword">if</span> (<span class="hljs-built_in">..PythonPath</span> = <span class="hljs-string">""</span>) || (<span class="hljs-built_in">..PythonClassname</span> = <span class="hljs-string">""</span>) || (<span class="hljs-built_in">..PythonModule</span> = <span class="hljs-string">""</span>) {
	<span class="hljs-comment">//quit ##super(pStrategy)</span>
	<span class="hljs-keyword">set</span> <span class="hljs-built_in">..PythonPath</span> = <span class="hljs-string">"/irisdev/app/src/python/"</span>
	<span class="hljs-keyword">set</span> <span class="hljs-built_in">..PythonClassname</span> = <span class="hljs-string">"CustomInteraction"</span>
	<span class="hljs-keyword">set</span> <span class="hljs-built_in">..PythonModule</span> = <span class="hljs-string">"custom"</span>
}


<span class="hljs-comment">// Então, define a classe Python</span>
<span class="hljs-keyword">do</span> <span class="hljs-built_in">..SetPythonPath</span>(<span class="hljs-built_in">..PythonPath</span>)
<span class="hljs-keyword">set</span> <span class="hljs-built_in">..PythonClass</span> = <span class="hljs-keyword">##class</span>(FHIR.Python.Interactions).GetPythonInstance(<span class="hljs-built_in">..PythonModule</span>, <span class="hljs-built_in">..PythonClassname</span>)

<span class="hljs-keyword">quit</span> <span class="hljs-keyword">##super</span>(pStrategy)

}

Method OnBeforeRequest( pFHIRService As HS.FHIRServer.API.Service, pFHIRRequest As HS.FHIRServer.API.Data.Request, pTimeout As%Integer) { // OnBeforeRequest é chamado antes de cada requisição ser processada.if$ISOBJECT(..PythonClass) { set body = ##class(%SYS.Python).None() if pFHIRRequest.Json '= "" { set jsonLib = ##class(%SYS.Python).Import("json") set body = jsonLib.loads(pFHIRRequest.Json.%ToJSON()) } do..PythonClass."on_before_request"(pFHIRService, pFHIRRequest, body, pTimeout) } }

Method OnAfterRequest( pFHIRService As HS.FHIRServer.API.Service, pFHIRRequest As HS.FHIRServer.API.Data.Request, pFHIRResponse As HS.FHIRServer.API.Data.Response) { // OnAfterRequest é chamado depois de cada requisição ser processada.if$ISOBJECT(..PythonClass) { set body = ##class(%SYS.Python).None() if pFHIRResponse.Json '= "" { set jsonLib = ##class(%SYS.Python).Import("json") set body = jsonLib.loads(pFHIRResponse.Json.%ToJSON()) } do..PythonClass."on_after_request"(pFHIRService, pFHIRRequest, pFHIRResponse, body) } }

Method PostProcessRead(pResourceObject As%DynamicObject) As%Boolean { // PostProcessRead é chamada após um recurso ser lido na base de dados.// Retorna 1 para indicar que o recurso deve ser incluído na resposta.// Retorna 0 para indicar que o recurso deve ser excluído da resposta.if$ISOBJECT(..PythonClass) { if pResourceObject '= "" { set jsonLib = ##class(%SYS.Python).Import("json") set body = jsonLib.loads(pResourceObject.%ToJSON()) } return..PythonClass."post_process_read"(body) } quit1 }

Method PostProcessSearch( pRS As HS.FHIRServer.Util.SearchResult, pResourceType As%String) As%Status { // PostProcessSearch é chamado depois de uma busca.// Retorna $$$OK para indicar que a busca teve sucesso.// Retorna um código de erro para indicar que a busca falhou.if$ISOBJECT(..PythonClass) { return..PythonClass."post_process_search"(pRS, pResourceType) } quit$$$OK }

Method Read( pResourceType As%String, pResourceId As%String, pVersionId As%String = "") As%DynamicObject { return##super(pResourceType, pResourceId, pVersionId) }

Method Add( pResourceObj As%DynamicObject, pResourceIdToAssign As%String = "", pHttpMethod = "POST") As%String { return##super(pResourceObj, pResourceIdToAssign, pHttpMethod) }

/// Returns VersionId for the "deleted" version Method Delete( pResourceType As%String, pResourceId As%String) As%String { return##super(pResourceType, pResourceId) }

Method Update(pResourceObj As%DynamicObject) As%String { return##super(pResourceObj) }

}

A classeFHIR.Python.Interactions herda das classes HS.FHIRServer.Storage.Json.Interactions e FHIR.Python.Helper.

A classe HS.FHIRServer.Storage.Json.Interactions é o padrão de implementação do Servidor FHIR.

A classe FHIR.Python.Helper foca em ajudar chamar o código Python pelo ObjectScript .

A classe FHIR.Python.Interactions sobrescreve os métodos a seguir:

  • %OnNew : chamado quando o objeto é criado
    • nós usamos esse método para definir o caminho, nome da classe de, e nome de módulo do Python a partir das variáveis de ambiente.
    • se as variáveis de ambiente não forem definidas, utilizamos valores padrão.
    • também definimos a classe python
    • chamamos o método %OnNew da classe pai.
Method %OnNew(pStrategy As HS.FHIRServer.Storage.Json.InteractionsStrategy) As %Status
{
	// Primeiro, definimos o caminho Python por uma variável de ambiente
	set ..PythonPath = $system.Util.GetEnviron("INTERACTION_PATH")
	// Então, definimos o nome da classe Python pela variável de ambiente
	set ..PythonClassname = $system.Util.GetEnviron("INTERACTION_CLASS")
	// Depois, definimos o nome do módulo Python da variável de ambiente
	set ..PythonModule = $system.Util.GetEnviron("INTERACTION_MODULE")

	if (..PythonPath = "") || (..PythonClassname = "") || (..PythonModule = "") {
		// usa valores padrão
		set ..PythonPath = "/irisdev/app/src/python/"
		set ..PythonClassname = "CustomInteraction"
		set ..PythonModule = "custom"
	}

	// A seguir, definimos a classe Python
	do ..SetPythonPath(..PythonPath)
	set ..PythonClass = ..GetPythonInstance(..PythonModule, ..PythonClassname)

	quit ##super(pStrategy)
}
  • OnBeforeRequest : chamada antes da requisição ser enviada ao servidor
    • chamamos o método on_before_request da classe Python
    • passamos os objetos HS.FHIRServer.API.Service e HS.FHIRServer.API.Data.Request , o corpo da requisição e o tempo limite de execução.
Method OnBeforeRequest(
	pFHIRService As HS.FHIRServer.API.Service,
	pFHIRRequest As HS.FHIRServer.API.Data.Request,
	pTimeout As %Integer)
{
	// OnBeforeRequest é chamado antes de cada requisição ser processada.
	if $ISOBJECT(..PythonClass) {
		set body = ##class(%SYS.Python).None()
		if pFHIRRequest.Json '= "" {
			set jsonLib = ##class(%SYS.Python).Import("json")
			set body = jsonLib.loads(pFHIRRequest.Json.%ToJSON())
		}
		do ..PythonClass."on_before_request"(pFHIRService, pFHIRRequest, body, pTimeout)
	}
}
  • OnAfterRequest : chamado após a requisição ser enviada ao servidor
    • chamamos o método on_after_request da classe Python
    • passamos os objetos HS.FHIRServer.API.Service, HS.FHIRServer.API.Data.Request e HS.FHIRServer.API.Data.Response e o corpo da resposta
Method OnAfterRequest(
	pFHIRService As HS.FHIRServer.API.Service,
	pFHIRRequest As HS.FHIRServer.API.Data.Request,
	pFHIRResponse As HS.FHIRServer.API.Data.Response)
{
	// OnAfterRequest é chamado após cada requisição ser processada
	if $ISOBJECT(..PythonClass) {
		set body = ##class(%SYS.Python).None()
		if pFHIRResponse.Json '= "" {
			set jsonLib = ##class(%SYS.Python).Import("json")
			set body = jsonLib.loads(pFHIRResponse.Json.%ToJSON())
		}
		do ..PythonClass."on_after_request"(pFHIRService, pFHIRRequest, pFHIRResponse, body)
	}
}
  • E por aí em diante...

Interactions em Python

A classe FHIR.Python.Interactions chama os métodos on_before_request, on_after_request, ... da classe Python.

Aqui está uma classe Python abstrata:

import abc
import iris

class Interaction(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def on_before_request(self, 
                          fhir_service:'iris.HS.FHIRServer.API.Service',
                          fhir_request:'iris.HS.FHIRServer.API.Data.Request',
                          body:dict,
                          timeout:int):
        """
        on_before_request é chamada depois que a requisição é enviada ao servidor.
        param fhir_service: o objeto de serviço fhir iris.HS.FHIRServer.API.Service
        param fhir_request: o objeto de requisição fhir iris.FHIRServer.API.Data.Request
        param timeout: o tempo limite de execução em segundos
        return: None
        """
        

    @abc.abstractmethod
    def on_after_request(self,
                         fhir_service:'iris.HS.FHIRServer.API.Service',
                         fhir_request:'iris.HS.FHIRServer.API.Data.Request',
                         fhir_response:'iris.HS.FHIRServer.API.Data.Response',
                         body:dict):
        """
        on_after_request é chamada após a requisição ser enviada ao servidor.
        param fhir_service: o objeto de serviço fhir iris.HS.FHIRServer.API.Service
        param fhir_request: o objeto de requisição fhir iris.FHIRServer.API.Data.Request
        param fhir_response: o objeto de resposta fhir iris.FHIRServer.API.Data.Response
        return: None
        """
        

    @abc.abstractmethod
    def post_process_read(self,
                          fhir_object:dict) -> bool:
        """
        post_process_read é chamado após a operação de leitura finalizar.
        param fhir_object: o objeto fhir
        return: True - o recurso deve ser  retornado ao cliente, False - caso contrário
        """
        

    @abc.abstractmethod
    def post_process_search(self,
                            rs:'iris.HS.FHIRServer.Util.SearchResult',
                            resource_type:str):
        """
        post_process_search é chamada após a operação de pesquisa finalizar.
        param rs: o resultado da pesquisa iris.HS.FHIRServer.Util.SearchResult
        param resource_type: o tipo de recurso
        return: None
        """

Implementação da classe Python abstrata

from FhirInteraction import Interaction

class CustomInteraction(Interaction):

    def on_before_request(self, fhir_service, fhir_request, body, timeout):
        # Extrai o usuário e seus papéis para essa requisição
        # então o consentimento pode avaliado.
        self.requesting_user = fhir_request.Username
        self.requesting_roles = fhir_request.Roles

    def on_after_request(self, fhir_service, fhir_request, fhir_response, body):
        # Limpa o usuário e seus papéis entre as requisições.
        self.requesting_user = ""
        self.requesting_roles = ""

    def post_process_read(self, fhir_object):
        # Avalia consentimento baseado no recurso e usuários/papéis
        # Retornar 0 indica que esse recurso não deveria ser exibido - um erro  "404 Not Found" (não encontrado)
        # Será retornado ao usuário.
        return self.consent(fhir_object['resourceType'],
                        self.requesting_user,
                        self.requesting_roles)

    def post_process_search(self, rs, resource_type):
        # Itera por cada recurso no conjunto de pesquisa e avalia
        # Consentimento baseado no recurso e usuário/papéis
        # Cada linha marcada como deletada e salva será excluída do Bundle (conjunto ad resposta).
        rs._SetIterator(0)
        while rs._Next():
            if not self.consent(rs.ResourceType,
                            self.requesting_user,
                            self.requesting_roles):
                # Marca a linha como deletada e salva.
                rs.MarkAsDeleted()
                rs._SaveRow()

    def consent(self, resource_type, user, roles):
        # Exemplo de lógica de consentimento - só permite que usuários com o papel '%All' vejam
        # Recursos de observações.
        if resource_type == 'Observation':
            if '%All' in roles:
                return True
            else:
                return False
        else:
            return True

Muito longo, faça um resumo

A classe FHIR.Python.Interactions é um invólucro para chamar a classe Python.

As classes abstratas IRSI são implementadas para envolver as classes abstratas Python 🥳.

Isso nos ajuda a manter o código Python e o código ObjectScript separados e então se beneficiar do melhor dos dois mundos.

0
0 93
Artigo Nicole Raimundo · Maio 16, 2024 9m read

DNA Similarity and Classification é uma API REST utilizando a tecnologia InterSystems Vector Search para investigar semelhanças genéticas e classificar eficientemente sequências de DNA. Este é um aplicativo que utiliza técnicas de inteligência artificial, como aprendizado de máquina, aprimorado por recursos de pesquisa vetorial, para classificar famílias genéticas e identificar DNAs semelhantes conhecidos a partir de um DNA de entrada desconhecido.

Análise K-mer: Fundamentos em Análise de Sequência de DNA

1
1 133
Artigo Lucas Fernandes · Maio 16, 2024 2m read

A introdução da "Pesquisa Vetorial" da InterSystems marca uma mudança de paradigma no processamento de dados. Esta tecnologia de ponta emprega um modelo de incorporação para transformar dados não estruturados, como texto, em vetores estruturados, resultando em capacidades de pesquisa significativamente aprimoradas. Inspirados por esta inovação, desenvolvemos um motor de busca especializado e adaptado às empresas.

Aproveitamos a inteligência artificial generativa para gerar resumos abrangentes dessas empresas, oferecendo aos usuários uma ferramenta poderosa e informativa.

0
0 78
Artigo Danusa Calixto · Mar. 12, 2024 9m read

Neste GitHub, você pode encontrar todas as informações sobre como usar um modelo de machine learning / IA do HuggingFace no Framework IRIS usando python.

1. iris-huggingface

Uso de modelos de machine learning no IRIS usando Python. Para modelos text-to-text, text-to-image e image-to-image.

Modelos de exemplo:

2. Instalação

2.1. Iniciando a produção

Na pasta iris-local-ml, abra um terminal e insira:

docker-compose up

Na primeira vez, pode levar alguns minutos para criar a imagem corretamente e instalar todos os módulos necessários para o Python.

2.2. Acesse a produção

Seguindo este link, acesse a produção: Acesse a produção

2.3. Encerrando a produção

docker-compose down

Como funciona

Por enquanto, alguns modelos talvez não funcionem com essa implementação, já que tudo é feito automaticamente, ou seja, não importa o modelo de entrada, tentaremos fazer com que funcione usando a biblioteca transformerspipeline.

Pipeline é uma ferramenta poderosa da equipe HuggingFace que analisa a pasta em que o modelo foi baixado e entende qual biblioteca deve usar entre PyTorch, Keras, Tensorflow ou JAX. Em seguida, ela carrega esse modelo usando AutoModel.
Então, ao inserir a tarefa, o pipeline sabe o que fazer com o modelo, tokenizer ou até extrator de características nessa pasta e gerencia a entrada automaticamente, tokeniza, processa, transfere para o modelo e retorna um resultado decodificado que podemos usar diretamente.

3. API do HuggingFace

Primeiro, você precisa iniciar a demonstração, usando o botão verde Start, ou use Stop e Start novamente para aplicar as mudanças nas configurações.

Em seguida, ao clicar na operação Python.HFOperation escolhida e selecionar na guia à direita action, você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.HFRequest

Para json, veja um exemplo de uma chamada para GPT2:

{
    "api_url":"https://api-inference.huggingface.co/models/gpt2",
    "payload":"Can you please let us know more details about your ",
    "api_key":"----------------------"
}

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que você precisa ter uma chave de API do HuggingFace antes de usar essa Operação (as chaves de API são gratuitas, basta fazer a inscrição na HF)

OBSERVE que você pode mudar o URL para testar outros modelos do HuggingFace. Talvez seja necessário mudar o payload.

Veja este exemplo:
sending hf reqhf reqhf resp

4. Use qualquer modelo da web

Nesta seção, vamos ensinar você a usar praticamente qualquer modelo da internet, HuggingFace ou não.

4.1. PRIMEIRO CASO: VOCÊ TEM SEU PRÓPRIO MODELO

Nesse caso, você precisa copiar e colar seu modelo, com config, tokenizer.json etc. dentro de uma pasta na pasta do modelo.
Caminho: src/model/yourmodelname/

Depois, você precisa acessar os parâmetros de Python.MLOperation.
Clique em Python.MLOperation e vá para settings na guia à direita. Depois, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja a configuração padrão para esse caso:
%settings

name=yourmodelname
task=text-generation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE.

Agora você pode clicar duas vezes na operação Python.MLOperation e executar o start. Você precisa ver na parte Log a inicialização do modelo.

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

Para chamar esse pipeline, clique na operação Python.MLOperation e selecione action na guia à direita. Você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Aqui está um exemplo de uma chamada para GPT2:

{
    "text_inputs":"Unfortunately, the outcome",
    "max_length":100,
    "num_return_sequences":3
}

Clique em Invoke Testing Service (Invocar serviço de teste) e aguarde a operação do modelo.

Veja este exemplo:
sending ml req

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

Veja este exemplo:
ml req

ml resp

4.2. SEGUNDO CASO: VOCÊ QUER BAIXAR UM MODELO DO HUGGINGFACE

Nesse caso, você precisa encontrar o URL do modelo no HuggingFace.

4.2.1. Configurações

Depois, você precisa acessar os parâmetros de Python.MLOperation.
Clique em Python.MLOperation e vá para settings na guia à direita. Depois, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja um exemplo de configuração para alguns modelos que encontramos no HuggingFace:

%settings para gpt2

model_url=https://huggingface.co/gpt2
name=gpt2
task=text-generation

%settings para camembert-ner

name=camembert-ner
model_url=https://huggingface.co/Jean-Baptiste/camembert-ner
task=ner
aggregation_strategy=simple

%settings para bert-base-uncased

name=bert-base-uncased
model_url=https://huggingface.co/bert-base-uncased
task=fill-mask

%settings para detr-resnet-50

name=detr-resnet-50
model_url=https://huggingface.co/facebook/detr-resnet-50
task=object-detection

%settings para detr-resnet-50-protnic

name=detr-resnet-50-panoptic
model_url=https://huggingface.co/facebook/detr-resnet-50-panoptic
task=image-segmentation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE. Então, no segundo exemplo, o pipeline camembert-ner requer a especificação de aggregation_strategy e task, enquanto gpt2 requer apenas uma task.

Veja este exemplo:
settings ml ope2

Agora você pode clicar duas vezes na operação Python.MLOperation e executar o start.
Você precisa ver na parte Log a inicialização e o download do modelo.
OBSERVAÇÃO Você pode atualizar esses logs a cada x segundos para ver o avanço dos downloads. dl in real time

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

4.2.2. Testes

Para chamar esse pipeline, clique na operação Python.MLOperation e selecione action na guia à direita. Você pode aplicar test à demonstração.

Na janela de test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Aqui está um exemplo de uma chamada para GPT2 (Python.MLOperation):

{
    "text_inputs":"George Washington lived",
    "max_length":30,
    "num_return_sequences":3
}

Aqui está um exemplo de uma chamada para Camembert-ner (Python.MLOperation2):

{
    "inputs":"George Washington lived in washington"
}

Aqui está um exemplo de uma chamada para bert-base-uncased (Python.MLOperation3):

{
    "inputs":"George Washington lived in [MASK]."
}

Aqui está um exemplo de uma chamada para detr-resnet-50 usando um URL online (Python.MLOperationDETRRESNET):

{
    "url":"http://images.cocodataset.org/val2017/000000039769.jpg"
}

Aqui está um exemplo de uma chamada para detr-resnet-50-panoptic usando um URL como caminho (Python.MLOperationDetrPanoptic):

{
    "url":"/irisdev/app/misc/000000039769.jpg"
}

Clique em Invoke Testing Service (Invocar serviço de teste) e aguarde a operação do modelo.
Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que, após fazer pela primeira vez o download de um modelo, a produção não fará o download novamente, mas usará os arquivos em cache encontrados em src/model/TheModelName/.
Se alguns arquivos estiverem ausentes, a Produção fará o download novamente.

Veja este exemplo:
sending ml reqml reqml resp

Veja este exemplo:
sending ml reqml resp

5. Solução de problemas

Se você tiver problemas, a leitura é o primeiro conselho que podemos dar a você. A maioria dos erros são facilmente compreendidos apenas ao ler os logs, pois quase todos os erros são capturados por um try/catch e registrados.

Se você precisar instalar um novo módulo ou dependência do Python, abra um terminal dentro do contêiner e digite, por exemplo: "pip install new-module"
Há várias formas de abrir um terminal,

  • Se você usa os plugins da InterSystems, pode clicar na barra abaixo no VSCode, que se parece com docker:iris:52795[IRISAPP], e selecionar Open Shell in Docker (Abrir Shell no Docker).
  • Em qualquer terminal local, digite: docker-compose exec -it iris bash
  • No Docker-Desktop, encontre o contêiner IRIS e clique em Open in terminal (Abrir no terminal)

Alguns modelos talvez exijam algumas alterações no pipeline ou nas configurações, por exemplo. É sua responsabilidade adicionar as informações corretas nas configurações e na solicitação.

6. Conclusão

Depois disso, você poderá usar qualquer modelo que de precisa ou possui no IRIS.
OBSERVE que você pode criar uma Python.MLOperation para cada um dos seus modelos e ter todos ativados ao mesmo tempo.

0
0 166
Artigo Danusa Calixto · jan 10, 2024 2m read

No momento, vários artistas digitais usam a tecnologia de IA generativa como apoio para acelerar a entrega das suas obras. Hoje em dia, é possível gerar uma imagem correspondente a partir de uma frase. Há várias soluções no mercado para isso, incluindo algumas disponíveis para uso por APIs. Veja algumas neste link: https://www.analyticsvidhya.com/blog/2023/08/ai-image-generators/.

Criei um novo aplicativo para usar no IRIS aproveitando uma dessas APIs. Escolhi a API Imagine. Ela permite até 50 chamadas gratuitas por dia e tem um pacote pago interessante que possibilita a criação de milhares de imagens por mês. Para assinar a API e obter uma chave de API para usar o serviço, acesse: https://platform.imagine.art/dashboard/auth.

Depois disso, você pode usar meu aplicativo, alterando sua chave, gerar o JAR, copiar para a raiz do meu projeto IRIS e gerar suas imagens. Meu projeto está em https://github.com/yurimarx/imageaicreator.

O Criador de imagens de IA em ação

1. Copie, compile e execute o projeto docker:

git clone https://github.com/yurimarx/imageaicreator.git
$ docker-compose build
$ docker-compose up -d

2. Abra http://localhost:/swagger-ui/index.html. No swagger explore, coloque http://localhost:/image-ai-creator/_spec:

3. Execute o método /generate passando no corpo um texto com instruções para gerar a imagem (em inglês):

4. Baixe o arquivo png no link Download file (Baixar arquivo) e veja os resultados:

5. Veja a imagem para a frase "a ragdoll playing tennis", ou um ragdoll jogando tênis, (a IA sabe que ragdoll é uma raça de gatos, fantástico!):

0
0 85
Artigo Danusa Calixto · Set. 1, 2023 4m read

Visão geral

Com o cross-skilling do objectScript do IRIS para o Python, ficam claras algumas diferenças fascinantes na sintaxe.

Uma dessas áreas é como o Python retorna Tuplas de um método com desempacotamento automático.

Efetivamente, isso se apresenta como um método que retorna vários valores. Que invenção incrível :)

out1, out2 = some_function(in1, in2)

O ObjectScript tem uma abordagem diferente com o ByRef e os parâmetros de saída.

Do ##class(some_class).SomeMethod(.inAndOut1, in2, .out2)

Onde:

  • inAndOut1 é o ByRef
  • out2 é a saída

O ponto à esquerda (".") na frente do nome da variável passa o ByRef e a saída.

A finalidade deste artigo é descrever como a comunidade do utilitário PyHelper foi otimizada para oferecer uma maneira pythônica de aproveitar o ByRef e os parâmetros de saída. Ele dá acesso a %objlasterror e tem uma abordagem para lidar com o tipo None do Python.
 

ByRef de exemplo

A invocação normal para o embedded python seria:

oHL7=iris.cls("EnsLib.HL7.Message")._OpenId('er12345')

Quando a abertura desse método falha, a variável "oHL7" é uma string vazia.
Na assinatura desse método, há um parâmetro de status disponível para o object script que fornece uma explicação do problema exato.
Por exemplo:

  • O registro pode não existir
  • Não foi possível abrir o registro no modo de simultaneidade exclusiva padrão ("1"), dentro do tempo limite
ClassMethod %OpenId(id As %String = "", concurrency As %Integer = -1, ByRef sc As %Status = {$$$OK}) As %ObjectHandle

O método TupleOut pode ajudar no retorno do valor do argumento sc, de volta a um contexto python.
 

> oHL7,tsc=iris.cls("alwo.PyHelper").TupleOut("EnsLib.HL7.Message","%OpenId",['sc'],1,'er145999', 0)
> oHL7
''
> iris.cls("%SYSTEM.Status").DisplayError(tsc)
ERROR #5809: Object to Load not found, class 'EnsLib.HL7.Message', ID 'er145999'1
```

A lista ['sc'] contém um único item nesse caso. Ela pode retornar vários valores Byref, e na ordem especificada. O que é útil para descompactar automaticamente as variáveis pretendidas do Python.

Exemplo de como lidar com um parâmetro de saída

Código em Python:

> oHL7=iris.cls("EnsLib.HL7.Message")._OpenId('145')
> oHL7.GetValueAt('&lt;%MSH:9.1')
''

A string retornada está vazia, mas isso se deve ao elemento realmente estar vazio OU algo que deu errado.
No object script, há também um parâmetro de status de saída (pStatus) que pode ser acessado para determinar essa condição.

Código em object script:

> write oHL7.GetValueAt("&lt;%MSH:9.1",,.pStatus)
''
> Do $System.Status.DisplayError(pStatus)
ERROR &lt;Ens>ErrGeneral: No segment found at path '&lt;%MSH'

Com TupleOut, a funcionalidade equivalente pode ser obtida ao retornar e descompactar ambos o valor de retorno do método E o parâmetro de saída do status.

Código em Python:

> hl7=iris.cls("EnsLib.HL7.Message")._OpenId(145,0)
> val, status = iris.cls("alwo.PyHelper").TupleOut(hl7,"GetValueAt",['pStatus'],1,"&lt;&$BadMSH:9.1")
> val==''
True
> iris.cls("%SYSTEM.Status").IsError(status)
1
> iris.cls("%SYSTEM.Status").DisplayError(status)
ERROR &lt;Ens>ErrGeneral: No segment found at path '&lt;&$BadMSH'1

###Variável especial %objlasterror

No objectscript, há acesso a variáveis de porcentagem no escopo do método.
Há cenários em que detectar ou acessar a variável especial %objlasterror é útil após chamar uma API de terceiros ou CORE
O método TupleOut permite o acesso a %objlasterror, como se tivesse sido definido como um parâmetro de saída, ao invocar métodos do Python

> del _objlasterror

> out,_objlasterror=iris.cls("alwo.PyHelper").TupleOut("EnsLib.HL7.Message","%OpenId",['%objlasterror'],1,'er145999', 0) 

> iris.cls("%SYSTEM.Status").DisplayError(_objlasterror)
ERROR #5809: Object to Load not found, class 'EnsLib.HL7.Message', ID 'er145999'1

Quando None não é uma String

O TupleOut lida com as referências a None do Python como objectscript indefinido. Isso permite que os parâmetros sejam padronizados e os métodos se comportem de forma consistente.
Isso é importante, por exemplo, com %Persistent::%OnNew, em que o método %OnNew não é acionado quando None é fornecido para initvalue, mas seria acionado se uma string vazia fosse fornecida.

No objectscript, a implementação pode dizer:

do oHL7.myMethod("val1",,,"val2")

Observe a ausência de variáveis entre vírgulas.

O TupleOut facilita o mesmo comportamento com:

Python:

iris.cls("alwo.PyHelper").TupleOut(oHL7,"myMethod",[],0,"val1",None,None,"val2")

Outra maneira de considerar isso é poder ter uma implementação de uma linha de código de invocação, com um comportamento flexível dependendo da pré-configuração das variáveis:

Object Script:

set arg1="val1"
kill arg2
kill arg3
set arg4="val2"
do oHL7.myMethod(.arg1, .arg2, .arg3, .arg4)

O TupleOut facilita o mesmo comportamento com:

Python:

arg1="val1"
arg2=None
arg3=None
arg4="val2"
iris.cls("alwo.PyHelper").TupleOut(oHL7,"myMethod",[],0,arg1,arg2,arg3,arg4)

Lista e dicionários

Ao lidar com parâmetros para entrada, ByRef e saída, o TupleOut utiliza o mapeamento automático do PyHelper entre:
Listas do IRIS e do Python
Arrays do IRIS e do Python
Onde é preciso sempre usar strings para representar as chaves do dicionário ao passar de Arrays do IRIS para tipos Dict do Python.

Conclusão

Espero que este artigo ajude a inspirar novas ideias, discussões e sugestões sobre o Embedded Python.

Também espero que incentive a explorar a flexibilidade do IRIS em se adaptar facilmente para enfrentar novos desafios.

0
0 52
Artigo Claudio Devecchi · Jun. 20, 2023 4m read

Neste artigo, vou compartilhar o tema que apresentamos no Global Summit 2023, na sessão Tech Exchange. Eu e @Rochael.Ribeiro.

Nesta oportunidade, abordamos os seguintes tópicos, os quais iremos explorar neste artigo:

  • Ferramentas Open Exchange para o desenvolvimento rápido de APIs
  • Open Api Specification (OAS)
  • Maneira Tradicional versus Desenvolvimento Rápido
  • API Composta (Interoperabilidade)
  • Abordagens Spec-First ou Api-First
  • Governança e Monitoramento de Api's
  • Demonstração (vídeo)

Ferramentas Open Exchange para o Desenvolvimento Rápido de APIs Rest

4
0 145
Artigo Danusa Calixto · Out. 18, 2022 17m read

Olá a todos, sou um estudante francês que acabou de chegar em Praga para um intercâmbio acadêmico no meu quinto ano da faculdade de engenharia e aqui está minha participação no concurso de interoperabilidade.

Não tive muito tempo para programar desde a mudança da França para Praga e estou participando sozinho, então decidi criar um projeto que é mais um modelo do que um aplicativo.

Queria participar já que minha área (Ciência de Dados e IA) não é geralmente associada à sustentabilidade, e o concurso era uma maneira de me expressar nesse tema importante que é a sustentabilidade e o meio ambiente.

Como você sabe, a Inteligência Artificial está cada vez mais popular, com várias firmas conhecidas tentando seguir o movimento e vender ferramentas para criar, treinar e usar modelos de machine learning com facilidade. Tudo isso é prático e fácil, mas tem um custo, financeiro e também ambiental.

Treinar modelos enormes repetidamente pode exigir muitos recursos e produzir uma grande quantidade de CO2. Os supercomputadores são executados durante vários dias, e o período e o tamanho dos modelos estão aumentando exponencialmente, tomando mais espaço do que nunca. Todo esse esforço para ter alguma melhoria no desempenho, que em alguns casos não é nem garantida.

É claro que várias firmas precisam desse processo, em que até mesmo 0,1% de melhoria na precisão de um modelo pode salvar milhares de vidas. Por isso, esse modelo foi criado para usos mais comuns.

No entanto, como tive a oportunidade de trabalhar com Processamento de Linguagem Natural (PLN) ou Classificação de Imagens, percebi que alguns modelos e ferramentas já são quase utilizáveis no estado em que se encontram e podem nos ajudar a economizar centenas de horas de treinamento e, consequentemente, emissões de CO2 e consumo de eletricidade.

Por isso, decidi criar um modelo usando as tecnologias da InterSystems para desenvolver uma solução interoperável que resolvesse alguns problemas de sustentabilidade ao permitir facilmente que você, em alguns cliques, faça o download único de modelos pré-treinados da Internet, use de acordo com sua própria necessidade e, claro, ajuste esses modelos pré-treinados com novo conteúdo disponível na base de dados IRIS e adicione conteúdo ao modelo existente.

Dessa forma, no modelo, estamos pegando um modelo PLN, testando e treinando com dados para criar cinco novos rótulos no modelo para classificar a avaliação da internet.

Portanto, ao fazer isso, o resultado (se você tiver tempo e algum poder computacional) é um ótimo modelo que pode ser usado para prever a nota de avaliação da internet, que não tem custo e emite uma quantidade pequena de CO2.

Consulte o GitHub e a postagem do Open Exchange vinculada a este artigo.

Ou veja o ReadMe aqui:

1. Contest-Sustainability

Este modelo usa as tecnologias da InterSystems para desenvolver uma solução interoperável e resolver alguns problemas de sustentabilidade ao permitir facilmente que você, em alguns cliques, faça o download único de modelos pré-treinados da Internet, use de acordo com sua própria necessidade e, claro, ajuste esses modelos pré-treinados com novo conteúdo disponível na base de dados IRIS e adicione conteúdo ao modelo existente.

Neste exemplo, estamos pegando um modelo PLN, testando e treinando com dados para criar cinco novos rótulos no modelo para classificar a avaliação da internet. No processo, poupamos uma grande quantidade de recursos e emissões de CO2.

Veja alguns modelos de exemplo que você pode testar: https://huggingface.co/gpt2
https://huggingface.co/Jean-Baptiste/camembert-ner
https://huggingface.co/bert-base-uncased
https://huggingface.co/facebook/detr-resnet-50
https://huggingface.co/facebook/detr-resnet-50-panoptic

ÍNDICE:

2. Instalação

2.1. Início da produção

Na pasta "contest-sustainability", abra um terminal e insira:

docker-compose up

Na primeira vez, talvez leve alguns minutos para o build correto da imagem e a instalação de todos os módulos necessários para o Python.

2.2. Acesso à produção

Seguindo este link, acesse a produção: Acessar a produção

2.3. Encerramento da produção

docker-compose down

3. Como funciona

Por enquanto, alguns modelos talvez não funcionem com essa implementação, já que tudo é feito automaticamente, ou seja, não importa o modelo de entrada, tentaremos fazer com que funcione usando a biblioteca transformerspipeline.

Pipeline é uma ferramenta poderosa da equipe HuggingFace que analisa a pasta em que o modelo foi transferido e entende qual biblioteca deve usar entre PyTorch, Keras, Tensorflow ou JAX. Em seguida, ela carrega esse modelo usando AutoModel.
Então, ao inserir a tarefa, o pipeline sabe o que fazer com o modelo, tokenizer ou até extrator de características nessa pasta e gerencia a entrada automaticamente, tokeniza, processa, transfere para o modelo e retorna um resultado decodificado que podemos usar diretamente.

4. API HuggingFace

Algumas pessoas ou sistemas não conseguem fazer o download de modelos ou usá-los devido a restrições. Por isso, é possível usar a API HuggingFace e chamar alguns modelos diretamente através desse serviço.
Veja uma explicação mais simples:

Primeiro, você precisa iniciar a demonstração, usando o botão verde Start, ou use Stop e Start novamente para aplicar as mudanças nas configurações.

Em seguida, ao clicar na operação Python.HFOperation escolhida e selecionar na guia à direita action, você pode aplicar test à demonstração.

Na janela test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.HFRequest

Para json, veja um exemplo de uma chamada para GPT2:

{
    "api_url":"https://api-inference.huggingface.co/models/gpt2",
    "payload":"Can you please let us know more details about your ",
    "api_key":"----------------------"
}

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que você precisa ter uma chave de API do HuggingFace antes de usar esta Operação (as chaves de API são gratuitas, basta fazer a inscrição no HF)

OBSERVE que você pode mudar o URL para testar outros modelos do HuggingFace. Talvez seja necessário mudar o payload.

Veja este exemplo:
envio de hf reqhf reqhf resp

5. Use qualquer modelo da Web

Nesta seção, vamos ensinar você a usar praticamente qualquer modelo pré-treinado da internet, HuggingFace ou não, para poupar recursos ou simplesmente usar esses modelos dentro do IRIS.

5.1. PRIMEIRO EXEMPLO: VOCÊ TEM SEU PRÓPRIO MODELO

Nesse caso, você precisa copiar e colar seu modelo, com config, tokenizer.json etc. dentro de uma pasta na pasta do modelo.
Caminho: src/model/yourmodelname/

Em seguida, você precisa criar uma nova operação, chame-a como quiser e acesse os parâmetros dessa operação.
Então, acesse settings na guia à direita, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja a configuração padrão para esse caso:
%settings

name=yourmodelname
task=text-generation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE.

Agora você pode clicar duas vezes na operação e executar o start. Você precisa ver na parte Log a inicialização do modelo.

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

Para chamar esse pipeline, clique na operação e selecione na guia à direita action. Você pode aplicar test à demonstração.

Na janela test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Veja um exemplo de uma chamada para GPT2:

{
    "text_inputs":"Unfortunately, the outcome",
    "max_length":100,
    "num_return_sequences":3
}

Clique em Invoke Testing Service e aguarde a operação do modelo.

Veja este exemplo:
envio de ml req

Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

Veja este exemplo :
ml req

ml resp

5.2. SEGUNDO EXEMPLO: VOCÊ QUER FAZER O DOWNLOAD DE UM MODELO DO HUGGINGFACE

Nesse caso, você precisa encontrar o URL do modelo no HuggingFace.
Encontre um modelo que faça o que você busca e use-o sem gastar recursos utilizando as tecnologias da InterSystems.

5.2.1. Configurações

Vá até os parâmetros do Hugging.
Clique na operação HuggingFace escolhida e acesse settings na guia à direita, na parte Python e na parte %settings. Aqui, você pode inserir ou modificar quaisquer parâmetros (não se esqueça de pressionar apply depois de terminar).
Veja um exemplo de configuração para alguns modelos que encontramos no HuggingFace:

%settings para gpt2

model_url=https://huggingface.co/gpt2
name=gpt2
task=text-generation

%settings para camembert-ner

name=camembert-ner
model_url=https://huggingface.co/Jean-Baptiste/camembert-ner
task=ner
aggregation_strategy=simple

%settings para bert-base-uncased

name=bert-base-uncased
model_url=https://huggingface.co/bert-base-uncased
task=fill-mask

%settings para detr-resnet-50

name=detr-resnet-50
model_url=https://huggingface.co/facebook/detr-resnet-50
task=object-detection

%settings para detr-resnet-50-protnic

name=detr-resnet-50-panoptic
model_url=https://huggingface.co/facebook/detr-resnet-50-panoptic
task=image-segmentation

OBSERVE que qualquer configuração que não for name ou model_url entrará nas configurações PIPELINE. Então, no segundo exemplo, o pipeline camembert-ner requer a especificação de aggregation_strategy e task, enquanto gpt2 requer apenas uma task.

Veja este exemplo:
configurações ml ope2

Agora você pode clicar duas vezes na operação e executar o start.
Você precisa ver na parte Log a inicialização e o download do modelo.
OBSERVAÇÃO: Você pode atualizar os registros a cada x segundos para ver o avanço dos downloads. dl em tempo real

Em seguida, criamos um PIPELINE utilizando transformers que usam o arquivo config na pasta como vimos antes.

5.2.2. Teste

Para chamar esse pipeline, clique na operação e selecione na guia à direita action. Você pode aplicar test à demonstração.

Na janela test, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo.
Veja um exemplo de uma chamada para GPT2:

{
    "text_inputs":"George Washington lived",
    "max_length":30,
    "num_return_sequences":3
}

Aqui está um exemplo de uma chamada para Camembert-ner:

{
    "inputs":"George Washington lived in washington"
}

Aqui está um exemplo de uma chamada para bert-base-uncased:

{
    "inputs":"George Washington lived in [MASK]."
}

Aqui está um exemplo de uma chamada para detr-resnet-50 usando um URL online:

{
    "url":"http://images.cocodataset.org/val2017/000000039769.jpg"
}

Aqui está um exemplo de uma chamada para detr-resnet-50-panoptic usando um URL como caminho:

{
    "url":"/irisdev/app/misc/000000039769.jpg"
}

Clique em Invoke Testing Service e aguarde a operação do modelo.
Agora, você pode clicar em Visual Trace para ver nos detalhes o que aconteceu e visualizar os registros.

OBSERVE que, após fazer pela primeira vez o download de um modelo, a produção não fará o download novamente, mas usará os arquivos em cache encontrados em src/model/TheModelName/.
Se alguns arquivos estiverem ausentes, a Produção fará o download novamente.

Veja este exemplo:
envio de ml reqml reqml resp

Veja este exemplo:
envio de ml reqml resp

6. Ajuste dos modelos

Nesta parte, tentamos ajustar um modelo para reaproveitá-lo e torná-lo ainda melhor sem usar muitos recursos.

6.1. Personalização do modelo

6.1.1. Download do modelo

Para utilizar esse GitHub, você precisa ter um modelo do HuggingFace compatível com pipeline para usar e treinar, além de um conjunto de dados para treinar seu modelo.

Para ajudar, oferecemos a possibilidade de usar script Python em src/utils/download_bert.py. Ele fará o download para você do modelo "https://huggingface.co/bert-base-cased" e colocará dentro da pasta src/model/bert-base-cased se já não estiver lá.
Além disso, também disponibilizamos um conjunto de dados para treinar o modelo bert. Esse conjunto de dados já estava carregado dentro da base de dados IRIS e nenhuma ação adicional é necessária se você quiser usá-lo. (Para acessá-lo, vá até a parte SQL do portal, o namespace da base de dados iris e depois a tabela de revisão)

Para usar o script, se você estiver no contêiner, pode executá-lo sem se preocupar. Se você estiver no local, talvez seja necessário aplicar pip3 install requests e pip3 install beautifulsoup4

Veja o resultado: Download do resultado

6.1.2. Configurações

Se você quiser usar o modelo bert-base-cased e já fez o download usando o script, não é necessário adicionar mais nada às configurações, e você pode avançar para o treinamento do modelo.

Se você quiser treinar seu próprio modelo, clique em Python.TuningOperation e selecione Settings na guia à direita, depois Python e, na parte %settings, insira o caminho do modelo, o nome da pasta e o número do rótulo que você quer para o treinamento.

Exemplo:

path=/irisdev/app/src/model/
model_name=bert-base-cased
num_labels=5

6.1.3. Treinamento do modelo

Para treinar o modelo, você precisa acessar Production neste link:

http://localhost:52795/csp/irisapp/EnsPortal.ProductionConfig.zen?PRODUCTION=iris.Production

E conectar usando:
SuperUser como nome de usuário e SYS como senha.


Para chamar o treinamento, clique em Python.TuningOperation e selecione na guia à direita Actions. Você pode aplicar Test à demonstração.

Na janela de teste, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.TrainRequest

Para json, você precisa inserir todos os argumentos necessários para o treinamento. Aqui está um exemplo que treina com as primeiras 20 linhas (não é um treinamento adequado, mas é rápido):

{
    "columns":"ReviewLabel,ReviewText",
    "table":"iris.Review",
    "limit":20,
    "p_of_train":0.8,

    "output_dir":"/irisdev/app/src/model/checkpoints",
    "evaluation_strategy":"steps",
    "learning_rate":0.01,
    "num_train_epochs":1
}

Veja este exemplo: Pedido de treinamento

Como pode ver, é preciso inserir

  • a table usada.
  • as columns usadas (primeiro é label e segundo é input para a tokenização)
  • o limit de linhas compreendidas (se você não especificar um número de linhas, todos os dados serão usados)
  • p_of_train, a porcentagem de dados de treinamento usados do conjunto de dados, e 1 - p_of_train, a porcentagem de dados de teste usados do conjunto de dados.

Depois disso, os outros parâmetros cabem a você e podem variar de acordo com os parâmetros https://huggingface.co/docs/transformers/main_classes/trainer.

OBSERVE que o tamanho do lote para treinamento e teste será calculado automaticamente se não for inserido na solicitação. (É o maior divisor do número de linhas que é menor do que a raiz quadrada do número de linhas e do que 32)

Clique em "Invoke Testing Service" e feche a janela de teste sem esperar.
Agora acesse Python.TuningOperation e selecione na guia à direita log. Aqui você pode ver o avanço do treinamento e das avaliações.
Após a conclusão, você verá um log dizendo que o novo modelo foi salvo em uma pasta temporária.
Agora acesse Python.TuningOperation, selecione na guia à direita message e clique no cabeçalho do último item para selecioná-lo. Aqui você pode ver o avanço do treinamento e das avaliações e, ao final, é possível acessar as Métricas do modelo novo e antigo para comparação.

6.1.4. Substituição do modelo

Se você quiser manter o modelo antigo, nenhuma ação é necessária: o antigo permanecerá na pasta não temporária e ainda será carregado para treinamento adicional.

Se você quiser manter o modelo novo, clique em Python.TuningOperation, selecione na guia à direita Actions e teste. Na janela de teste, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.OverrideRequest

Para json, chaves vazias:

{}

Clique em Invoke Testing Service e veja a mensagem de resposta. O novo modelo foi movido da pasta temporária para a não temporária.

6.2. Uso do modelo

Treinar um modelo é interessante, mas você também pode testá-lo.

6.2.1. Configurações

Se você quiser usar o modelo bert-base-cased e já fez o download usando o script, não é necessário adicionar mais nada às configurações, e você pode avançar para o teste do modelo.

Se você quiser treinar seu próprio modelo, clique em Python.TuningOperation e selecione Settings na guia à direita, depois Python e, na parte %settings, insira o parâmetro para adicionar ao pipeline.

6.2.2. Teste do modelo

Para testar o modelo, você precisa acessar Production neste link:

http://localhost:52795/csp/irisapp/EnsPortal.ProductionConfig.zen?PRODUCTION=iris.Production

E conectar usando:
SuperUser como nome de usuário e SYS como senha.


Para chamar o teste, clique em Python.MLOperation e selecione na guia à direita Actions. Você pode aplicar Test à demonstração.

Na janela de teste, selecione:

Tipo de solicitação: Grongier.PEX.Message

Em classname, insira:

msg.MLRequest

Para json, você precisa inserir todos os argumentos necessários para o modelo funcionar

{
    "inputs":"This was a really bad experience"
}

Pressione Call test services e veja o resultado.

7. Observação importante

O ajuste fino de modelos pode exigir MUITO tempo e recursos, mas sempre consumirá menos recursos do que o treinamento de um modelo do zero.
Você pode ver que já está levando muito tempo e poder computacional para o ajuste fino do modelo, então imagine o custo se tivesse que treiná-lo do zero e começar de novo várias vezes para obter resultados ideais.

8. Solução de problemas

Se você tiver problemas, a leitura é o primeiro conselho que podemos dar a você. A maioria dos erros são facilmente compreendidos apenas ao ler os logs, pois quase todos os erros são capturados por um try/catch e registrados.

Se você precisar instalar um novo módulo ou dependência do Python, abra um terminal dentro do contêiner e digite, por exemplo: "pip install new-module"
Há várias formas de abrir um terminal,

  • Se você usa os plugins da InterSystems, pode clicar na barra abaixo no VSCode, que se parece com docker:iris:52795[IRISAPP], e selecionar Open Shell in Docker.
  • Em qualquer terminal local, digite: docker-compose exec -it iris bash
  • No Docker-Desktop, encontre o contêiner IRIS e clique em Open in terminal

Alguns modelos talvez exijam algumas alterações no pipeline ou nas configurações, por exemplo. É sua responsabilidade adicionar as informações corretas nas configurações e na solicitação.

9. Conclusão

Daqui em diante, você poderá usar modelos de que talvez precise no IRIS e ajustá-los como desejar.
Esse modelo precisa ser modificado para atender às suas necessidades e foi criado como base para qualquer projeto de IA e IRIS que considere a sustentabilidade e interoperabilidade.

Por falta de tempo, não consegui adicionar uma API que usasse um Diretor para se comunicar diretamente com a produção e permitir que os usuários fizessem solicitações aos modelos.
No entanto, se você ainda tiver interesse em uma API IRIS usando esse módulo do Python, confira meu GitHub ou acesse meu exemplo de API no Python para IRIS.

Link para meu perfil do DC: https://community.intersystems.com/user/lucas-enard-0

0
0 71
Artigo Danusa Calixto · Set. 13, 2022 31m read

A interoperabilidade é cada vez mais importante atualmente. O InterSystems IRIS 2022.1 tem uma nova API de mensagens para a comunicação com plataformas de streaming de eventos, como Kafka, AWS SQS/SNS, JMS e RabbitMQ.

Este artigo mostra como você pode se conectar ao Kafka e AWS SQS com facilidade.
Começamos com uma breve discussão dos conceitos e termos básicos das plataformas de streaming de eventos. 

Finalidade das plataformas de streaming de eventos e termos comuns

As plataformas de streaming de eventos, como Kafka ou AWS SQS, são capazes de consumir um stream de eventos sem restrições em uma frequência bastante alta e podem reagir a eventos. Os consumidores leem os dados dos streams para processamento adicional. Eles são geralmente usados em ambientes de IoT.

Os termos comuns nessa área são:

  • Tópico/Fila, o local onde os dados são armazenados
  • Produtor, cria e envia os dados (eventos, mensagens) para um tópico ou uma fila
  • Consumidor, lê os eventos/mensagens de um ou mais tópicos ou filas
  • Publicar/Assinar, os produtores enviam os dados para um tópico/fila (publicar), os consumidores assinam um tópico/fila e recebem notificações automáticas com a chegada de novos dados
  • Polling, os consumidores precisam buscar ativamente novos dados em um tópico/fila

Por que eles são usados?

  • Dissociação de produtores e consumidores
  • Altamente escalonável para dados em tempo real

Preciso mesmo deles? Como desenvolvedor do InterSystems IRIS, provavelmente não, mas você não está sozinho...

API de mensagens externas

As novas classes da API estão localizadas no pacote %External.Messaging. Ele contém as classes genéricas Client-, Settings- e Message.  As classes especializadas do Kafka, AWS SQS/SNS, JMS e RabbitMQ são subclasses dessas classes genéricas. 

O fluxo de comunicação básico é:

  1. Criar um objeto de configurações para a plataforma de destino. Isso também é responsável pela autenticação em relação à plataforma de destino.
  2. Criar um objeto de cliente específico e transmitir o objeto de configurações a ele.
  3. Criar um objeto de mensagem e enviar para o destino.

As seguintes seções demonstram como você pode se comunicar com Kafka e AWS SQS (Simple Queue Service).

Interação com o Kafka

Vamos começar com um exemplo do Kafka. Primeiro, criamos uma classe que usa a nova API %External Messaging para criar um tópico, enviar uma mensagem ao Kafka e receber uma mensagem dele.

Primeiro, ela cria um objeto de configurações do Kafka:

&lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
&lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
&lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>

Após definir o endereço do servidor do Kafka, ela define um ID de grupo do Kafka.

Com essas configurações, um objeto de cliente do Kafka é criado:

&lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)

Em seguida, um topico é criado ao invocar o método CreateTopic() do cliente do Kafka:

&lt;span class="hljs-keyword">Set&lt;/span> tSC = tClient.CreateTopic(pTopicName,tNumberOfPartitions,tReplicationFactor)

 Veja abaixo a amostra de código completa:

Include Kafka.Settings

&lt;span class="hljs-keyword">Class&lt;/span> Kafka.api [ Abstract ]
{

&lt;span class="hljs-keyword">ClassMethod&lt;/span> CreateTopic(pTopicName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> tNumberOfPartitions = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tReplicationFactor = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tSC = tClient.CreateTopic(pTopicName,tNumberOfPartitions,tReplicationFactor)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSC)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())
        }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}



}

Depois de criar um tópico, podemos enviar e receber mensagens do Kafka. O código é semelhante ao exibido acima.

&lt;span class="hljs-keyword">ClassMethod&lt;/span> SendMessage(pMessage &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pTopic &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tMessage &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tMessage = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.topic = pTopic
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.value = pMessage
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> producerSettings = &lt;span class="hljs-string">"{""key.serializer"":""org.apache.kafka.common.serialization.StringSerializer""}"&lt;/span>
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.UpdateProducerConfig(producerSettings))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.SendMessage(tMessage))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())

    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> ReceiveMessage(pTopicName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pGroupId &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span> = &lt;span class="hljs-string">"iris-consumer"&lt;/span>, Output pMessages) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tMessage &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = pGroupId
        
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> producerSettings = &lt;span class="hljs-string">"{""key.serializer"":""org.apache.kafka.common.serialization.StringSerializer""}"&lt;/span>
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.UpdateProducerConfig(producerSettings))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.ReceiveMessage(pTopicName, .pMessages))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())
        }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

Vamos testar. Com uma instância do Kafka em execução, criamos um tópico community com o método CreateTopic acima:

Ignore os avisos log4j aqui. O método retorna um código de status OK. Então, o tópico foi criado. Em seguida, vamos enviar uma mensagem para esse tópico. Para verificar que a mensagem foi enviada ao tópico, executo um consumidor do Kafka genérico. Esse consumidor ouve o tópico community:

Então, vamos enviar uma mensagem para esse tópico. Vou enviar uma JSON-String para ele, mas você basicamente pode enviar qualquer formato de mensagem para um tópico.

Vamos conferir se o consumidor recebeu a mensagem:

A mensagem foi recebida com sucesso pelo consumidor.

Para receber mensagens e excluir tópicos, é parecido com a amostra acima. Veja abaixo a implementação da amostra completa. O arquivo include Kafka.settings só contém uma definição macro: #define KAFKASERVER <Kafka server location and port>.

Include Kafka.Settings

&lt;span class="hljs-keyword">Class&lt;/span> Kafka.api [ Abstract ]
{

&lt;span class="hljs-keyword">ClassMethod&lt;/span> CreateTopic(pTopicName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> tNumberOfPartitions = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tReplicationFactor = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tSC = tClient.CreateTopic(pTopicName,tNumberOfPartitions,tReplicationFactor)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSC)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())
        }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> DeleteTopic(pTopicName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> tNumberOfPartitions = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tReplicationFactor = &lt;span class="hljs-number">1&lt;/span>
        &lt;span class="hljs-keyword">Set&lt;/span> tSC = tClient.DeleteTopic(pTopicName)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSC)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())
        }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> SendMessage(pMessage &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pTopic &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tMessage &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = &lt;span class="hljs-string">"iris-consumer"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tMessage = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.topic = pTopic
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.value = pMessage
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> producerSettings = &lt;span class="hljs-string">"{""key.serializer"":""org.apache.kafka.common.serialization.StringSerializer""}"&lt;/span>
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.UpdateProducerConfig(producerSettings))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.SendMessage(tMessage))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())

    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> ReceiveMessage(pTopicName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pGroupId &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span> = &lt;span class="hljs-string">"iris-consumer"&lt;/span>, Output pMessages) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tMessage &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.KafkaMessage&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.KafkaSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.servers = &lt;span class="hljs-built_in">$$$KAFKASERVER&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.groupId = pGroupId
        
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateKafkaClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-keyword">Set&lt;/span> producerSettings = &lt;span class="hljs-string">"{""key.serializer"":""org.apache.kafka.common.serialization.StringSerializer""}"&lt;/span>
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.UpdateProducerConfig(producerSettings))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.ReceiveMessage(pTopicName, .pMessages))
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.&lt;span class="hljs-keyword">Close&lt;/span>())
        }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

}

 

Interação com o AWS SQS

Como você se comunicaria com o AWS SQS (Simple Queue Service)? 
O procedimento básico é bastante similar. No entanto, o AWS exige a autenticação e não usa o termo "tópico". Ele fala sobre filas. Você pode enviar uma mensagem para uma fila, e os consumidores podem receber mensagens de uma ou mais filas.

Semelhante à classe da API acima, criei algo para o AWS SQS.

&lt;span class="hljs-keyword">Class&lt;/span> AWS.SQS.api [ Abstract ]
{

&lt;span class="hljs-keyword">ClassMethod&lt;/span> SendMessage(pMessage &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pQueue &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tMessage &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSMessage&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(&lt;span class="hljs-keyword">##class&lt;/span>(AWS.Utils).GetCredentials(.tCredentials))
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.accessKey = tCredentials(&lt;span class="hljs-string">"aws_access_key_id"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.secretKey = tCredentials(&lt;span class="hljs-string">"aws_secret_access_key"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.sessionToken = tCredentials(&lt;span class="hljs-string">"aws_session_token"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.region = &lt;span class="hljs-string">"eu-central-1"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tMessage = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSMessage&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.body = pMessage
        &lt;span class="hljs-keyword">set&lt;/span> tMessage.queue = pQueue

        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateSQSClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.SendMessage(tMessage))

    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> ReceiveMessage(pQueueName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, Output pMessages) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(&lt;span class="hljs-keyword">##class&lt;/span>(AWS.Utils).GetCredentials(.tCredentials))
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.accessKey = tCredentials(&lt;span class="hljs-string">"aws_access_key_id"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.secretKey = tCredentials(&lt;span class="hljs-string">"aws_secret_access_key"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.sessionToken = tCredentials(&lt;span class="hljs-string">"aws_session_token"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.region = &lt;span class="hljs-string">"eu-central-1"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateSQSClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.ReceiveMessage(pQueueName, .pMessages))

    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> DeleteMessage(pQueueName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>, pReceiptHandle &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(&lt;span class="hljs-keyword">##class&lt;/span>(AWS.Utils).GetCredentials(.tCredentials))
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.accessKey = tCredentials(&lt;span class="hljs-string">"aws_access_key_id"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.secretKey = tCredentials(&lt;span class="hljs-string">"aws_secret_access_key"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.sessionToken = tCredentials(&lt;span class="hljs-string">"aws_session_token"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.region = &lt;span class="hljs-string">"eu-central-1"&lt;/span>
                &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateSQSClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.DeleteMessage(pQueueName, pReceiptHandle))

    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> CreateQueue(pQueueName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSQSSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSQueueSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(&lt;span class="hljs-keyword">##class&lt;/span>(AWS.Utils).GetCredentials(.tCredentials))
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.accessKey = tCredentials(&lt;span class="hljs-string">"aws_access_key_id"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.secretKey = tCredentials(&lt;span class="hljs-string">"aws_secret_access_key"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.sessionToken = tCredentials(&lt;span class="hljs-string">"aws_session_token"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.region = &lt;span class="hljs-string">"eu-central-1"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateSQSClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)

        &lt;span class="hljs-keyword">set&lt;/span> tSQSSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSQueueSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()

        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.CreateQueue(pQueueName,tSQSSettings))


    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

&lt;span class="hljs-keyword">ClassMethod&lt;/span> DeleteQueue(pQueueName &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%String&lt;/span>) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tClient &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSClient&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSQSSettings &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%External.Messaging.SQSQueueSettings&lt;/span>
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(&lt;span class="hljs-keyword">##class&lt;/span>(AWS.Utils).GetCredentials(.tCredentials))
        &lt;span class="hljs-keyword">set&lt;/span> tSettings = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.SQSSettings&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.accessKey = tCredentials(&lt;span class="hljs-string">"aws_access_key_id"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.secretKey = tCredentials(&lt;span class="hljs-string">"aws_secret_access_key"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.sessionToken = tCredentials(&lt;span class="hljs-string">"aws_session_token"&lt;/span>)
        &lt;span class="hljs-keyword">set&lt;/span> tSettings.region = &lt;span class="hljs-string">"eu-central-1"&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tClient = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%External.Messaging.Client&lt;/span>).CreateSQSClient(tSettings.ToJSON(),.tSc)
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tSc)

        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tClient.DeleteQueue(pQueueName))


    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    }

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

}

Ele contém métodos para criar e excluir filas, além de enviar e receber mensagens de uma fila.

Um dos principais pontos aqui é como autenticar. Não queria colocar minhas credenciais no meu código. Por isso, criei um método de ajuda para recuperar minhas credenciais no meu arquivo local e retornar como uma array subscrita para usar nos meus métodos da API:

&lt;span class="hljs-keyword">ClassMethod&lt;/span> GetCredentials(Output pCredentials) &lt;span class="hljs-keyword">As&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span>
{
    &lt;span class="hljs-keyword">#dim&lt;/span> tSc &lt;span class="hljs-keyword">as&lt;/span> &lt;span class="hljs-built_in">%Status&lt;/span> = &lt;span class="hljs-built_in">$$$OK&lt;/span>
    &lt;span class="hljs-keyword">set&lt;/span> tFilename = &lt;span class="hljs-string">"/dur/.aws/credentials"&lt;/span>
    &lt;span class="hljs-keyword">try&lt;/span> {
        &lt;span class="hljs-keyword">set&lt;/span> tCredentialsFile = &lt;span class="hljs-keyword">##class&lt;/span>(&lt;span class="hljs-built_in">%Stream.FileCharacter&lt;/span>).&lt;span class="hljs-built_in">%New&lt;/span>()
        &lt;span class="hljs-built_in">$$$ThrowOnError&lt;/span>(tCredentialsFile.LinkToFile(tFilename))
        &lt;span class="hljs-comment">// first read the header&lt;/span>
        &lt;span class="hljs-keyword">set&lt;/span> tBuffer = tCredentialsFile.ReadLine()
        &lt;span class="hljs-keyword">for&lt;/span> i=&lt;span class="hljs-number">1&lt;/span>:&lt;span class="hljs-number">1&lt;/span>:&lt;span class="hljs-number">3&lt;/span> {
            &lt;span class="hljs-keyword">set&lt;/span> tBuffer = tCredentialsFile.ReadLine()
            &lt;span class="hljs-keyword">set&lt;/span> pCredentials(&lt;span class="hljs-built_in">$piece&lt;/span>(tBuffer,&lt;span class="hljs-string">" ="&lt;/span>,&lt;span class="hljs-number">1&lt;/span>)) = &lt;span class="hljs-built_in">$tr&lt;/span>(&lt;span class="hljs-built_in">$piece&lt;/span>(tBuffer,&lt;span class="hljs-string">"= "&lt;/span>,&lt;span class="hljs-number">2&lt;/span>),&lt;span class="hljs-built_in">$c&lt;/span>(&lt;span class="hljs-number">13&lt;/span>))
        }
    }
    &lt;span class="hljs-keyword">catch&lt;/span> tEx {
        &lt;span class="hljs-keyword">set&lt;/span> tSc = tEx.AsStatus()
    } 

    &lt;span class="hljs-keyword">return&lt;/span> tSc
}

Para concluir este artigo, vamos criar uma fila community na região do AWS "eu-central-1" (Frankfurt, Alemanha).

A fila foi criada com sucesso e está visível no console do AWS para minha conta:

Em seguida, vamos enviar uma mensagem para essa fila:

O método call retorna 1. Portanto, a mensagem foi enviada com êxito.

Por fim, vamos usar o poll na fila do console do AWS:

A mensagem foi enviada para a fila com êxito.

Conclusão

A API de mensagens externas no InterSystems IRIS 2022.1 simplifica bastante a comunicação com as plataformas de streaming de eventos.
Espero que isso tenha sido útil.

0
0 87
Anúncio Angelo Bruno Braga · Jun. 28, 2022

Olá Comunidade, 

Neste webinar nós iremos discutir como você pode integrar facilmente o Apache Kafka com a plataforma de dados InterSystems IRIS, incluindo a opção utilizando produções de interoperabilidade e programaticamente através de chamadas de API, tanto como produtor quanto como consumidor de mensagens do Apache Kafka: 

⏯ Papo Técnico InterSystems IRIS: Kafka

0
0 55
Anúncio Rochael Ribeiro · Maio 30, 2022

Olá Desenvolvedores,

Vocês são muito bem vindos para se juntar para nosso próximo webinar InterSystems chamado "Papo Técnico InterSystems IRIS: Python"! 

Data: Quarta-feira, 08 de Junho de 2022
Horário: 12:00, horário de Brasília

 

Neste papo técnico, nós iremos entrar em detalhes sobre a amplitude de suporte que os desenvolvedores Python tem utilizando a plataforma de dados IRIS da InterSystems, incluindo:

0
0 64