.env DELETED
@@ -1,5 +0,0 @@
1
- DB_HOST=gondola.proxy.rlwy.net
2
- DB_PORT=45741
3
- DB_USER=root
4
- DB_PASSWORD=OryNzMwGGmvoULIEGyBRgNLqolGdlsnw
5
- DB_NAME=railway
 
 
 
 
 
 
.gitattributes CHANGED
@@ -1,37 +1,35 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
36
- images/Logo[[:space:]]dashboard.png filter=lfs diff=lfs merge=lfs -text
37
- paginas/images/Logo[[:space:]]dashboard.png filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
.gitignore DELETED
Binary file (41 Bytes)
 
Dockerfile DELETED
Binary file (496 Bytes)
 
README.md CHANGED
@@ -1,13 +1,10 @@
1
- ---
2
- title: Forecast Sales SARIMA
3
- emoji:
4
- colorFrom: pink
5
- colorTo: yellow
6
- sdk: streamlit
7
- sdk_version: 1.40.2
8
- app_file: app.py
9
- pinned: false
10
- short_description: Modelo de prueba
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: PredictiveMLGenAI
3
+ emoji: 📈
4
+ colorFrom: yellow
5
+ colorTo: indigo
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
animations/laptopUser.json DELETED
@@ -1 +0,0 @@
1
- {"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":30,"ip":0,"op":120,"w":300,"h":225,"nm":"971 [Converted]g","ddd":1,"assets":[{"id":"image_0","w":65,"h":115,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_1","w":27,"h":17,"u":"","p":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAARCAYAAAAsT9czAAABGklEQVRIS7WUwU3DQBREZxCCI+kAd0C4II50gKkAUwEpISWkA6cDoIPQAVSQ0AGcUBAwaNAPWgwRdlh/ydd9nnl/l5JKACcAxiQf0eNQ0gTAJYAnABOS4754hg0ATAGcBuQBwIjkdW4oVwdKcpVOeRApi9y1fsESaBUOnS6rwx+wZnWSDLdH+3TyjacNzNt6lfisSM42If4J86Hh00u0H5BbknbcaVrBEp+jqHQPwCHJuy60TrBI6atSknTSz5E0bAPuDFuzQDWA+7ifa33mgDmp61z5vAnoovlj/4Yl1dqnP/v00+dqvwGzwBJ3RSzQOYCz5pOXFfbbZmpYD5bb79Xu69a0d9jzcV3wTXNBF73DnHZ5VJc7L5h9AM+/YPcpkIXXAAAAAElFTkSuQmCC","e":1},{"id":"image_2","w":77,"h":65,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_3","w":135,"h":134,"u":"","p":"data:image/png;base64,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","e":1},{"id":"image_4","w":291,"h":284,"u":"","p":"data:image/png;base64,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","e":1}],"layers":[{"ddd":1,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":11,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":45,"ix":10},"or":{"a":0,"k":[292,0,353],"ix":7},"p":{"a":0,"k":[51.2175,139.747,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[21.5,18.7615,43],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":22,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":4,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.949,0.43,0.249,0.5,0.945,0.319,0.289,1,0.941,0.207,0.328],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":13},"bm":0,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":80,"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":119.000004846969,"s":[720]}],"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":2,"ty":2,"nm":"Layer 11","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[91.398,72.2725,0],"to":[0,-1.667,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[91.398,67.2725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[91.398,72.2725,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[91.398,67.2725,0],"to":[0,0,0],"ti":[0,-1.667,0]},{"t":119.000004846969,"s":[91.398,72.2725,0]}],"ix":2},"a":{"a":0,"k":[32.334,57.477,0],"ix":1},"s":{"a":0,"k":[50,50,100],"ix":6}},"ao":0,"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":3,"ty":2,"nm":"Layer 9","parent":5,"refId":"image_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[99.575,54.653,0],"ix":2},"a":{"a":0,"k":[13.379,8.382,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":4,"ty":2,"nm":"Layer 8","parent":5,"refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[52.384,56.472,0],"ix":2},"a":{"a":0,"k":[38.333,32.236,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":5,"ty":2,"nm":"Layer 7","parent":6,"refId":"image_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[197.62,101.429,0],"ix":2},"a":{"a":0,"k":[67.454,66.635,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":18,"s":[0,0,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":22,"s":[120,120,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":26,"s":[70,70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,0]},"t":30,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":94,"s":[70,70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":98,"s":[120,120,100]},{"t":102.000004154545,"s":[0,0,100]}],"ix":6}},"ao":0,"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":6,"ty":2,"nm":"Layer 6","refId":"image_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[152.6655,98.2715,0],"to":[0,1.667,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":31,"s":[152.6655,103.2715,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":61,"s":[152.6655,98.2715,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[152.6655,103.2715,0],"to":[0,0,0],"ti":[0,1.667,0]},{"t":119.000004846969,"s":[152.6655,98.2715,0]}],"ix":2},"a":{"a":0,"k":[145.174,141.543,0],"ix":1},"s":{"a":0,"k":[50,50,100],"ix":6}},"ao":0,"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":7,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":0,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":0,"ix":10},"or":{"a":0,"k":[0,0,0],"ix":7},"p":{"a":0,"k":[150,112.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[50,50,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-61,-32],[-162,38],[9,136],[129,65]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":12,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":4,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.949,0.43,0.249,0.5,0.945,0.319,0.289,1,0.941,0.207,0.328],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":13},"bm":0,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":80,"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":119.000004846969,"s":[-360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0},{"ddd":1,"ind":8,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"rx":{"a":0,"k":11,"ix":8},"ry":{"a":0,"k":0,"ix":9},"rz":{"a":0,"k":45,"ix":10},"or":{"a":0,"k":[292,0,358],"ix":7},"p":{"a":0,"k":[81.173,91.3375,72.9015],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[34.0275,34.584,78],"ix":6}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,100],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":22,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":4,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.949,0.43,0.249,0.5,0.945,0.319,0.289,1,0.941,0.207,0.328],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"ml2":{"a":0,"k":4,"ix":13},"bm":0,"nm":"Gradient Stroke 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":80,"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":119.000004846969,"s":[-720]}],"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120.0000048877,"st":0,"bm":0}],"markers":[]}
 
 
animations/loginUser.json DELETED
@@ -1 +0,0 @@
1
- {"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":25,"ip":0,"op":50,"w":1000,"h":1000,"nm":"User","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 1 Outlines","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[100]},{"t":15,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[500,500.305,0],"ix":2},"a":{"a":0,"k":[428.342,494.37,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,93.473],[-93.473,0],[0,-93.473],[93.473,0]],"o":[[0,-93.473],[93.473,0],[0,93.473],[-93.473,0]],"v":[[-169.248,0],[0,-169.248],[169.248,0],[0,169.248]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0.4627,0.498,0.6784,1]},{"t":5,"s":[0.1554,0.2269,0.5846,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":47,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[428.342,286.748],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.001,14.488],[0,0],[3.082,17.225],[4.699,14.677],[7.919,13.93],[10.273,9.831],[14.821,5.866],[16.294,0.436],[0,0],[0,0],[4.363,-2.841],[12.785,-8.173],[19.383,-6.263],[19.525,0],[19.406,6.275],[12.139,7.738],[10.029,6.535],[3.059,1.627],[0,0],[0,0],[13.646,-5.404],[10.29,-9.852],[7.921,-13.929],[4.695,-14.664],[3.08,-17.146],[1.023,-14.798],[0,-15.601],[-21.466,-20.433],[-14.643,-5.103],[-17.417,0],[0,0],[-13.942,4.859],[-10.993,10.463],[-5.376,14.366],[-0.002,17.229]],"o":[[0,0],[-1.018,-14.698],[-3.067,-17.108],[-4.69,-14.654],[-7.922,-13.941],[-10.304,-9.856],[-13.649,-5.403],[0,0],[0,0],[-3.01,1.602],[-9.316,6.075],[-12.104,7.718],[-19.405,6.271],[-19.525,0],[-19.363,-6.249],[-11.744,-7.501],[-4.325,-2.821],[0,0],[0,0],[-16.292,0.436],[-14.835,5.869],[-10.271,9.837],[-7.912,13.93],[-4.682,14.626],[-3.078,17.128],[-1.023,14.691],[0,35.256],[10.992,10.461],[13.941,4.858],[0,0],[17.415,0],[14.644,-5.103],[10.988,-10.454],[5.101,-13.633],[-0.003,-15.378]],"v":[[309.329,24.263],[309.285,23.609],[303.106,-24.499],[291.402,-72.396],[272.399,-115.473],[244.978,-151.299],[207.114,-174.991],[161.988,-183.791],[155.657,-183.96],[150.067,-180.982],[138.954,-174.286],[106.117,-153.117],[58.651,-132.039],[-0.017,-122.589],[-58.687,-132.045],[-106.156,-153.121],[-138.979,-174.28],[-150.113,-180.988],[-155.7,-183.96],[-162.025,-183.791],[-207.142,-174.989],[-245.011,-151.294],[-272.426,-115.479],[-291.424,-72.391],[-303.121,-24.511],[-309.301,23.603],[-310.842,69.26],[-278.492,153.185],[-239.861,176.639],[-192.603,183.96],[192.598,183.96],[239.853,176.637],[278.488,153.178],[303.151,115.771],[310.842,69.262]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0.4627,0.498,0.6784,1]},{"t":5,"s":[0.1554,0.2269,0.5846,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":47,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[428.342,687.279],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":15,"s":[0]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[100]},{"t":15,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":15,"s":[-100]}],"ix":3},"m":1,"ix":3,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":250,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 1 Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[500.001,500,0],"ix":2},"a":{"a":0,"k":[428.342,494.37,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":15,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":20,"s":[105,105,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":25,"s":[97,97,100]},{"t":30,"s":[100,100,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":15,"s":[{"i":[[0,93.473],[-93.473,0],[0,-93.473],[93.473,0]],"o":[[0,-93.473],[93.473,0],[0,93.473],[-93.473,0]],"v":[[-169.248,0],[0,-169.248],[169.248,0],[0,169.248]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":20,"s":[{"i":[[0,93.473],[-93.473,0],[0,-93.473],[93.473,0]],"o":[[0,-93.473],[93.473,0],[0,93.473],[-93.473,0]],"v":[[-168.75,-23.81],[0.498,-193.058],[169.746,-23.81],[0.498,145.439]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":25,"s":[{"i":[[0,93.473],[-93.473,0],[0,-93.473],[93.473,0]],"o":[[0,-93.473],[93.473,0],[0,93.473],[-93.473,0]],"v":[[-168.723,41.237],[0.525,-128.011],[169.773,41.237],[0.525,210.485]],"c":true}]},{"t":30,"s":[{"i":[[0,93.473],[-93.473,0],[0,-93.473],[93.473,0]],"o":[[0,-93.473],[93.473,0],[0,93.473],[-93.473,0]],"v":[[-169.248,0],[0,-169.248],[169.248,0],[0,169.248]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0.4627,0.498,0.6784,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[0.4627,0.498,0.6784,1]},{"t":15,"s":[0.1554,0.2269,0.5846,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":47,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[428.342,286.748],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.001,14.488],[0,0],[3.082,17.225],[4.699,14.677],[7.919,13.93],[10.273,9.831],[14.821,5.866],[16.294,0.436],[0,0],[0,0],[4.363,-2.841],[12.785,-8.173],[19.383,-6.263],[19.525,0],[19.406,6.275],[12.139,7.738],[10.029,6.535],[3.059,1.627],[0,0],[0,0],[13.646,-5.404],[10.29,-9.852],[7.921,-13.929],[4.695,-14.664],[3.08,-17.146],[1.023,-14.798],[0,-15.601],[-21.466,-20.433],[-14.643,-5.103],[-17.417,0],[0,0],[-13.942,4.859],[-10.993,10.463],[-5.376,14.366],[-0.002,17.229]],"o":[[0,0],[-1.018,-14.698],[-3.067,-17.108],[-4.69,-14.654],[-7.922,-13.941],[-10.304,-9.856],[-13.649,-5.403],[0,0],[0,0],[-3.01,1.602],[-9.316,6.075],[-12.104,7.718],[-19.405,6.271],[-19.525,0],[-19.363,-6.249],[-11.744,-7.501],[-4.325,-2.821],[0,0],[0,0],[-16.292,0.436],[-14.835,5.869],[-10.271,9.837],[-7.912,13.93],[-4.682,14.626],[-3.078,17.128],[-1.023,14.691],[0,35.256],[10.992,10.461],[13.941,4.858],[0,0],[17.415,0],[14.644,-5.103],[10.988,-10.454],[5.101,-13.633],[-0.003,-15.378]],"v":[[309.329,24.263],[309.285,23.609],[303.106,-24.499],[291.402,-72.396],[272.399,-115.473],[244.978,-151.299],[207.114,-174.991],[161.988,-183.791],[155.657,-183.96],[150.067,-180.982],[138.954,-174.286],[106.117,-153.117],[58.651,-132.039],[-0.017,-122.589],[-58.687,-132.045],[-106.156,-153.121],[-138.979,-174.28],[-150.113,-180.988],[-155.7,-183.96],[-162.025,-183.791],[-207.142,-174.989],[-245.011,-151.294],[-272.426,-115.479],[-291.424,-72.391],[-303.121,-24.511],[-309.301,23.603],[-310.842,69.26],[-278.492,153.185],[-239.861,176.639],[-192.603,183.96],[192.598,183.96],[239.853,176.637],[278.488,153.178],[303.151,115.771],[310.842,69.262]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0.4627,0.498,0.6784,1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14,"s":[0.4627,0.498,0.6784,1]},{"t":15,"s":[0.1554,0.2269,0.5846,1]}],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":47,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[428.342,687.279],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":250,"st":0,"bm":0}],"markers":[]}
 
 
app.py DELETED
@@ -1,32 +0,0 @@
1
- import streamlit as st
2
- from paginas import login, dashboardDemo
3
-
4
-
5
- def main():
6
- # Configurar la página y el estado de la sesión (solo una vez en app.py)
7
- st.set_page_config(
8
- page_title=":beginner: Dashboard Sales", # Título de la página
9
- page_icon=":smile:", # Icono de la página
10
- layout="wide", # Configurar el layout para que ocupe todo el ancho
11
- initial_sidebar_state="expanded" # Barra lateral expandida por defecto
12
- )
13
-
14
- # Leer parámetros de la URL
15
- query_params = st.query_params
16
- logged_in = query_params.get("logged_in", ["False"])[0] == "True"
17
-
18
- # Verificar si el usuario está logueado
19
- if logged_in or ("logged_in" in st.session_state and st.session_state.get("logged_in", False)):
20
- st.session_state.logged_in = True # Asegurar consistencia interna del estado
21
- if "archivo_subido" not in st.session_state:
22
- st.session_state.archivo_subido = False
23
- dashboardDemo.mostrar_dashboard()
24
- else:
25
- # Si no, mostramos el login
26
- login.showLogin()
27
- # Si inicia sesión correctamente, actualiza el parámetro en la URL
28
- if "logged_in" in st.session_state and st.session_state.logged_in:
29
- st.query_params.set(logged_in="True")
30
-
31
- if __name__ == "__main__":
32
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
catboost.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:059f80be82f0f5ace74dc7ee09cd8a24502bb2e106623f43404a65c1df9abd0f
3
- size 1115713
 
 
 
 
dbpredictivesystemgenai.sql DELETED
@@ -1,74 +0,0 @@
1
- -- phpMyAdmin SQL Dump
2
- -- version 5.2.1
3
- -- https://www.phpmyadmin.net/
4
- --
5
- -- Servidor: 127.0.0.1
6
- -- Tiempo de generación: 19-06-2025 a las 19:52:38
7
- -- Versión del servidor: 10.4.32-MariaDB
8
- -- Versión de PHP: 8.2.12
9
-
10
- SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
11
- START TRANSACTION;
12
- SET time_zone = "+00:00";
13
-
14
-
15
- /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
16
- /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
17
- /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
18
- /*!40101 SET NAMES utf8mb4 */;
19
-
20
- --
21
- -- Base de datos: `dbpredictivesystemgenai`
22
- --
23
-
24
- -- --------------------------------------------------------
25
-
26
- --
27
- -- Estructura de tabla para la tabla `usuarios`
28
- --
29
-
30
- CREATE TABLE `usuarios` (
31
- `id` int(11) NOT NULL,
32
- `nombre` varchar(20) NOT NULL,
33
- `apellido` varchar(30) NOT NULL,
34
- `correo` varchar(30) NOT NULL,
35
- `telefono` varchar(9) NOT NULL,
36
- `username` varchar(30) NOT NULL,
37
- `password` varchar(50) NOT NULL
38
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
39
-
40
- --
41
- -- Volcado de datos para la tabla `usuarios`
42
- --
43
-
44
- INSERT INTO `usuarios` (`id`, `nombre`, `apellido`, `correo`, `telefono`, `username`, `password`) VALUES
45
- (1, 'Administrador', 'Admin', '[email protected]', '985615263', 'admin', 'pass_admin'),
46
- (2, 'Juan Pablo', 'Perez Gonzalez', '[email protected]', '978451223', 'juanperez', 'pass_juanperez'),
47
- (3, 'Carlos Eduardo', 'Luna Martinez', '[email protected]', '978456129', 'carlosluna', 'pass_carlosluna'),
48
- (4, 'Maria Gabriela', 'Gomez Rodriguez', '[email protected]', '998565236', 'mariagomez', 'pass_mariagomez'),
49
- (5, 'Ana Lucia', 'Hernandez Diaz', '[email protected]', '963365125', 'analucia', 'pass_analucia');
50
-
51
- --
52
- -- Índices para tablas volcadas
53
- --
54
-
55
- --
56
- -- Indices de la tabla `usuarios`
57
- --
58
- ALTER TABLE `usuarios`
59
- ADD PRIMARY KEY (`id`);
60
-
61
- --
62
- -- AUTO_INCREMENT de las tablas volcadas
63
- --
64
-
65
- --
66
- -- AUTO_INCREMENT de la tabla `usuarios`
67
- --
68
- ALTER TABLE `usuarios`
69
- MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=31;
70
- COMMIT;
71
-
72
- /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
73
- /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
74
- /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df_articles.csv DELETED
The diff for this file is too large to render. See raw diff
 
gradientboosting.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:5bb28622f5a612db81f8c5d12f56913710303da5778551e6931dd97393ebad1c
3
- size 145876
 
 
 
 
histgradientboosting.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:13dca14204a9cbdd7bb407ae68697b9d4acc5b4969119b5abd2301f8c6e674cd
3
- size 375945
 
 
 
 
lightgbm.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:ae50d6dfc075ff1b930fcb207169710ab452f384a006ed4a3c61e3d2baae35f5
3
- size 281459
 
 
 
 
mlpregressor.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:287880615fc3e4cfedbba56d537bb7217ea86808ed896d81fd75b43f3b596387
3
- size 261329
 
 
 
 
paginas/__init__.py DELETED
File without changes
paginas/conexionMysql.py DELETED
@@ -1,24 +0,0 @@
1
- from contextlib import contextmanager
2
- import MySQLdb
3
- import os
4
- from dotenv import load_dotenv
5
-
6
-
7
-
8
- load_dotenv()
9
-
10
-
11
- @contextmanager
12
- def get_db_connection():
13
- connection = MySQLdb.connect(
14
- host=os.environ["DB_HOST"],
15
- port=int(os.environ["DB_PORT"]),
16
- user=os.environ["DB_USER"],
17
- passwd=os.environ["DB_PASSWORD"],
18
- db=os.environ["DB_NAME"]
19
- )
20
-
21
- try:
22
- yield connection
23
- finally:
24
- connection.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paginas/conexionTest.py DELETED
@@ -1 +0,0 @@
1
-
 
 
paginas/dashboard.py DELETED
@@ -1,813 +0,0 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import plotly.express as px
4
- import random
5
- import time
6
- import joblib
7
- import os
8
- import statsmodels
9
- from dotenv import load_dotenv
10
- import os
11
- from groq import Groq
12
- import html
13
- from pydub import AudioSegment
14
- import tempfile
15
- from io import BytesIO
16
- import tempfile
17
- #from langchain.agents.agent_toolkits import create_csv_agent
18
- #from langchain_groq import ChatGroq
19
- # ===========================
20
- # Función para generar datos ficticios
21
- # ===========================
22
- def generar_datos():
23
- meses = [
24
- "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
25
- "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
26
- ]
27
- paises = ["México", "Colombia", "Argentina", "Chile", "Perú"]
28
- data = [
29
- {"mes": mes, "pais": pais, "Total": random.randint(100, 1000)}
30
- for mes in meses for pais in paises
31
- ]
32
- return pd.DataFrame(data), meses, paises
33
-
34
- # ===========================
35
- # Función para el dashboard principal
36
- # ===========================
37
- def mostrar_dashboard():
38
- # Cargar variables desde el archivo .env
39
- load_dotenv()
40
-
41
- # Acceder a la clave
42
- groq_key = os.getenv("GROQ_API_KEY")
43
- client = Groq(api_key=groq_key)
44
-
45
- dfDatos, meses, paises = generar_datos()
46
-
47
- # Opciones del selectbox
48
- lista_opciones = ['5 años', '3 años', '1 año', '5 meses']
49
-
50
- # Mostrar barra lateral
51
- mostrar_sidebar(client)
52
-
53
- # Título principal
54
- st.header(':bar_chart: Dashboard Sales')
55
-
56
- # Mostrar métricas
57
- #mostrar_metricas()
58
-
59
- # Mostrar gráficos
60
- mostrar_graficos(lista_opciones)
61
-
62
- # ===========================
63
- # Configuración inicial de la página
64
- # ===========================
65
- #def configurar_pagina():
66
- #st.set_page_config(
67
- # page_title="Dashboard Sales",
68
- # page_icon=":smile:",
69
- # layout="wide",
70
- # initial_sidebar_state="expanded"
71
- #)
72
-
73
-
74
-
75
- # ===========================
76
- # Función para la barra lateral
77
- # ===========================
78
- def mostrar_sidebar(client):
79
- sidebar_logo = r"paginas\images\Logo general.png"
80
- main_body_logo = r"paginas\images\Logo.png"
81
- sidebar_logo_dashboard = r"paginas\images\Logo dashboard.png"
82
-
83
- st.logo(sidebar_logo, size="large", icon_image=main_body_logo)
84
-
85
- st.sidebar.image(sidebar_logo_dashboard)
86
- st.sidebar.title('🧠 GenAI Forecast')
87
-
88
- loadCSV()
89
-
90
- archivo_csv = "df_articles.csv"
91
- chatBotProtech(client)
92
- downloadCSV(archivo_csv)
93
-
94
-
95
- # Mostrar la tabla solo si se ha subido un archivo válido
96
- '''
97
- if 'archivo_subido' in st.session_state and st.session_state.archivo_subido: # Verificamos si el archivo ha sido subido y es válido
98
- st.sidebar.markdown("Vista previa del archivo CSV:")
99
- # Usar st.dataframe() para que ocupe todo el ancho disponible
100
- st.sidebar.dataframe(st.session_state.df_subido, use_container_width=True) # Mostrar la tabla con el archivo subido
101
- '''
102
-
103
-
104
-
105
- if st.sidebar.button("Cerrar Sesión"):
106
- cerrar_sesion()
107
-
108
-
109
- # ===========================
110
- # Función para métricas principales
111
- # ===========================
112
- '''
113
- def mostrar_metricas():
114
- c1, c2, c3, c4, c5 = st.columns(5)
115
- valores = [89, 78, 67, 56, 45]
116
- for i, col in enumerate([c1, c2, c3, c4, c5]):
117
- valor1 = valores[i]
118
- valor2 = valor1 - 10 # Simulación de variación
119
- variacion = valor1 - valor2
120
- unidad = "unidades" if i < 4 else "%"
121
- col.metric(f"Productos vendidos", f'{valor1:,.0f} {unidad}', f'{variacion:,.0f}')
122
- '''
123
-
124
-
125
- # Función para obtener los meses relevantes
126
- def obtener_meses_relevantes(df):
127
- # Extraemos los años y meses de la columna 'Date'
128
- df['Year'] = pd.to_datetime(df['orddt']).dt.year
129
- df['Month'] = pd.to_datetime(df['orddt']).dt.month
130
-
131
- # Encontramos el primer y último año en el dataset
132
- primer_ano = df['Year'].min()
133
- ultimo_ano = df['Year'].max()
134
-
135
- meses_relevantes = []
136
- nombres_meses_relevantes = []
137
-
138
- # Recorrer todos los años dentro del rango
139
- for ano in range(primer_ano, ultimo_ano + 1):
140
- for mes in [1, 4, 7, 10]: # Meses relevantes: enero (1), abril (4), julio (7), octubre (10)
141
- if mes in df[df['Year'] == ano]['Month'].values:
142
- # Obtener el nombre del mes
143
- nombre_mes = pd.to_datetime(f"{ano}-{mes}-01").strftime('%B') # Mes en formato textual (Enero, Abril, etc.)
144
- meses_relevantes.append(f"{nombre_mes}-{ano}")
145
- nombres_meses_relevantes.append(f"{nombre_mes}-{ano}")
146
-
147
- return meses_relevantes, nombres_meses_relevantes
148
-
149
- # ===========================
150
- # Función para gráficos
151
- # ===========================
152
- def mostrar_graficos(lista_opciones):
153
-
154
- """
155
- c1, c2 = st.columns([20, 80])
156
-
157
- with c1:
158
- filtroAnios = st.selectbox('Año', options=lista_opciones)
159
-
160
- with c2:
161
- st.markdown("### :pushpin: Ventas actuales")
162
- # Si hay un archivo válido subido
163
- if "archivo_subido" in st.session_state and st.session_state.archivo_subido:
164
- # Cargar datos del archivo subido
165
- df = st.session_state.df_subido.copy()
166
- df['Date'] = pd.to_datetime(df['Date'])
167
- df['Mes-Año'] = df['Date'].dt.strftime('%B-%Y') # Formato deseado
168
- df = df.sort_values('Date') # Ordenar por fecha
169
-
170
- # Obtener los meses relevantes del dataset
171
- meses_relevantes, nombres_meses_relevantes = obtener_meses_relevantes(df)
172
-
173
- # Crear la gráfica
174
- fig = px.line(
175
- df,
176
- x='Mes-Año',
177
- y='Sale',
178
- title='Ventas mensuales (Archivo Subido)',
179
- labels={'Mes-Año': 'Mes-Año', 'Sale': 'Ventas'},
180
- )
181
- else:
182
- # Datos por defecto
183
- df = pd.DataFrame({
184
- "Mes-Año": ["Enero-2024", "Febrero-2024", "Marzo-2024", "Abril-2024", "Mayo-2024", "Junio-2024", "Julio-2024", "Agosto-2024", "Septiembre-2024", "Octubre-2024", "Noviembre-2024", "Diciembre-2024"],
185
- "Sale": [100, 150, 120, 200, 250, 220, 280, 300, 350, 400, 450, 500],
186
- })
187
-
188
- # Obtener los meses relevantes
189
- meses_relevantes = ["Enero-2024", "Abril-2024", "Julio-2024", "Octubre-2024"]
190
- nombres_meses_relevantes = ["Enero-2024", "Abril-2024", "Julio-2024", "Octubre-2024"]
191
-
192
- # Crear la gráfica
193
- fig = px.line(
194
- df,
195
- x='Mes-Año',
196
- y='Sale',
197
- title='Ventas mensuales (Datos por defecto)',
198
- labels={'Mes-Año': 'Mes-Año', 'Sale': 'Ventas'},
199
- line_shape='linear' # Línea continua
200
- )
201
-
202
-
203
- fig.update_xaxes(tickangle=-45) # Ajustar ángulo de etiquetas en X
204
-
205
- # Mejorar el diseño de la gráfica
206
- fig = mejorar_diseno_grafica(fig, meses_relevantes, nombres_meses_relevantes)
207
- st.plotly_chart(fig, use_container_width=True) # Evita que ocupe todo el ancho
208
-
209
- # Gráfica 2: Ventas actuales y proyectadas
210
- st.markdown("### :chart_with_upwards_trend: Pronóstico")
211
- mostrar_ventas_proyectadas(filtroAnios)
212
- """
213
- if "archivo_subido" not in st.session_state or not st.session_state.archivo_subido:
214
- st.warning("Por favor, sube un archivo CSV válido para visualizar los gráficos.")
215
- return
216
-
217
- df = st.session_state.df_subido.copy()
218
-
219
- # Fila 1: 3 gráficas
220
- col1, col2, col3 = st.columns(3)
221
- with col1:
222
- fig1 = px.histogram(df, x='sales', title='Distribución de Ventas')
223
- st.plotly_chart(fig1, use_container_width=True)
224
-
225
- with col2:
226
- fig2 = px.box(df, x='segmt', y='sales', title='Ventas por Segmento')
227
- st.plotly_chart(fig2, use_container_width=True)
228
-
229
- with col3:
230
- print("")
231
-
232
- # Fila 2: 2 gráficas
233
- col4, col5 = st.columns(2)
234
- with col4:
235
- fig4 = px.pie(df, names='categ', values='sales', title='Ventas por Categoría')
236
- st.plotly_chart(fig4, use_container_width=True)
237
-
238
- with col5:
239
-
240
- # Agrupar por nombre de producto y sumar las ventas
241
- top_productos = (
242
- df.groupby('prdna')['sales']
243
- .sum()
244
- .sort_values(ascending=False)
245
- .head(10)
246
- .reset_index()
247
- )
248
-
249
- # Crear gráfica de barras horizontales
250
- fig5 = px.bar(
251
- top_productos,
252
- x='sales',
253
- y='prdna',
254
- orientation='h',
255
- title='Top 10 productos más vendidos',
256
- labels={'sales': 'Ventas', 'prdna': 'Producto'},
257
- color='sales',
258
- color_continuous_scale='Blues'
259
- )
260
-
261
- fig5.update_layout(yaxis={'categoryorder': 'total ascending'})
262
- st.plotly_chart(fig5, use_container_width=True)
263
-
264
- col6, col7 = st.columns(2)
265
- with col6:
266
- # Fuera del sistema de columnas
267
- tabla = df.pivot_table(index='state', columns='subct', values='sales', aggfunc='sum').fillna(0)
268
-
269
- if not tabla.empty:
270
- tabla = tabla.astype(float)
271
- fig6 = px.imshow(
272
- tabla.values,
273
- labels=dict(x="Categoría", y="Estado", color="Ventas"),
274
- x=tabla.columns,
275
- y=tabla.index,
276
- text_auto=True,
277
- title="Mapa de Calor: Ventas por Estado y Categoría"
278
- )
279
-
280
- # Ajuste del tamaño de la figura
281
- # fig6.update_layout(height=600, width=1000) # Puedes ajustar según tu pantalla
282
- st.plotly_chart(fig6, use_container_width=True)
283
- else:
284
- st.warning("No hay datos suficientes para mostrar el mapa de calor.")
285
-
286
-
287
- with col7:
288
- fig7 = px.bar(df.groupby('state')['sales'].sum().reset_index(), x='state', y='sales', title='Ventas por Estado')
289
- st.plotly_chart(fig7, use_container_width=True)
290
-
291
- # -------------------------------
292
- # CARGA DE CSV Y GUARDADO EN SESIÓN
293
- # -------------------------------
294
-
295
- def loadCSV():
296
- columnas_requeridas = [
297
- 'rowid','ordid','orddt',
298
- 'shpdt','segmt','state',
299
- 'cono','prodid','categ',
300
- 'subct','prdna','sales'
301
- ]
302
- with st.sidebar.expander("📁 Subir archivo"):
303
- uploaded_file = st.file_uploader("Sube un archivo CSV:", type=["csv"], key="upload_csv")
304
-
305
-
306
- if uploaded_file is not None:
307
- # Reseteamos el estado de 'descargado' cuando se sube un archivo
308
- st.session_state.descargado = False
309
- st.session_state.archivo_subido = False # Reinicia el estado
310
- try:
311
- # Leer el archivo subido
312
- df = pd.read_csv(uploaded_file)
313
-
314
- # Verificar que las columnas estén presentes y en el orden correcto
315
- if list(df.columns) == columnas_requeridas:
316
- st.session_state.df_subido = df
317
- st.session_state.archivo_subido = True
318
- aviso = st.sidebar.success("✅ Archivo subido correctamente.")
319
- time.sleep(3)
320
- aviso.empty()
321
-
322
-
323
- else:
324
- st.session_state.archivo_subido = False
325
- aviso = st.sidebar.error(f"El archivo no tiene las columnas requeridas: {columnas_requeridas}.")
326
- time.sleep(3)
327
- aviso.empty()
328
-
329
- except Exception as e:
330
- aviso = st.sidebar.error(f"Error al procesar el archivo: {str(e)}")
331
- time.sleep(3)
332
- aviso.empty()
333
-
334
- # ===========================
335
- # Función para descargar archivo CSV
336
- # ===========================
337
- def downloadCSV(archivo_csv):
338
- # Verificamos si el archivo ya ha sido descargado
339
- if 'descargado' not in st.session_state:
340
- st.session_state.descargado = False
341
-
342
- if not st.session_state.descargado:
343
-
344
- # Usamos st.spinner para mostrar un estado de descarga inicial
345
- #with st.spinner("Preparando archivo para descarga..."):
346
- # time.sleep(2) # Simulación de preparación del archivo
347
- # Botón de descarga
348
- descarga = st.sidebar.download_button(
349
- label="Descargar archivo CSV",
350
- data=open(archivo_csv, "rb"),
351
- file_name="ventas.csv",
352
- mime="text/csv"
353
- )
354
-
355
- if descarga:
356
- # Marcamos el archivo como descargado
357
- st.session_state.descargado = True
358
- aviso = st.sidebar.success("¡Descarga completada!")
359
- # Hacer que el mensaje desaparezca después de 2 segundos
360
- time.sleep(3)
361
- aviso.empty()
362
- else:
363
- aviso = st.sidebar.success("¡Ya has descargado el archivo!")
364
- time.sleep(3)
365
- aviso.empty()
366
-
367
- # -------------------------------
368
- # CREACIÓN DE AGENTE CSV
369
- # -------------------------------
370
- '''
371
- def createCSVAgent(client, df):
372
- temp_csv = tempfile.NamedTemporaryFile(delete=False, suffix=".csv")
373
- df.to_csv(temp_csv.name, index=False)
374
- agent = create_csv_agent(
375
- client,
376
- temp_csv.name,
377
- verbose=False,
378
- handle_parsing_errors=True
379
- )
380
- return agent
381
- '''
382
- '''
383
- def callCSVAgent(client, prompt):
384
- if "df_csv" not in st.session_state:
385
- return "No hay CSV cargado aún."
386
-
387
- df = st.session_state.df_csv
388
- agente = createCSVAgent(client, df)
389
-
390
- try:
391
- respuesta = agente.run(prompt)
392
- except Exception as e:
393
- respuesta = f"Error al procesar la pregunta: {e}"
394
-
395
- return respuesta
396
- '''
397
-
398
- # -------------------------------
399
- # FUNCIÓN PARA DETECTAR REFERENCIA AL CSV
400
- # -------------------------------
401
- def detectedReferenceToCSV(prompt: str) -> bool:
402
- palabras_clave = ["csv", "archivo", "contenido cargado", "file", "dataset"]
403
- prompt_lower = prompt.lower()
404
- return any(palabra in prompt_lower for palabra in palabras_clave)
405
-
406
- # ===========================
407
- # Función para interactuar con el bot
408
- # ===========================
409
- def chatBotProtech(client):
410
- with st.sidebar.expander("📁 Chatbot"):
411
-
412
- # Inicializar estados
413
- if "chat_history" not in st.session_state:
414
- st.session_state.chat_history = []
415
-
416
- if "audio_data" not in st.session_state:
417
- st.session_state.audio_data = None
418
-
419
- if "transcripcion" not in st.session_state:
420
- st.session_state.transcripcion = ""
421
-
422
- if "mostrar_grabador" not in st.session_state:
423
- st.session_state.mostrar_grabador = True
424
-
425
- # Contenedor para mensajes
426
- messages = st.container(height=400)
427
-
428
-
429
- # CSS: estilo tipo Messenger
430
- st.markdown("""
431
- <style>
432
- .chat-message {
433
- display: flex;
434
- align-items: flex-start;
435
- margin: 10px 0;
436
- }
437
- .chat-message.user {
438
- justify-content: flex-end;
439
- }
440
- .chat-message.assistant {
441
- justify-content: flex-start;
442
- }
443
- .chat-icon {
444
- width: 30px;
445
- height: 30px;
446
- border-radius: 50%;
447
- background-color: #ccc;
448
- display: flex;
449
- align-items: center;
450
- justify-content: center;
451
- font-size: 18px;
452
- margin: 0 5px;
453
- }
454
- .chat-bubble {
455
- max-width: 70%;
456
- padding: 10px 15px;
457
- border-radius: 15px;
458
- font-size: 14px;
459
- line-height: 1.5;
460
- word-wrap: break-word;
461
- }
462
- .chat-bubble.user {
463
- background-color: #DCF8C6;
464
- color: black;
465
- border-top-right-radius: 0;
466
- }
467
- .chat-bubble.assistant {
468
- background-color: #F1F0F0;
469
- color: black;
470
- border-top-left-radius: 0;
471
- }
472
- </style>
473
- """, unsafe_allow_html=True)
474
-
475
- # Mostrar historial de mensajes
476
- with messages:
477
- st.header("🤖 ChatBot Protech")
478
- for message in st.session_state.chat_history:
479
- role = message["role"]
480
- content = html.escape(message["content"]) # Escapar contenido HTML
481
- bubble_class = "user" if role == "user" else "assistant"
482
- icon = "👤" if role == "user" else "🤖"
483
-
484
- # Mostrar el mensaje en una sola burbuja con ícono en el mismo bloque
485
- st.markdown(f"""
486
- <div class="chat-message {bubble_class}">
487
- <div class="chat-icon">{icon}</div>
488
- <div class="chat-bubble {bubble_class}">{content}</div>
489
- </div>
490
- """, unsafe_allow_html=True)
491
-
492
- # --- Manejar transcripción como mensaje automático ---
493
- if st.session_state.transcripcion:
494
- prompt = st.session_state.transcripcion
495
- st.session_state.transcripcion = ""
496
-
497
- st.session_state.chat_history.append({"role": "user", "content": prompt})
498
-
499
- with messages:
500
- st.markdown(f"""
501
- <div class="chat-message user">
502
- <div class="chat-bubble user">{html.escape(prompt)}</div>
503
- <div class="chat-icon">👤</div>
504
- </div>
505
- """, unsafe_allow_html=True)
506
-
507
- with messages:
508
- with st.spinner("Pensando..."):
509
- completion = callDeepseek(client, prompt)
510
- response = ""
511
- response_placeholder = st.empty()
512
-
513
- for chunk in completion:
514
- content = chunk.choices[0].delta.content or ""
515
- response += content
516
- response_placeholder.markdown(f"""
517
- <div class="chat-message assistant">
518
- <div class="chat-icon">🤖</div>
519
- <div class="chat-bubble assistant">{response}</div>
520
- </div>
521
- """, unsafe_allow_html=True)
522
-
523
- st.session_state.chat_history.append({"role": "assistant", "content": response})
524
-
525
- # Captura del input tipo chat
526
- if prompt := st.chat_input("Escribe algo..."):
527
- st.session_state.chat_history.append({"role": "user", "content": prompt})
528
-
529
- # Mostrar mensaje del usuario escapado
530
- with messages:
531
-
532
- st.markdown(f"""
533
- <div class="chat-message user">
534
- <div class="chat-bubble user">{prompt}</div>
535
- <div class="chat-icon">👤</div>
536
- </div>
537
- """, unsafe_allow_html=True)
538
-
539
- # Mostrar respuesta del asistente
540
- with messages:
541
- with st.spinner("Pensando..."):
542
- completion = callDeepseek(client, prompt)
543
- response = ""
544
- response_placeholder = st.empty()
545
-
546
- for chunk in completion:
547
- content = chunk.choices[0].delta.content or ""
548
- response += content
549
-
550
- response_placeholder.markdown(f"""
551
- <div class="chat-message assistant">
552
- <div class="chat-icon">🤖</div>
553
- <div class="chat-bubble assistant">{response}</div>
554
- </div>
555
- """, unsafe_allow_html=True)
556
-
557
- st.session_state.chat_history.append({"role": "assistant", "content": response})
558
-
559
- # Grabación de audio (solo si está habilitada)
560
- if st.session_state.mostrar_grabador and st.session_state.audio_data is None:
561
- audio_data = st.audio_input("Graba tu voz aquí 🎤")
562
- if audio_data:
563
- st.session_state.audio_data = audio_data
564
- st.session_state.mostrar_grabador = False # Ocultar input después de grabar
565
- st.rerun() # Forzar recarga para ocultar input y evitar que reaparezca el audio cargado
566
-
567
- # Mostrar controles solo si hay audio cargado
568
- if st.session_state.audio_data:
569
- st.audio(st.session_state.audio_data, format="audio/wav")
570
- col1, col2 = st.columns(2)
571
-
572
- with col1:
573
- if st.button("✅ Aceptar grabación"):
574
- with st.spinner("Convirtiendo y transcribiendo..."):
575
- m4a_path = converter_bytes_m4a(st.session_state.audio_data)
576
-
577
- with open(m4a_path, "rb") as f:
578
- texto = callWhisper(client, m4a_path, f)
579
-
580
- os.remove(m4a_path)
581
-
582
- st.session_state.transcripcion = texto
583
- st.session_state.audio_data = None
584
- st.session_state.mostrar_grabador = True
585
- st.rerun()
586
-
587
- with col2:
588
- if st.button("❌ Descartar grabación"):
589
- st.session_state.audio_data = None
590
- st.session_state.transcripcion = ""
591
- st.session_state.mostrar_grabador = True
592
- st.rerun()
593
-
594
- # Mostrar transcripción como texto previo al input si existe
595
- '''
596
- if st.session_state.transcripcion:
597
- st.info(f"📝 Transcripción: {st.session_state.transcripcion}")
598
- # Prellenar el input simuladamente
599
- prompt = st.session_state.transcripcion
600
- st.session_state.transcripcion = "" # Limpiar
601
- st.rerun() # Simular que se envió el mensaje
602
- '''
603
-
604
- #def speechRecognition():
605
- #audio_value = st.audio_input("Record a voice message")
606
-
607
- def callDeepseek(client, prompt):
608
- completion = client.chat.completions.create(
609
- #model="meta-llama/llama-4-scout-17b-16e-instruct",
610
- model = "deepseek-r1-distill-llama-70b",
611
- messages=[{"role": "user", "content": prompt}],
612
- temperature=0.6,
613
- max_tokens=1024,
614
- top_p=1,
615
- stream=True,
616
- )
617
- return completion
618
-
619
- def callWhisper(client, filename_audio,file):
620
- transcription = client.audio.transcriptions.create(
621
- file=(filename_audio, file.read()),
622
- model="whisper-large-v3",
623
- response_format="verbose_json",
624
- )
625
- return transcription.text
626
-
627
- def converter_bytes_m4a(audio_bytes: BytesIO) -> str:
628
- """
629
- Convierte un audio en bytes (WAV, etc.) a un archivo M4A temporal.
630
- Retorna la ruta del archivo .m4a temporal.
631
- """
632
- # Asegurarse de que el cursor del stream esté al inicio
633
- audio_bytes.seek(0)
634
-
635
- # Leer el audio desde BytesIO usando pydub
636
- audio = AudioSegment.from_file(audio_bytes)
637
-
638
- # Crear archivo temporal para guardar como .m4a
639
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".m4a")
640
- m4a_path = temp_file.name
641
- temp_file.close() # Cerramos para que pydub pueda escribirlo
642
-
643
- # Exportar a M4A usando formato compatible con ffmpeg
644
- audio.export(m4a_path, format="ipod") # 'ipod' genera .m4a
645
-
646
- return m4a_path
647
- # ===========================
648
- # Función para cargar el modelo SARIMA
649
- # ===========================
650
- """def cargar_modelo_sarima(ruta_modelo):
651
- # Cargar el modelo utilizando joblib
652
- modelo = joblib.load(ruta_modelo)
653
- return modelo"""
654
-
655
- # ===========================
656
- # Función para obtener el número de periodos basado en el filtro
657
- # ===========================
658
- def obtener_periodos(filtro):
659
- opciones_periodos = {
660
- '5 años': 60,
661
- '3 años': 36,
662
- '1 año': 12,
663
- '5 meses': 5
664
- }
665
- return opciones_periodos.get(filtro, 12)
666
-
667
- # ===========================
668
- # Función para mostrar ventas actuales y proyectadas
669
- # ===========================
670
- """
671
- def mostrar_ventas_proyectadas(filtro):
672
- ruta_modelo = os.path.join("arima_sales_model.pkl")
673
- modelo_sarima = cargar_modelo_sarima(ruta_modelo)
674
-
675
- if "archivo_subido" in st.session_state and st.session_state.archivo_subido:
676
- # Cargar datos del archivo subido
677
- df = st.session_state.df_subido.copy()
678
- df['Date'] = pd.to_datetime(df['Date'])
679
- df = df.sort_values('Date')
680
-
681
- # Generar predicciones
682
- periodos = obtener_periodos(filtro)
683
- predicciones = generar_predicciones(modelo_sarima, df, periodos)
684
-
685
- # Redondear y formatear las ventas
686
- df['Sale'] = df['Sale'].round(2).apply(lambda x: f"{x:,.2f}") # Formato con 2 decimales y comas
687
- predicciones = [round(val, 2) for val in predicciones] # Redondear predicciones
688
-
689
- # Preparar datos para graficar
690
- df['Tipo'] = 'Ventas Actuales'
691
- df_pred = pd.DataFrame({
692
- 'Date': pd.date_range(df['Date'].max(), periods=periodos + 1, freq='ME')[1:],
693
- 'Sale': predicciones,
694
- 'Tipo': 'Ventas Pronosticadas'
695
- })
696
-
697
- df_grafico = pd.concat([df[['Date', 'Sale', 'Tipo']], df_pred])
698
- else:
699
- st.warning("Por favor, sube un archivo CSV válido para generasr predicciones.")
700
- return
701
-
702
- # Crear gráfica
703
- fig = px.line(
704
- df_grafico,
705
- x='Date',
706
- y='Sale',
707
- color='Tipo',
708
- title='Ventas pronosticadas (Ventas vs Mes)',
709
- labels={'Date': 'Fecha', 'Sale': 'Ventas', 'Tipo': 'Serie'}
710
- )
711
-
712
- # Centramos el título del gráfico
713
- fig.update_layout(
714
- title={
715
- 'text': "Ventas Actuales y Pronosticadas",
716
-
717
- 'x': 0.5, # Centrado horizontal
718
- 'xanchor': 'center', # Asegura el anclaje central
719
- 'yanchor': 'top' # Anclaje superior (opcional)
720
- },
721
- title_font=dict(size=18, family="Arial, sans-serif", color='black'),
722
- )
723
-
724
- fig.update_xaxes(tickangle=-45)
725
-
726
- # Mejorar el diseño de la leyenda
727
- fig.update_layout(
728
- legend=dict(
729
- title="Leyenda", # Título de la leyenda
730
- title_font=dict(size=12, color="black"),
731
- font=dict(size=10, color="black"),
732
- bgcolor="rgba(240,240,240,0.8)", # Fondo semitransparente
733
- bordercolor="gray",
734
- borderwidth=1,
735
- orientation="h", # Leyenda horizontal
736
- yanchor="top",
737
- y=-0.3, # Ajustar la posición vertical
738
- xanchor="right",
739
- x=0.5 # Centrar horizontalmente
740
- )
741
- )
742
-
743
- st.plotly_chart(fig, use_container_width=True)
744
- """
745
- # ===========================
746
- # Función para generar predicciones
747
- # ===========================
748
- def generar_predicciones(modelo, df, periodos):
749
- ventas = df['Sale']
750
- predicciones = modelo.forecast(steps=periodos)
751
- return predicciones
752
-
753
- # Función para mejorar el diseño de las gráficas
754
- def mejorar_diseno_grafica(fig, meses_relevantes, nombres_meses_relevantes):
755
- fig.update_layout(
756
- title={
757
- 'text': "Ventas vs Mes",
758
-
759
- 'x': 0.5, # Centrado horizontal
760
- 'xanchor': 'center', # Asegura el anclaje central
761
- 'yanchor': 'top' # Anclaje superior (opcional)
762
- },
763
- title_font=dict(size=18, family="Arial, sans-serif", color='black'),
764
- xaxis=dict(
765
- title='Mes-Año',
766
- title_font=dict(size=14, family="Arial, sans-serif", color='black'),
767
- tickangle=-45, # Rotar las etiquetas
768
- showgrid=True,
769
- gridwidth=0.5,
770
- gridcolor='lightgrey',
771
- showline=True,
772
- linecolor='black',
773
- linewidth=2,
774
- tickmode='array', # Controla qué etiquetas mostrar
775
- tickvals=meses_relevantes, # Selecciona solo los meses relevantes
776
- ticktext=nombres_meses_relevantes, # Meses seleccionados
777
- tickfont=dict(size=10), # Reducir el tamaño de la fuente de las etiquetas
778
- ),
779
- yaxis=dict(
780
- title='Ventas',
781
- title_font=dict(size=14, family="Arial, sans-serif", color='black'),
782
- showgrid=True,
783
- gridwidth=0.5,
784
- gridcolor='lightgrey',
785
- showline=True,
786
- linecolor='black',
787
- linewidth=2
788
- ),
789
- plot_bgcolor='white', # Fondo blanco
790
- paper_bgcolor='white', # Fondo del lienzo de la gráfica
791
- font=dict(family="Arial, sans-serif", size=12, color="black"),
792
- showlegend=False, # Desactivar la leyenda si no es necesaria
793
- margin=dict(l=50, r=50, t=50, b=50) # Márgenes ajustados
794
- )
795
-
796
-
797
-
798
- return fig
799
-
800
- # ===========================
801
- # Función para cerrar sesión
802
- # ===========================
803
- def cerrar_sesion():
804
- st.session_state.logged_in = False
805
- st.session_state.usuario = None
806
- st.session_state.pagina_actual = "login"
807
- st.session_state.archivo_subido = False # Limpiar el archivo subido al cerrar sesión
808
- st.session_state.df_subido = None # Limpiar datos del archivo
809
- # Eliminar parámetros de la URL usando st.query_params
810
- st.query_params.clear() # Método correcto para limpiar parámetros de consulta
811
-
812
- # Redirigir a la página de login
813
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paginas/dashboardDemo.py DELETED
@@ -1,947 +0,0 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import plotly.express as px
4
- import random
5
- import time
6
- import joblib
7
- import os
8
- import statsmodels
9
- from dotenv import load_dotenv
10
- import os
11
- from groq import Groq
12
- import html
13
- from pydub import AudioSegment
14
- import tempfile
15
- from io import BytesIO
16
- from fpdf import FPDF
17
- from PIL import Image
18
- from math import ceil
19
- from datetime import datetime
20
- from sklearn.metrics import r2_score
21
- #from langchain.agents.agent_toolkits import create_csv_agent
22
- #from langchain_groq import ChatGroq
23
- # ===========================
24
- # Función para generar datos ficticios
25
- # ===========================
26
- def generar_datos():
27
- meses = [
28
- "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio",
29
- "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
30
- ]
31
- paises = ["México", "Colombia", "Argentina", "Chile", "Perú"]
32
- data = [
33
- {"mes": mes, "pais": pais, "Total": random.randint(100, 1000)}
34
- for mes in meses for pais in paises
35
- ]
36
- return pd.DataFrame(data), meses, paises
37
-
38
-
39
- # ===========================
40
- # Función para el dashboard principal
41
- # ===========================
42
- def mostrar_dashboard():
43
- # Cargar variables desde el archivo .env
44
- load_dotenv()
45
-
46
- # Acceder a la clave
47
- groq_key = os.getenv("GROQ_API_KEY")
48
- client = Groq(api_key=groq_key)
49
-
50
- dfDatos, meses, paises = generar_datos()
51
-
52
- # Opciones del selectbox
53
- lista_opciones = ['5 años', '3 años', '1 año', '5 meses']
54
-
55
- # Mostrar barra lateral
56
- mostrar_sidebar(client)
57
-
58
- # Título principal
59
- st.header(':bar_chart: Dashboard Sales')
60
-
61
- # Mostrar gráficos
62
- mostrar_graficos(lista_opciones)
63
-
64
- # ===========================
65
- # Configuración inicial de la página
66
- # ===========================
67
- #def configurar_pagina():
68
- #st.set_page_config(
69
- # page_title="Dashboard Sales",
70
- # page_icon=":smile:",
71
- # layout="wide",
72
- # initial_sidebar_state="expanded"
73
- #)
74
-
75
-
76
-
77
- # ===========================
78
- # Función para la barra lateral
79
- # ===========================
80
- def mostrar_sidebar(client):
81
- """
82
- Windows
83
- sidebar_logo = "paginas/images/Logo general.png"
84
- main_body_logo = "paginas/images/Logo.png"
85
- sidebar_logo_dashboard = "paginas/images/Logo dashboard.png"
86
-
87
- """
88
- sidebar_logo = "paginas/images/Logo general.png"
89
- main_body_logo = "paginas/images/Logo.png"
90
- sidebar_logo_dashboard = "paginas/images/Logo dashboard.png"
91
-
92
-
93
- st.logo(sidebar_logo, size="large", icon_image=main_body_logo)
94
-
95
- st.sidebar.image(sidebar_logo_dashboard)
96
- st.sidebar.title('🧠 GenAI Forecast')
97
-
98
- uploaded_file = selectedFile()
99
- verifyFile(uploaded_file)
100
- archivo_csv = "df_articles.csv"
101
- chatBotProtech(client)
102
- downloadCSV(archivo_csv)
103
- closeSession()
104
-
105
-
106
-
107
- def closeSession():
108
- if st.sidebar.button("Cerrar Sesión"):
109
- cerrar_sesion()
110
-
111
-
112
- def guardar_graficas_como_imagen(figuras: dict):
113
- rutas_imagenes = []
114
- temp_dir = tempfile.gettempdir()
115
-
116
- for nombre, figura in figuras.items():
117
- ruta_png = os.path.join(temp_dir, f"{nombre}.png")
118
- ruta_jpeg = os.path.join(temp_dir, f"{nombre}.jpg")
119
-
120
- # Guardar como PNG primero
121
- figura.write_image(ruta_png, width=900, height=500, engine="kaleido")
122
-
123
- # Convertir a JPEG usando PIL
124
- with Image.open(ruta_png) as img:
125
- rgb_img = img.convert("RGB") # Asegura formato compatible con JPEG
126
- rgb_img.save(ruta_jpeg, "JPEG", quality=95)
127
-
128
- rutas_imagenes.append((nombre, ruta_jpeg))
129
-
130
- # Opcional: borrar el PNG temporal
131
- os.remove(ruta_png)
132
-
133
- return rutas_imagenes
134
-
135
- def generateHeaderPDF(pdf):
136
- # Logo
137
- logo_path = r"paginas\images\Logo general.png"
138
- if os.path.exists(logo_path):
139
- pdf.image(logo_path, x=7, y=6, w=35)
140
-
141
- # Título centrado
142
- pdf.set_font('Arial', 'B', 16)
143
- pdf.set_xy(5, 10)
144
- pdf.cell(w=0, h=10, txt="Reporte del Dashboard de Ventas", border=0, ln=0, align='C')
145
-
146
- # Fecha lado derecho
147
- fecha = datetime.now().strftime("%d/%m/%Y")
148
- pdf.set_xy(-40, 5)
149
- pdf.set_font('Arial', '', 10)
150
- pdf.cell(w=30, h=10, txt=fecha, border=0, ln=0, align='R')
151
-
152
- pdf.ln(15)
153
-
154
- def generateFooterPDF(pdf):
155
- pdf.set_y(-30)
156
- pdf.set_font('Arial', 'I', 8)
157
- pdf.set_text_color(100)
158
- pdf.cell(0, 5, "PRO TECHNOLOGY SOLUTIONS S.A.C - Área de ventas", 0, 1, 'C')
159
- pdf.cell(0, 5, "Reporte generado automáticamente por el sistema de análisis", 0, 1, 'C')
160
- pdf.cell(0, 5, f"Página {pdf.page_no()}", 0, 0, 'C')
161
-
162
- def generateContentPDF(pdf, imagenes):
163
- for i in range(0, len(imagenes), 2):
164
- pdf.add_page()
165
-
166
- generateHeaderPDF(pdf)
167
-
168
- # Primera imagen
169
- titulo1, ruta1 = imagenes[i]
170
- if os.path.exists(ruta1):
171
- img1 = Image.open(ruta1).convert("RGB")
172
- ruta_color1 = ruta1.replace(".png", "_color.png")
173
- img1.save(ruta_color1)
174
- pdf.image(ruta_color1, x=10, y=30, w=180)
175
-
176
- # Segunda imagen
177
- if i + 1 < len(imagenes):
178
- titulo2, ruta2 = imagenes[i + 1]
179
- if os.path.exists(ruta2):
180
- img2 = Image.open(ruta2).convert("RGB")
181
- ruta_color2 = ruta2.replace(".png", "_color.png")
182
- img2.save(ruta_color2)
183
- pdf.image(ruta_color2, x=10, y=150, w=180)
184
-
185
- generateFooterPDF(pdf)
186
-
187
- def generar_reporte_dashboard(imagenes):
188
- pdf = FPDF(orientation='P', unit='mm', format='A4')
189
- pdf.set_auto_page_break(auto=True, margin=15)
190
-
191
- generateContentPDF(pdf, imagenes)
192
-
193
- ruta_pdf = "reporte.pdf"
194
- pdf.output(ruta_pdf)
195
- return ruta_pdf
196
-
197
-
198
- # Función para obtener los meses relevantes
199
- def obtener_meses_relevantes(df):
200
- # Extraemos los años y meses de la columna 'Date'
201
- df['Year'] = pd.to_datetime(df['orddt']).dt.year
202
- df['Month'] = pd.to_datetime(df['orddt']).dt.month
203
-
204
- # Encontramos el primer y último año en el dataset
205
- primer_ano = df['Year'].min()
206
- ultimo_ano = df['Year'].max()
207
-
208
- meses_relevantes = []
209
- nombres_meses_relevantes = []
210
-
211
- # Recorrer todos los años dentro del rango
212
- for ano in range(primer_ano, ultimo_ano + 1):
213
- for mes in [1, 4, 7, 10]: # Meses relevantes: enero (1), abril (4), julio (7), octubre (10)
214
- if mes in df[df['Year'] == ano]['Month'].values:
215
- # Obtener el nombre del mes
216
- nombre_mes = pd.to_datetime(f"{ano}-{mes}-01").strftime('%B') # Mes en formato textual (Enero, Abril, etc.)
217
- meses_relevantes.append(f"{nombre_mes}-{ano}")
218
- nombres_meses_relevantes.append(f"{nombre_mes}-{ano}")
219
-
220
- return meses_relevantes, nombres_meses_relevantes
221
-
222
-
223
- # ===========================
224
- # Función para gráficos
225
- # ===========================
226
- def mostrar_graficos(lista_opciones):
227
- if "archivo_subido" not in st.session_state or not st.session_state.archivo_subido:
228
- st.warning("Por favor, sube un archivo CSV válido para visualizar los gráficos.")
229
- return
230
-
231
- df = st.session_state.df_subido.copy()
232
-
233
- # --- Tarjetas con métricas clave ---
234
- # Tasa de crecimiento por fecha si existe
235
- total_ventas = df["sales"].sum()
236
- promedio_ventas = df["sales"].mean()
237
-
238
- st.subheader("📈 Resumen General")
239
-
240
-
241
- # Tasa de crecimiento por fecha si existe
242
- df['orddt'] = pd.to_datetime(df['orddt'], errors='coerce')
243
-
244
- #Total de ventas
245
- total_ventas = df['sales'].sum()
246
- promedio_ventas = df['sales'].mean()
247
- total_registros = df.shape[0]
248
-
249
- # Tasa de crecimiento
250
- df_filtrado = df.dropna(subset=['orddt'])
251
- df_filtrado['mes_anio'] = df_filtrado['orddt'].dt.to_period('M')
252
- ventas_por_mes = df_filtrado.groupby('mes_anio')['sales'].sum().sort_index()
253
-
254
- tasa_crecimiento = None
255
- if len(ventas_por_mes) >= 2:
256
- primera_venta = ventas_por_mes.iloc[0]
257
- ultima_venta = ventas_por_mes.iloc[-1]
258
- if primera_venta != 0:
259
- tasa_crecimiento = ((ultima_venta - primera_venta) / primera_venta) * 100
260
-
261
- tarjetas = [
262
- {"titulo": "Total de Ventas", "valor": abreviar_monto(total_ventas), "color": "#4CAF50"},
263
- {"titulo": "Promedio de Ventas", "valor": f"${promedio_ventas:,.0f}", "color": "#2196F3"},
264
- {"titulo": "Ventas registradas", "valor": total_registros, "color": "#9C27B0"},
265
- {"titulo": "Tasa de crecimiento", "valor": f"{tasa_crecimiento:.2f}%" if tasa_crecimiento is not None else "N/A", "color": "#FF5722"},
266
- ]
267
-
268
- col1, col2, col3, col4 = st.columns(4)
269
- cols = [col1, col2, col3, col4]
270
-
271
- for i, tarjeta in enumerate(tarjetas):
272
- with cols[i]:
273
- st.markdown(f"""
274
- <div style='background-color:{tarjeta["color"]}; padding:20px; border-radius:10px; color:white; text-align:center;'>
275
- <h4 style='margin:0;'>{tarjeta["titulo"]}</h4>
276
- <h2 style='margin:0;'>{tarjeta["valor"]}</h2>
277
- </div>
278
- """, unsafe_allow_html=True)
279
-
280
- st.markdown("---")
281
-
282
- # Opciones de modelos (incluye una opción por defecto)
283
- opciones_modelos = ["(Sin predicción)"] + ["LightGBM", "XGBoost",
284
- "HistGradientBoosting",
285
- "MLPRegressor", "GradientBoosting",
286
- "RandomForest", "CatBoost"]
287
-
288
- col_select, col_plot = st.columns([1, 5])
289
-
290
- with col_select:
291
- modelo_seleccionado = st.selectbox("Selecciona un modelo", opciones_modelos)
292
-
293
- with col_plot.container(border=True):
294
- if modelo_seleccionado == "(Sin predicción)":
295
- if modelo_seleccionado == "(Sin predicción)":
296
- df_real = df.copy()
297
- df_real = df_real.dropna(subset=["orddt", "sales"])
298
-
299
- fig_real = px.scatter(
300
- df_real,
301
- x="orddt",
302
- y="sales",
303
- trendline="ols", # Línea de regresión
304
- color_discrete_sequence=["#1f77b4"],
305
- trendline_color_override="orange",
306
- labels={"sales": "Ventas", "orddt": "Fecha"},
307
- title="Ventas Reales (Dispersión + Tendencia)",
308
- width=600,
309
- height=400
310
- )
311
-
312
- fig_real.update_traces(marker=dict(size=6), selector=dict(mode='markers'))
313
- fig_real.update_layout(
314
- template="plotly_white",
315
- margin=dict(l=40, r=40, t=60, b=40),
316
- legend_title_text="Datos",
317
- showlegend=True
318
- )
319
-
320
- st.plotly_chart(fig_real, use_container_width=True)
321
-
322
- else:
323
- # Cargar modelo .pkl correspondiente
324
- modelo_path = f"regressionmodels/{modelo_seleccionado.lower()}.pkl"
325
- modelo = joblib.load(modelo_path)
326
-
327
- # Preparar datos
328
- df_pred = df.copy()
329
- df_pred = df_pred.dropna(subset=["orddt"])
330
- X_nuevo = df_pred.drop(columns=["sales"]) # Asegúrate que coincida con el modelo
331
- y_pred = modelo.predict(X_nuevo)
332
- df_pred["pred"] = y_pred
333
-
334
- # Calcular precisión del modelo
335
- r2 = r2_score(df_pred["sales"], df_pred["pred"])
336
-
337
- # Gráfico de dispersión con línea de regresión
338
- fig_pred = px.scatter(
339
- df_pred,
340
- x="sales",
341
- y="pred",
342
- trendline="ols",
343
- color_discrete_sequence=["#1f77b4"],
344
- trendline_color_override="orange",
345
- labels={"sales": "Ventas Reales", "pred": "Ventas Predichas"},
346
- title=f"Ventas Reales vs Predicción ({modelo_seleccionado})<br><sup>Precisión (R²): {r2:.3f}</sup>",
347
- width=600, height=400
348
- )
349
- fig_pred.update_traces(marker=dict(size=6), selector=dict(mode='markers'))
350
- fig_pred.update_layout(
351
- legend_title_text='Datos',
352
- template="plotly_white",
353
- showlegend=True
354
- )
355
- st.plotly_chart(fig_pred, use_container_width=True)
356
-
357
-
358
-
359
- # Fila 1: 3 gráficas
360
- col1, col2 = st.columns(2)
361
- with col1:
362
- with col1.container(border=True):
363
- fig1 = px.histogram(df, x='sales', title='Distribución de Ventas',
364
- color_discrete_sequence=['#1f77b4'])
365
-
366
- fig1.update_layout(
367
- template="plotly_white",
368
- margin=dict(l=40, r=40, t=60, b=40),
369
- width=600,
370
- height=400,
371
- legend_title_text="Leyenda"
372
- )
373
- fig1.update_traces(marker=dict(line=dict(width=0.5, color='white')))
374
-
375
- st.plotly_chart(fig1, use_container_width=True)
376
-
377
- with col2:
378
- with col2.container(border=True):
379
- fig2 = px.box(df, x='segmt', y='sales', title='Ventas por Segmento',
380
- color='segmt', color_discrete_sequence=px.colors.qualitative.Plotly)
381
- st.plotly_chart(fig2, use_container_width=True)
382
-
383
- # Fila 2: 2 gráficas
384
- col4, col5 = st.columns(2)
385
- with col4:
386
- with col4.container(border=True):
387
- fig4 = px.pie(df, names='categ', values='sales', title='Ventas por Categoría',
388
- color_discrete_sequence=px.colors.qualitative.Set3)
389
- st.plotly_chart(fig4, use_container_width=True)
390
-
391
- with col5:
392
- top_productos = (
393
- df.groupby('prdna')['sales']
394
- .sum()
395
- .sort_values(ascending=False)
396
- .head(10)
397
- .reset_index()
398
- )
399
- with col5.container(border=True):
400
- fig5 = px.bar(
401
- top_productos,
402
- x='sales',
403
- y='prdna',
404
- orientation='h',
405
- title='Top 10 productos más vendidos',
406
- labels={'sales': 'Ventas', 'prdna': 'Producto'},
407
- color='sales',
408
- color_continuous_scale='Blues'
409
- )
410
-
411
- fig5.update_layout(yaxis={'categoryorder': 'total ascending'})
412
- st.plotly_chart(fig5, use_container_width=True)
413
-
414
- col6, col7 = st.columns(2)
415
- with col6:
416
- with col6.container(border=True):
417
- tabla = df.pivot_table(index='state', columns='subct', values='sales', aggfunc='sum').fillna(0)
418
-
419
- if not tabla.empty:
420
- tabla = tabla.astype(float)
421
- fig6 = px.imshow(
422
- tabla.values,
423
- labels=dict(x="Categoría", y="Estado", color="Ventas"),
424
- x=tabla.columns,
425
- y=tabla.index,
426
- text_auto=True,
427
- title="Mapa de Calor: Ventas por distrito y categoría",
428
- color_continuous_scale="Viridis"
429
- )
430
- st.plotly_chart(fig6, use_container_width=True)
431
- else:
432
- st.warning("No hay datos suficientes para mostrar el mapa de calor.")
433
-
434
- with col7:
435
- ventas_estado = df.groupby('state')['sales'].sum().reset_index()
436
- with col7.container(border=True):
437
- fig7 = px.bar(ventas_estado, x='state', y='sales', title='Ventas por distrito',
438
- color='sales', color_continuous_scale='Teal')
439
- st.plotly_chart(fig7, use_container_width=True)
440
-
441
- if st.button("📄 Generar Reporte PDF del Dashboard"):
442
- figs = [fig1, fig2, fig4, fig5, fig6, fig7]
443
-
444
- figuras = {}
445
- for fig in figs:
446
- titulo = fig.layout.title.text or "Sin Título"
447
- figuras[titulo] = fig
448
-
449
- st.info("Generando imágenes de las gráficas...")
450
- imagenes = guardar_graficas_como_imagen(figuras)
451
- st.info("Generando PDF...")
452
- ruta_pdf = generar_reporte_dashboard(imagenes)
453
-
454
- with open(ruta_pdf, "rb") as f:
455
- st.download_button("⬇️ Descargar Reporte PDF", f, file_name="reporte_dashboard.pdf")
456
-
457
-
458
-
459
- def abreviar_monto(valor):
460
- if valor >= 1_000_000:
461
- return f"${valor / 1_000_000:.2f}M"
462
- elif valor >= 1_000:
463
- return f"${valor / 1_000:.2f}K"
464
- else:
465
- return f"${valor:.2f}"
466
-
467
- # -------------------------------
468
- # CARGA DE CSV Y GUARDADO EN SESIÓN
469
- # -------------------------------
470
-
471
- def loadCSV():
472
- columnas_requeridas = [
473
- 'rowid','ordid','orddt','shpdt',
474
- 'segmt','state','cono','prodid',
475
- 'categ','subct','prdna','sales',
476
- 'order_month','order_day','order_year',
477
- 'order_dayofweek','shipping_delay'
478
- ]
479
- with st.sidebar.expander("📁 Subir archivo"):
480
- uploaded_file = st.file_uploader("Sube un archivo CSV:", type=["csv"], key="upload_csv")
481
-
482
- if uploaded_file is not None:
483
- # Reseteamos el estado de 'descargado' cuando se sube un archivo
484
- st.session_state.descargado = False
485
- st.session_state.archivo_subido = False # Reinicia el estado
486
- try:
487
- # Leer el archivo subido
488
- df = pd.read_csv(uploaded_file)
489
-
490
- # Verificar que las columnas estén presentes y en el orden correcto
491
- if list(df.columns) == columnas_requeridas:
492
- st.session_state.df_subido = df
493
- st.session_state.archivo_subido = True
494
- aviso = st.sidebar.success("✅ Archivo subido correctamente.")
495
- time.sleep(3)
496
- aviso.empty()
497
-
498
-
499
- else:
500
- st.session_state.archivo_subido = False
501
- aviso = st.sidebar.error(f"El archivo no tiene las columnas requeridas: {columnas_requeridas}.")
502
- time.sleep(3)
503
- aviso.empty()
504
-
505
- except Exception as e:
506
- aviso = st.sidebar.error(f"Error al procesar el archivo: {str(e)}")
507
- time.sleep(3)
508
- aviso.empty()
509
-
510
- # -------------------------------
511
- # Mostrar uploader y manejar estado
512
- # -------------------------------
513
- def selectedFile():
514
- with st.sidebar.expander("📁 Subir archivo"):
515
- uploaded_file = st.file_uploader("Sube un archivo CSV:", type=["csv"], key="upload_csv")
516
-
517
- if uploaded_file is not None:
518
- st.session_state.descargado = False
519
- st.session_state.archivo_subido = False
520
- return uploaded_file
521
- return None
522
-
523
- # -------------------------------
524
- # Procesar y validar archivo (con cache)
525
- # -------------------------------
526
- @st.cache_data
527
- def loadCSV(uploaded_file):
528
- columnas_requeridas = [
529
- 'rowid','ordid','orddt','shpdt',
530
- 'segmt','state','cono','prodid',
531
- 'categ','subct','prdna','sales',
532
- 'order_month','order_day','order_year',
533
- 'order_dayofweek','shipping_delay'
534
- ]
535
-
536
- df = pd.read_csv(uploaded_file)
537
-
538
- if list(df.columns) == columnas_requeridas:
539
- return df, None
540
- else:
541
- return None, f"❌ El archivo no tiene las columnas requeridas: {columnas_requeridas}"
542
-
543
- # -------------------------------
544
- # Procesar y validar archivo (con cache)
545
- # -------------------------------
546
- def verifyFile(uploadedFile):
547
- if uploadedFile:
548
- try:
549
- df, error = loadCSV(uploadedFile)
550
- if error is None:
551
- st.session_state.df_subido = df
552
- st.session_state.archivo_subido = True
553
- aviso = st.sidebar.success("✅ Archivo subido correctamente.")
554
- else:
555
- aviso = st.sidebar.error(error)
556
- time.sleep(3)
557
- aviso.empty()
558
-
559
- except Exception as e:
560
- aviso = st.sidebar.error(f"⚠️ Error al procesar el archivo: {str(e)}")
561
- time.sleep(3)
562
- aviso.empty()
563
-
564
- # ===========================
565
- # Función para descargar archivo CSV
566
- # ===========================
567
- def downloadCSV(archivo_csv):
568
- # Verificamos si el archivo ya ha sido descargado
569
- if 'descargado' not in st.session_state:
570
- st.session_state.descargado = False
571
-
572
- if not st.session_state.descargado:
573
- descarga = st.sidebar.download_button(
574
- label="Descargar archivo CSV",
575
- data=open(archivo_csv, "rb"),
576
- file_name="ventas.csv",
577
- mime="text/csv"
578
- )
579
- if descarga:
580
- # Marcamos el archivo como descargado
581
- st.session_state.descargado = True
582
- aviso = st.sidebar.success("¡Descarga completada!")
583
- # Hacer que el mensaje desaparezca después de 2 segundos
584
- time.sleep(3)
585
- aviso.empty()
586
- else:
587
- aviso = st.sidebar.success("¡Ya has descargado el archivo!")
588
- time.sleep(3)
589
- aviso.empty()
590
-
591
- # -------------------------------
592
- # FUNCIÓN PARA DETECTAR REFERENCIA AL CSV
593
- # -------------------------------
594
- def detectedReferenceToCSV(prompt: str) -> bool:
595
- palabras_clave = ["csv", "archivo", "contenido cargado", "file", "dataset"]
596
- prompt_lower = prompt.lower()
597
- return any(palabra in prompt_lower for palabra in palabras_clave)
598
-
599
- # ===========================
600
- # Función para interactuar con el bot
601
- # ===========================
602
- def seleccionar_modelo_llm():
603
- modelos_disponibles = {
604
- "Alibaba Cloud - Qwen QWQ 32B": "qwen-qwq-32b",
605
- "Alibaba Cloud - Qwen3 32B": "qwen/qwen3-32b",
606
- "DeepSeek - LLaMA 70B Distill": "deepseek-r1-distill-llama-70b",
607
- "Google - Gemma2 9B IT": "gemma2-9b-it",
608
- "Meta - LLaMA 3.1 8B Instant": "llama-3.1-8b-instant",
609
- "Meta - LLaMA 3.3 70B Versatile": "llama-3.3-70b-versatile",
610
- "Meta - LLaMA 3 70B": "llama3-70b-8192",
611
- "Meta - LLaMA 3 8B": "llama3-8b-8192",
612
- "Meta - LLaMA 4 Maverick 17B": "meta-llama/llama-4-maverick-17b-128e-instruct",
613
- "Meta - LLaMA 4 Scout 17B": "meta-llama/llama-4-scout-17b-16e-instruct",
614
- "Meta - LLaMA Guard 4 12B": "meta-llama/llama-guard-4-12b",
615
- "Meta - Prompt Guard 2 22M": "meta-llama/llama-prompt-guard-2-22m",
616
- "Meta - Prompt Guard 2 86M": "meta-llama/llama-prompt-guard-2-86m",
617
- "Mistral - Saba 24B": "mistral-saba-24b"
618
- }
619
-
620
- seleccion = st.selectbox(
621
- "🧠 Elige un modelo LLM de Groq:",
622
- list(modelos_disponibles.keys())
623
- )
624
-
625
- return modelos_disponibles[seleccion]
626
-
627
-
628
- def chatBotProtech(client):
629
- with st.sidebar.expander("📁 Chatbot"):
630
-
631
- modelo_llm = seleccionar_modelo_llm()
632
-
633
- # Inicializar estados
634
- if "chat_history" not in st.session_state:
635
- st.session_state.chat_history = []
636
-
637
- if "audio_data" not in st.session_state:
638
- st.session_state.audio_data = None
639
-
640
- if "transcripcion" not in st.session_state:
641
- st.session_state.transcripcion = ""
642
-
643
- if "mostrar_grabador" not in st.session_state:
644
- st.session_state.mostrar_grabador = True
645
-
646
- # Contenedor para mensajes
647
- messages = st.container(height=400)
648
-
649
- # CSS: estilo tipo Messenger
650
- st.markdown("""
651
- <style>
652
- .chat-message {
653
- display: flex;
654
- align-items: flex-start;
655
- margin: 10px 0;
656
- }
657
- .chat-message.user {
658
- justify-content: flex-end;
659
- }
660
- .chat-message.assistant {
661
- justify-content: flex-start;
662
- }
663
- .chat-icon {
664
- width: 30px;
665
- height: 30px;
666
- border-radius: 50%;
667
- background-color: #ccc;
668
- display: flex;
669
- align-items: center;
670
- justify-content: center;
671
- font-size: 18px;
672
- margin: 0 5px;
673
- }
674
- .chat-bubble {
675
- max-width: 70%;
676
- padding: 10px 15px;
677
- border-radius: 15px;
678
- font-size: 14px;
679
- line-height: 1.5;
680
- word-wrap: break-word;
681
- }
682
- .chat-bubble.user {
683
- background-color: #DCF8C6;
684
- color: black;
685
- border-top-right-radius: 0;
686
- }
687
- .chat-bubble.assistant {
688
- background-color: #F1F0F0;
689
- color: black;
690
- border-top-left-radius: 0;
691
- }
692
- </style>
693
- """, unsafe_allow_html=True)
694
-
695
- # Mostrar historial de mensajes
696
- with messages:
697
- st.header("🤖 ChatBot Protech")
698
- for message in st.session_state.chat_history:
699
- role = message["role"]
700
- content = html.escape(message["content"]) # Escapar contenido HTML
701
- bubble_class = "user" if role == "user" else "assistant"
702
- icon = "👤" if role == "user" else "🤖"
703
-
704
- # Mostrar el mensaje en una sola burbuja con ícono en el mismo bloque
705
- st.markdown(f"""
706
- <div class="chat-message {bubble_class}">
707
- <div class="chat-icon">{icon}</div>
708
- <div class="chat-bubble {bubble_class}">{content}</div>
709
- </div>
710
- """, unsafe_allow_html=True)
711
-
712
- # --- Manejar transcripción como mensaje automático ---
713
- if st.session_state.transcripcion:
714
- prompt = st.session_state.transcripcion
715
- st.session_state.transcripcion = ""
716
-
717
- st.session_state.chat_history.append({"role": "user", "content": prompt})
718
-
719
- with messages:
720
- st.markdown(f"""
721
- <div class="chat-message user">
722
- <div class="chat-bubble user">{html.escape(prompt)}</div>
723
- <div class="chat-icon">👤</div>
724
- </div>
725
- """, unsafe_allow_html=True)
726
-
727
- with messages:
728
- with st.spinner("Pensando..."):
729
- completion = callModelLLM(client, prompt, modelo_llm)
730
- response = ""
731
- response_placeholder = st.empty()
732
-
733
- for chunk in completion:
734
- content = chunk.choices[0].delta.content or ""
735
- response += content
736
- response_placeholder.markdown(f"""
737
- <div class="chat-message assistant">
738
- <div class="chat-icon">🤖</div>
739
- <div class="chat-bubble assistant">{response}</div>
740
- </div>
741
- """, unsafe_allow_html=True)
742
-
743
- st.session_state.chat_history.append({"role": "assistant", "content": response})
744
-
745
- # Captura del input tipo chat
746
- if prompt := st.chat_input("Escribe algo..."):
747
- st.session_state.chat_history.append({"role": "user", "content": prompt})
748
-
749
- # Mostrar mensaje del usuario escapado
750
- with messages:
751
-
752
- st.markdown(f"""
753
- <div class="chat-message user">
754
- <div class="chat-bubble user">{prompt}</div>
755
- <div class="chat-icon">👤</div>
756
- </div>
757
- """, unsafe_allow_html=True)
758
-
759
- # Mostrar respuesta del asistente
760
- with messages:
761
- with st.spinner("Pensando..."):
762
- completion = callModelLLM(client, prompt, modelo_llm)
763
- response = ""
764
- response_placeholder = st.empty()
765
-
766
- for chunk in completion:
767
- content = chunk.choices[0].delta.content or ""
768
- response += content
769
-
770
- response_placeholder.markdown(f"""
771
- <div class="chat-message assistant">
772
- <div class="chat-icon">🤖</div>
773
- <div class="chat-bubble assistant">{response}</div>
774
- </div>
775
- """, unsafe_allow_html=True)
776
-
777
- st.session_state.chat_history.append({"role": "assistant", "content": response})
778
-
779
- # Grabación de audio (solo si está habilitada)
780
- if st.session_state.mostrar_grabador and st.session_state.audio_data is None:
781
- audio_data = st.audio_input("Graba tu voz aquí 🎤")
782
- if audio_data:
783
- st.session_state.audio_data = audio_data
784
- st.session_state.mostrar_grabador = False # Ocultar input después de grabar
785
- st.rerun() # Forzar recarga para ocultar input y evitar que reaparezca el audio cargado
786
-
787
- # Mostrar controles solo si hay audio cargado
788
- if st.session_state.audio_data:
789
- st.audio(st.session_state.audio_data, format="audio/wav")
790
- col1, col2 = st.columns(2)
791
-
792
- with col1:
793
- if st.button("✅ Aceptar grabación"):
794
- with st.spinner("Convirtiendo y transcribiendo..."):
795
- m4a_path = converter_bytes_m4a(st.session_state.audio_data)
796
-
797
- with open(m4a_path, "rb") as f:
798
- texto = callWhisper(client, m4a_path, f)
799
-
800
- os.remove(m4a_path)
801
-
802
- st.session_state.transcripcion = texto
803
- st.session_state.audio_data = None
804
- st.session_state.mostrar_grabador = True
805
- st.rerun()
806
-
807
- with col2:
808
- if st.button("❌ Descartar grabación"):
809
- st.session_state.audio_data = None
810
- st.session_state.transcripcion = ""
811
- st.session_state.mostrar_grabador = True
812
- st.rerun()
813
-
814
-
815
- def callModelLLM(client, prompt, idModel):
816
- completion = client.chat.completions.create(
817
- model=idModel,
818
- messages=[
819
- {
820
- "role": "system",
821
- "content": (
822
- "Tu nombre es Protech, el asistente virtual de PRO TECHNOLOGY SOLUTIONS S.A.C. "
823
- "Saluda al usuario con cordialidad y responde en español de forma clara, profesional y amable. "
824
- "Debes responder como un asistente humano capacitado en atención al cliente. "
825
- "Comienza con un saludo y pregunta: '¿En qué puedo ayudarte hoy?'."
826
- )
827
- },
828
- {"role": "user", "content": prompt}
829
- ],
830
- temperature=0.6,
831
- max_tokens=4096,
832
- top_p=1,
833
- stream=True,
834
- )
835
- return completion
836
-
837
- def callWhisper(client, filename_audio,file):
838
- transcription = client.audio.transcriptions.create(
839
- file=(filename_audio, file.read()),
840
- model="whisper-large-v3",
841
- response_format="verbose_json",
842
- )
843
- return transcription.text
844
-
845
- def converter_bytes_m4a(audio_bytes: BytesIO) -> str:
846
- """
847
- Convierte un audio en bytes (WAV, etc.) a un archivo M4A temporal.
848
- Retorna la ruta del archivo .m4a temporal.
849
- """
850
- # Asegurarse de que el cursor del stream esté al inicio
851
- audio_bytes.seek(0)
852
-
853
- # Leer el audio desde BytesIO usando pydub
854
- audio = AudioSegment.from_file(audio_bytes)
855
-
856
- # Crear archivo temporal para guardar como .m4a
857
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".m4a")
858
- m4a_path = temp_file.name
859
- temp_file.close() # Cerramos para que pydub pueda escribirlo
860
-
861
- # Exportar a M4A usando formato compatible con ffmpeg
862
- audio.export(m4a_path, format="ipod") # 'ipod' genera .m4a
863
-
864
- return m4a_path
865
-
866
- # ===========================
867
- # Función para obtener el número de periodos basado en el filtro
868
- # ===========================
869
- def obtener_periodos(filtro):
870
- opciones_periodos = {
871
- '5 años': 60,
872
- '3 años': 36,
873
- '1 año': 12,
874
- '5 meses': 5
875
- }
876
- return opciones_periodos.get(filtro, 12)
877
-
878
-
879
- # ===========================
880
- # Función para generar predicciones
881
- # ===========================
882
- def generar_predicciones(modelo, df, periodos):
883
- ventas = df['Sale']
884
- predicciones = modelo.forecast(steps=periodos)
885
- return predicciones
886
-
887
- # Función para mejorar el diseño de las gráficas
888
- def mejorar_diseno_grafica(fig, meses_relevantes, nombres_meses_relevantes):
889
- fig.update_layout(
890
- title={
891
- 'text': "Ventas vs Mes",
892
-
893
- 'x': 0.5, # Centrado horizontal
894
- 'xanchor': 'center', # Asegura el anclaje central
895
- 'yanchor': 'top' # Anclaje superior (opcional)
896
- },
897
- title_font=dict(size=18, family="Arial, sans-serif", color='black'),
898
- xaxis=dict(
899
- title='Mes-Año',
900
- title_font=dict(size=14, family="Arial, sans-serif", color='black'),
901
- tickangle=-45, # Rotar las etiquetas
902
- showgrid=True,
903
- gridwidth=0.5,
904
- gridcolor='lightgrey',
905
- showline=True,
906
- linecolor='black',
907
- linewidth=2,
908
- tickmode='array', # Controla qué etiquetas mostrar
909
- tickvals=meses_relevantes, # Selecciona solo los meses relevantes
910
- ticktext=nombres_meses_relevantes, # Meses seleccionados
911
- tickfont=dict(size=10), # Reducir el tamaño de la fuente de las etiquetas
912
- ),
913
- yaxis=dict(
914
- title='Ventas',
915
- title_font=dict(size=14, family="Arial, sans-serif", color='black'),
916
- showgrid=True,
917
- gridwidth=0.5,
918
- gridcolor='lightgrey',
919
- showline=True,
920
- linecolor='black',
921
- linewidth=2
922
- ),
923
- plot_bgcolor='white', # Fondo blanco
924
- paper_bgcolor='white', # Fondo del lienzo de la gráfica
925
- font=dict(family="Arial, sans-serif", size=12, color="black"),
926
- showlegend=False, # Desactivar la leyenda si no es necesaria
927
- margin=dict(l=50, r=50, t=50, b=50) # Márgenes ajustados
928
- )
929
-
930
-
931
-
932
- return fig
933
-
934
- # ===========================
935
- # Función para cerrar sesión
936
- # ===========================
937
- def cerrar_sesion():
938
- st.session_state.logged_in = False
939
- st.session_state.usuario = None
940
- st.session_state.pagina_actual = "login"
941
- st.session_state.archivo_subido = False # Limpiar el archivo subido al cerrar sesión
942
- st.session_state.df_subido = None # Limpiar datos del archivo
943
- # Eliminar parámetros de la URL usando st.query_params
944
- st.query_params.clear() # Método correcto para limpiar parámetros de consulta
945
-
946
- # Redirigir a la página de login
947
- st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paginas/demo.py DELETED
@@ -1,27 +0,0 @@
1
- from base64 import b64encode
2
- from fpdf import FPDF
3
- import streamlit as st
4
-
5
- st.title("Demo of fpdf2 usage with streamlit")
6
-
7
- @st.cache_data
8
- def gen_pdf():
9
- pdf = FPDF()
10
- pdf.add_page()
11
- pdf.set_font("Helvetica", size=24)
12
- pdf.cell(w=40,h=10,border=1,txt="hello world")
13
- return pdf.output(dest='S').encode('latin1')
14
-
15
-
16
- # Embed PDF to display it:
17
- base64_pdf = b64encode(gen_pdf()).decode("utf-8")
18
- pdf_display = f'<embed src="data:application/pdf;base64,{base64_pdf}" width="700" height="400" type="application/pdf">'
19
- st.markdown(pdf_display, unsafe_allow_html=True)
20
-
21
- # Add a download button:
22
- st.download_button(
23
- label="Download PDF",
24
- data=gen_pdf(),
25
- file_name="file_name.pdf",
26
- mime="application/pdf",
27
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paginas/demokaleido.py DELETED
@@ -1,5 +0,0 @@
1
- import plotly.express as px
2
-
3
- fig = px.line(x=[1, 2, 3], y=[4, 5, 6])
4
- fig.write_image("test_fig.png", width=900, height=500)
5
- print("✅ Imagen guardada correctamente")
 
 
 
 
 
 
paginas/images/Logo dashboard.png DELETED

Git LFS Details

  • SHA256: 02512c7d3aa1a268ef6fde26dba8c0791bb9718212877bafa4bf9e656b374b64
  • Pointer size: 131 Bytes
  • Size of remote file: 387 kB
paginas/images/Logo general.png DELETED
Binary file (1.93 kB)
 
paginas/images/Logo.png DELETED
Binary file (1.8 kB)
 
paginas/login.py DELETED
@@ -1,59 +0,0 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import json
4
- from streamlit_lottie import st_lottie
5
- import os
6
- import time
7
- from .userManagement import verifyCredentials
8
-
9
- def validateCredentials(usuario, contrasena):
10
- return verifyCredentials(usuario, contrasena)
11
-
12
- def load_lottiefile(filepath: str):
13
- with open(filepath, "r") as f:
14
- return json.load(f)
15
-
16
-
17
- def showLogin():
18
-
19
- c1, c2 = st.columns([60, 40])
20
-
21
- with c1:
22
- # Ajusta la ruta al archivo JSON de animación
23
- ruta_animacion_laptop = os.path.join("animations", "laptopUser.json")
24
- lottie_coding = load_lottiefile(ruta_animacion_laptop)
25
- st_lottie(
26
- lottie_coding,
27
- speed=1,
28
- reverse=False,
29
- loop=True,
30
- quality="low",
31
- height=None,
32
- width=None,
33
- key=None,
34
- )
35
-
36
- with c2:
37
- st.title("🔐 Inicio de :blue[Sesión] :sunglasses:")
38
-
39
- # Formulario de inicio de sesión
40
- with st.form("login_form"):
41
- usuario = st.text_input("Usuario 👇")
42
- contrasena = st.text_input("Contraseña 👇", type="password")
43
- boton_login = st.form_submit_button("Iniciar Sesión", type="primary",use_container_width=True)
44
-
45
- # Validación de credenciales
46
- if boton_login:
47
- if validateCredentials(usuario, contrasena):
48
- st.session_state.logged_in = True
49
- st.session_state.usuario = usuario
50
- aviso = st.success("Inicio de sesión exitoso. Redirigiendo al dashboard...")
51
- time.sleep(3)
52
- aviso.empty()
53
- # Simular redirección recargando el flujo principal
54
- st.session_state.pagina_actual = "dashboard"
55
- st.rerun()
56
- else:
57
- aviso = st.error("Usuario o contraseña incorrectos")
58
- time.sleep(3)
59
- aviso.empty()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
paginas/userManagement.py DELETED
@@ -1,32 +0,0 @@
1
- import MySQLdb
2
- from .conexionMysql import get_db_connection
3
-
4
- def verifyCredentials(username: str, password: str) -> bool:
5
- """
6
- Verifica si las credenciales del usuario son válidas.
7
- Retorna True si el usuario existe y la contraseña es correcta.
8
- """
9
- try:
10
- with get_db_connection() as conn:
11
- cursor = conn.cursor()
12
- query = "SELECT COUNT(*) FROM usuarios WHERE username = %s AND password = %s"
13
- cursor.execute(query, (username, password))
14
- resultado = cursor.fetchone()
15
- return resultado[0] > 0
16
- except MySQLdb.Error as e:
17
- print(f"Error en la verificación de credenciales: {e}")
18
- return False
19
-
20
- def getDataUser(correo: str) -> dict | None:
21
- """
22
- Devuelve un diccionario con los datos del usuario si existe, o None si no se encuentra.
23
- """
24
- try:
25
- with get_db_connection() as conn:
26
- cursor = conn.cursor(MySQLdb.cursors.DictCursor)
27
- query = "SELECT nombre, apellido, correo, telefono FROM usuarios WHERE correo = %s"
28
- cursor.execute(query, (correo,))
29
- return cursor.fetchone()
30
- except MySQLdb.Error as e:
31
- print(f"Error al obtener datos del usuario: {e}")
32
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
randomforest.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8ec6cfc13fafd2835935508ad2778f15ee5c6c54eee26caca9299e5710ec24b6
3
- size 26262394
 
 
 
 
regressionmodels/catboost.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:059f80be82f0f5ace74dc7ee09cd8a24502bb2e106623f43404a65c1df9abd0f
3
- size 1115713
 
 
 
 
regressionmodels/gradientboosting.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:5bb28622f5a612db81f8c5d12f56913710303da5778551e6931dd97393ebad1c
3
- size 145876
 
 
 
 
regressionmodels/histgradientboosting.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:13dca14204a9cbdd7bb407ae68697b9d4acc5b4969119b5abd2301f8c6e674cd
3
- size 375945
 
 
 
 
regressionmodels/lightgbm.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:ae50d6dfc075ff1b930fcb207169710ab452f384a006ed4a3c61e3d2baae35f5
3
- size 281459
 
 
 
 
regressionmodels/mlpregressor.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:287880615fc3e4cfedbba56d537bb7217ea86808ed896d81fd75b43f3b596387
3
- size 261329
 
 
 
 
regressionmodels/randomforest.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:8ec6cfc13fafd2835935508ad2778f15ee5c6c54eee26caca9299e5710ec24b6
3
- size 26262394
 
 
 
 
regressionmodels/xgboost.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:31639da06ebc5667ef2fffb043e3acb0ecea1294ffa6dd1dd0df3c6ee772d36c
3
- size 358669
 
 
 
 
requirements.txt DELETED
Binary file (5 kB)
 
xgboost.pkl DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:31639da06ebc5667ef2fffb043e3acb0ecea1294ffa6dd1dd0df3c6ee772d36c
3
- size 358669