feat:
- 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:
6
.env.example
Normal file
6
.env.example
Normal 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
78
.zed/tasks.json
Normal 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}"
|
||||
}
|
||||
}
|
||||
]
|
||||
13
README.md
13
README.md
@@ -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
0
app/__init___.py
Normal file
21
app/llm_service.py
Normal file
21
app/llm_service.py
Normal 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
32
app/main.py
Normal 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
1
app/state.py
Normal file
@@ -0,0 +1 @@
|
||||
from typing import TypedDict, Annotated, Sequence
|
||||
0
app/tools/__init__.py
Normal file
0
app/tools/__init__.py
Normal file
0
core/__init__.py
Normal file
0
core/__init__.py
Normal file
68
core/database.py
Normal file
68
core/database.py
Normal 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
|
||||
6
main.py
6
main.py
@@ -1,6 +0,0 @@
|
||||
def main():
|
||||
print("Hello from r3wmsagents!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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
58
requirements.txt
Normal 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
0
tests/__init__.py
Normal file
15
tests/test_database.py
Normal file
15
tests/test_database.py
Normal 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
0
tests/tools/__init__.py
Normal file
Reference in New Issue
Block a user