- Criado um serviço de llm (por enquanto está obtendo somente o gemini, necessita adicioanr suporte para entrada do usuário na pergunta)

test:
- Criado teste para conexão com o banco de dados oracle por meio da
engine do sqlAlchemy
This commit is contained in:
Ubuntu
2025-05-21 22:26:23 -03:00
parent fc04fabaf9
commit e705d42d46
16 changed files with 300 additions and 7 deletions

6
.env.example Normal file
View File

@@ -0,0 +1,6 @@
GEMINI_API_KEY=
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=
DB_SERVICE_NAME=

78
.zed/tasks.json Normal file
View File

@@ -0,0 +1,78 @@
// Static tasks configuration.
//
// Example:
[
{
"label": "Example task",
"command": "for i in {1..5}; do echo \"Hello $i/5\"; sleep 1; done",
//"args": [],
// Env overrides for the command, will be appended to the terminal's environment from the settings.
"env": { "foo": "bar" },
// Current working directory to spawn the command into, defaults to current project root.
//"cwd": "/path/to/working/directory",
// Whether to use a new terminal tab or reuse the existing one to spawn the process, defaults to `false`.
"use_new_terminal": false,
// Whether to allow multiple instances of the same task to be run, or rather wait for the existing ones to finish, defaults to `false`.
"allow_concurrent_runs": false,
// What to do with the terminal pane and tab, after the command was started:
// * `always` — always show the task's pane, and focus the corresponding tab in it (default)
// * `no_focus` — always show the task's pane, add the task's tab in it, but don't focus it
// * `never` — do not alter focus, but still add/reuse the task's tab in its pane
"reveal": "always",
// Where to place the task's terminal item after starting the task:
// * `dock` — in the terminal dock, "regular" terminal items' place (default)
// * `center` — in the central pane group, "main" editor area
"reveal_target": "dock",
// What to do with the terminal pane and tab, after the command had finished:
// * `never` — Do nothing when the command finishes (default)
// * `always` — always hide the terminal tab, hide the pane also if it was the last tab in it
// * `on_success` — hide the terminal tab on task success only, otherwise behaves similar to `always`
"hide": "never",
// Which shell to use when running a task inside the terminal.
// May take 3 values:
// 1. (default) Use the system's default terminal configuration in /etc/passwd
// "shell": "system"
// 2. A program:
// "shell": {
// "program": "sh"
// }
// 3. A program with arguments:
// "shell": {
// "with_arguments": {
// "program": "/bin/bash",
// "args": ["--login"]
// }
// }
"shell": "system",
// Represents the tags for inline runnable indicators, or spawning multiple tasks at once.
"tags": []
},
{
"label": "run_main",
"type": "shell",
"name": "Run main.py in venv",
"command": "python3",
"args": ["app/main.py"],
"options": {
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${workspaceFolder}"
},
"dependsOn": ["activate_venv"],
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "activate_venv",
"type": "shell",
"name": "Activate venv",
"command": "source",
"args": [".venv/bin/activate"],
"options": {
"cwd": "${workspaceFolder}"
}
}
]

View File

@@ -0,0 +1,13 @@
### Variáveis .env
**GEMINI_API_KEY** -> API do gemini para consumir
### Database
*SQLAlchemy* -> Fornece um conjunto de ferramentas para banco de dados abstraindo o DBA, tendo um ORM e pode construir consulta sql de forma programática.
**Lembre-se de configurar a conexão com o banco de dados em DATABASE_URL no .env**

0
app/__init___.py Normal file
View File

21
app/llm_service.py Normal file
View File

@@ -0,0 +1,21 @@
import os
from langchain_core.language_models.chat_models import BaseChatModel
from langchain_google_genai import ChatGoogleGenerativeAI
from dotenv import load_dotenv
load_dotenv()
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
def get_llm() -> BaseChatModel | None:
if not GEMINI_API_KEY:
print("⚠️ Variável de ambiente GEMINI_API_KEY não definida.")
# raise ValueError("OPENAI_API_KEY não está configurada.")
return None
try:
llm = ChatGoogleGenerativeAI(model="gemma-3-27b-it", google_api_key=GEMINI_API_KEY)
print("Gemma 3 configurado com sucesso")
return llm
except Exception as e:
print(f"Erro ao configurar o llm: {e}")
return None

32
app/main.py Normal file
View File

@@ -0,0 +1,32 @@
from llm_service import get_llm
from langchain_core.messages import HumanMessage
def main():
print("Hello from r3wmsagents!")
llm_instance = get_llm()
if not llm_instance:
print("Não carregou o llm")
return
pergunta_usuario = "Qual é a capital da França e qual sua principal atração turística?"
print(f"\n🧑 Enviando pergunta: {pergunta_usuario}")
try:
# Para interações simples, você pode passar a string diretamente para .invoke()
# ou usar uma lista de mensagens para mais controle (ex: com mensagens do sistema)
# response = llm_instance.invoke(pergunta_usuario)
# Usando HumanMessage para ser mais explícito (bom para LangGraph depois)
messages = [HumanMessage(content=pergunta_usuario)]
response = llm_instance.invoke(messages)
print(response)
# 5. Imprimir a resposta
# A resposta (response) é geralmente um AIMessage, então acessamos seu .content
if hasattr(response, 'content'):
print(f"\n🤖 Resposta do LLM: {response.content}")
else:
print(f"\n🤖 Resposta do LLM (formato desconhecido): {response}")
except Exception as e:
print(f"\n❌ Ocorreu um erro ao interagir com o LLM: {e}")
if __name__ == "__main__":
main()

1
app/state.py Normal file
View File

@@ -0,0 +1 @@
from typing import TypedDict, Annotated, Sequence

0
app/tools/__init__.py Normal file
View File

0
core/__init__.py Normal file
View File

68
core/database.py Normal file
View File

@@ -0,0 +1,68 @@
from dotenv import load_dotenv
import os
import oracledb
from sqlalchemy import create_engine, Engine
load_dotenv()
DB_USER=os.getenv("DB_USER")
DB_PASSWORD=os.getenv("DB_PASSWORD")
DB_HOST=os.getenv("DB_HOST")
DB_PORT=os.getenv("DB_PORT")
DB_SERVICE_NAME=os.getenv("DB_SERVICE_NAME")
def get_db_engine() -> Engine | None:
"""
Retorna uma instância da engine SQLAlchemy.
Cria a engine na primeira chamada e a reutiliza nas subsequentes.
"""
# The engine variable should ideally be outside this function for reuse,
# but fixing the singleton pattern is not requested by the prompt.
# We are fixing the diagnostics related to variable types.
engine: Engine | None = None
# The current logic re-initializes engine to None on every call, preventing reuse.
# However, this structure is kept as per the original code.
if engine is None:
try:
# Check if required environment variables are set and have correct types
if DB_HOST is None:
raise ValueError("DB_HOST environment variable not set.")
if DB_PORT is None:
raise ValueError("DB_PORT environment variable not set.")
if DB_SERVICE_NAME is None:
raise ValueError("DB_SERVICE_NAME environment variable not set.")
# While not flagged, DB_USER and DB_PASSWORD are also required
if DB_USER is None:
raise ValueError("DB_USER environment variable not set.")
if DB_PASSWORD is None:
raise ValueError("DB_PASSWORD environment variable not set.")
# Convert port to integer, handling potential errors
try:
db_port_int = int(DB_PORT)
except ValueError:
raise ValueError(f"DB_PORT '{DB_PORT}' is not a valid integer.")
# Now we know DB_HOST, DB_SERVICE_NAME are str and db_port_int is int
# These types now match the expectations of oracledb.makedsn
dsn = oracledb.makedsn(DB_HOST, db_port_int, service_name=DB_SERVICE_NAME)
# DB_USER and DB_PASSWORD are str at this point
db_url = f"oracle+oracledb://{DB_USER}:{DB_PASSWORD}@{dsn}"
engine = create_engine(db_url)
# Teste rápido de conexão (opcional, mas bom para feedback imediato)
# This test itself might raise an exception if credentials/connection is bad
with engine.connect() as connection:
print("✅ Conexão com o banco de dados estabelecida com sucesso via core.database!")
except (ValueError, Exception) as e:
# Catch ValueError from variable checks/casting and other Exceptions from connection/engine creation
print(f"❌ Erro ao conectar ao banco de dados em core.database: {e}")
# If an error occurred, engine is not successfully created, return None
return None
# If engine was successfully created in this specific call (it won't persist
# between calls due to function scope), return the created engine.
return engine

View File

@@ -1,6 +0,0 @@
def main():
print("Hello from r3wmsagents!")
if __name__ == "__main__":
main()

View File

@@ -4,4 +4,11 @@ version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
dependencies = [
"dotenv>=0.9.9",
"langchain-google-genai>=2.1.4",
"langgraph>=0.4.5",
"oracledb>=3.1.1",
"pytest>=8.3.5",
"sqlalchemy>=2.0.41",
]

58
requirements.txt Normal file
View File

@@ -0,0 +1,58 @@
Package Version
---------------------------- ---------
annotated-types 0.7.0
anyio 4.9.0
cachetools 5.5.2
certifi 2025.4.26
cffi 1.17.1
charset-normalizer 3.4.2
cryptography 45.0.2
dotenv 0.9.9
filetype 1.2.0
google-ai-generativelanguage 0.6.18
google-api-core 2.24.2
google-auth 2.40.2
googleapis-common-protos 1.70.0
greenlet 3.2.2
grpcio 1.71.0
grpcio-status 1.71.0
h11 0.16.0
httpcore 1.0.9
httpx 0.28.1
idna 3.10
iniconfig 2.1.0
jsonpatch 1.33
jsonpointer 3.0.0
langchain-core 0.3.60
langchain-google-genai 2.1.4
langgraph 0.4.5
langgraph-checkpoint 2.0.26
langgraph-prebuilt 0.1.8
langgraph-sdk 0.1.69
langsmith 0.3.42
oracledb 3.1.1
orjson 3.10.18
ormsgpack 1.9.1
packaging 24.2
pluggy 1.6.0
proto-plus 1.26.1
protobuf 5.29.4
pyasn1 0.6.1
pyasn1-modules 0.4.2
pycparser 2.22
pydantic 2.11.4
pydantic-core 2.33.2
pytest 8.3.5
python-dotenv 1.1.0
pyyaml 6.0.2
requests 2.32.3
requests-toolbelt 1.0.0
rsa 4.9.1
sniffio 1.3.1
sqlalchemy 2.0.41
tenacity 9.1.2
typing-extensions 4.13.2
typing-inspection 0.4.1
urllib3 2.4.0
xxhash 3.5.0
zstandard 0.23.0

0
tests/__init__.py Normal file
View File

15
tests/test_database.py Normal file
View File

@@ -0,0 +1,15 @@
import os
import pytest
from sqlalchemy import Engine,text, exc
from core.database import get_db_engine, DB_URL
def test_get_db_engine_success():
"""
Testa se get_db_engine retorna uma instância de Engine válida
quando DATABASE_URL está configurada corretamente.
"""
engine = get_db_engine()
assert engine is not None, "get_db_engine() retornou None mesmo com DATABASE_URL configurada."
assert isinstance(engine, Engine), "get_db_engine() não retornou uma instância de sqlalchemy.engine.Engine."
print("✅ get_db_engine() retornou uma Engine.")

0
tests/tools/__init__.py Normal file
View File