Spaces:
Running
Running
Update routers/searchterm.py
Browse files- routers/searchterm.py +131 -0
routers/searchterm.py
CHANGED
@@ -15,6 +15,8 @@ from fastapi import APIRouter, HTTPException, Body
|
|
15 |
from fastapi.responses import FileResponse
|
16 |
from newspaper import Article
|
17 |
from threading import Timer
|
|
|
|
|
18 |
|
19 |
router = APIRouter()
|
20 |
|
@@ -22,6 +24,10 @@ BRAVE_API_KEY = os.getenv("BRAVE_API_KEY")
|
|
22 |
if not BRAVE_API_KEY:
|
23 |
raise ValueError("BRAVE_API_KEY não está definido!")
|
24 |
|
|
|
|
|
|
|
|
|
25 |
BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search"
|
26 |
BRAVE_HEADERS = {
|
27 |
"Accept": "application/json",
|
@@ -111,6 +117,86 @@ def create_temp_file(data: Dict[str, Any]) -> Dict[str, str]:
|
|
111 |
}
|
112 |
|
113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
async def search_brave_term(client: httpx.AsyncClient, term: str) -> List[Dict[str, str]]:
|
115 |
params = {"q": term, "count": 10, "safesearch": "off", "summary": "false"}
|
116 |
|
@@ -244,6 +330,51 @@ async def search_terms(payload: Dict[str, List[str]] = Body(...)) -> Dict[str, A
|
|
244 |
}
|
245 |
|
246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
@router.get("/download-temp/{file_id}")
|
248 |
async def download_temp_file(file_id: str):
|
249 |
"""Endpoint para download do arquivo temporário"""
|
|
|
15 |
from fastapi.responses import FileResponse
|
16 |
from newspaper import Article
|
17 |
from threading import Timer
|
18 |
+
from google import genai
|
19 |
+
from google.genai import types
|
20 |
|
21 |
router = APIRouter()
|
22 |
|
|
|
24 |
if not BRAVE_API_KEY:
|
25 |
raise ValueError("BRAVE_API_KEY não está definido!")
|
26 |
|
27 |
+
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
28 |
+
if not GEMINI_API_KEY:
|
29 |
+
raise ValueError("GEMINI_API_KEY não está definido!")
|
30 |
+
|
31 |
BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search"
|
32 |
BRAVE_HEADERS = {
|
33 |
"Accept": "application/json",
|
|
|
117 |
}
|
118 |
|
119 |
|
120 |
+
async def generate_gemini_response(input_text: str) -> str:
|
121 |
+
"""Gera resposta usando o modelo Gemini"""
|
122 |
+
try:
|
123 |
+
client = genai.Client(api_key=GEMINI_API_KEY)
|
124 |
+
model = "gemini-2.5-flash-lite"
|
125 |
+
|
126 |
+
contents = [
|
127 |
+
types.Content(
|
128 |
+
role="user",
|
129 |
+
parts=[
|
130 |
+
types.Part.from_text(text="Retorne um json de exemplo"),
|
131 |
+
],
|
132 |
+
),
|
133 |
+
types.Content(
|
134 |
+
role="model",
|
135 |
+
parts=[
|
136 |
+
types.Part.from_text(text="""Com certeza! Aqui está um exemplo de JSON simples:
|
137 |
+
```json
|
138 |
+
{
|
139 |
+
\"nome\": \"Maria Silva\",
|
140 |
+
\"idade\": 30,
|
141 |
+
\"profissao\": \"Engenheira de Software\",
|
142 |
+
\"habilidades\": [
|
143 |
+
\"Python\",
|
144 |
+
\"JavaScript\",
|
145 |
+
\"SQL\",
|
146 |
+
\"Docker\"
|
147 |
+
],
|
148 |
+
\"contato\": {
|
149 |
+
\"email\": \"[email protected]\",
|
150 |
+
\"telefone\": \"+55 11 98765-4321\"
|
151 |
+
},
|
152 |
+
\"ativo\": true,
|
153 |
+
\"projetos\": null
|
154 |
+
}
|
155 |
+
```
|
156 |
+
**Explicação dos elementos:**
|
157 |
+
* **`{}`**: Representa um objeto JSON.
|
158 |
+
* **`\"chave\": valor`**: Um objeto é composto por pares de chave-valor.
|
159 |
+
* As **chaves** são sempre strings, delimitadas por aspas duplas.
|
160 |
+
* Os **valores** podem ser de diversos tipos:
|
161 |
+
* **String:** ` \"Maria Silva\" ` (delimitada por aspas duplas)
|
162 |
+
* **Número:** ` 30 ` (inteiro ou decimal)
|
163 |
+
* **Booleano:** ` true ` ou ` false `
|
164 |
+
* **Array (Lista):** ` [\"Python\", \"JavaScript\", \"SQL\", \"Docker\"] ` (uma lista de valores, delimitada por colchetes `[]`, onde os elementos são separados por vírgulas)
|
165 |
+
* **Objeto:** ` {\"email\": \"[email protected]\", \"telefone\": \"+55 11 98765-4321\"} ` (outro objeto JSON aninhado)
|
166 |
+
* **`null`**: Representa a ausência de valor.
|
167 |
+
Este é um exemplo bastante comum e demonstra a estrutura básica do JSON."""),
|
168 |
+
],
|
169 |
+
),
|
170 |
+
types.Content(
|
171 |
+
role="user",
|
172 |
+
parts=[
|
173 |
+
types.Part.from_text(text=input_text),
|
174 |
+
],
|
175 |
+
),
|
176 |
+
]
|
177 |
+
|
178 |
+
generate_content_config = types.GenerateContentConfig(
|
179 |
+
thinking_config=types.ThinkingConfig(
|
180 |
+
thinking_budget=0,
|
181 |
+
),
|
182 |
+
)
|
183 |
+
|
184 |
+
# Coletamos toda a resposta em stream
|
185 |
+
full_response = ""
|
186 |
+
for chunk in client.models.generate_content_stream(
|
187 |
+
model=model,
|
188 |
+
contents=contents,
|
189 |
+
config=generate_content_config,
|
190 |
+
):
|
191 |
+
if chunk.text:
|
192 |
+
full_response += chunk.text
|
193 |
+
|
194 |
+
return full_response
|
195 |
+
|
196 |
+
except Exception as e:
|
197 |
+
raise HTTPException(status_code=500, detail=f"Erro ao gerar resposta do Gemini: {str(e)}")
|
198 |
+
|
199 |
+
|
200 |
async def search_brave_term(client: httpx.AsyncClient, term: str) -> List[Dict[str, str]]:
|
201 |
params = {"q": term, "count": 10, "safesearch": "off", "summary": "false"}
|
202 |
|
|
|
330 |
}
|
331 |
|
332 |
|
333 |
+
@router.post("/inference/terms")
|
334 |
+
async def inference_terms(payload: Dict[str, str] = Body(...)) -> Dict[str, Any]:
|
335 |
+
"""
|
336 |
+
Endpoint para fazer inferência com o modelo Gemini
|
337 |
+
|
338 |
+
Body:
|
339 |
+
{
|
340 |
+
"input": "Sua pergunta ou texto aqui"
|
341 |
+
}
|
342 |
+
"""
|
343 |
+
input_text = payload.get("input")
|
344 |
+
|
345 |
+
if not input_text or not isinstance(input_text, str):
|
346 |
+
raise HTTPException(
|
347 |
+
status_code=400,
|
348 |
+
detail="Campo 'input' é obrigatório e deve ser uma string."
|
349 |
+
)
|
350 |
+
|
351 |
+
if len(input_text.strip()) == 0:
|
352 |
+
raise HTTPException(
|
353 |
+
status_code=400,
|
354 |
+
detail="Campo 'input' não pode estar vazio."
|
355 |
+
)
|
356 |
+
|
357 |
+
try:
|
358 |
+
# Gera resposta usando o Gemini
|
359 |
+
response = await generate_gemini_response(input_text)
|
360 |
+
|
361 |
+
return {
|
362 |
+
"input": input_text,
|
363 |
+
"response": response,
|
364 |
+
"model": "gemini-2.5-flash-lite",
|
365 |
+
"timestamp": time.time()
|
366 |
+
}
|
367 |
+
|
368 |
+
except HTTPException:
|
369 |
+
# Re-raise HTTPExceptions para manter o status code correto
|
370 |
+
raise
|
371 |
+
except Exception as e:
|
372 |
+
raise HTTPException(
|
373 |
+
status_code=500,
|
374 |
+
detail=f"Erro interno do servidor: {str(e)}"
|
375 |
+
)
|
376 |
+
|
377 |
+
|
378 |
@router.get("/download-temp/{file_id}")
|
379 |
async def download_temp_file(file_id: str):
|
380 |
"""Endpoint para download do arquivo temporário"""
|