dksNoob commited on
Commit
4561404
·
1 Parent(s): 4a35b62

Deploy limpo do AutisMind AI API com gpt2-small-portuguese

Browse files
Files changed (3) hide show
  1. README.md +77 -8
  2. app.py +213 -60
  3. requirements.txt +6 -1
README.md CHANGED
@@ -1,13 +1,82 @@
1
  ---
2
- title: Autismind Ai
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.0.1
8
  app_file: app.py
9
- pinned: false
10
- license: mit
11
  ---
12
 
13
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: AutisMind AI API Backend
3
+ emoji: 🧠
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: gradio
7
+ python_version: 3.10 # OU 3.11, OU 3.12 (versões mais recentes e estáveis)
8
  app_file: app.py
9
+ requirements_file: requirements.txt
10
+ command: uvicorn app:app --host 0.0.0.0 --port 7860
11
  ---
12
 
13
+ # AutisMind AI API Backend
14
+
15
+ Este Hugging Face Space hospeda o servidor Python da API de Inteligência Artificial para o projeto **AutisMind**.
16
+
17
+ Ele fornece uma API RESTful para gerar respostas de texto em português e realizar análises básicas de conversas, focando no desenvolvimento socioemocional de pessoas neurodivergentes.
18
+
19
+ ### **Modelo de Linguagem Utilizado:**
20
+
21
+ O modelo de linguagem utilizado é o **`pierreguillou/gpt2-small-portuguese`**, que é baixado dinamicamente do Hugging Face Hub durante a inicialização do Space. Este modelo é otimizado para o idioma português e é leve o suficiente para ser executado no plano gratuito do Hugging Face Spaces.
22
+
23
+ ### **Endpoints da API:**
24
+
25
+ 1. **`POST /generate-response`**
26
+ * **Função:** Gera uma resposta de texto da IA para uma mensagem do usuário, considerando um histórico de conversa e uma personalidade de personagem. Também realiza uma análise básica da mensagem do usuário.
27
+ * **URL de Exemplo (após o deploy):** `https://SEU_NOME_DE_USUARIO-SEU_NOME_DO_SPACE.hf.space/generate-response`
28
+ * **Corpo da Requisição (JSON):**
29
+ ```json
30
+ {
31
+ "message": "Qual é a sua cor favorita?",
32
+ "history": [
33
+ {
34
+ "role": "user",
35
+ "content": "Olá, tudo bem?"
36
+ },
37
+ {
38
+ "role": "assistant",
39
+ "content": "Olá! Estou bem, obrigado. Como posso ajudar você hoje?"
40
+ }
41
+ ],
42
+ "persona": "Você é um robô de apoio amigável chamado 'Robô Guia', sempre com uma atitude positiva e prestativa.",
43
+ "chatId": "chat-id-exemplo"
44
+ }
45
+ ```
46
+ * **Exemplo de Resposta (JSON):**
47
+ ```json
48
+ {
49
+ "ai_response": "Como um robô guia, não tenho uma cor favorita como os humanos, mas eu adoro a cor azul, pois me lembra do céu e da vasta quantidade de informações que posso processar!",
50
+ "analysis": {
51
+ "sentiment": "positivo",
52
+ "emotion": "alegria"
53
+ }
54
+ }
55
+ ```
56
+
57
+ 2. **`GET /health`**
58
+ * **Função:** Verifica o status do servidor da API e se o modelo de IA foi carregado com sucesso.
59
+ * **URL de Exemplo (após o deploy):** `https://SEU_NOME_DE_USUARIO-SEU_NOME_DO_SPACE.hf.space/health`
60
+ * **Exemplo de Resposta (JSON):**
61
+ ```json
62
+ {
63
+ "status": "ok",
64
+ "model_loaded": true
65
+ }
66
+ ```
67
+
68
+ ### **Como Usar:**
69
+
70
+ 1. **Crie um Space no Hugging Face** com o SDK "Gradio" (conforme instruído, para usar o ambiente Python).
71
+ 2. **Clone este repositório** para a sua máquina local.
72
+ 3. **Copie os arquivos** `app.py`, `requirements.txt`, `.env` (se tiver outras variáveis) e este `README.md` para o diretório raiz do Space clonado. **Não inclua arquivos de modelo grandes (`.gguf` ou `.bin`)**.
73
+ 4. **Faça o `git add .`, `git commit` e `git push`** das suas alterações para o Space.
74
+ 5. O Hugging Face irá construir e iniciar sua API. Monitore a aba "Logs" para verificar o progresso e o status.
75
+ 6. Uma vez que o Space esteja "Running", use as URLs fornecidas acima para integrar com seu servidor Express e front-end.
76
+
77
+ ---
78
+
79
+ **Lembre-se de:**
80
+
81
+ * Substituir `SEU_NOME_DE_USUARIO` e `SEU_NOME_DO_SPACE` pelas informações reais do seu Space nas URLs de exemplo.
82
+ * Verificar a `python_version` no cabeçalho YAML (`3.10` é um bom padrão, mas confirme a sua com `python3 --version` no terminal).
app.py CHANGED
@@ -1,64 +1,217 @@
1
- import gradio as gr
2
- from huggingface_hub import InferenceClient
3
-
4
- """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
- """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
-
9
-
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
19
-
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
-
26
- messages.append({"role": "user", "content": message})
27
-
28
- response = ""
29
-
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- demo = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
  )
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
 
63
  if __name__ == "__main__":
64
- demo.launch()
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+ from fastapi import FastAPI, HTTPException
4
+ from fastapi.middleware.cors import CORSMiddleware
5
+ from pydantic import BaseModel, Field
6
+ from typing import List, Dict, Union, Optional
7
+
8
+ # --- NOVAS IMPORTAÇÕES PARA TRANSFORMERS E PyTorch ---
9
+ try:
10
+ from transformers import AutoTokenizer, AutoModelForCausalLM
11
+ import torch
12
+ except ImportError:
13
+ print("Erro: As bibliotecas 'transformers' ou 'torch' não foram encontradas.")
14
+ print("Certifique-se de instalá-las: pip install transformers torch")
15
+ exit(1)
16
+
17
+ # Carregar variáveis de ambiente (MODEL_PATH não será mais usado diretamente aqui)
18
+ load_dotenv()
19
+
20
+ # --- Configurações do Modelo ---
21
+ # O nome do modelo no Hugging Face Hub
22
+ HF_MODEL_ID = "pierreguillou/gpt2-small-portuguese"
23
+
24
+ # Instâncias globais para o modelo e tokenizer
25
+ tokenizer: Optional[AutoTokenizer] = None
26
+ model: Optional[AutoModelForCausalLM] = None
27
+
28
+ # --- Inicialização do FastAPI ---
29
+ app = FastAPI(
30
+ title="AutisMind AI Server",
31
+ description="API para interação com o modelo GPT2-small-portuguese e análise de conversas.",
32
+ version="1.0.0",
33
+ )
34
+
35
+ # --- Configuração CORS ---
36
+ origins = [
37
+ "http://localhost:3000",
38
+ "http://localhost:5000",
39
+ "http://127.0.0.1:3000",
40
+ "http://127.0.0.1:5000",
41
+ # Adicione aqui os domínios do seu frontend e do Express API quando estiverem em produção
42
+ # Ex: "https://seunome-seu-space-name.hf.space"
43
+ ]
44
+
45
+ app.add_middleware(
46
+ CORSMiddleware,
47
+ allow_origins=origins,
48
+ allow_credentials=True,
49
+ allow_methods=["*"],
50
+ allow_headers=["*"],
 
 
 
 
 
 
 
 
 
51
  )
52
 
53
+ # --- Modelos Pydantic para Requisições e Respostas (Mantidos) ---
54
+ class ChatMessage(BaseModel):
55
+ role: str # "user" ou "assistant"
56
+ content: str
57
+
58
+ class ChatRequest(BaseModel):
59
+ message: str = Field(..., description="A mensagem do usuário.")
60
+ history: List[ChatMessage] = Field(default_factory=list, description="Histórico da conversa (opcional).")
61
+ persona: str = Field(
62
+ "Você é um assistente útil e amigável. Responda de forma clara e empática.",
63
+ description="A personalidade do personagem para a IA."
64
+ )
65
+ chatId: Optional[str] = Field(None, description="ID do chat para contexto (não usado pela IA, mas pode ser útil para logs).")
66
+
67
+ class AnalysisResult(BaseModel):
68
+ sentiment: str = Field("neutro", description="Sentimento da mensagem (positivo, negativo, neutro).")
69
+ emotion: str = Field("desconhecida", description="Emoção detectada (ex: alegria, tristeza, raiva).")
70
+
71
+ class ChatResponse(BaseModel):
72
+ ai_response: str = Field(..., description="A resposta gerada pela IA.")
73
+ analysis: AnalysisResult = Field(..., description="Resultados da análise da mensagem do usuário ou da resposta da IA.")
74
+
75
+ # --- Evento de inicialização da aplicação (carrega o modelo) ---
76
+ @app.on_event("startup")
77
+ async def startup_event():
78
+ global model, tokenizer
79
+ print(f"Carregando modelo Transformers: {HF_MODEL_ID}")
80
+ try:
81
+ tokenizer = AutoTokenizer.from_pretrained(HF_MODEL_ID)
82
+ # O GPT-2 não tem um token PAD padrão, define um.
83
+ # 50256 é o token EOS padrão do GPT-2, pode ser usado como PAD também.
84
+ tokenizer.pad_token = tokenizer.eos_token
85
+
86
+ # Ajusta o tamanho máximo de sequência do tokenizer para algo comum como 1024
87
+ tokenizer.model_max_length = 1024
88
+
89
+ model = AutoModelForCausalLM.from_pretrained(HF_MODEL_ID)
90
+ model.eval() # Coloca o modelo em modo de avaliação (desativa dropout, etc.)
91
+
92
+ # Tenta mover o modelo para a GPU se disponível e compatível com PyTorch/Transformers
93
+ if torch.cuda.is_available():
94
+ model.to("cuda")
95
+ print("Modelo movido para GPU!")
96
+ else:
97
+ print("Modelo carregado na CPU.")
98
+
99
+ print(f"Modelo {HF_MODEL_ID} carregado com sucesso!")
100
+ except Exception as e:
101
+ print(f"Erro ao carregar o modelo {HF_MODEL_ID}: {e}")
102
+ raise RuntimeError(f"Falha ao carregar o modelo LLM: {e}")
103
+
104
+ # --- Endpoint de Saúde ---
105
+ @app.get("/health")
106
+ async def health_check():
107
+ if model and tokenizer: # Verifica se ambos foram carregados
108
+ return {"status": "ok", "model_loaded": True}
109
+ return {"status": "loading", "model_loaded": False}
110
+
111
+ # --- Endpoint Principal para Geração de Resposta e Análise ---
112
+ @app.post("/generate-response", response_model=ChatResponse)
113
+ async def generate_ai_response(request: ChatRequest):
114
+ global model, tokenizer
115
+ if not model or not tokenizer:
116
+ raise HTTPException(status_code=503, detail="Modelo AI ainda não carregado. Tente novamente em breve.")
117
+
118
+ user_message = request.message
119
+ chat_history = request.history
120
+ character_persona = request.persona
121
+
122
+ # --- Construir o Prompt para GPT-2 ---
123
+ # GPT-2 é um modelo generativo, não segue o formato <|system|> como Phi.
124
+ # A persona e o histórico são concatenados.
125
+ prompt_parts = []
126
+ # Inclui a persona no início do prompt, como uma instrução inicial para o modelo.
127
+ prompt_parts.append(f"{character_persona}\n\n")
128
+
129
+ # Adicionar histórico da conversa
130
+ # É importante limitar o histórico para não exceder o model_max_length (1024 tokens para GPT-2 small).
131
+ # Uma boa estratégia é adicionar o histórico mais recente.
132
+ # O GPT-2 não tem roles, então formatamos como um diálogo.
133
+ for turn in chat_history[-5:]: # Inclui os últimos 5 turnos (adaptar conforme necessidade)
134
+ if turn.role == 'user':
135
+ prompt_parts.append(f"Usuário: {turn.content}\n")
136
+ elif turn.role == 'assistant':
137
+ prompt_parts.append(f"Assistente: {turn.content}\n")
138
+
139
+ # Adiciona a mensagem atual do usuário e pede para a IA responder
140
+ prompt_parts.append(f"Usuário: {user_message}\nAssistente:")
141
+
142
+ full_prompt = "".join(prompt_parts)
143
+
144
+ try:
145
+ # Codifica o prompt para tokens
146
+ # return_tensors="pt" para PyTorch
147
+ # max_length para garantir que o prompt não exceda o limite do modelo
148
+ inputs = tokenizer(
149
+ full_prompt,
150
+ return_tensors="pt",
151
+ max_length=tokenizer.model_max_length,
152
+ truncation=True
153
+ )
154
+
155
+ # Mover os inputs para a GPU se o modelo estiver na GPU
156
+ if torch.cuda.is_available():
157
+ inputs = {k: v.to("cuda") for k, v in inputs.items()}
158
+
159
+ # Gerar a resposta
160
+ # pad_token_id: O token usado para preencher sequências, aqui usamos o EOS token do GPT-2
161
+ # do_sample=True: Habilita amostragem (para criatividade)
162
+ # top_k, top_p: Métodos de amostragem para controlar a diversidade da resposta
163
+ # max_new_tokens: O número máximo de novos tokens que a IA pode gerar APÓS o prompt
164
+ sample_outputs = model.generate(
165
+ inputs.input_ids,
166
+ pad_token_id=tokenizer.pad_token_id, # Usando o token de pad que definimos
167
+ do_sample=True,
168
+ max_new_tokens=150, # Gera até 150 tokens novos de resposta
169
+ temperature=0.7,
170
+ top_k=50,
171
+ top_p=0.9,
172
+ num_return_sequences=1
173
+ )
174
+
175
+ # Decodificar a resposta gerada
176
+ # skip_special_tokens=True: Remove tokens especiais como <bos>, <eos>, <pad>
177
+ generated_text = tokenizer.decode(sample_outputs[0], skip_special_tokens=True)
178
+
179
+ # --- Pós-processamento da Resposta do GPT-2 ---
180
+ # GPT-2 vai gerar o prompt INTEIRO MAIS a resposta.
181
+ # Precisamos remover o prompt original para obter apenas a resposta do "Assistente:".
182
+ # Isso pode ser um pouco delicado e pode precisar de ajustes finos dependendo da saída real do modelo.
183
+ ai_response_raw = generated_text.replace(full_prompt, "").strip()
184
+
185
+ # O GPT-2 pode continuar gerando texto ou até começar um "Usuário:" de novo.
186
+ # Tentamos cortar a resposta na primeira ocorrência de "Usuário:" ou "Assistente:" para evitar isso.
187
+ if "\nUsuário:" in ai_response_raw:
188
+ ai_response = ai_response_raw.split("\nUsuário:")[0].strip()
189
+ elif "\nAssistente:" in ai_response_raw:
190
+ ai_response = ai_response_raw.split("\nAssistente:")[0].strip()
191
+ else:
192
+ ai_response = ai_response_raw
193
+
194
+
195
+ # --- Lógica de Análise (Mantida) ---
196
+ analysis_result = AnalysisResult()
197
+ user_message_lower = user_message.lower()
198
+ if "triste" in user_message_lower or "chateado" in user_message_lower or "mal" in user_message_lower:
199
+ analysis_result.sentiment = "negativo"
200
+ analysis_result.emotion = "tristeza"
201
+ elif "feliz" in user_message_lower or "alegre" in user_message_lower or "bom" in user_message_lower:
202
+ analysis_result.sentiment = "positivo"
203
+ analysis_result.emotion = "alegria"
204
+ else:
205
+ analysis_result.sentiment = "neutro"
206
+ analysis_result.emotion = "desconhecida"
207
+
208
+ return ChatResponse(ai_response=ai_response, analysis=analysis_result)
209
+
210
+ except Exception as e:
211
+ print(f"Erro na geração da IA: {e}")
212
+ raise HTTPException(status_code=500, detail=f"Erro interno do servidor AI: {str(e)}")
213
 
214
+ # --- Executar o Servidor (apenas para teste direto via Python) ---
215
  if __name__ == "__main__":
216
+ import uvicorn
217
+ uvicorn.run(app, host="0.0.0.0", port=5001)
requirements.txt CHANGED
@@ -1 +1,6 @@
1
- huggingface_hub==0.25.2
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ python-dotenv
4
+ transformers
5
+ torch # ou tensorflow, dependendo da sua preferência, mas transformers usa pytorch por padrão
6
+ pydantic>=2.0