add healthcheck to remaining apps
43
.github/workflows/release.yml
vendored
@@ -20,13 +20,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
bursatil: ${{ steps.filter.outputs.bursatil }}
|
bursatil: ${{ steps.filter.outputs.bursatil }}
|
||||||
ChatEgresos: ${{ steps.filter.outputs.ChatEgresos }}
|
egresos: ${{ steps.filter.outputs.egresos }}
|
||||||
inversionistas: ${{ steps.filter.outputs.inversionistas }}
|
inversionistas: ${{ steps.filter.outputs.inversionistas }}
|
||||||
normativa: ${{ steps.filter.outputs.normativa }}
|
normativa: ${{ steps.filter.outputs.normativa }}
|
||||||
ocp: ${{ steps.filter.outputs.ocp }}
|
ocp: ${{ steps.filter.outputs.ocp }}
|
||||||
pyme: ${{ steps.filter.outputs.pyme }}
|
pyme: ${{ steps.filter.outputs.pyme }}
|
||||||
riesgos: ${{ steps.filter.outputs.riesgos }}
|
riesgos: ${{ steps.filter.outputs.riesgos }}
|
||||||
Test: ${{ steps.filter.outputs.Test }}
|
|
||||||
voz-del-cliente: ${{ steps.filter.outputs.voz-del-cliente }}
|
voz-del-cliente: ${{ steps.filter.outputs.voz-del-cliente }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -39,8 +38,8 @@ jobs:
|
|||||||
filters: |
|
filters: |
|
||||||
bursatil:
|
bursatil:
|
||||||
- 'apps/bursatil/**'
|
- 'apps/bursatil/**'
|
||||||
ChatEgresos:
|
egresos:
|
||||||
- 'apps/ChatEgresos/**'
|
- 'apps/egresos/**'
|
||||||
inversionistas:
|
inversionistas:
|
||||||
- 'apps/inversionistas/**'
|
- 'apps/inversionistas/**'
|
||||||
normativa:
|
normativa:
|
||||||
@@ -51,8 +50,6 @@ jobs:
|
|||||||
- 'apps/pyme/**'
|
- 'apps/pyme/**'
|
||||||
riesgos:
|
riesgos:
|
||||||
- 'apps/riesgos/**'
|
- 'apps/riesgos/**'
|
||||||
Test:
|
|
||||||
- 'apps/Test/**'
|
|
||||||
voz-del-cliente:
|
voz-del-cliente:
|
||||||
- 'apps/voz-del-cliente/**'
|
- 'apps/voz-del-cliente/**'
|
||||||
|
|
||||||
@@ -80,9 +77,9 @@ jobs:
|
|||||||
build-args: |
|
build-args: |
|
||||||
PACKAGE=bursatil
|
PACKAGE=bursatil
|
||||||
|
|
||||||
build-ChatEgresos:
|
build-egresos:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.ChatEgresos == 'true'
|
if: needs.detect-changes.outputs.egresos == 'true'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -99,10 +96,10 @@ jobs:
|
|||||||
file: .containers/python/Dockerfile
|
file: .containers/python/Dockerfile
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-ChatEgresos:latest
|
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-egresos:latest
|
||||||
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-ChatEgresos:${{ github.sha }}
|
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-egresos:${{ github.sha }}
|
||||||
build-args: |
|
build-args: |
|
||||||
PACKAGE=ChatEgresos
|
PACKAGE=egresos
|
||||||
|
|
||||||
build-inversionistas:
|
build-inversionistas:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
@@ -224,30 +221,6 @@ jobs:
|
|||||||
build-args: |
|
build-args: |
|
||||||
PACKAGE=riesgos
|
PACKAGE=riesgos
|
||||||
|
|
||||||
build-Test:
|
|
||||||
needs: detect-changes
|
|
||||||
if: needs.detect-changes.outputs.Test == 'true'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Log in to Gitea Registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
|
||||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: .containers/python/Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-Test:latest
|
|
||||||
${{ env.REGISTRY }}/${{ env.REGISTRY_PATH }}-Test:${{ github.sha }}
|
|
||||||
build-args: |
|
|
||||||
PACKAGE=Test
|
|
||||||
|
|
||||||
build-voz-del-cliente:
|
build-voz-del-cliente:
|
||||||
needs: detect-changes
|
needs: detect-changes
|
||||||
if: needs.detect-changes.outputs.voz-del-cliente == 'true'
|
if: needs.detect-changes.outputs.voz-del-cliente == 'true'
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
root: true,
|
|
||||||
env: { browser: true, es2020: true },
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:react-hooks/recommended',
|
|
||||||
],
|
|
||||||
ignorePatterns: ['dist', '.eslintrc.cjs'],
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
plugins: ['react-refresh'],
|
|
||||||
rules: {
|
|
||||||
'react-refresh/only-export-components': [
|
|
||||||
'warn',
|
|
||||||
{ allowConstantExport: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import { Chat, ChatSidebar } from "@banorte/chat-ui";
|
|
||||||
import { messageStore } from "./store/messageStore";
|
|
||||||
import { conversationStore } from "./store/conversationStore";
|
|
||||||
import { httpRequest } from "./utils/request";
|
|
||||||
|
|
||||||
// Assets
|
|
||||||
import banorteLogo from "./assets/banortelogo.png";
|
|
||||||
import sidebarMaya from "./assets/sidebar_maya_contigo.png";
|
|
||||||
import brujulaElipse from "./assets/brujula_elipse.png";
|
|
||||||
import sendIcon from "./assets/chat_maya_boton_enviar.png";
|
|
||||||
import userAvatar from "./assets/chat_maya_default_avatar.png";
|
|
||||||
import botAvatar from "./assets/brujula.png";
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
const { messages, pushMessage } = messageStore();
|
|
||||||
const {
|
|
||||||
conversationId,
|
|
||||||
setConversationId,
|
|
||||||
setAssistantName,
|
|
||||||
receivingMsg,
|
|
||||||
setReceivingMsg
|
|
||||||
} = conversationStore();
|
|
||||||
|
|
||||||
const handleStartConversation = async (user: string, assistant: string): Promise<string> => {
|
|
||||||
const response = await httpRequest("POST", "/v1/conversation", { user, assistant });
|
|
||||||
console.log("Conversation id:", response.conversation_id);
|
|
||||||
return response.conversation_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFeedback = async (key: string, rating: string): Promise<void> => {
|
|
||||||
await httpRequest("POST", "/v1/feedback", { key, rating });
|
|
||||||
};
|
|
||||||
|
|
||||||
const assistant = "Maya" + "Test";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="w-screen flex flex-col h-screen min-h-screen scrollbar-none">
|
|
||||||
<div className="w-full flex">
|
|
||||||
<ChatSidebar
|
|
||||||
assistant={assistant}
|
|
||||||
logoSrc={banorteLogo}
|
|
||||||
sidebarImageSrc={sidebarMaya}
|
|
||||||
assistantAvatarSrc={brujulaElipse}
|
|
||||||
/>
|
|
||||||
<Chat
|
|
||||||
assistant={assistant}
|
|
||||||
messages={messages}
|
|
||||||
pushMessage={pushMessage}
|
|
||||||
conversationId={conversationId}
|
|
||||||
setConversationId={setConversationId}
|
|
||||||
setAssistantName={setAssistantName}
|
|
||||||
receivingMsg={receivingMsg}
|
|
||||||
setReceivingMsg={setReceivingMsg}
|
|
||||||
onStartConversation={handleStartConversation}
|
|
||||||
sendIcon={sendIcon}
|
|
||||||
userAvatar={userAvatar}
|
|
||||||
botAvatar={botAvatar}
|
|
||||||
onFeedback={handleFeedback}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
||||||
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 97 KiB |
@@ -1,16 +0,0 @@
|
|||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
.markdown a {
|
|
||||||
color: #0000FF;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown a:hover {
|
|
||||||
color: #FF0000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown a:visited {
|
|
||||||
color: #800080;
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import ReactDOM from "react-dom/client";
|
|
||||||
import App from "./App.tsx";
|
|
||||||
import "./index.css";
|
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root")!).render(<App />);
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
|
|
||||||
interface conversationState {
|
|
||||||
assistantName: string;
|
|
||||||
conversationId: string;
|
|
||||||
receivingMsg: boolean;
|
|
||||||
setConversationId: (newId: string) => void;
|
|
||||||
setAssistantName: (newName: string) => void;
|
|
||||||
setReceivingMsg: (newState: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const conversationStore = create<conversationState>()((set) => ({
|
|
||||||
assistantName: "",
|
|
||||||
conversationId: "",
|
|
||||||
receivingMsg: false,
|
|
||||||
setConversationId: (newId) => set({ conversationId: newId }),
|
|
||||||
setAssistantName: (newName) => set({ assistantName: newName }),
|
|
||||||
setReceivingMsg: (newState) => set({ receivingMsg: newState }),
|
|
||||||
}));
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { create } from "zustand";
|
|
||||||
|
|
||||||
interface messageState {
|
|
||||||
messages: Array<{ user: boolean; content: string }>;
|
|
||||||
pushMessage: (newMessage: { user: boolean; content: string }) => void;
|
|
||||||
resetConversation: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const messageStore = create<messageState>()((set) => ({
|
|
||||||
messages: [],
|
|
||||||
pushMessage: (newMessage) =>
|
|
||||||
set((state) => ({ messages: [...state.messages, newMessage] })),
|
|
||||||
resetConversation: () => set(() => ({ messages: [] })),
|
|
||||||
}));
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
export async function httpRequest(
|
|
||||||
method: string,
|
|
||||||
endpoint: string,
|
|
||||||
body: object | null,
|
|
||||||
) {
|
|
||||||
const url = "/api" + endpoint;
|
|
||||||
const data = {
|
|
||||||
method: method,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
credentials: "include" as RequestCredentials,
|
|
||||||
};
|
|
||||||
return await fetch(url, data).then((response) => response.json());
|
|
||||||
}
|
|
||||||
1
apps/Test/gui/vite-env.d.ts
vendored
@@ -1 +0,0 @@
|
|||||||
/// <reference types="vite/client" />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Test</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
<script type="module" src="/gui/main.tsx"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Test",
|
|
||||||
"private": true,
|
|
||||||
"version": "0.0.7",
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build": "tsc && vite build",
|
|
||||||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
|
||||||
"preview": "vite preview"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@banorte/chat-ui": "workspace:*",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"react-markdown": "^9.0.1",
|
|
||||||
"react-spring": "^9.7.4",
|
|
||||||
"rehype-raw": "^7.0.0",
|
|
||||||
"sse.js": "^2.5.0",
|
|
||||||
"zustand": "^4.5.2"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@iconify-icon/react": "^2.1.0",
|
|
||||||
"@types/react": "^18.2.67",
|
|
||||||
"@types/react-dom": "^18.2.22",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
|
||||||
"@typescript-eslint/parser": "^7.3.1",
|
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
|
||||||
"autoprefixer": "^10.4.19",
|
|
||||||
"daisyui": "^4.7.3",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
|
||||||
"postcss": "^8.4.38",
|
|
||||||
"tailwind-scrollbar": "^3.1.0",
|
|
||||||
"tailwindcss": "^3.4.1",
|
|
||||||
"typescript": "^5.4.3",
|
|
||||||
"vite": "^5.2.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export default {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
[project]
|
|
||||||
name = "Test"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "Add your description here"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.12, <4"
|
|
||||||
dependencies = [
|
|
||||||
"aiohttp>=3.11.16",
|
|
||||||
"fastapi>=0.115.6",
|
|
||||||
"hvac>=2.3.0",
|
|
||||||
"langchain-azure-ai[opentelemetry]>=0.1.4",
|
|
||||||
"mongo-memory",
|
|
||||||
"pydantic-settings>=2.8.1",
|
|
||||||
"uvicorn>=0.34.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.uv.sources]
|
|
||||||
mongo-memory = { workspace = true }
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
export default {
|
|
||||||
content: ["./index.html", "./gui/**/*.{js,ts,jsx,tsx}"],
|
|
||||||
theme: {
|
|
||||||
extend: {
|
|
||||||
backgroundImage: {
|
|
||||||
"navigation-pattern": "url('./assets/navigation.webp')",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
require("daisyui"),
|
|
||||||
require("tailwind-scrollbar"),
|
|
||||||
require("@banorte/chat-ui/tailwind")
|
|
||||||
],
|
|
||||||
daisyui: {
|
|
||||||
themes: [
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
...require("daisyui/src/theming/themes")["light"],
|
|
||||||
primary: "red",
|
|
||||||
secondary: "teal",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2023",
|
|
||||||
"useDefineForClassFields": true,
|
|
||||||
"lib": ["ES2023", "DOM", "DOM.Iterable", "ES2021.String"],
|
|
||||||
"module": "ESNext",
|
|
||||||
"skipLibCheck": true,
|
|
||||||
|
|
||||||
/* Bundler mode */
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
|
||||||
"noEmit": true,
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
|
|
||||||
/* Linting */
|
|
||||||
"strict": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noFallthroughCasesInSwitch": true
|
|
||||||
},
|
|
||||||
"include": ["gui"],
|
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"strict": true
|
|
||||||
},
|
|
||||||
"include": ["vite.config.ts"]
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { defineConfig } from "vite";
|
|
||||||
import react from "@vitejs/plugin-react";
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [react()],
|
|
||||||
server: {
|
|
||||||
host: "0.0.0.0",
|
|
||||||
port: 3000,
|
|
||||||
proxy: {
|
|
||||||
"/api": {
|
|
||||||
target: "http://localhost:8000",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
allowedHosts: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
42
apps/bursatil/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-bursatil
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-bursatil
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-bursatil
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-bursatil
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-bursatil
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-bursatil:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-bursatil-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/bursatil/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-bursatil-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-bursatil.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-bursatil-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/bursatil/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-bursatil-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-bursatil-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-bursatil
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/bursatil/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-bursatil-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-bursatil
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-bursatil
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
42
apps/egresos/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-egresos
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-egresos
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-egresos
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-egresos
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-egresos
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-egresos:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-egresos-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/egresos/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-egresos-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-egresos.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-egresos-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/egresos/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-egresos-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-egresos-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-egresos
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/egresos/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-egresos-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-egresos
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-egresos
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
import uuid
|
|
||||||
import time
|
import time
|
||||||
|
import uuid
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic import BaseModel
|
|
||||||
from langfuse import Langfuse
|
from langfuse import Langfuse
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from api import services
|
from api import services
|
||||||
from api.agent import Agent
|
from api.agent import Agent
|
||||||
@@ -15,9 +15,10 @@ from api.config import config
|
|||||||
langfuse = Langfuse(
|
langfuse = Langfuse(
|
||||||
public_key="pk-lf-49cb04b3-0c7d-475b-8105-ad8b8749ecdd",
|
public_key="pk-lf-49cb04b3-0c7d-475b-8105-ad8b8749ecdd",
|
||||||
secret_key="sk-lf-e02fa322-c709-4d80-bef2-9cb279846a0c",
|
secret_key="sk-lf-e02fa322-c709-4d80-bef2-9cb279846a0c",
|
||||||
host="https://ailogger.azurewebsites.net"
|
host="https://ailogger.azurewebsites.net",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(_: FastAPI):
|
async def lifespan(_: FastAPI):
|
||||||
await config.init_mongo_db()
|
await config.init_mongo_db()
|
||||||
@@ -39,6 +40,7 @@ class Message(BaseModel):
|
|||||||
conversation_id: uuid.UUID
|
conversation_id: uuid.UUID
|
||||||
prompt: str
|
prompt: str
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/v1/message")
|
@app.post("/api/v1/message")
|
||||||
async def send(message: Message):
|
async def send(message: Message):
|
||||||
# Crear trace principal
|
# Crear trace principal
|
||||||
@@ -47,8 +49,8 @@ async def send(message: Message):
|
|||||||
session_id=str(message.conversation_id),
|
session_id=str(message.conversation_id),
|
||||||
input={
|
input={
|
||||||
"prompt": message.prompt,
|
"prompt": message.prompt,
|
||||||
"conversation_id": str(message.conversation_id)
|
"conversation_id": str(message.conversation_id),
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def b64_sse(func):
|
def b64_sse(func):
|
||||||
@@ -68,16 +70,15 @@ async def send(message: Message):
|
|||||||
latency_ms = round((end_time - start_time) * 1000)
|
latency_ms = round((end_time - start_time) * 1000)
|
||||||
full_response = "".join(response_parts)
|
full_response = "".join(response_parts)
|
||||||
|
|
||||||
|
|
||||||
input_tokens = len(message.prompt.split()) * 1.3
|
input_tokens = len(message.prompt.split()) * 1.3
|
||||||
output_tokens = len(full_response.split()) * 1.3
|
output_tokens = len(full_response.split()) * 1.3
|
||||||
total_tokens = int(input_tokens + output_tokens)
|
total_tokens = int(input_tokens + output_tokens)
|
||||||
|
|
||||||
|
|
||||||
cost_per_1k_input = 0.03
|
cost_per_1k_input = 0.03
|
||||||
cost_per_1k_output = 0.06
|
cost_per_1k_output = 0.06
|
||||||
total_cost = (input_tokens/1000 * cost_per_1k_input) + (output_tokens/1000 * cost_per_1k_output)
|
total_cost = (input_tokens / 1000 * cost_per_1k_input) + (
|
||||||
|
output_tokens / 1000 * cost_per_1k_output
|
||||||
|
)
|
||||||
|
|
||||||
trace.update(
|
trace.update(
|
||||||
output={"response": full_response},
|
output={"response": full_response},
|
||||||
@@ -85,24 +86,22 @@ async def send(message: Message):
|
|||||||
"input": int(input_tokens),
|
"input": int(input_tokens),
|
||||||
"output": int(output_tokens),
|
"output": int(output_tokens),
|
||||||
"total": total_tokens,
|
"total": total_tokens,
|
||||||
"unit": "TOKENS"
|
"unit": "TOKENS",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
langfuse.score(
|
langfuse.score(
|
||||||
trace_id=trace.id,
|
trace_id=trace.id,
|
||||||
name="latency",
|
name="latency",
|
||||||
value=latency_ms,
|
value=latency_ms,
|
||||||
comment=f"Response time: {latency_ms}ms"
|
comment=f"Response time: {latency_ms}ms",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
langfuse.score(
|
langfuse.score(
|
||||||
trace_id=trace.id,
|
trace_id=trace.id,
|
||||||
name="cost",
|
name="cost",
|
||||||
value=round(total_cost, 4),
|
value=round(total_cost, 4),
|
||||||
comment=f"Estimated cost: ${round(total_cost, 4)}"
|
comment=f"Estimated cost: ${round(total_cost, 4)}",
|
||||||
)
|
)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
@@ -110,3 +109,8 @@ async def send(message: Message):
|
|||||||
sse_stream = b64_sse(services.stream)
|
sse_stream = b64_sse(services.stream)
|
||||||
generator = sse_stream(agent, message.prompt, message.conversation_id)
|
generator = sse_stream(agent, message.prompt, message.conversation_id)
|
||||||
return StreamingResponse(generator, media_type="text/event-stream")
|
return StreamingResponse(generator, media_type="text/event-stream")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def health():
|
||||||
|
return {"status": "ok"}
|
||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
@@ -1,5 +1,5 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ChatEgresos"
|
name = "egresos"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Add your description here"
|
description = "Add your description here"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
42
apps/normativa/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-normativa
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-normativa
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-normativa
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-normativa
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-normativa
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-normativa:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-normativa-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/normativa/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-normativa-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-normativa.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-normativa-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/normativa/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-normativa-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-normativa-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-normativa
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/normativa/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-normativa-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-normativa
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-normativa
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import uuid
|
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv # ← Agregar este import
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import StreamingResponse, FileResponse, RedirectResponse
|
from fastapi.responses import FileResponse, RedirectResponse, StreamingResponse
|
||||||
from pydantic import BaseModel
|
|
||||||
from langfuse import Langfuse
|
from langfuse import Langfuse
|
||||||
|
from pydantic import BaseModel
|
||||||
from dotenv import load_dotenv # ← Agregar este import
|
|
||||||
|
|
||||||
from api import services
|
from api import services
|
||||||
from api.agent import Agent
|
from api.agent import Agent
|
||||||
@@ -22,7 +21,7 @@ load_dotenv()
|
|||||||
langfuse = Langfuse(
|
langfuse = Langfuse(
|
||||||
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
|
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
|
||||||
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
|
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
|
||||||
host=os.getenv("LANGFUSE_HOST")
|
host=os.getenv("LANGFUSE_HOST"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -34,12 +33,10 @@ PDF_PUBLIC_URLS = {
|
|||||||
"Disposiciones de carácter general aplicables a las sociedades controladoras de grupos financieros y subcontroladoras que regulan las materias que corresponden de manera conjunta a las Comisio.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20las%20sociedades%20controladoras%20de%20grupos%20financieros%20y%20subcontroladoras%20que%20regulan%20las%20materias%20que%20corresponden%20de%20manera%20conjunta%20a%20las%20Comisiones%20Nacionales%20Supervisoras.pdf",
|
"Disposiciones de carácter general aplicables a las sociedades controladoras de grupos financieros y subcontroladoras que regulan las materias que corresponden de manera conjunta a las Comisio.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20las%20sociedades%20controladoras%20de%20grupos%20financieros%20y%20subcontroladoras%20que%20regulan%20las%20materias%20que%20corresponden%20de%20manera%20conjunta%20a%20las%20Comisiones%20Nacionales%20Supervisoras.pdf",
|
||||||
"Disposiciones de carácter general aplicables a los fondos de inversión y a las personas que les prestan servicios.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20los%20fondos%20de%20inversi%C3%B3n%20y%20a%20las%20personas%20que%20les%20prestan%20servicios.pdf",
|
"Disposiciones de carácter general aplicables a los fondos de inversión y a las personas que les prestan servicios.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20los%20fondos%20de%20inversi%C3%B3n%20y%20a%20las%20personas%20que%20les%20prestan%20servicios.pdf",
|
||||||
"Ley para la Transparencia y Ordenamiento de los Servicios Financieros.pdf": "https://www.cnbv.gob.mx/Normatividad/Ley%20para%20la%20Transparencia%20y%20Ordenamiento%20de%20los%20Servicios%20Financieros.pdf",
|
"Ley para la Transparencia y Ordenamiento de los Servicios Financieros.pdf": "https://www.cnbv.gob.mx/Normatividad/Ley%20para%20la%20Transparencia%20y%20Ordenamiento%20de%20los%20Servicios%20Financieros.pdf",
|
||||||
|
|
||||||
# Circulares CNBV adicionales
|
# Circulares CNBV adicionales
|
||||||
"circular_servicios_de_inversion.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20las%20entidades%20financieras%20y%20dem%C3%A1s%20personas%20que%20proporcionen%20servicios%20de.pdf",
|
"circular_servicios_de_inversion.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20aplicables%20a%20las%20entidades%20financieras%20y%20dem%C3%A1s%20personas%20que%20proporcionen%20servicios%20de.pdf",
|
||||||
"circular_unica_de_auditores_externos.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20que%20establecen%20los%20requisitos%20que%20deber%C3%A1n%20cumplir%20los%20auditores%20y%20otros%20profesionales%20que.pdf",
|
"circular_unica_de_auditores_externos.pdf": "https://www.cnbv.gob.mx/Normatividad/Disposiciones%20de%20car%C3%A1cter%20general%20que%20establecen%20los%20requisitos%20que%20deber%C3%A1n%20cumplir%20los%20auditores%20y%20otros%20profesionales%20que.pdf",
|
||||||
"ley_de_instituciones_de_Credito.pdf": "https://www.cnbv.gob.mx/Normatividad/Ley%20de%20Instituciones%20de%20Cr%C3%A9dito.pdf",
|
"ley_de_instituciones_de_Credito.pdf": "https://www.cnbv.gob.mx/Normatividad/Ley%20de%20Instituciones%20de%20Cr%C3%A9dito.pdf",
|
||||||
|
|
||||||
# Circulares de Banxico
|
# Circulares de Banxico
|
||||||
"circular_13_2007.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-13-2007/cobro-intereses-por-adelantad.html",
|
"circular_13_2007.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-13-2007/cobro-intereses-por-adelantad.html",
|
||||||
"circular_13_2011.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-13-2011/%7BBA4CBC28-A468-16C9-6F17-9EA9D7B03318%7D.pdf",
|
"circular_13_2011.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-13-2011/%7BBA4CBC28-A468-16C9-6F17-9EA9D7B03318%7D.pdf",
|
||||||
@@ -55,15 +52,12 @@ PDF_PUBLIC_URLS = {
|
|||||||
"circular_36_2010.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-36-2010/%7B26C55DE6-CC3A-3368-34FC-1A6C50B11130%7D.pdf",
|
"circular_36_2010.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-36-2010/%7B26C55DE6-CC3A-3368-34FC-1A6C50B11130%7D.pdf",
|
||||||
"circular_3_2012.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-3-2012/%7B4E0281A4-7AD8-1462-BC79-7F2925F3171D%7D.pdf",
|
"circular_3_2012.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-3-2012/%7B4E0281A4-7AD8-1462-BC79-7F2925F3171D%7D.pdf",
|
||||||
"circular_4_2012.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-4-2012/%7B97C62974-1C94-19AE-AB5A-D0D949A36247%7D.pdf",
|
"circular_4_2012.pdf": "https://www.banxico.org.mx/marco-normativo/normativa-emitida-por-el-banco-de-mexico/circular-4-2012/%7B97C62974-1C94-19AE-AB5A-D0D949A36247%7D.pdf",
|
||||||
|
|
||||||
# CONDUSEF
|
# CONDUSEF
|
||||||
"circular_unica_de_condusef.pdf": "https://www.condusef.gob.mx/documentos/marco_legal/disposiciones-transparencia-if-sofom.pdf",
|
"circular_unica_de_condusef.pdf": "https://www.condusef.gob.mx/documentos/marco_legal/disposiciones-transparencia-if-sofom.pdf",
|
||||||
"ley_para_regular_las_sociedades_de_informacion_crediticia.pdf": "https://www.condusef.gob.mx/documentos/marco_legal/disposiciones-transparencia-if-sofom.pdf",
|
"ley_para_regular_las_sociedades_de_informacion_crediticia.pdf": "https://www.condusef.gob.mx/documentos/marco_legal/disposiciones-transparencia-if-sofom.pdf",
|
||||||
|
|
||||||
# Leyes federales
|
# Leyes federales
|
||||||
"ley_federal_de_proteccion_de_datos_personales_en_posesion_de_los_particulares.pdf": "https://www.diputados.gob.mx/LeyesBiblio/pdf/LFPDPPP.pdf",
|
"ley_federal_de_proteccion_de_datos_personales_en_posesion_de_los_particulares.pdf": "https://www.diputados.gob.mx/LeyesBiblio/pdf/LFPDPPP.pdf",
|
||||||
"reglamento_de_la_ley_federal_de_proteccion_de_datos_personales_en_posesion_de_los_particulares.pdf": "https://www.diputados.gob.mx/LeyesBiblio/regley/Reg_LFPDPPP.pdf",
|
"reglamento_de_la_ley_federal_de_proteccion_de_datos_personales_en_posesion_de_los_particulares.pdf": "https://www.diputados.gob.mx/LeyesBiblio/regley/Reg_LFPDPPP.pdf",
|
||||||
|
|
||||||
# SharePoint Banorte
|
# SharePoint Banorte
|
||||||
"Modificaciones Recursos Procedencia Ilícita jul 25 PLD.pdf": "https://gfbanorte.sharepoint.com/:w:/r/sites/Formatosyplantillas/Documentos%20compartidos/Otros/Modificaciones%20Recursos%20Procedencia%20Il%C3%ADcita%20jul%2025%20PLD.docx?d=w6a941e9e2c26403ea41c12de35536516&csf=1&web=1&e=EHtc9b",
|
"Modificaciones Recursos Procedencia Ilícita jul 25 PLD.pdf": "https://gfbanorte.sharepoint.com/:w:/r/sites/Formatosyplantillas/Documentos%20compartidos/Otros/Modificaciones%20Recursos%20Procedencia%20Il%C3%ADcita%20jul%2025%20PLD.docx?d=w6a941e9e2c26403ea41c12de35536516&csf=1&web=1&e=EHtc9b",
|
||||||
}
|
}
|
||||||
@@ -83,7 +77,7 @@ app.add_middleware(
|
|||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
expose_headers=["*"]
|
expose_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
agent = Agent()
|
agent = Agent()
|
||||||
@@ -110,7 +104,7 @@ async def send(message: Message):
|
|||||||
trace = langfuse.trace(
|
trace = langfuse.trace(
|
||||||
name="rag_chat",
|
name="rag_chat",
|
||||||
session_id=str(message.conversation_id),
|
session_id=str(message.conversation_id),
|
||||||
input={"prompt": message.prompt}
|
input={"prompt": message.prompt},
|
||||||
)
|
)
|
||||||
|
|
||||||
def b64_sse(func):
|
def b64_sse(func):
|
||||||
@@ -140,11 +134,15 @@ async def send(message: Message):
|
|||||||
async def get_pdf(filename: str):
|
async def get_pdf(filename: str):
|
||||||
print(f"🔍 Solicitud PDF para: {filename}")
|
print(f"🔍 Solicitud PDF para: {filename}")
|
||||||
|
|
||||||
if not filename.lower().endswith('.pdf'):
|
if not filename.lower().endswith(".pdf"):
|
||||||
print(f"❌ Archivo no es PDF: {filename}")
|
print(f"❌ Archivo no es PDF: {filename}")
|
||||||
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
||||||
|
|
||||||
if '..' in filename or ('/' in filename and not filename.startswith('http')) or '\\' in filename:
|
if (
|
||||||
|
".." in filename
|
||||||
|
or ("/" in filename and not filename.startswith("http"))
|
||||||
|
or "\\" in filename
|
||||||
|
):
|
||||||
print(f"❌ Nombre de archivo inválido: {filename}")
|
print(f"❌ Nombre de archivo inválido: {filename}")
|
||||||
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
||||||
|
|
||||||
@@ -159,15 +157,17 @@ async def get_pdf(filename: str):
|
|||||||
"Cache-Control": "public, max-age=3600",
|
"Cache-Control": "public, max-age=3600",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||||
"Access-Control-Allow-Headers": "*"
|
"Access-Control-Allow-Headers": "*",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
pdf_path = PDF_FOLDER / filename
|
pdf_path = PDF_FOLDER / filename
|
||||||
|
|
||||||
if not pdf_path.exists():
|
if not pdf_path.exists():
|
||||||
print(f"❌ PDF no encontrado: {pdf_path}")
|
print(f"❌ PDF no encontrado: {pdf_path}")
|
||||||
raise HTTPException(status_code=404, detail=f"PDF no encontrado. Archivo: {filename}")
|
raise HTTPException(
|
||||||
|
status_code=404, detail=f"PDF no encontrado. Archivo: {filename}"
|
||||||
|
)
|
||||||
|
|
||||||
if not pdf_path.is_file():
|
if not pdf_path.is_file():
|
||||||
print(f"❌ No es un archivo: {pdf_path}")
|
print(f"❌ No es un archivo: {pdf_path}")
|
||||||
@@ -190,8 +190,8 @@ async def get_pdf(filename: str):
|
|||||||
"Cache-Control": "public, max-age=3600",
|
"Cache-Control": "public, max-age=3600",
|
||||||
"X-Frame-Options": "ALLOWALL",
|
"X-Frame-Options": "ALLOWALL",
|
||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
"Access-Control-Allow-Origin": "*"
|
"Access-Control-Allow-Origin": "*",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -201,24 +201,28 @@ async def list_pdfs():
|
|||||||
pdf_files = []
|
pdf_files = []
|
||||||
|
|
||||||
for filename, url in PDF_PUBLIC_URLS.items():
|
for filename, url in PDF_PUBLIC_URLS.items():
|
||||||
pdf_files.append({
|
pdf_files.append(
|
||||||
|
{
|
||||||
"filename": filename,
|
"filename": filename,
|
||||||
"size": "N/A (Público)",
|
"size": "N/A (Público)",
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"public_url": url,
|
"public_url": url,
|
||||||
"type": "public"
|
"type": "public",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
local_files = []
|
local_files = []
|
||||||
for pattern in ["*.pdf", "*.PDF"]:
|
for pattern in ["*.pdf", "*.PDF"]:
|
||||||
for file_path in PDF_FOLDER.glob(pattern):
|
for file_path in PDF_FOLDER.glob(pattern):
|
||||||
if file_path.is_file() and file_path.name not in PDF_PUBLIC_URLS:
|
if file_path.is_file() and file_path.name not in PDF_PUBLIC_URLS:
|
||||||
local_files.append({
|
local_files.append(
|
||||||
|
{
|
||||||
"filename": file_path.name,
|
"filename": file_path.name,
|
||||||
"size": file_path.stat().st_size,
|
"size": file_path.stat().st_size,
|
||||||
"url": f"/api/pdf/{file_path.name}",
|
"url": f"/api/pdf/{file_path.name}",
|
||||||
"type": "local"
|
"type": "local",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
pdf_files.extend(local_files)
|
pdf_files.extend(local_files)
|
||||||
|
|
||||||
@@ -231,29 +235,26 @@ async def list_pdfs():
|
|||||||
"public_files": list(PDF_PUBLIC_URLS.keys()),
|
"public_files": list(PDF_PUBLIC_URLS.keys()),
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {"pdfs": pdf_files, "debug": debug_info, "total_pdfs": len(pdf_files)}
|
||||||
"pdfs": pdf_files,
|
|
||||||
"debug": debug_info,
|
|
||||||
"total_pdfs": len(pdf_files)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"error": str(e),
|
"error": str(e),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
"debug": {
|
"debug": {
|
||||||
"current_working_directory": str(Path.cwd()),
|
"current_working_directory": str(Path.cwd()),
|
||||||
"script_file_path": __file__ if '__file__' in globals() else "unknown"
|
"script_file_path": __file__ if "__file__" in globals() else "unknown",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/pdf/{filename}/info")
|
@app.get("/api/pdf/{filename}/info")
|
||||||
async def get_pdf_info(filename: str):
|
async def get_pdf_info(filename: str):
|
||||||
if not filename.lower().endswith('.pdf'):
|
if not filename.lower().endswith(".pdf"):
|
||||||
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
||||||
|
|
||||||
if '..' in filename or '/' in filename or '\\' in filename:
|
if ".." in filename or "/" in filename or "\\" in filename:
|
||||||
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
||||||
|
|
||||||
public_url = PDF_PUBLIC_URLS.get(filename)
|
public_url = PDF_PUBLIC_URLS.get(filename)
|
||||||
@@ -265,7 +266,7 @@ async def get_pdf_info(filename: str):
|
|||||||
"modified": "N/A",
|
"modified": "N/A",
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"public_url": public_url,
|
"public_url": public_url,
|
||||||
"type": "public"
|
"type": "public",
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf_path = PDF_FOLDER / filename
|
pdf_path = PDF_FOLDER / filename
|
||||||
@@ -284,10 +285,12 @@ async def get_pdf_info(filename: str):
|
|||||||
"size_mb": round(file_stat.st_size / (1024 * 1024), 2),
|
"size_mb": round(file_stat.st_size / (1024 * 1024), 2),
|
||||||
"modified": file_stat.st_mtime,
|
"modified": file_stat.st_mtime,
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"type": "local"
|
"type": "local",
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Error al obtener información del PDF: {str(e)}")
|
raise HTTPException(
|
||||||
|
status_code=500, detail=f"Error al obtener información del PDF: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/health")
|
@app.get("/api/health")
|
||||||
@@ -296,5 +299,10 @@ async def health_check():
|
|||||||
"status": "healthy",
|
"status": "healthy",
|
||||||
"pdf_folder": str(PDF_FOLDER),
|
"pdf_folder": str(PDF_FOLDER),
|
||||||
"pdf_folder_exists": PDF_FOLDER.exists(),
|
"pdf_folder_exists": PDF_FOLDER.exists(),
|
||||||
"public_urls_configured": len(PDF_PUBLIC_URLS)
|
"public_urls_configured": len(PDF_PUBLIC_URLS),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def health():
|
||||||
|
return {"status": "ok"}
|
||||||
|
|||||||
42
apps/pyme/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-pyme
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-pyme
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-pyme
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-pyme
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-pyme
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-pyme:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-pyme-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/pyme/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-pyme-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-pyme.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-pyme-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/pyme/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-pyme-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-pyme-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-pyme
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/pyme/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-pyme-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-pyme
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-pyme
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
import uuid
|
|
||||||
import os
|
import os
|
||||||
|
import uuid
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv # ← Agregar este import
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import StreamingResponse, FileResponse, RedirectResponse
|
from fastapi.responses import FileResponse, RedirectResponse, StreamingResponse
|
||||||
from pydantic import BaseModel
|
|
||||||
from langfuse import Langfuse
|
from langfuse import Langfuse
|
||||||
|
from pydantic import BaseModel
|
||||||
from dotenv import load_dotenv # ← Agregar este import
|
|
||||||
|
|
||||||
from api import services
|
from api import services
|
||||||
from api.agent import Agent
|
from api.agent import Agent
|
||||||
@@ -22,13 +21,12 @@ load_dotenv()
|
|||||||
langfuse = Langfuse(
|
langfuse = Langfuse(
|
||||||
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
|
public_key=os.getenv("LANGFUSE_PUBLIC_KEY"),
|
||||||
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
|
secret_key=os.getenv("LANGFUSE_SECRET_KEY"),
|
||||||
host=os.getenv("LANGFUSE_HOST")
|
host=os.getenv("LANGFUSE_HOST"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Mapeo completo de archivos a URLs públicas
|
# Mapeo completo de archivos a URLs públicas
|
||||||
PDF_PUBLIC_URLS = {
|
PDF_PUBLIC_URLS = {}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
@@ -45,7 +43,7 @@ app.add_middleware(
|
|||||||
allow_credentials=True,
|
allow_credentials=True,
|
||||||
allow_methods=["*"],
|
allow_methods=["*"],
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
expose_headers=["*"]
|
expose_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
agent = Agent()
|
agent = Agent()
|
||||||
@@ -72,7 +70,7 @@ async def send(message: Message):
|
|||||||
trace = langfuse.trace(
|
trace = langfuse.trace(
|
||||||
name="rag_chat",
|
name="rag_chat",
|
||||||
session_id=str(message.conversation_id),
|
session_id=str(message.conversation_id),
|
||||||
input={"prompt": message.prompt}
|
input={"prompt": message.prompt},
|
||||||
)
|
)
|
||||||
|
|
||||||
def b64_sse(func):
|
def b64_sse(func):
|
||||||
@@ -102,11 +100,15 @@ async def send(message: Message):
|
|||||||
async def get_pdf(filename: str):
|
async def get_pdf(filename: str):
|
||||||
print(f"🔍 Solicitud PDF para: {filename}")
|
print(f"🔍 Solicitud PDF para: {filename}")
|
||||||
|
|
||||||
if not filename.lower().endswith('.pdf'):
|
if not filename.lower().endswith(".pdf"):
|
||||||
print(f"❌ Archivo no es PDF: {filename}")
|
print(f"❌ Archivo no es PDF: {filename}")
|
||||||
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
||||||
|
|
||||||
if '..' in filename or ('/' in filename and not filename.startswith('http')) or '\\' in filename:
|
if (
|
||||||
|
".." in filename
|
||||||
|
or ("/" in filename and not filename.startswith("http"))
|
||||||
|
or "\\" in filename
|
||||||
|
):
|
||||||
print(f"❌ Nombre de archivo inválido: {filename}")
|
print(f"❌ Nombre de archivo inválido: {filename}")
|
||||||
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
||||||
|
|
||||||
@@ -121,15 +123,17 @@ async def get_pdf(filename: str):
|
|||||||
"Cache-Control": "public, max-age=3600",
|
"Cache-Control": "public, max-age=3600",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
"Access-Control-Allow-Methods": "GET, OPTIONS",
|
||||||
"Access-Control-Allow-Headers": "*"
|
"Access-Control-Allow-Headers": "*",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
pdf_path = PDF_FOLDER / filename
|
pdf_path = PDF_FOLDER / filename
|
||||||
|
|
||||||
if not pdf_path.exists():
|
if not pdf_path.exists():
|
||||||
print(f"❌ PDF no encontrado: {pdf_path}")
|
print(f"❌ PDF no encontrado: {pdf_path}")
|
||||||
raise HTTPException(status_code=404, detail=f"PDF no encontrado. Archivo: {filename}")
|
raise HTTPException(
|
||||||
|
status_code=404, detail=f"PDF no encontrado. Archivo: {filename}"
|
||||||
|
)
|
||||||
|
|
||||||
if not pdf_path.is_file():
|
if not pdf_path.is_file():
|
||||||
print(f"❌ No es un archivo: {pdf_path}")
|
print(f"❌ No es un archivo: {pdf_path}")
|
||||||
@@ -152,8 +156,8 @@ async def get_pdf(filename: str):
|
|||||||
"Cache-Control": "public, max-age=3600",
|
"Cache-Control": "public, max-age=3600",
|
||||||
"X-Frame-Options": "ALLOWALL",
|
"X-Frame-Options": "ALLOWALL",
|
||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
"Access-Control-Allow-Origin": "*"
|
"Access-Control-Allow-Origin": "*",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -163,24 +167,28 @@ async def list_pdfs():
|
|||||||
pdf_files = []
|
pdf_files = []
|
||||||
|
|
||||||
for filename, url in PDF_PUBLIC_URLS.items():
|
for filename, url in PDF_PUBLIC_URLS.items():
|
||||||
pdf_files.append({
|
pdf_files.append(
|
||||||
|
{
|
||||||
"filename": filename,
|
"filename": filename,
|
||||||
"size": "N/A (Público)",
|
"size": "N/A (Público)",
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"public_url": url,
|
"public_url": url,
|
||||||
"type": "public"
|
"type": "public",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
local_files = []
|
local_files = []
|
||||||
for pattern in ["*.pdf", "*.PDF"]:
|
for pattern in ["*.pdf", "*.PDF"]:
|
||||||
for file_path in PDF_FOLDER.glob(pattern):
|
for file_path in PDF_FOLDER.glob(pattern):
|
||||||
if file_path.is_file() and file_path.name not in PDF_PUBLIC_URLS:
|
if file_path.is_file() and file_path.name not in PDF_PUBLIC_URLS:
|
||||||
local_files.append({
|
local_files.append(
|
||||||
|
{
|
||||||
"filename": file_path.name,
|
"filename": file_path.name,
|
||||||
"size": file_path.stat().st_size,
|
"size": file_path.stat().st_size,
|
||||||
"url": f"/api/pdf/{file_path.name}",
|
"url": f"/api/pdf/{file_path.name}",
|
||||||
"type": "local"
|
"type": "local",
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
pdf_files.extend(local_files)
|
pdf_files.extend(local_files)
|
||||||
|
|
||||||
@@ -193,29 +201,26 @@ async def list_pdfs():
|
|||||||
"public_files": list(PDF_PUBLIC_URLS.keys()),
|
"public_files": list(PDF_PUBLIC_URLS.keys()),
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {"pdfs": pdf_files, "debug": debug_info, "total_pdfs": len(pdf_files)}
|
||||||
"pdfs": pdf_files,
|
|
||||||
"debug": debug_info,
|
|
||||||
"total_pdfs": len(pdf_files)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"error": str(e),
|
"error": str(e),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
"debug": {
|
"debug": {
|
||||||
"current_working_directory": str(Path.cwd()),
|
"current_working_directory": str(Path.cwd()),
|
||||||
"script_file_path": __file__ if '__file__' in globals() else "unknown"
|
"script_file_path": __file__ if "__file__" in globals() else "unknown",
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/pdf/{filename}/info")
|
@app.get("/api/pdf/{filename}/info")
|
||||||
async def get_pdf_info(filename: str):
|
async def get_pdf_info(filename: str):
|
||||||
if not filename.lower().endswith('.pdf'):
|
if not filename.lower().endswith(".pdf"):
|
||||||
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
raise HTTPException(status_code=400, detail="El archivo debe ser un PDF")
|
||||||
|
|
||||||
if '..' in filename or '/' in filename or '\\' in filename:
|
if ".." in filename or "/" in filename or "\\" in filename:
|
||||||
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
raise HTTPException(status_code=400, detail="Nombre de archivo inválido")
|
||||||
|
|
||||||
public_url = PDF_PUBLIC_URLS.get(filename)
|
public_url = PDF_PUBLIC_URLS.get(filename)
|
||||||
@@ -227,7 +232,7 @@ async def get_pdf_info(filename: str):
|
|||||||
"modified": "N/A",
|
"modified": "N/A",
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"public_url": public_url,
|
"public_url": public_url,
|
||||||
"type": "public"
|
"type": "public",
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf_path = PDF_FOLDER / filename
|
pdf_path = PDF_FOLDER / filename
|
||||||
@@ -246,10 +251,12 @@ async def get_pdf_info(filename: str):
|
|||||||
"size_mb": round(file_stat.st_size / (1024 * 1024), 2),
|
"size_mb": round(file_stat.st_size / (1024 * 1024), 2),
|
||||||
"modified": file_stat.st_mtime,
|
"modified": file_stat.st_mtime,
|
||||||
"url": f"/api/pdf/{filename}",
|
"url": f"/api/pdf/{filename}",
|
||||||
"type": "local"
|
"type": "local",
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=500, detail=f"Error al obtener información del PDF: {str(e)}")
|
raise HTTPException(
|
||||||
|
status_code=500, detail=f"Error al obtener información del PDF: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/health")
|
@app.get("/api/health")
|
||||||
@@ -258,5 +265,10 @@ async def health_check():
|
|||||||
"status": "healthy",
|
"status": "healthy",
|
||||||
"pdf_folder": str(PDF_FOLDER),
|
"pdf_folder": str(PDF_FOLDER),
|
||||||
"pdf_folder_exists": PDF_FOLDER.exists(),
|
"pdf_folder_exists": PDF_FOLDER.exists(),
|
||||||
"public_urls_configured": len(PDF_PUBLIC_URLS)
|
"public_urls_configured": len(PDF_PUBLIC_URLS),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def health():
|
||||||
|
return {"app": "RAG PyME", "status": "OK"}
|
||||||
|
|||||||
42
apps/riesgos/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-riesgos
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-riesgos
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-riesgos
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-riesgos
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-riesgos
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-riesgos:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-riesgos-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/riesgos/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-riesgos-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-riesgos.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-riesgos-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/riesgos/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-riesgos-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-riesgos-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-riesgos
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/riesgos/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-riesgos-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-riesgos
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-riesgos
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -20,4 +20,10 @@ app = FastAPI(
|
|||||||
openapi_url="/api/openapi.json",
|
openapi_url="/api/openapi.json",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def health():
|
||||||
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
|
|||||||
42
apps/voz-del-cliente/.k8s/deployment.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-voz-del-cliente
|
||||||
|
namespace: apps
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-voz-del-cliente
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mayacontigo-voz-del-cliente
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-voz-del-cliente
|
||||||
|
spec:
|
||||||
|
imagePullSecrets:
|
||||||
|
- name: gitea-registry-cred
|
||||||
|
containers:
|
||||||
|
- name: mayacontigo-voz-del-cliente
|
||||||
|
image: gitea.ia-innovacion.work/innovacion/mayacontigo-voz-del-cliente:latest
|
||||||
|
env:
|
||||||
|
- name: VAULT_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: mayacontigo-voz-del-cliente-secret
|
||||||
|
key: VAULT_TOKEN
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
19
apps/voz-del-cliente/.k8s/ingress.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-voz-del-cliente-ingress
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: mayacontigo-voz-del-cliente.app.ia-innovacion.work
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: mayacontigo-voz-del-cliente-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
17
apps/voz-del-cliente/.k8s/secrets.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
apiVersion: external-secrets.io/v1
|
||||||
|
kind: ExternalSecret
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-voz-del-cliente-vault
|
||||||
|
namespace: apps
|
||||||
|
spec:
|
||||||
|
refreshInterval: "15s"
|
||||||
|
secretStoreRef:
|
||||||
|
name: vault-backend
|
||||||
|
kind: ClusterSecretStore
|
||||||
|
target:
|
||||||
|
name: mayacontigo-voz-del-cliente-secret
|
||||||
|
data:
|
||||||
|
- secretKey: VAULT_TOKEN
|
||||||
|
remoteRef:
|
||||||
|
key: mayacontigo-voz-del-cliente
|
||||||
|
property: VAULT_TOKEN
|
||||||
14
apps/voz-del-cliente/.k8s/service.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mayacontigo-voz-del-cliente-service
|
||||||
|
labels:
|
||||||
|
app: mayacontigo-voz-del-cliente
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mayacontigo-voz-del-cliente
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
type: ClusterIP
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
from hvac import Client
|
from hvac import Client
|
||||||
from pydantic import Field
|
from pydantic import Field
|
||||||
from dotenv import load_dotenv
|
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
|
|
||||||
|
|
||||||
client = Client(url="https://vault.ia-innovacion.work")
|
client = Client(url="https://vault.ia-innovacion.work")
|
||||||
|
|
||||||
if not client.is_authenticated():
|
if not client.is_authenticated():
|
||||||
@@ -14,6 +12,7 @@ secret_map = client.secrets.kv.v2.read_secret_version(
|
|||||||
)["data"]["data"]
|
)["data"]["data"]
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Esta clase obtiene sus valores de variables de ambiente.
|
Esta clase obtiene sus valores de variables de ambiente.
|
||||||
Si no estan en el ambiente, los jala de nuestra Vault.
|
Si no estan en el ambiente, los jala de nuestra Vault.
|
||||||
@@ -39,11 +38,10 @@ class Settings(BaseSettings):
|
|||||||
async def init_mongo_db(self):
|
async def init_mongo_db(self):
|
||||||
"""Este helper inicia la conexion enter el MongoDB ORM y nuestra instancia"""
|
"""Este helper inicia la conexion enter el MongoDB ORM y nuestra instancia"""
|
||||||
|
|
||||||
|
from banortegpt.database.mongo_memory.models import Conversation
|
||||||
from beanie import init_beanie
|
from beanie import init_beanie
|
||||||
from motor.motor_asyncio import AsyncIOMotorClient
|
from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
|
|
||||||
from banortegpt.database.mongo_memory.models import Conversation
|
|
||||||
|
|
||||||
await init_beanie(
|
await init_beanie(
|
||||||
database=AsyncIOMotorClient(self.mongodb_url).voz_del_cliente,
|
database=AsyncIOMotorClient(self.mongodb_url).voz_del_cliente,
|
||||||
document_models=[Conversation],
|
document_models=[Conversation],
|
||||||
|
|||||||
@@ -35,16 +35,24 @@ class Message(BaseModel):
|
|||||||
|
|
||||||
@app.post("/api/v1/message")
|
@app.post("/api/v1/message")
|
||||||
async def send(message: Message):
|
async def send(message: Message):
|
||||||
|
|
||||||
def b64_sse(func):
|
def b64_sse(func):
|
||||||
"""Este helper transforma un generador de strings a un generador del protocolo SSE"""
|
"""Este helper transforma un generador de strings a un generador del protocolo SSE"""
|
||||||
|
|
||||||
async def wrapper(*args, **kwargs):
|
async def wrapper(*args, **kwargs):
|
||||||
async for chunk in func(*args, **kwargs):
|
async for chunk in func(*args, **kwargs):
|
||||||
content = chunk.model_dump_json()
|
content = chunk.model_dump_json()
|
||||||
data = f"data: {content}\n\n"
|
data = f"data: {content}\n\n"
|
||||||
yield data
|
yield data
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
sse_stream = b64_sse(services.stream)
|
sse_stream = b64_sse(services.stream)
|
||||||
generator = sse_stream(agent, message.prompt, message.conversation_id, message.with_deep_research)
|
generator = sse_stream(
|
||||||
|
agent, message.prompt, message.conversation_id, message.with_deep_research
|
||||||
|
)
|
||||||
return StreamingResponse(generator, media_type="text/event-stream")
|
return StreamingResponse(generator, media_type="text/event-stream")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def health():
|
||||||
|
return {"app": "Voz del Cliente", "status": "OK"}
|
||||||
|
|||||||
46
compose.yaml
@@ -45,16 +45,16 @@ services:
|
|||||||
- traefik.http.routers.ocp.entrypoints=web
|
- traefik.http.routers.ocp.entrypoints=web
|
||||||
- traefik.http.routers.ocp.middlewares=ocp-strip
|
- traefik.http.routers.ocp.middlewares=ocp-strip
|
||||||
- traefik.http.middlewares.ocp-strip.stripprefix.prefixes=/api/mayaocp
|
- traefik.http.middlewares.ocp-strip.stripprefix.prefixes=/api/mayaocp
|
||||||
ChatEgresos:
|
egresos:
|
||||||
image: mayacontigo/chategresos:latest
|
image: mayacontigo/egresos:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: .containers/unit/Dockerfile
|
dockerfile: .containers/unit/Dockerfile
|
||||||
args:
|
args:
|
||||||
PACKAGE: ChatEgresos
|
PACKAGE: egresos
|
||||||
x-bake:
|
x-bake:
|
||||||
tags:
|
tags:
|
||||||
- mayacontigo/chategresos:latest
|
- mayacontigo/egresos:latest
|
||||||
ports:
|
ports:
|
||||||
- 8001:80
|
- 8001:80
|
||||||
labels:
|
labels:
|
||||||
@@ -69,7 +69,7 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
dockerfile: .containers/unit/Dockerfile
|
dockerfile: .containers/unit/Dockerfile
|
||||||
args:
|
args:
|
||||||
PACKAGE: nnormativa
|
PACKAGE: voz-del-cliente
|
||||||
x-bake:
|
x-bake:
|
||||||
tags:
|
tags:
|
||||||
- mayacontigo/nnormativa:latest
|
- mayacontigo/nnormativa:latest
|
||||||
@@ -99,42 +99,6 @@ services:
|
|||||||
- traefik.http.routers.normativa.entrypoints=web
|
- traefik.http.routers.normativa.entrypoints=web
|
||||||
- traefik.http.routers.normativa.middlewares=normativa-strip
|
- traefik.http.routers.normativa.middlewares=normativa-strip
|
||||||
- traefik.http.middlewares.normativa-strip.stripprefix.prefixes=/api/mayanormativa
|
- traefik.http.middlewares.normativa-strip.stripprefix.prefixes=/api/mayanormativa
|
||||||
Test:
|
|
||||||
image: mayacontigo/Test:latest
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: .containers/unit/Dockerfile
|
|
||||||
args:
|
|
||||||
PACKAGE: Test
|
|
||||||
x-bake:
|
|
||||||
tags:
|
|
||||||
- mayacontigo/Test:latest
|
|
||||||
ports:
|
|
||||||
- 8002:80
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.http.routers.Test.rule=PathPrefix(`/api/mayaTest`)
|
|
||||||
- traefik.http.routers.Test.entrypoints=web
|
|
||||||
- traefik.http.routers.Test.middlewares=Test-strip
|
|
||||||
- traefik.http.middlewares.Test-strip.stripprefix.prefixes=/api/mayaTest
|
|
||||||
nnormativa:
|
|
||||||
image: mayacontigo/nnormativa:latest
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: .containers/unit/Dockerfile
|
|
||||||
args:
|
|
||||||
PACKAGE: nnormativa
|
|
||||||
x-bake:
|
|
||||||
tags:
|
|
||||||
- mayacontigo/nnormativa:latest
|
|
||||||
ports:
|
|
||||||
- 8003:80
|
|
||||||
labels:
|
|
||||||
- traefik.enable=true
|
|
||||||
- traefik.http.routers.nnormativa.rule=PathPrefix(`/api/mayannormativa`)
|
|
||||||
- traefik.http.routers.nnormativa.entrypoints=web
|
|
||||||
- traefik.http.routers.nnormativa.middlewares=nnormativa-strip
|
|
||||||
- traefik.http.middlewares.nnormativa-strip.stripprefix.prefixes=/api/mayannormativa
|
|
||||||
pyme:
|
pyme:
|
||||||
image: mayacontigo/pyme:latest
|
image: mayacontigo/pyme:latest
|
||||||
build:
|
build:
|
||||||
|
|||||||
30
scripts/replace-app-name.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Replace app name in Kubernetes manifest files
|
||||||
|
# Usage: ./replace-app-name.sh <app_name> <old_name>
|
||||||
|
# Example: ./replace-app-name.sh bursatil inversionistas
|
||||||
|
|
||||||
|
if [ $# -ne 2 ]; then
|
||||||
|
echo "Usage: $0 <app_name> <old_name>"
|
||||||
|
echo "Example: $0 bursatil inversionistas"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
APP_NAME=$1
|
||||||
|
OLD_NAME=$2
|
||||||
|
K8S_DIR="apps/$APP_NAME/.k8s"
|
||||||
|
|
||||||
|
if [ ! -d "$K8S_DIR" ]; then
|
||||||
|
echo "Error: Directory $K8S_DIR does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Replacing '$OLD_NAME' with '$APP_NAME' in $K8S_DIR"
|
||||||
|
|
||||||
|
for file in "$K8S_DIR"/*.yaml; do
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
echo " Processing: $(basename $file)"
|
||||||
|
sed -i "s/$OLD_NAME/$APP_NAME/g" "$file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Done!"
|
||||||
82
uv.lock
generated
@@ -13,8 +13,8 @@ members = [
|
|||||||
"azure-storage",
|
"azure-storage",
|
||||||
"banortegpt",
|
"banortegpt",
|
||||||
"bursatil",
|
"bursatil",
|
||||||
"chategresos",
|
|
||||||
"chunk-with-llm",
|
"chunk-with-llm",
|
||||||
|
"egresos",
|
||||||
"google-storage",
|
"google-storage",
|
||||||
"inversionistas",
|
"inversionistas",
|
||||||
"mongo-memory",
|
"mongo-memory",
|
||||||
@@ -27,7 +27,6 @@ members = [
|
|||||||
"riesgos",
|
"riesgos",
|
||||||
"search-evaluator",
|
"search-evaluator",
|
||||||
"synthetic-question-generator",
|
"synthetic-question-generator",
|
||||||
"test",
|
|
||||||
"vector-db-migrator",
|
"vector-db-migrator",
|
||||||
"vertex-ai-gemini",
|
"vertex-ai-gemini",
|
||||||
"voz-del-cliente",
|
"voz-del-cliente",
|
||||||
@@ -503,33 +502,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chategresos"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = { virtual = "apps/ChatEgresos" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "aiohttp" },
|
|
||||||
{ name = "fastapi" },
|
|
||||||
{ name = "hvac" },
|
|
||||||
{ name = "langchain-azure-ai", extra = ["opentelemetry"] },
|
|
||||||
{ name = "mongo-memory" },
|
|
||||||
{ name = "pydantic-settings" },
|
|
||||||
{ name = "qdrant" },
|
|
||||||
{ name = "uvicorn" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
|
||||||
requires-dist = [
|
|
||||||
{ name = "aiohttp", specifier = ">=3.11.16" },
|
|
||||||
{ name = "fastapi", specifier = ">=0.115.6" },
|
|
||||||
{ name = "hvac", specifier = ">=2.3.0" },
|
|
||||||
{ name = "langchain-azure-ai", extras = ["opentelemetry"], specifier = ">=0.1.4" },
|
|
||||||
{ name = "mongo-memory", editable = "packages/mongo-memory" },
|
|
||||||
{ name = "pydantic-settings", specifier = ">=2.8.1" },
|
|
||||||
{ name = "qdrant", editable = "packages/qdrant" },
|
|
||||||
{ name = "uvicorn", specifier = ">=0.34.0" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chunk-with-llm"
|
name = "chunk-with-llm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -749,6 +721,33 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" },
|
{ url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "egresos"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "apps/egresos" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "aiohttp" },
|
||||||
|
{ name = "fastapi" },
|
||||||
|
{ name = "hvac" },
|
||||||
|
{ name = "langchain-azure-ai", extra = ["opentelemetry"] },
|
||||||
|
{ name = "mongo-memory" },
|
||||||
|
{ name = "pydantic-settings" },
|
||||||
|
{ name = "qdrant" },
|
||||||
|
{ name = "uvicorn" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "aiohttp", specifier = ">=3.11.16" },
|
||||||
|
{ name = "fastapi", specifier = ">=0.115.6" },
|
||||||
|
{ name = "hvac", specifier = ">=2.3.0" },
|
||||||
|
{ name = "langchain-azure-ai", extras = ["opentelemetry"], specifier = ">=0.1.4" },
|
||||||
|
{ name = "mongo-memory", editable = "packages/mongo-memory" },
|
||||||
|
{ name = "pydantic-settings", specifier = ">=2.8.1" },
|
||||||
|
{ name = "qdrant", editable = "packages/qdrant" },
|
||||||
|
{ name = "uvicorn", specifier = ">=0.34.0" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "email-validator"
|
name = "email-validator"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@@ -3438,31 +3437,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
|
{ url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "test"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = { virtual = "apps/Test" }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "aiohttp" },
|
|
||||||
{ name = "fastapi" },
|
|
||||||
{ name = "hvac" },
|
|
||||||
{ name = "langchain-azure-ai", extra = ["opentelemetry"] },
|
|
||||||
{ name = "mongo-memory" },
|
|
||||||
{ name = "pydantic-settings" },
|
|
||||||
{ name = "uvicorn" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
|
||||||
requires-dist = [
|
|
||||||
{ name = "aiohttp", specifier = ">=3.11.16" },
|
|
||||||
{ name = "fastapi", specifier = ">=0.115.6" },
|
|
||||||
{ name = "hvac", specifier = ">=2.3.0" },
|
|
||||||
{ name = "langchain-azure-ai", extras = ["opentelemetry"], specifier = ">=0.1.4" },
|
|
||||||
{ name = "mongo-memory", editable = "packages/mongo-memory" },
|
|
||||||
{ name = "pydantic-settings", specifier = ">=2.8.1" },
|
|
||||||
{ name = "uvicorn", specifier = ">=0.34.0" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tiktoken"
|
name = "tiktoken"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|||||||