This commit is contained in:
rafa-ruiz 2026-02-11 00:13:13 -08:00
parent be65aa977b
commit 4cf171c8a2
4 changed files with 82 additions and 123 deletions

View File

@ -8,20 +8,18 @@ WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \ build-essential \
curl \ curl \
libpq-dev \
protobuf-compiler \ protobuf-compiler \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir --upgrade pip RUN pip install --no-cache-dir --upgrade pip
RUN pip install --no-cache-dir \ RUN pip install --no-cache-dir \
langchain==0.1.0 \ langchain==0.1.0 \
langfuse>=2.0.0 \ langchain-community==0.0.10 \
langgraph \
langchain-openai \
langchain-elasticsearch \ langchain-elasticsearch \
grpcio \ grpcio \
grpcio-tools \ grpcio-tools \
psycopg2-binary \ grpcio-reflection \
pydantic pydantic
COPY ./protos ./protos COPY ./protos ./protos
@ -34,5 +32,5 @@ RUN python -m grpc_tools.protoc \
./protos/brunix.proto ./protos/brunix.proto
EXPOSE 50051 EXPOSE 50051
#CMD ["tail", "-f", "/dev/null"]
CMD ["python", "src/server.py"] CMD ["python", "src/server.py"]

View File

@ -14,35 +14,21 @@ The following diagram illustrates the interaction between the AVAP technology, t
```mermaid ```mermaid
graph TD graph TD
subgraph Client_Layer [External Interface] subgraph Local_Dev [Laptop Ivar/Rafael]
Client[External Services / UI]
end
subgraph Engine_Layer
BE[Brunix Assistance Engine] BE[Brunix Assistance Engine]
LG[LangGraph Logic] KT[Kubectl Tunnel]
LC[LangChain Framework]
end end
subgraph Intelligence_Layer subgraph Vultr_K8s_Cluster [Production - Vultr Cloud]
LLM[Fine-tuned Model / OpenAI or other] EDB[(Elasticsearch Vector DB - HDD)]
Prompt[Prompt Engineering]
end
subgraph Data_Observability_Layer [System Support]
EDB[(Elasticsearch Vector DB)]
LF[Langfuse Observability]
PG[(Postgres - System Data)] PG[(Postgres - System Data)]
LF[Langfuse UI]
end end
Client -- gRPC:50052 --> BE BE -- localhost:9200/5432 --> KT
BE --> LG KT -- Secure Tunnel --> EDB
LG --> LC KT -- Secure Tunnel --> PG
LC --> LLM BE -- Public IP --> LF
LLM --> Prompt
LC -- Semantic Search --> EDB
LC -- Tracing/Metrics --> LF
LF -- Persistence --> PG
``` ```
--- ---

View File

@ -7,57 +7,15 @@ services:
ports: ports:
- "50052:50051" - "50052:50051"
environment: environment:
- ELASTICSEARCH_URL=http://elasticsearch:9200 - ELASTICSEARCH_URL=http://host.docker.internal:9200
- DATABASE_URL=postgresql://postgres:brunix_pass@host.docker.internal:5432/postgres
- LANGFUSE_HOST=http://45.77.119.180
- LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY} - LANGFUSE_PUBLIC_KEY=${LANGFUSE_PUBLIC_KEY}
- LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY} - LANGFUSE_SECRET_KEY=${LANGFUSE_SECRET_KEY}
- LANGFUSE_HOST=http://langfuse:3000 - LLM_BASE_URL=http://host.docker.internal:11434
- OPENAI_API_KEY=${OPENAI_API_KEY} # O el proveedor que elija Ivar - OPENAI_API_KEY=${OPENAI_API_KEY}
depends_on:
- elasticsearch
- langfuse
networks:
- avap-network
elasticsearch: extra_hosts:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0 - "host.docker.internal:host-gateway"
container_name: brunix-vector-db
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ports:
- "9200:9200"
networks:
- avap-network
langfuse:
image: langfuse/langfuse:2.33.0
container_name: brunix-observability
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:brunix_pass@langfuse-db:5432/postgres
- NEXTAUTH_URL=http://localhost:3000
- NEXTAUTH_SECRET=my_ultra_secret
- SALT=my_salt
depends_on:
- langfuse-db
networks:
- avap-network
langfuse-db:
image: postgres:15
container_name: brunix-postgres
environment:
- POSTGRES_PASSWORD=brunix_pass
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- avap-network
networks:
avap-network:
driver: bridge
volumes:
postgres_data:

View File

@ -1,68 +1,85 @@
import os import os
import grpc import grpc
from concurrent import futures
import logging import logging
from concurrent import futures
from grpc_reflection.v1alpha import reflection
import brunix_pb2 import brunix_pb2
import brunix_pb2_grpc import brunix_pb2_grpc
#from langfuse.callback import CallbackHandler # Descomentar cuando este configurado
#from langchain_openai import ChatOpenAI # Cambiar por el que corresponda from langchain_community.llms import Ollama
from langchain_core.messages import HumanMessage from langchain_community.embeddings import OllamaEmbeddings
from langchain_elasticsearch import ElasticsearchStore
from langchain_core.prompts import ChatPromptTemplate
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("BrunixServer") logger = logging.getLogger("brunix-engine")
class BrunixService(brunix_pb2_grpc.AssistanceEngineServicer): class BrunixEngine(brunix_pb2_grpc.AssistanceEngineServicer):
def __init__(self): def __init__(self):
#self.langfuse_handler = CallbackHandler( # Descomentar cuando este configurado
# public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
# secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
# host=os.getenv("LANGFUSE_HOST")
#)
# AQUI IMPLEMENTAR EL MODELO QUE CORRESPONDA - IVAR
#self.llm = ChatOpenAI(
# model="gpt-4-turbo-preview",
# temperature=0.2,
# streaming=True
#)
logger.info("Brunix Engine initializing.")
def AskAgent(self, request, context): # PLACEHOLDER DE FUNCIONAMIENTO self.base_url = os.getenv("LLM_BASE_URL", "http://ollama-light-service:11434")
logger.info(f"Request received: {request.query}") self.model_name = os.getenv("LLM_MODEL", "qwen2.5:1.5b")
logger.info(f"Starting server")
self.llm = Ollama(base_url=self.base_url, model=self.model_name)
self.embeddings = OllamaEmbeddings(base_url=self.base_url, model="nomic-embed-text")
es_url = os.getenv("ELASTICSEARCH_URL", "http://elasticsearch:9200")
logger.info(f"ElasticSearch on: {es_url}")
self.vector_store = ElasticsearchStore(
es_url=es_url,
index_name="avap_manuals",
embedding=self.embeddings
)
def AskAgent(self, request, context):
logger.info(f"request {request.session_id}): {request.query[:50]}.")
try: try:
context_text = "AVAP is a virtual programming language for API development."
# 4. Prompt Engineering
prompt = ChatPromptTemplate.from_template("""
You are Brunix, the 101OBEX artificial intelligence for the AVAP Sphere platform. Respond in a professional manner.
config = {"callbacks": [self.langfuse_handler], "run_name": "Brunix_Query"} CONTEXT:
{context}
full_response_text = "" QUESTION:
{question}
""")
chunks = [ chain = prompt | self.llm
{"text": ""},
]
for chunk in chunks: for chunk in chain.stream({"context": context_text, "question": request.query}):
yield brunix_pb2.AgentResponse( yield brunix_pb2.AgentResponse(
text=chunk["text"], text=str(chunk),
avap_code="", avap_code="AVAP-2026",
node_id=chunk["node"],
is_final=False is_final=False
) )
yield brunix_pb2.AgentResponse(text="", is_final=True) yield brunix_pb2.AgentResponse(text="", avap_code="", is_final=True)
except Exception as e: except Exception as e:
logger.error(f"AGENT ERROR: {str(e)}") logger.error(f"Error in AskAgent: {str(e)}")
context.set_details(str(e)) yield brunix_pb2.AgentResponse(text=f"[Error Motor]: {str(e)}", is_final=True)
context.set_code(grpc.StatusCode.INTERNAL)
def serve(): def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
brunix_pb2_grpc.add_AssistanceEngineServicer_to_server(BrunixService(), server)
brunix_pb2_grpc.add_AssistanceEngineServicer_to_server(BrunixEngine(), server)
SERVICE_NAMES = (
brunix_pb2.DESCRIPTOR.services_by_name['AssistanceEngine'].full_name,
reflection.SERVICE_NAME,
)
reflection.enable_server_reflection(SERVICE_NAMES, server)
server.add_insecure_port('[::]:50051') server.add_insecure_port('[::]:50051')
logger.info("Brunix gRPC Server listen on port 50051") logger.info("Brunix Engine on port 50051")
server.start() server.start()
server.wait_for_termination() server.wait_for_termination()