Spaces:
Build error
Build error
Commit
·
c3907b6
1
Parent(s):
3909924
fdf
Browse files- .cursor/rules/principal.mdc +51 -0
- .gitignore +15 -0
- LLaMA-Omni2 +0 -1
- README.md +121 -42
- app.py +58 -33
- audio_interface.py +41 -1
- launch_llama_omni2.py +104 -87
- model_downloader.py +219 -0
- no_download.py +55 -0
- run_without_downloads.sh +55 -0
.cursor/rules/principal.mdc
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
description:
|
3 |
+
globs:
|
4 |
+
alwaysApply: false
|
5 |
+
---
|
6 |
+
. envia o mínimo possível de arquivos, na verdade tem que baixar mais os arquivos durante a inicialização
|
7 |
+
|
8 |
+
# Resumo do Projeto LLaMA-Omni2 para Hugging Face Spaces
|
9 |
+
|
10 |
+
Estou configurando uma aplicação de demonstração do LLaMA-Omni2, um assistente de linguagem e fala, para ser facilmente implantada no Hugging Face Spaces. Aqui está um resumo do que foi implementado:
|
11 |
+
|
12 |
+
## Objetivo do Projeto
|
13 |
+
Criar uma interface web interativa que demonstre as capacidades do LLaMA-Omni2, permitindo aos usuários interagir com o modelo através de texto e fala, recebendo respostas também nos dois formatos.
|
14 |
+
|
15 |
+
## Componentes Principais
|
16 |
+
|
17 |
+
1. **Interface Gradio**: Uma interface web amigável com duas abas:
|
18 |
+
- **Entrada de Áudio**: Permite aos usuários falar ou fazer upload de arquivos de áudio
|
19 |
+
- **Entrada de Texto**: Permite interações baseadas em texto
|
20 |
+
|
21 |
+
2. **Pipeline de Reconhecimento de Fala**:
|
22 |
+
- Usa o modelo Whisper (tiny) para transcrever áudio para texto
|
23 |
+
- Configurado para carregar diretamente do Hugging Face
|
24 |
+
|
25 |
+
3. **Geração de Texto e Fala**:
|
26 |
+
- Usa o modelo LLaMA-Omni2-0.5B para gerar respostas
|
27 |
+
- Suporta dois métodos de geração de fala: `generate_with_speech` e `generate_speech`
|
28 |
+
- Gerencia a conversão de respostas de texto para áudio
|
29 |
+
|
30 |
+
4. **Otimizações para Hugging Face Spaces**:
|
31 |
+
- Carregamento dinâmico de modelos (não incluídos no repositório)
|
32 |
+
- Configuração para utilizar GPU quando disponível
|
33 |
+
- Sistema de logging abrangente para depuração
|
34 |
+
|
35 |
+
5. **Gestão de Repositório**:
|
36 |
+
- Arquivo `.gitignore` configurado para excluir modelos grandes e artefatos desnecessários
|
37 |
+
- Remoção de arquivos grandes do histórico do git
|
38 |
+
- Estrutura de projeto limpa e organizada
|
39 |
+
|
40 |
+
## Arquivos Principais
|
41 |
+
- `app.py`: Contém a lógica principal da aplicação e a interface Gradio
|
42 |
+
- `requirements.txt`: Lista todas as dependências necessárias
|
43 |
+
- `.huggingface-space`: Configuração para o ambiente Hugging Face Spaces
|
44 |
+
- `.gitignore`: Exclui arquivos grandes e temporários do controle de versão
|
45 |
+
|
46 |
+
## Tecnologias Utilizadas
|
47 |
+
- **Frameworks**: PyTorch, Transformers, Gradio
|
48 |
+
- **Modelos**: LLaMA-Omni2-0.5B (para texto/fala), Whisper-tiny (para reconhecimento de fala)
|
49 |
+
- **Infraestrutura**: Hugging Face Spaces para hospedagem
|
50 |
+
|
51 |
+
O projeto está configurado para baixar os modelos dinamicamente quando implantado, em vez de incluí-los no repositório, resultando em um código limpo e eficiente que pode ser facilmente compartilhado e implantado.
|
.gitignore
CHANGED
@@ -37,6 +37,21 @@ models/
|
|
37 |
.cache/
|
38 |
*/.cache/
|
39 |
*incomplete
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
# IDEs
|
42 |
.vscode/
|
|
|
37 |
.cache/
|
38 |
*/.cache/
|
39 |
*incomplete
|
40 |
+
whisper-large-v3/
|
41 |
+
cosy2_decoder/
|
42 |
+
speech_encoder/
|
43 |
+
# Excluir todos os arquivos grandes de modelos de forma explícita
|
44 |
+
flow.decoder.estimator.fp32.onnx
|
45 |
+
flow.decoder.estimator.fp16.A10.plan
|
46 |
+
flow.encoder.fp32.zip
|
47 |
+
flow.decoder.estimator.fp16.Volta.plan
|
48 |
+
hift.pt
|
49 |
+
campplus.onnx
|
50 |
+
vocab.json
|
51 |
+
tokenizer_config.json
|
52 |
+
tokenizer.json
|
53 |
+
pytorch_model.bin.index.fp32.json
|
54 |
+
model.safetensors.index.fp32.json
|
55 |
|
56 |
# IDEs
|
57 |
.vscode/
|
LLaMA-Omni2
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
Subproject commit feb85982d9effc4ecbc090a71ba6516ef4adaaf0
|
|
|
|
README.md
CHANGED
@@ -12,72 +12,151 @@ pinned: false
|
|
12 |
# Ex: hardware: nvidia-t4
|
13 |
---
|
14 |
|
15 |
-
# LLaMA-Omni2
|
16 |
|
17 |
-
|
18 |
|
19 |
-
##
|
20 |
|
21 |
-
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
##
|
24 |
-
|
25 |
-
- 🎤 **Reconhecimento de Fala**: Usando o OpenAI Whisper-tiny para transcrição de áudio
|
26 |
-
- 💬 **Geração de Texto**: Usando o modelo LLaMA-Omni2 para geração de respostas de texto
|
27 |
-
- 🔊 **Síntese de Fala**: Geração de fala a partir das respostas de texto (quando disponível)
|
28 |
-
- 🔄 **Pipeline Completo**: Fluxo integrado de áudio → texto → resposta → fala
|
29 |
-
|
30 |
-
## Como Usar
|
31 |
|
32 |
-
|
|
|
|
|
|
|
|
|
33 |
|
34 |
-
|
35 |
-
2. **Reconhecimento de Fala**: Teste apenas a capacidade de transcrição do Whisper
|
36 |
-
3. **Geração de Texto/Fala**: Forneça seu próprio texto para geração de resposta
|
37 |
|
38 |
-
|
39 |
|
40 |
-
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
4. **Decodificador TTS Streaming**: Converte tokens de texto em fala de forma contínua
|
46 |
|
47 |
-
|
48 |
|
49 |
-
|
50 |
|
|
|
51 |
```bash
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
|
56 |
-
|
|
|
57 |
pip install -r requirements.txt
|
|
|
58 |
|
59 |
-
|
|
|
60 |
python app.py
|
61 |
```
|
62 |
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
|
|
68 |
|
69 |
-
|
70 |
|
71 |
-
|
72 |
-
- A geração de fala pode não estar disponível se o modelo não tiver sido carregado corretamente
|
73 |
-
- Requer recursos computacionais significativos para execução ideal
|
74 |
|
75 |
-
|
76 |
|
77 |
-
|
78 |
-
|
79 |
-
-
|
|
|
|
|
80 |
|
81 |
## Licença
|
82 |
|
83 |
-
Este projeto
|
|
|
12 |
# Ex: hardware: nvidia-t4
|
13 |
---
|
14 |
|
15 |
+
# LLaMA-Omni2 Interface
|
16 |
|
17 |
+
Interface para o modelo LLaMA-Omni2, que permite entrada e saída de áudio com processamento de linguagem natural.
|
18 |
|
19 |
+
## Características
|
20 |
|
21 |
+
- Transcrição de áudio usando Whisper
|
22 |
+
- Processamento de texto com LLaMA-Omni2
|
23 |
+
- Síntese de fala usando CosyVoice 2
|
24 |
+
- Geração de texto e fala em tempo real
|
25 |
+
- Download automático de modelos durante a inicialização
|
26 |
|
27 |
+
## Requisitos
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
- Python 3.8+
|
30 |
+
- PyTorch 2.0+
|
31 |
+
- Transformers 4.36+
|
32 |
+
- Gradio 3.50+
|
33 |
+
- CUDA (opcional, mas recomendado para melhor desempenho)
|
34 |
|
35 |
+
## Configuração de Modelos
|
|
|
|
|
36 |
|
37 |
+
Este projeto utiliza um sistema de download automático de modelos durante a inicialização, evitando a necessidade de armazenar arquivos grandes no repositório Git.
|
38 |
|
39 |
+
Os modelos serão baixados automaticamente na primeira execução:
|
40 |
|
41 |
+
- **Whisper Large V3** - Modelo de reconhecimento de fala
|
42 |
+
- **CosyVoice 2** - Vocoder para síntese de fala
|
43 |
+
- **LLaMA-Omni2** - Modelo de linguagem multimodal
|
|
|
44 |
|
45 |
+
Todos os modelos são armazenados na pasta `models/`, que está no `.gitignore` para evitar o commit de arquivos grandes.
|
46 |
|
47 |
+
## Configuração
|
48 |
|
49 |
+
1. Clone o repositório:
|
50 |
```bash
|
51 |
+
git clone https://github.com/seu-usuario/llama-omni2.git
|
52 |
+
cd llama-omni2
|
53 |
+
```
|
54 |
|
55 |
+
2. Instale as dependências:
|
56 |
+
```bash
|
57 |
pip install -r requirements.txt
|
58 |
+
```
|
59 |
|
60 |
+
3. Execute o aplicativo:
|
61 |
+
```bash
|
62 |
python app.py
|
63 |
```
|
64 |
|
65 |
+
Na primeira execução, os modelos serão baixados automaticamente. Isso pode levar algum tempo, dependendo da sua conexão com a internet.
|
66 |
+
|
67 |
+
## Uso
|
68 |
+
|
69 |
+
Após iniciar o aplicativo, acesse a interface web em http://localhost:7860 para interagir com o modelo.
|
70 |
+
|
71 |
+
- **Entrada de Áudio**: Grave ou faça upload de um arquivo de áudio
|
72 |
+
- **Saída de Texto**: Veja a transcrição e a resposta do modelo
|
73 |
+
- **Saída de Áudio**: Ouça a resposta sintetizada
|
74 |
+
|
75 |
+
## Usando o launcher
|
76 |
+
|
77 |
+
Você também pode usar o launcher para iniciar a aplicação completa:
|
78 |
+
|
79 |
+
```bash
|
80 |
+
python launch_llama_omni2.py
|
81 |
+
```
|
82 |
+
|
83 |
+
Opções do launcher:
|
84 |
+
- `--skip-download`: Pula o download das dependências
|
85 |
+
- `--extraction-dir`: Define o diretório de extração (padrão: extraction_dir)
|
86 |
+
- `--models-dir`: Define o diretório de modelos (padrão: models)
|
87 |
+
- `--controller-only`: Inicia apenas o controlador
|
88 |
+
- `--worker-only`: Inicia apenas o worker do modelo
|
89 |
+
- `--gradio-only`: Inicia apenas a interface Gradio
|
90 |
+
|
91 |
+
## Estrutura do Projeto
|
92 |
+
|
93 |
+
- `app.py` - Aplicativo Gradio principal
|
94 |
+
- `audio_interface.py` - Interface de áudio para LLaMA-Omni2
|
95 |
+
- `launch_llama_omni2.py` - Script para lançar todos os componentes
|
96 |
+
- `model_downloader.py` - Sistema de download automático de modelos
|
97 |
+
- `models/` - Diretório para armazenar os modelos baixados
|
98 |
+
- `requirements.txt` - Dependências do projeto
|
99 |
+
|
100 |
+
## Funcionamento do Download Automático
|
101 |
+
|
102 |
+
O sistema de download automático funciona da seguinte forma:
|
103 |
+
|
104 |
+
1. Na inicialização, o script verifica se os modelos necessários existem localmente
|
105 |
+
2. Se um modelo não for encontrado, ele é baixado automaticamente do Hugging Face Hub
|
106 |
+
3. Após o download, o modelo é carregado normalmente pelo aplicativo
|
107 |
+
|
108 |
+
Isso permite:
|
109 |
+
- Manter o repositório Git leve, sem arquivos grandes
|
110 |
+
- Facilitar a implantação em diferentes ambientes
|
111 |
+
- Garantir que os usuários sempre tenham os modelos corretos
|
112 |
+
|
113 |
+
## Modo Sem Download
|
114 |
+
|
115 |
+
Este projeto suporta um modo "sem download" que permite usar os modelos diretamente do Hugging Face Hub, sem baixá-los localmente. Isso é útil para:
|
116 |
+
|
117 |
+
- Desenvolvimento e testes onde não é necessário baixar os modelos completos
|
118 |
+
- Ambientes com espaço em disco limitado
|
119 |
+
- Integração contínua e cenários de implantação onde os modelos são acessados remotamente
|
120 |
+
|
121 |
+
Para ativar o modo sem download, você pode:
|
122 |
+
|
123 |
+
1. **Usar o script Python no_download.py (recomendado)**:
|
124 |
+
```bash
|
125 |
+
# Executar app.py sem download
|
126 |
+
python no_download.py app.py
|
127 |
+
|
128 |
+
# Executar outro script sem download
|
129 |
+
python no_download.py audio_interface.py
|
130 |
+
```
|
131 |
+
|
132 |
+
2. **Usar o script auxiliar**:
|
133 |
+
```bash
|
134 |
+
./run_without_downloads.sh
|
135 |
+
```
|
136 |
+
|
137 |
+
3. **Definir a variável de ambiente**:
|
138 |
+
```bash
|
139 |
+
export NO_DOWNLOAD=1
|
140 |
+
python app.py
|
141 |
+
```
|
142 |
|
143 |
+
4. **Usar a opção de linha de comando no launcher**:
|
144 |
+
```bash
|
145 |
+
python launch_llama_omni2.py --no-model-download
|
146 |
+
```
|
147 |
|
148 |
+
No modo sem download, o aplicativo usará os modelos diretamente do Hugging Face Hub, sem baixar arquivos localmente. Isso pode ser mais lento para uso contínuo, mas é mais rápido para inicializar e não ocupa espaço em disco.
|
149 |
|
150 |
+
## Contribuição
|
|
|
|
|
151 |
|
152 |
+
Contribuições são bem-vindas! Por favor, siga estas diretrizes:
|
153 |
|
154 |
+
1. Faça um fork do repositório
|
155 |
+
2. Crie um branch para sua feature (`git checkout -b feature/nova-feature`)
|
156 |
+
3. Faça commit das suas mudanças (`git commit -am 'Adiciona nova feature'`)
|
157 |
+
4. Faça push para o branch (`git push origin feature/nova-feature`)
|
158 |
+
5. Crie um novo Pull Request
|
159 |
|
160 |
## Licença
|
161 |
|
162 |
+
Este projeto está licenciado sob os termos da licença MIT.
|
app.py
CHANGED
@@ -17,6 +17,25 @@ from huggingface_hub import snapshot_download
|
|
17 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
18 |
logger = logging.getLogger(__name__)
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
# Configuração do caminho para os modelos
|
21 |
MODELS_DIR = os.environ.get("MODELS_DIR", "models")
|
22 |
os.makedirs(MODELS_DIR, exist_ok=True)
|
@@ -39,53 +58,59 @@ else:
|
|
39 |
logger.info(f"Using device: {torch_device} for model loading.")
|
40 |
logger.info(f"Pipelines will use device_id: {device_for_pipelines} and dtype: {dtype_for_pipelines}")
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
# --- Load Speech-to-Text (ASR) Pipeline ---
|
43 |
asr_pipeline_instance = None
|
44 |
try:
|
45 |
-
logger.info(f"Loading ASR model: {
|
|
|
46 |
asr_pipeline_instance = pipeline(
|
47 |
"automatic-speech-recognition",
|
48 |
-
model=
|
49 |
torch_dtype=dtype_for_pipelines,
|
50 |
device=device_for_pipelines
|
51 |
)
|
52 |
-
logger.info(f"ASR model
|
53 |
except Exception as e:
|
54 |
-
logger.error(f"Error loading ASR model
|
55 |
asr_pipeline_instance = None
|
56 |
|
57 |
# --- Load Text Generation Model ---
|
58 |
text_gen_pipeline_instance = None
|
59 |
text_generation_model_id = None # Will be set to the model that successfully loads
|
60 |
|
61 |
-
# Verificar se o modelo já está baixado ou baixá-lo usando HF Hub
|
62 |
-
try:
|
63 |
-
# Verificar se o modelo está na pasta local
|
64 |
-
local_model_path = os.path.join(MODELS_DIR, os.path.basename(llama_omni_model_id))
|
65 |
-
if os.path.exists(local_model_path) and os.path.isdir(local_model_path):
|
66 |
-
logger.info(f"Found local model at {local_model_path}")
|
67 |
-
model_path_to_use = local_model_path
|
68 |
-
else:
|
69 |
-
# Se não existir localmente, verificar se precisamos baixar
|
70 |
-
logger.info(f"Local model not found, checking if we need to predownload files for {llama_omni_model_id}")
|
71 |
-
# Verifica se estamos no ambiente Hugging Face
|
72 |
-
if os.environ.get("SPACE_ID") is not None:
|
73 |
-
logger.info("Running in Hugging Face Spaces environment")
|
74 |
-
# No Hugging Face Spaces, usamos o caminho direto para o modelo na nuvem
|
75 |
-
model_path_to_use = llama_omni_model_id
|
76 |
-
else:
|
77 |
-
# Em ambientes locais, podemos baixar explicitamente
|
78 |
-
logger.info(f"Downloading model {llama_omni_model_id} to {local_model_path}")
|
79 |
-
snapshot_download(
|
80 |
-
repo_id=llama_omni_model_id,
|
81 |
-
local_dir=local_model_path,
|
82 |
-
token=HF_TOKEN
|
83 |
-
)
|
84 |
-
model_path_to_use = local_model_path
|
85 |
-
except Exception as download_error:
|
86 |
-
logger.error(f"Error preparing model path: {download_error}")
|
87 |
-
model_path_to_use = llama_omni_model_id # Fallback to use the direct model ID
|
88 |
-
|
89 |
try:
|
90 |
logger.info(f"Attempting to load LLaMA-Omni2 model: {model_path_to_use}...")
|
91 |
# LLaMA models often require specific loading configurations
|
@@ -116,7 +141,7 @@ try:
|
|
116 |
device=device_for_pipelines if not torch.cuda.is_available() else None
|
117 |
)
|
118 |
text_generation_model_id = llama_omni_model_id
|
119 |
-
logger.info(f"LLaMA-Omni2 model
|
120 |
logger.info(f"Model has speech generation capabilities: {is_omni2_speech_model}")
|
121 |
|
122 |
except Exception as e:
|
|
|
17 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
18 |
logger = logging.getLogger(__name__)
|
19 |
|
20 |
+
# Verificar modo sem download (primeiro, antes de importar model_downloader)
|
21 |
+
NO_DOWNLOAD = os.environ.get("NO_DOWNLOAD", "0").lower() in ("1", "true", "yes")
|
22 |
+
logger.info(f"Inicializando app.py com NO_DOWNLOAD={NO_DOWNLOAD} (valor da env: {os.environ.get('NO_DOWNLOAD', 'não definido')})")
|
23 |
+
|
24 |
+
# Import do novo model_downloader
|
25 |
+
try:
|
26 |
+
from model_downloader import download_model_if_needed, download_all_models, get_model_repo_id, NO_DOWNLOAD as DOWNLOADER_NO_DOWNLOAD
|
27 |
+
# Verificar se os valores são consistentes
|
28 |
+
if NO_DOWNLOAD != DOWNLOADER_NO_DOWNLOAD:
|
29 |
+
logger.warning(f"Inconsistência detectada: NO_DOWNLOAD no app.py={NO_DOWNLOAD}, mas NO_DOWNLOAD no model_downloader.py={DOWNLOADER_NO_DOWNLOAD}")
|
30 |
+
# Atualizar para o valor no model_downloader.py
|
31 |
+
NO_DOWNLOAD = DOWNLOADER_NO_DOWNLOAD
|
32 |
+
except ImportError:
|
33 |
+
logger.warning("model_downloader não pôde ser importado, trabalhando sem ele")
|
34 |
+
# Definir funções vazias para manter compatibilidade
|
35 |
+
def download_model_if_needed(model_key): return False
|
36 |
+
def download_all_models(): pass
|
37 |
+
def get_model_repo_id(model_key): return None
|
38 |
+
|
39 |
# Configuração do caminho para os modelos
|
40 |
MODELS_DIR = os.environ.get("MODELS_DIR", "models")
|
41 |
os.makedirs(MODELS_DIR, exist_ok=True)
|
|
|
58 |
logger.info(f"Using device: {torch_device} for model loading.")
|
59 |
logger.info(f"Pipelines will use device_id: {device_for_pipelines} and dtype: {dtype_for_pipelines}")
|
60 |
|
61 |
+
# --- Check Download Mode ---
|
62 |
+
if NO_DOWNLOAD:
|
63 |
+
logger.warning("Modo NO_DOWNLOAD ativado. Os modelos não serão baixados, usando diretamente do Hugging Face Hub.")
|
64 |
+
# Usar IDs dos modelos diretamente do Hugging Face
|
65 |
+
whisper_repo_id = get_model_repo_id("speech_encoder") or "openai/whisper-large-v3"
|
66 |
+
llama_omni_repo_id = get_model_repo_id("llama_omni2") or llama_omni_model_id
|
67 |
+
|
68 |
+
# Definir caminhos para modelo
|
69 |
+
whisper_path_to_use = whisper_repo_id
|
70 |
+
model_path_to_use = llama_omni_repo_id
|
71 |
+
|
72 |
+
logger.info(f"Usando modelo whisper direto do HF: {whisper_path_to_use}")
|
73 |
+
logger.info(f"Usando modelo LLaMA-Omni2 direto do HF: {model_path_to_use}")
|
74 |
+
else:
|
75 |
+
# --- Download Models if Needed ---
|
76 |
+
logger.info("Verificando se os modelos estão disponíveis localmente...")
|
77 |
+
|
78 |
+
# Download do modelo de speech recognition (Whisper)
|
79 |
+
download_model_if_needed("speech_encoder")
|
80 |
+
|
81 |
+
# Download do modelo de síntese de voz
|
82 |
+
download_model_if_needed("cosy2_decoder")
|
83 |
+
|
84 |
+
# Download do modelo LLaMA-Omni2
|
85 |
+
download_model_if_needed("llama_omni2")
|
86 |
+
|
87 |
+
# Configurar caminhos para modelos locais
|
88 |
+
whisper_local_path = os.path.join(MODELS_DIR, "speech_encoder", "whisper-large-v3")
|
89 |
+
whisper_path_to_use = whisper_local_path if os.path.exists(whisper_local_path) else whisper_model_id
|
90 |
+
|
91 |
+
local_model_path = os.path.join(MODELS_DIR, "LLaMA-Omni2-0.5B")
|
92 |
+
model_path_to_use = local_model_path if os.path.exists(local_model_path) and os.path.isdir(local_model_path) else llama_omni_model_id
|
93 |
+
|
94 |
# --- Load Speech-to-Text (ASR) Pipeline ---
|
95 |
asr_pipeline_instance = None
|
96 |
try:
|
97 |
+
logger.info(f"Loading ASR model: {whisper_path_to_use}...")
|
98 |
+
|
99 |
asr_pipeline_instance = pipeline(
|
100 |
"automatic-speech-recognition",
|
101 |
+
model=whisper_path_to_use,
|
102 |
torch_dtype=dtype_for_pipelines,
|
103 |
device=device_for_pipelines
|
104 |
)
|
105 |
+
logger.info(f"ASR model loaded successfully.")
|
106 |
except Exception as e:
|
107 |
+
logger.error(f"Error loading ASR model: {e}")
|
108 |
asr_pipeline_instance = None
|
109 |
|
110 |
# --- Load Text Generation Model ---
|
111 |
text_gen_pipeline_instance = None
|
112 |
text_generation_model_id = None # Will be set to the model that successfully loads
|
113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
try:
|
115 |
logger.info(f"Attempting to load LLaMA-Omni2 model: {model_path_to_use}...")
|
116 |
# LLaMA models often require specific loading configurations
|
|
|
141 |
device=device_for_pipelines if not torch.cuda.is_available() else None
|
142 |
)
|
143 |
text_generation_model_id = llama_omni_model_id
|
144 |
+
logger.info(f"LLaMA-Omni2 model loaded successfully.")
|
145 |
logger.info(f"Model has speech generation capabilities: {is_omni2_speech_model}")
|
146 |
|
147 |
except Exception as e:
|
audio_interface.py
CHANGED
@@ -28,6 +28,14 @@ import whisper
|
|
28 |
import aiohttp
|
29 |
import numpy as np
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
# Configure logging
|
32 |
logging.basicConfig(level=logging.INFO)
|
33 |
logger = logging.getLogger(__name__)
|
@@ -52,11 +60,19 @@ class AudioInterface:
|
|
52 |
self.read_tokens = read_tokens # Number of text tokens to read
|
53 |
self.write_tokens = write_tokens # Number of speech tokens to write
|
54 |
|
|
|
|
|
|
|
55 |
# Load Whisper model
|
56 |
try:
|
|
|
|
|
|
|
|
|
|
|
57 |
logger.info(f"Loading Whisper model from {whisper_model_path}")
|
58 |
self.whisper_model = whisper.load_model("large-v3",
|
59 |
-
download_root=whisper_model_path,
|
60 |
device=self.device)
|
61 |
logger.info("Whisper model loaded successfully")
|
62 |
except Exception as e:
|
@@ -65,6 +81,10 @@ class AudioInterface:
|
|
65 |
|
66 |
# Load CosyVoice vocoder
|
67 |
try:
|
|
|
|
|
|
|
|
|
68 |
sys.path.insert(0, vocoder_dir)
|
69 |
from cosy_voice_2.inference import CosyVoice
|
70 |
|
@@ -79,6 +99,26 @@ class AudioInterface:
|
|
79 |
|
80 |
logger.info(f"Using LLaMA-Omni2 model: {model_name}")
|
81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
async def get_worker_address(self):
|
83 |
"""Get the address of the worker serving the model"""
|
84 |
try:
|
|
|
28 |
import aiohttp
|
29 |
import numpy as np
|
30 |
|
31 |
+
# Import model downloader
|
32 |
+
try:
|
33 |
+
from model_downloader import download_model_if_needed, download_all_models, get_model_repo_id, NO_DOWNLOAD
|
34 |
+
has_model_downloader = True
|
35 |
+
except ImportError:
|
36 |
+
has_model_downloader = False
|
37 |
+
NO_DOWNLOAD = False
|
38 |
+
|
39 |
# Configure logging
|
40 |
logging.basicConfig(level=logging.INFO)
|
41 |
logger = logging.getLogger(__name__)
|
|
|
60 |
self.read_tokens = read_tokens # Number of text tokens to read
|
61 |
self.write_tokens = write_tokens # Number of speech tokens to write
|
62 |
|
63 |
+
# Download required models if needed
|
64 |
+
self._ensure_models_available()
|
65 |
+
|
66 |
# Load Whisper model
|
67 |
try:
|
68 |
+
# Se NO_DOWNLOAD estiver ativado, usar diretamente o modelo do Hugging Face
|
69 |
+
if has_model_downloader and NO_DOWNLOAD:
|
70 |
+
whisper_model_path = "openai/whisper-large-v3"
|
71 |
+
logger.info(f"Modo NO_DOWNLOAD: Carregando Whisper direto do Hugging Face: {whisper_model_path}")
|
72 |
+
|
73 |
logger.info(f"Loading Whisper model from {whisper_model_path}")
|
74 |
self.whisper_model = whisper.load_model("large-v3",
|
75 |
+
download_root=whisper_model_path if not NO_DOWNLOAD else None,
|
76 |
device=self.device)
|
77 |
logger.info("Whisper model loaded successfully")
|
78 |
except Exception as e:
|
|
|
81 |
|
82 |
# Load CosyVoice vocoder
|
83 |
try:
|
84 |
+
# Se NO_DOWNLOAD estiver ativado, usar diretamente o modelo do Hugging Face
|
85 |
+
if has_model_downloader and NO_DOWNLOAD:
|
86 |
+
logger.warning("Modo NO_DOWNLOAD ativado. O vocoder CosyVoice pode não funcionar corretamente sem os arquivos locais.")
|
87 |
+
|
88 |
sys.path.insert(0, vocoder_dir)
|
89 |
from cosy_voice_2.inference import CosyVoice
|
90 |
|
|
|
99 |
|
100 |
logger.info(f"Using LLaMA-Omni2 model: {model_name}")
|
101 |
|
102 |
+
def _ensure_models_available(self):
|
103 |
+
"""Garante que os modelos necessários estão disponíveis"""
|
104 |
+
# Verificar se temos o model_downloader disponível
|
105 |
+
if has_model_downloader:
|
106 |
+
if NO_DOWNLOAD:
|
107 |
+
logger.info("Modo NO_DOWNLOAD ativado. Pulando verificação de modelos locais.")
|
108 |
+
return
|
109 |
+
|
110 |
+
logger.info("Verificando modelos necessários...")
|
111 |
+
|
112 |
+
# Baixar modelo Whisper
|
113 |
+
download_model_if_needed("speech_encoder")
|
114 |
+
|
115 |
+
# Baixar modelo CosyVoice
|
116 |
+
download_model_if_needed("cosy2_decoder")
|
117 |
+
|
118 |
+
logger.info("Verificação de modelos concluída")
|
119 |
+
else:
|
120 |
+
logger.warning("model_downloader não está disponível. Assumindo que os modelos já estão disponíveis localmente.")
|
121 |
+
|
122 |
async def get_worker_address(self):
|
123 |
"""Get the address of the worker serving the model"""
|
124 |
try:
|
launch_llama_omni2.py
CHANGED
@@ -14,6 +14,11 @@ import argparse
|
|
14 |
import shutil
|
15 |
import importlib.util
|
16 |
import tempfile
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
# Define paths
|
19 |
EXTRACTION_DIR = "/home/user/app/llama_omni2_extracted"
|
@@ -22,6 +27,30 @@ LLAMA_OMNI2_MODEL_NAME = "LLaMA-Omni2-0.5B"
|
|
22 |
LLAMA_OMNI2_MODEL_PATH = f"{MODELS_DIR}/{LLAMA_OMNI2_MODEL_NAME}"
|
23 |
COSYVOICE_PATH = f"{MODELS_DIR}/cosy2_decoder"
|
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
# Additional imports
|
26 |
def download_dependencies():
|
27 |
"""Download and install required Python packages for LLaMA-Omni2"""
|
@@ -32,7 +61,8 @@ def download_dependencies():
|
|
32 |
"uvicorn",
|
33 |
"pydantic",
|
34 |
"transformers>=4.36.2",
|
35 |
-
"sentencepiece"
|
|
|
36 |
]
|
37 |
|
38 |
try:
|
@@ -376,94 +406,81 @@ except ImportError:
|
|
376 |
return patched_files
|
377 |
|
378 |
def main():
|
379 |
-
"""Main
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
print("
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
if not
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
if
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
print("\nAll components started successfully!")
|
442 |
-
print(f"Gradio interface should be available at http://0.0.0.0:7860")
|
443 |
-
|
444 |
try:
|
445 |
-
|
446 |
-
|
|
|
447 |
except KeyboardInterrupt:
|
448 |
-
print("
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
-
(
|
453 |
-
|
454 |
-
(
|
455 |
-
|
456 |
-
if process and process.poll() is None:
|
457 |
-
print(f"Shutting down {name}...")
|
458 |
-
process.terminate()
|
459 |
-
try:
|
460 |
-
process.wait(timeout=30)
|
461 |
-
except subprocess.TimeoutExpired:
|
462 |
-
print(f"{name} did not terminate gracefully. Killing...")
|
463 |
-
process.kill()
|
464 |
-
|
465 |
-
print("All processes have been shut down.")
|
466 |
-
return 0
|
467 |
|
468 |
if __name__ == "__main__":
|
469 |
sys.exit(main())
|
|
|
14 |
import shutil
|
15 |
import importlib.util
|
16 |
import tempfile
|
17 |
+
import logging
|
18 |
+
|
19 |
+
# Configure logging
|
20 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
21 |
+
logger = logging.getLogger(__name__)
|
22 |
|
23 |
# Define paths
|
24 |
EXTRACTION_DIR = "/home/user/app/llama_omni2_extracted"
|
|
|
27 |
LLAMA_OMNI2_MODEL_PATH = f"{MODELS_DIR}/{LLAMA_OMNI2_MODEL_NAME}"
|
28 |
COSYVOICE_PATH = f"{MODELS_DIR}/cosy2_decoder"
|
29 |
|
30 |
+
# Importe o model_downloader se disponível
|
31 |
+
try:
|
32 |
+
from model_downloader import download_model_if_needed, download_all_models, get_model_repo_id, NO_DOWNLOAD
|
33 |
+
has_model_downloader = True
|
34 |
+
except ImportError:
|
35 |
+
has_model_downloader = False
|
36 |
+
NO_DOWNLOAD = False
|
37 |
+
|
38 |
+
# Garantir que os modelos estão disponíveis
|
39 |
+
def ensure_models_available():
|
40 |
+
"""Garante que os modelos necessários estão disponíveis"""
|
41 |
+
if has_model_downloader:
|
42 |
+
if NO_DOWNLOAD:
|
43 |
+
logger.info("Modo NO_DOWNLOAD ativado. Os modelos não serão baixados, usando diretamente do Hugging Face Hub.")
|
44 |
+
return
|
45 |
+
|
46 |
+
logger.info("Verificando modelos necessários para o LLaMA-Omni2...")
|
47 |
+
download_model_if_needed("llama_omni2")
|
48 |
+
download_model_if_needed("cosy2_decoder")
|
49 |
+
download_model_if_needed("speech_encoder")
|
50 |
+
logger.info("Verificação de modelos concluída")
|
51 |
+
else:
|
52 |
+
logger.warning("model_downloader não está disponível. Os modelos devem estar disponíveis em: " + MODELS_DIR)
|
53 |
+
|
54 |
# Additional imports
|
55 |
def download_dependencies():
|
56 |
"""Download and install required Python packages for LLaMA-Omni2"""
|
|
|
61 |
"uvicorn",
|
62 |
"pydantic",
|
63 |
"transformers>=4.36.2",
|
64 |
+
"sentencepiece",
|
65 |
+
"huggingface_hub"
|
66 |
]
|
67 |
|
68 |
try:
|
|
|
406 |
return patched_files
|
407 |
|
408 |
def main():
|
409 |
+
"""Main entry point for the launcher script"""
|
410 |
+
parser = argparse.ArgumentParser(description="LLaMA-Omni2 Direct Launcher")
|
411 |
+
parser.add_argument("--skip-download", action="store_true", help="Skip downloading dependencies")
|
412 |
+
parser.add_argument("--no-model-download", action="store_true", help="Don't download models, use them directly from HF Hub")
|
413 |
+
parser.add_argument("--extraction-dir", type=str, default=EXTRACTION_DIR, help="Directory to extract LLaMA-Omni2 to")
|
414 |
+
parser.add_argument("--models-dir", type=str, default=MODELS_DIR, help="Directory containing models")
|
415 |
+
parser.add_argument("--skip-modules", action="store_true", help="Skip module structure creation")
|
416 |
+
parser.add_argument("--controller-only", action="store_true", help="Start only the controller")
|
417 |
+
parser.add_argument("--worker-only", action="store_true", help="Start only the model worker")
|
418 |
+
parser.add_argument("--gradio-only", action="store_true", help="Start only the Gradio interface")
|
419 |
+
args = parser.parse_args()
|
420 |
+
|
421 |
+
# Update paths based on arguments
|
422 |
+
global EXTRACTION_DIR, MODELS_DIR, LLAMA_OMNI2_MODEL_PATH, COSYVOICE_PATH
|
423 |
+
EXTRACTION_DIR = args.extraction_dir
|
424 |
+
MODELS_DIR = args.models_dir
|
425 |
+
LLAMA_OMNI2_MODEL_PATH = f"{MODELS_DIR}/{LLAMA_OMNI2_MODEL_NAME}"
|
426 |
+
COSYVOICE_PATH = f"{MODELS_DIR}/cosy2_decoder"
|
427 |
+
|
428 |
+
# Set NO_DOWNLOAD environment variable if --no-model-download is specified
|
429 |
+
if args.no_model_download:
|
430 |
+
os.environ["NO_DOWNLOAD"] = "1"
|
431 |
+
global NO_DOWNLOAD
|
432 |
+
NO_DOWNLOAD = True
|
433 |
+
logger.info("Modo NO_DOWNLOAD ativado via linha de comando")
|
434 |
+
|
435 |
+
print("=== LLaMA-Omni2 Direct Launcher ===")
|
436 |
+
print(f"Extraction directory: {EXTRACTION_DIR}")
|
437 |
+
print(f"Models directory: {MODELS_DIR}")
|
438 |
+
print(f"Downloading models: {'No' if NO_DOWNLOAD else 'Yes'}")
|
439 |
+
|
440 |
+
# Ensure models are available
|
441 |
+
ensure_models_available()
|
442 |
+
|
443 |
+
# Download dependencies if needed
|
444 |
+
if not args.skip_download:
|
445 |
+
download_dependencies()
|
446 |
+
|
447 |
+
# Create module structure if needed
|
448 |
+
if not args.skip_modules:
|
449 |
+
ensure_module_structure(EXTRACTION_DIR)
|
450 |
+
|
451 |
+
# Start the controller if needed
|
452 |
+
controller_process = None
|
453 |
+
if not args.worker_only and not args.gradio_only:
|
454 |
+
controller_process = start_controller()
|
455 |
+
# Give the controller time to start up
|
456 |
+
time.sleep(5)
|
457 |
+
|
458 |
+
# Start the model worker if needed
|
459 |
+
worker_process = None
|
460 |
+
if not args.controller_only and not args.gradio_only:
|
461 |
+
worker_process = start_model_worker()
|
462 |
+
# Give the worker time to start up
|
463 |
+
time.sleep(5)
|
464 |
+
|
465 |
+
# Start the Gradio interface if needed
|
466 |
+
gradio_process = None
|
467 |
+
if not args.controller_only and not args.worker_only:
|
468 |
+
gradio_process = start_gradio_server()
|
469 |
+
|
470 |
+
# Keep the main process running to maintain subprocesses
|
|
|
|
|
|
|
471 |
try:
|
472 |
+
print("Press Ctrl+C to exit...")
|
473 |
+
while True:
|
474 |
+
time.sleep(1)
|
475 |
except KeyboardInterrupt:
|
476 |
+
print("Shutting down...")
|
477 |
+
if controller_process:
|
478 |
+
controller_process.terminate()
|
479 |
+
if worker_process:
|
480 |
+
worker_process.terminate()
|
481 |
+
if gradio_process:
|
482 |
+
gradio_process.terminate()
|
483 |
+
print("Shutdown complete")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
|
485 |
if __name__ == "__main__":
|
486 |
sys.exit(main())
|
model_downloader.py
ADDED
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
Model Downloader para LLaMA-Omni2
|
4 |
+
---------------------------------
|
5 |
+
Este script gerencia o download automático dos modelos necessários para o LLaMA-Omni2.
|
6 |
+
Os modelos serão baixados apenas quando necessário durante a inicialização.
|
7 |
+
"""
|
8 |
+
|
9 |
+
import os
|
10 |
+
import sys
|
11 |
+
import logging
|
12 |
+
import huggingface_hub
|
13 |
+
from huggingface_hub import snapshot_download, hf_hub_download
|
14 |
+
from pathlib import Path
|
15 |
+
import torch
|
16 |
+
import shutil
|
17 |
+
|
18 |
+
# Configurar logging
|
19 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
20 |
+
logger = logging.getLogger(__name__)
|
21 |
+
|
22 |
+
# Configurações de modelos
|
23 |
+
MODELS_DIR = os.environ.get("MODELS_DIR", "models")
|
24 |
+
HF_TOKEN = os.environ.get("HF_TOKEN", None)
|
25 |
+
|
26 |
+
# Modo sem download (NO_DOWNLOAD=1)
|
27 |
+
NO_DOWNLOAD = os.environ.get("NO_DOWNLOAD", "0").lower() in ("1", "true", "yes")
|
28 |
+
|
29 |
+
# Mensagem de debug para verificar o status da variável
|
30 |
+
logger.info(f"Inicializando model_downloader.py com NO_DOWNLOAD={NO_DOWNLOAD} (valor da env: {os.environ.get('NO_DOWNLOAD', 'não definido')})")
|
31 |
+
|
32 |
+
# Modelos necessários
|
33 |
+
MODEL_CONFIGS = {
|
34 |
+
"speech_encoder": {
|
35 |
+
"repo_id": "openai/whisper-large-v3",
|
36 |
+
"local_dir": os.path.join(MODELS_DIR, "speech_encoder", "whisper-large-v3"),
|
37 |
+
"files": None, # None significa baixar o modelo completo
|
38 |
+
},
|
39 |
+
"cosy2_decoder": {
|
40 |
+
"repo_id": "ICTNLP/cosy2_decoder",
|
41 |
+
"local_dir": os.path.join(MODELS_DIR, "cosy2_decoder"),
|
42 |
+
"files": [
|
43 |
+
"flow.decoder.estimator.fp32.onnx",
|
44 |
+
"flow.decoder.estimator.fp16.A10.plan",
|
45 |
+
"flow.encoder.fp32.zip",
|
46 |
+
"flow.decoder.estimator.fp16.Volta.plan",
|
47 |
+
"hift.pt",
|
48 |
+
"campplus.onnx",
|
49 |
+
"cosyvoice.yaml",
|
50 |
+
],
|
51 |
+
},
|
52 |
+
"llama_omni2": {
|
53 |
+
"repo_id": "ICTNLP/LLaMA-Omni2-0.5B",
|
54 |
+
"local_dir": os.path.join(MODELS_DIR, "LLaMA-Omni2-0.5B"),
|
55 |
+
"files": None, # None significa baixar o modelo completo
|
56 |
+
}
|
57 |
+
}
|
58 |
+
|
59 |
+
def ensure_model_dir():
|
60 |
+
"""Garante que o diretório models existe"""
|
61 |
+
if NO_DOWNLOAD:
|
62 |
+
logger.info("Modo NO_DOWNLOAD ativado. Pulando criação de diretórios.")
|
63 |
+
return
|
64 |
+
|
65 |
+
os.makedirs(MODELS_DIR, exist_ok=True)
|
66 |
+
for model_config in MODEL_CONFIGS.values():
|
67 |
+
os.makedirs(model_config["local_dir"], exist_ok=True)
|
68 |
+
|
69 |
+
def is_model_downloaded(model_key):
|
70 |
+
"""Verifica se um modelo já foi baixado"""
|
71 |
+
# No modo sem download, sempre retorna False para pular a verificação
|
72 |
+
if NO_DOWNLOAD:
|
73 |
+
logger.info(f"Modo NO_DOWNLOAD ativado. Pulando verificação para {model_key}.")
|
74 |
+
return False
|
75 |
+
|
76 |
+
config = MODEL_CONFIGS[model_key]
|
77 |
+
local_dir = config["local_dir"]
|
78 |
+
|
79 |
+
# Se não temos uma lista específica de arquivos, verificar apenas se o diretório existe
|
80 |
+
if config["files"] is None:
|
81 |
+
# Verificar se o diretório existe e tem arquivos
|
82 |
+
if os.path.exists(local_dir) and any(os.listdir(local_dir)):
|
83 |
+
logger.info(f"Modelo {model_key} já parece estar baixado em {local_dir}")
|
84 |
+
return True
|
85 |
+
return False
|
86 |
+
|
87 |
+
# Verificar se todos os arquivos específicos existem
|
88 |
+
for file in config["files"]:
|
89 |
+
file_path = os.path.join(local_dir, file)
|
90 |
+
if not os.path.exists(file_path):
|
91 |
+
logger.info(f"Arquivo {file} não encontrado para o modelo {model_key}")
|
92 |
+
return False
|
93 |
+
|
94 |
+
logger.info(f"Todos os arquivos para o modelo {model_key} já estão disponíveis em {local_dir}")
|
95 |
+
return True
|
96 |
+
|
97 |
+
def download_model(model_key):
|
98 |
+
"""Baixa um modelo específico do Hugging Face Hub"""
|
99 |
+
# Verificar o modo sem download
|
100 |
+
if NO_DOWNLOAD:
|
101 |
+
logger.warning(f"Modo NO_DOWNLOAD ativado. Pulando download de {model_key}")
|
102 |
+
return False
|
103 |
+
|
104 |
+
config = MODEL_CONFIGS[model_key]
|
105 |
+
repo_id = config["repo_id"]
|
106 |
+
local_dir = config["local_dir"]
|
107 |
+
files = config["files"]
|
108 |
+
|
109 |
+
try:
|
110 |
+
logger.info(f"Baixando modelo {model_key} do repo {repo_id}...")
|
111 |
+
|
112 |
+
# Se temos uma lista específica de arquivos, baixar um por um
|
113 |
+
if files is not None:
|
114 |
+
for file in files:
|
115 |
+
file_path = os.path.join(local_dir, file)
|
116 |
+
|
117 |
+
# Pular se o arquivo já existe
|
118 |
+
if os.path.exists(file_path):
|
119 |
+
logger.info(f"Arquivo {file} já existe, pulando download")
|
120 |
+
continue
|
121 |
+
|
122 |
+
logger.info(f"Baixando arquivo {file} para {file_path}")
|
123 |
+
try:
|
124 |
+
hf_hub_download(
|
125 |
+
repo_id=repo_id,
|
126 |
+
filename=file,
|
127 |
+
local_dir=local_dir,
|
128 |
+
local_dir_use_symlinks=False,
|
129 |
+
token=HF_TOKEN
|
130 |
+
)
|
131 |
+
except Exception as e:
|
132 |
+
logger.warning(f"Erro ao baixar arquivo {file}: {e}. Tentando continuar.")
|
133 |
+
else:
|
134 |
+
# Baixar o modelo completo
|
135 |
+
snapshot_download(
|
136 |
+
repo_id=repo_id,
|
137 |
+
local_dir=local_dir,
|
138 |
+
local_dir_use_symlinks=False,
|
139 |
+
token=HF_TOKEN
|
140 |
+
)
|
141 |
+
|
142 |
+
logger.info(f"Modelo {model_key} baixado com sucesso para {local_dir}")
|
143 |
+
return True
|
144 |
+
except Exception as e:
|
145 |
+
logger.error(f"Erro ao baixar modelo {model_key}: {e}")
|
146 |
+
return False
|
147 |
+
|
148 |
+
def cleanup_model_dir(model_key):
|
149 |
+
"""Remove arquivos incompletos ou corruptos de um diretório de modelo"""
|
150 |
+
# Verificar o modo sem download
|
151 |
+
if NO_DOWNLOAD:
|
152 |
+
logger.info(f"Modo NO_DOWNLOAD ativado. Pulando limpeza de diretório para {model_key}.")
|
153 |
+
return True
|
154 |
+
|
155 |
+
config = MODEL_CONFIGS[model_key]
|
156 |
+
local_dir = config["local_dir"]
|
157 |
+
|
158 |
+
try:
|
159 |
+
# Procurar por arquivos .incomplete e removê-los
|
160 |
+
for root, dirs, files in os.walk(local_dir):
|
161 |
+
for file in files:
|
162 |
+
if file.endswith(".incomplete"):
|
163 |
+
file_path = os.path.join(root, file)
|
164 |
+
logger.info(f"Removendo arquivo incompleto: {file_path}")
|
165 |
+
os.remove(file_path)
|
166 |
+
|
167 |
+
return True
|
168 |
+
except Exception as e:
|
169 |
+
logger.error(f"Erro ao limpar diretório do modelo {model_key}: {e}")
|
170 |
+
return False
|
171 |
+
|
172 |
+
def download_all_models():
|
173 |
+
"""Baixa todos os modelos configurados, se necessário"""
|
174 |
+
# Verificar o modo sem download
|
175 |
+
if NO_DOWNLOAD:
|
176 |
+
logger.warning("Modo NO_DOWNLOAD ativado. Nenhum modelo será baixado.")
|
177 |
+
return
|
178 |
+
|
179 |
+
ensure_model_dir()
|
180 |
+
|
181 |
+
for model_key in MODEL_CONFIGS:
|
182 |
+
if not is_model_downloaded(model_key):
|
183 |
+
logger.info(f"Iniciando download do modelo {model_key}")
|
184 |
+
cleanup_model_dir(model_key)
|
185 |
+
download_model(model_key)
|
186 |
+
else:
|
187 |
+
logger.info(f"Modelo {model_key} já está disponível localmente")
|
188 |
+
|
189 |
+
def download_model_if_needed(model_key):
|
190 |
+
"""Baixa um modelo específico se ele não estiver disponível"""
|
191 |
+
# Verificar o modo sem download
|
192 |
+
if NO_DOWNLOAD:
|
193 |
+
logger.info(f"Modo NO_DOWNLOAD ativado. Usando repo_id diretamente para {model_key}")
|
194 |
+
return False
|
195 |
+
|
196 |
+
ensure_model_dir()
|
197 |
+
|
198 |
+
if model_key not in MODEL_CONFIGS:
|
199 |
+
logger.error(f"Modelo {model_key} não está configurado para download")
|
200 |
+
return False
|
201 |
+
|
202 |
+
if not is_model_downloaded(model_key):
|
203 |
+
logger.info(f"Modelo {model_key} não encontrado localmente. Iniciando download...")
|
204 |
+
cleanup_model_dir(model_key)
|
205 |
+
return download_model(model_key)
|
206 |
+
else:
|
207 |
+
logger.info(f"Modelo {model_key} já está disponível localmente")
|
208 |
+
return True
|
209 |
+
|
210 |
+
def get_model_repo_id(model_key):
|
211 |
+
"""Retorna o repo_id do modelo para uso direto sem download"""
|
212 |
+
if model_key not in MODEL_CONFIGS:
|
213 |
+
logger.error(f"Modelo {model_key} não está configurado")
|
214 |
+
return None
|
215 |
+
return MODEL_CONFIGS[model_key]["repo_id"]
|
216 |
+
|
217 |
+
if __name__ == "__main__":
|
218 |
+
# Se executado diretamente, baixar todos os modelos
|
219 |
+
download_all_models()
|
no_download.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
"""
|
3 |
+
Script para iniciar aplicações no modo sem download.
|
4 |
+
Este script define explicitamente a variável NO_DOWNLOAD=1 no ambiente Python,
|
5 |
+
garantindo que nenhum modelo seja baixado.
|
6 |
+
"""
|
7 |
+
|
8 |
+
import os
|
9 |
+
import sys
|
10 |
+
import subprocess
|
11 |
+
import logging
|
12 |
+
|
13 |
+
# Configurar logging
|
14 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
15 |
+
logger = logging.getLogger("no_download")
|
16 |
+
|
17 |
+
# Definir a variável NO_DOWNLOAD no ambiente
|
18 |
+
os.environ["NO_DOWNLOAD"] = "1"
|
19 |
+
logger.info(f"Variável NO_DOWNLOAD definida como: {os.environ.get('NO_DOWNLOAD')}")
|
20 |
+
|
21 |
+
# Verificar argumentos de linha de comando
|
22 |
+
if len(sys.argv) < 2:
|
23 |
+
logger.info("Nenhum script especificado. Executando app.py por padrão.")
|
24 |
+
target_script = "app.py"
|
25 |
+
else:
|
26 |
+
target_script = sys.argv[1]
|
27 |
+
logger.info(f"Executando script: {target_script}")
|
28 |
+
|
29 |
+
# Lista de argumentos extras
|
30 |
+
args = sys.argv[2:]
|
31 |
+
|
32 |
+
# Exibir informações
|
33 |
+
print("=" * 70)
|
34 |
+
print(f"Executando {target_script} no modo SEM DOWNLOAD (NO_DOWNLOAD=1)")
|
35 |
+
print("Os modelos serão usados diretamente do Hugging Face Hub, sem baixar localmente")
|
36 |
+
print("=" * 70)
|
37 |
+
|
38 |
+
# Executar o script alvo com os mesmos argumentos
|
39 |
+
try:
|
40 |
+
# Criar um dicionário de ambiente com NO_DOWNLOAD definido
|
41 |
+
env = os.environ.copy()
|
42 |
+
env["NO_DOWNLOAD"] = "1"
|
43 |
+
|
44 |
+
# Construir o comando
|
45 |
+
command = [sys.executable, target_script] + args
|
46 |
+
logger.info(f"Executando comando: {' '.join(command)}")
|
47 |
+
|
48 |
+
# Execute o comando com o ambiente modificado
|
49 |
+
process = subprocess.Popen(command, env=env)
|
50 |
+
process.wait()
|
51 |
+
|
52 |
+
sys.exit(process.returncode)
|
53 |
+
except Exception as e:
|
54 |
+
logger.error(f"Erro ao executar {target_script}: {e}")
|
55 |
+
sys.exit(1)
|
run_without_downloads.sh
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
# Script para executar o LLaMA-Omni2 sem baixar modelos localmente
|
3 |
+
|
4 |
+
# Definir a variável de ambiente NO_DOWNLOAD
|
5 |
+
export NO_DOWNLOAD=1
|
6 |
+
|
7 |
+
# Verificar se a variável foi definida
|
8 |
+
echo "Verificando variável de ambiente NO_DOWNLOAD..."
|
9 |
+
echo "NO_DOWNLOAD=$NO_DOWNLOAD"
|
10 |
+
|
11 |
+
# Adicionar modo de depuração para verificar o funcionamento
|
12 |
+
export PYTHONVERBOSE=1
|
13 |
+
export PYTHONPATH=$(pwd):$PYTHONPATH
|
14 |
+
|
15 |
+
# Criar arquivo temporário de verificação
|
16 |
+
python -c "
|
17 |
+
import os
|
18 |
+
with open('env_check.txt', 'w') as f:
|
19 |
+
f.write(f'NO_DOWNLOAD={os.environ.get(\"NO_DOWNLOAD\", \"não definido\")}')
|
20 |
+
"
|
21 |
+
|
22 |
+
# Mostrar o conteúdo do arquivo de verificação
|
23 |
+
echo "Conteúdo do arquivo de verificação:"
|
24 |
+
cat env_check.txt
|
25 |
+
|
26 |
+
# Executar a aplicação
|
27 |
+
echo "Executando LLaMA-Omni2 no modo sem download (NO_DOWNLOAD=1)"
|
28 |
+
echo "Os modelos serão usados diretamente do Hugging Face Hub, sem baixar localmente"
|
29 |
+
echo "======================================================================"
|
30 |
+
|
31 |
+
# Verificar qual aplicação iniciar
|
32 |
+
if [ "$1" == "app" ] || [ "$1" == "" ]; then
|
33 |
+
echo "Iniciando app.py..."
|
34 |
+
# Verificar se a variável está disponível para o Python
|
35 |
+
python -c "import os; print('NO_DOWNLOAD environment variable:', os.environ.get('NO_DOWNLOAD', 'not set'))"
|
36 |
+
# Executar com a variável de ambiente explícita
|
37 |
+
NO_DOWNLOAD=1 python app.py
|
38 |
+
elif [ "$1" == "launcher" ]; then
|
39 |
+
echo "Iniciando launcher..."
|
40 |
+
python -c "import os; print('NO_DOWNLOAD environment variable:', os.environ.get('NO_DOWNLOAD', 'not set'))"
|
41 |
+
# Usar a opção de linha de comando
|
42 |
+
NO_DOWNLOAD=1 python launch_llama_omni2.py --no-model-download
|
43 |
+
elif [ "$1" == "audio" ]; then
|
44 |
+
echo "Iniciando interface de áudio..."
|
45 |
+
python -c "import os; print('NO_DOWNLOAD environment variable:', os.environ.get('NO_DOWNLOAD', 'not set'))"
|
46 |
+
NO_DOWNLOAD=1 python audio_interface.py
|
47 |
+
else
|
48 |
+
echo "Uso: $0 [app|launcher|audio]"
|
49 |
+
echo " app - Inicia app.py (padrão)"
|
50 |
+
echo " launcher - Inicia launch_llama_omni2.py"
|
51 |
+
echo " audio - Inicia audio_interface.py"
|
52 |
+
fi
|
53 |
+
|
54 |
+
# Limpar arquivo temporário
|
55 |
+
rm -f env_check.txt
|