thes0ls

joined 1 year ago
[–] [email protected] 1 points 7 months ago

Só pra ficar registrado, não sei se os edits estão sendo federados corretamente, então o link pra versão mais atualizada tá aqui: https://lemmy.eco.br/comment/6300628

[–] [email protected] 1 points 7 months ago* (last edited 7 months ago) (1 children)

Welp que eu acabei mesmo passando a limpo o meu script.


Aqui estou levando em conta que o matrix já está com a bridge rodando e o script vai cuidar só de espiar se chega mensagem de áudio.

Quem for usar, leia o código que eu botei uns comentários nos trechos que deve editar.

Testei só no meu próprio ambiente, então pode ser que tenha uma dependência ou outra que esqueci de anotar (nem lembro como que instalei o whisper, por exemplo).

A documentação do nio fica em aqui: https://matrix-nio.readthedocs.io/en/latest/index.html


# -*- coding: utf-8 -*-


import requests

import os
import re
import time

import whisper

import asyncio
import json

from nio import AsyncClient, MatrixRoom, RoomMessageText, RoomMessageAudio, Api

# whisper requer o ffmpeg:
# sudo apt update && sudo apt install ffmpeg

# E no virtualenv do seu python, os requisitos provavelmente são:
# pip install asyncio openai-whisper matrix-nio

# Analisar o restante do script e substituir os valores do room_id na função audio_callback pelos da sua instância

# ------------------------------------------------

# Credenciais do login. Pegar os dados da response:
# curl -XPOST -d '{"type":"m.login.password", "user":"NOMEDOUSUARIO", "password":"SENHADOUSUARIO"}' "https://matrix.zzz/_matrix/client/r0/login"
CONFIG_FILE = "matrix-credentials.json"
if not os.path.isfile(CONFIG_FILE):
  f = open(CONFIG_FILE, 'w')
  f.write('{"user_id":"@usuario:matrix.zzz","access_token":"abc123","home_server":"https://matrix.zzz","device_id":"ABCD"}')
  f.close()
  print('Preencha as credenciais...')
  exit()
  
# Este arquivo é usado pro script ignorar mensagens anteriores a data dele
lastruntime='matrix.time.txt'
if not os.path.isfile(lastruntime):
  f = open(lastruntime, 'w')
  f.write("0")
  f.close()

# Pasta onde ficarão salvos os áudio temporários
if not os.path.isdir("matrixtemp"):
    os.mkdir("matrixtemp")

with open(CONFIG_FILE, "r") as f:
    config = json.load(f)
    client = AsyncClient(config["home_server"])
    client.access_token = config["access_token"]
    client.user_id = config["user_id"]
    client.device_id = config["device_id"]

async def matrix_message(text, room_id, server_timestamp, in_reply_to = 0):
    event_type="m.room.message"
    msgtype="m.text"
        
    if in_reply_to == 0:
        content = {
                "msgtype": msgtype,
                "body": cleanhtml(text),
                "format": "org.matrix.custom.html",
                "formatted_body": text
        }
    else:
        content = {
                "m.relates_to": {"m.in_reply_to": {"event_id": in_reply_to  }   },
                "msgtype": msgtype,
                "body": cleanhtml(text),
                "format": "org.matrix.custom.html",
                "formatted_body": text
        }
    
    await client.room_send(
        room_id,
        message_type="m.room.message",
        content=content,
        ignore_unverified_devices=True,
    )
    
    f = open(lastruntime, "w")
    f.write(str(server_timestamp))
    f.close()
    

CLEANR = re.compile('<.*?>') 

def cleanhtml(raw_html):
  cleantext = re.sub(CLEANR, '', raw_html)
  return cleantext
  

async def audio_callback(room: MatrixRoom, event: RoomMessageAudio) -> None:
    # Aqui os chats que podem receber a transcrição na própria conversa.
    # Pra pegar o id, no Element, clique direito na sala, Settings > Advanced > Internal room ID
    permitidos=[
    "!AsasasASas:matrix.zzz",
    "!Idasasas:matrix.zzz"
    ]
    if room.room_id in permitidos:    
        room_id = room.room_id
        event_id = event.event_id
    else:
        room_id = "!BHBhbHBHbhb:matrix.zzz" # Aqui especifica o room_id do chat que vai receber fora dos permitidos acima
        event_id = 0
    
    sender = event.source['sender']
    lastrun = open(lastruntime, "r")
    lastrun = lastrun.read()
    if event.server_timestamp > int(lastrun):
        print(vars(room))
        print(event)
        dllink = Api.mxc_to_http(event.source['content']['url'])
        print(dllink)
        filename = os.path.basename(dllink)+".ogg"
        filepath = "./matrixtemp/"+filename
        
        r = requests.get(dllink)
        
        print(r.status_code)
        
        with open(filepath, 'wb') as f:
            f.write(r.content)
        
        print("iniciando openai/whisper")
        start = time.time()
        model = whisper.load_model("medium")
        
        whisperconfig="bs3" #def p2bs5 bs3 bs2
        
        if whisperconfig == "p2bs5":
            result = model.transcribe(filepath, language="pt", fp16=False, verbose=True, patience=2, beam_size=5) #580 segundos
        if whisperconfig == "def":
            result = model.transcribe(filepath, language="pt", fp16=False, verbose=True) #56 segundos
        if whisperconfig == "bs3":
            result = model.transcribe(filepath, language="pt", fp16=False, verbose=True, beam_size=3) #181 segundos
        if whisperconfig == "bs2":
            result = model.transcribe(filepath, language="pt", fp16=False, verbose=True, beam_size=2) #136 segundos
            
        end = time.time()
        tempogasto = int(end - start)
        print("Conluido, tempo gasto: "+ str(tempogasto))
        text = result["text"]

        await matrix_message("<b>Transcrição:</b><br/><br/>"+sender+":<br/> "+text, room_id, str(event.server_timestamp), event_id)



async def main() -> None:        
    client.add_event_callback(audio_callback, RoomMessageAudio)
    
    await client.sync_forever(timeout=30000)  # milliseconds


asyncio.run(main())

EDIT: 2024-03-27 21h50: Corrigi um erro de copicola logo depois do if not os.path.isfile(CONFIG_FILE):.

[–] [email protected] 1 points 7 months ago* (last edited 7 months ago)

Hahah, tá no meio de um script enorme que eu também uso pra fazer o mirror das outras mensagens. Qualquer coisa alguma hora eu vejo se tento isolar só isso, mas pra dar um início seria:

Um script python com nio, que serve pra conectar no servidor, logar na conta e ficar espiando as mensagens que vão chegando.

Quando ele encontrar uma mensagem de áudio, eu faço ele baixar o arquivo numa pasta local e depois eu rodo o whisper hospedado localmente pra fazer a transcrição.

Depois com o resultado, eu tenho duas opções, enviar de volta o áudio para o mesmo chat, ou enviar pra um chat privado só comigo. Quando é com alguém chegado, eu envio pro mesmo chat, já o restante eu faço vir em separado.

Inicialmente eu usava o sr*, mas se a pessoa tinha um pouco de sotaque, o reconhecimento não funcionava legal.

Com o whisper o resultado é bem melhor, porém é bem mais pesado e demora um tanto pra transcrever. Um áudio de 30 segundos leva uns 3~4 minutos. Mas se a pessoa quis economizar o tempo dela enviando em audio, não deve se importar de esperar uns 5 minutos pra receber uma resposta do outro lado... hahah


*EDIT: Uma correção, o meu script também tava com o tesseract sendo usado em outro trecho, por isso eu confundi, mas a parte do audio era usando o SpeechRecognition. Foi mals. EDIT

[–] [email protected] 2 points 7 months ago* (last edited 7 months ago) (5 children)

O problema é que é totalmente aleatório. Ontem às 22h tava comendo os 35% de novo. Reiniciei o container e tá até agora rodando bonitinho consumindo de 1% pra baixo.

No dendrite eu não tinha notado esses problemas.

alias gastou quanto pra criar servidor doméstico?

Um fornecedor do meu irmão tava se desfazendo de equipamentos antigos e peguei um "HP Prodesk 600 Slim", acho que um i5 e 8gb de ram e um hdd mecânico de 500GB por uns R$600.

Só botei mais uns pentes de memória que eu tinha sobrando aqui e um ssd, que também tinha de sobra.

EDIT:

Btw, não sei se é bug, mas só consegui fazer o upload da imagem pela interface normal, tentando pelo old.lemmy só retornava erro.

[–] [email protected] 4 points 7 months ago* (last edited 7 months ago) (12 children)

Tenho feito selfhost de uma instância do matrix desde o ano passado.

A ideia era criar um mirror do grupo de trabalho do telegram (que vinha sendo ameaçado de bloqueios na época) e migrar pro matrix caso fosse necessário.

No fim, o meu provedor "esqueceu" de bloquear o telegram e acabou dando em nada.

Assim o matrix continuou só como um mirror e aproveitei para botar uma bridge do meu whatsapp pessoal lá, principalmente pra deixar rodando um script pra transcrever as mensagens de áudio que eu recebo e agora não consigo mais ficar sem isso.

Na época eu tinha optado por usar o Dendrite, que dizia ser uma versão mais enxuta do que o Synapse (que é o servidor padrão). Tava tudo redondo, até que recentemente as bridges foram atualizadas e passaram a precisar da api versão 1.4, mas o Dendrite meio que estagnou e tá empacado na api 1.2 ainda.

Então tentei instalar o Synapse aqui, mas aleatoriamente ele começa a comer 35% da CPU (de um i5-4590). Se eu reiniciar o container dele, normaliza por um tempo, mas depois de algumas horas volta a pesar de novo.

O próximo passo vai ser testar o Matrix Conduit pra ver :|

[–] [email protected] 4 points 8 months ago (1 children)

Ia dizer que é o que eu uso, mas na verdade é outro fork.

No PC eu tenho o KeePassXC (em conjunto com o addon KeePassXC-Browser do firefox). E no android eu tenho o Kepass2Android Offline, que eu uso como read-only.

E pra sincronizar do pc pro android uso Syncthing.

[–] [email protected] 2 points 9 months ago

Hey, thanks for the Audiobookshelf recommendation!

Recently I was looking for a audiobook player and Smart Audiobook Player was the best I found, but Audiobookshelf have almost all of the functions I liked like simultaneous dual timeline bar (one for the whole book and another for the current chapter), auto sleep, shake to reset sleep and so on. Just missed the small beep alert before the audio fade out on sleep.

Anyway, and all of this with the advantage of using my already selfhosted data, so no need to keep transferring files manually to the device. And all the progress are synced back to my homeserver, so I can use multiple devices without any problems.

[–] [email protected] 5 points 9 months ago (1 children)

Não sei porque o id é 2303 no link, mas o número é 4088 na postagem original lá do lemmy.ml

É que #4088 é o número da issue aberta pra discutir sobre o assunto (ou dependendo do caso informar sobre algum bug), enquanto o #2303 se refere ao pull request que de fato fez a alteração no código fonte.

[–] [email protected] 3 points 10 months ago* (last edited 10 months ago)

On newer webos, you need to enable developer mode and then you can install homebrews (adsless YouTube, kodi and more), without the need to root.

The downside is that to keep the develop mode apps for more than 48 hours, you need to setup a crontab or an ittt job to connect to LG servers to automatically renew the developer token.

[–] [email protected] 2 points 10 months ago (1 children)

Muitos sites, apesar de terem rss, acabam não incluindo a informação no header, então tem que ir mexendo na url na base do chute.

Acrescentando a lista dos que o MRLimcon postou:

G1 geral: https://g1.globo.com/rss/g1/

G1 SP: https://g1.globo.com/rss/g1/sp/sao-paulo/

Sobre cliente de rss, eu faço selfhost do ttrss, mas como o desenvolvedor é um tanto tóxico hoje em dia eu vejo muitas pessoas recomendando mais algo como o freshrss pra quem tem interesse em fazer selfhost.

[–] [email protected] 3 points 1 year ago (1 children)

Não sei se é com todo mundo, mas a interface padrão de todas as instâncias do lemmy me oferecem sempre a versão pt-PT em vez da pt-BR.

Só depois de cadastrado que eu posso mudar manualmente pra pt-BR, que eu nem sabia que existia.

No default, que é baseado no navegador fica sempre pt-PT em qualquer navegador que eu tente usar.

[–] [email protected] 2 points 1 year ago (1 children)

Depende muito das configurações, ou mesmo da imagem em si, mas em geral o avif fornece uma qualidade/compressão um pouco melhor que o webp.

O problema do avif é a menor compatibilidade com navegadores/aparelhos e também a forma de carregamento.

O jpeg carrega a imagem de cima pra baixo, meio que em linhas.

O webp, mostra primeiro uma imagem bem baixa definição e vai melhorando a qualidade até terminar de receber o arquivo.

Já o avif só mostra a imagem depois que ela tiver sido 100% baixada pelo navegador, aparecendo tudo de uma vez só.

view more: ‹ prev next ›