paso desarrollo 2
Browse files- .gitignore +6 -5
- chat_functions/__init__.py +2 -2
- chat_functions/buscar_google.py +25 -23
- chat_functions/leer_pagina_web.py +13 -10
- chat_functions/obtener_clima.py +17 -14
- error_map.py +40 -25
- main.py +21 -23
- requirements.txt +1 -1
- static/css/app.css +252 -252
- static/js/chatHandler.js +48 -61
- static/js/inputboxHandler.js +1 -1
- static/main.html +1 -1
.gitignore
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
-
.history/
|
| 2 |
-
.vscode/
|
| 3 |
-
__pycache__/
|
| 4 |
-
keys/
|
| 5 |
-
.env
|
|
|
|
|
|
| 1 |
+
.history/
|
| 2 |
+
.vscode/
|
| 3 |
+
__pycache__/
|
| 4 |
+
keys/
|
| 5 |
+
.env
|
| 6 |
+
logs/eventos.log
|
chat_functions/__init__.py
CHANGED
|
@@ -19,5 +19,5 @@ for archivo in archivos:
|
|
| 19 |
# Lee la variable "info" del m贸dulo
|
| 20 |
|
| 21 |
functions.append(modulo.info)
|
| 22 |
-
function_callbacks[modulo.info["name"]] = modulo.ejecutar
|
| 23 |
-
function_user_text[modulo.info["name"]] = modulo.user_text
|
|
|
|
| 19 |
# Lee la variable "info" del m贸dulo
|
| 20 |
|
| 21 |
functions.append(modulo.info)
|
| 22 |
+
function_callbacks[modulo.info["function"]["name"]] = modulo.ejecutar
|
| 23 |
+
function_user_text[modulo.info["function"]["name"]] = modulo.user_text
|
chat_functions/buscar_google.py
CHANGED
|
@@ -16,30 +16,32 @@ if not api_key or not cse_id:
|
|
| 16 |
user_text = "Buscando en google"
|
| 17 |
|
| 18 |
info = {
|
| 19 |
-
"
|
| 20 |
-
"
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
{ \n\
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
"
|
| 35 |
-
"
|
| 36 |
-
"
|
| 37 |
-
|
| 38 |
-
"
|
|
|
|
|
|
|
|
|
|
| 39 |
},
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
}
|
| 43 |
}
|
| 44 |
|
| 45 |
def ejecutar(busqueda):
|
|
|
|
| 16 |
user_text = "Buscando en google"
|
| 17 |
|
| 18 |
info = {
|
| 19 |
+
"type": "function",
|
| 20 |
+
"function":{
|
| 21 |
+
"name": "buscar_google",
|
| 22 |
+
"description": "Un API de B煤squeda de Google. 脷til cuando necesitas responder preguntas sobre\
|
| 23 |
+
eventos actuales, personas o noticias. Utiliza esta herramienta especialmente cuando busques\
|
| 24 |
+
informaci贸n sobre eventos o personas. El resultado ser谩 un JSON { \n\
|
| 25 |
+
\"conseguidos\": [\n\
|
| 26 |
+
{ \n\
|
| 27 |
+
\"titulo\": este contendr谩 el titulo del enlace , \n\
|
| 28 |
+
\"link\": este contendr谩 el enlace a la pagina donde est谩 la informaci贸n, puedes usar este enlace en \
|
| 29 |
+
la herramienta leer_pagina_web si est谩 disponible para obtener m谩s informaci贸n, \n\
|
| 30 |
+
\"resumen\": este contendr谩 un resumen del contenido de la pagina \n\
|
| 31 |
+
},\n\
|
| 32 |
+
...\n\
|
| 33 |
+
] \n\
|
| 34 |
+
}",
|
| 35 |
+
"parameters": {
|
| 36 |
+
"type": "object",
|
| 37 |
+
"properties": {
|
| 38 |
+
"busqueda": {
|
| 39 |
+
"type": "string",
|
| 40 |
+
"description": "El termino a buscar en google para obtener informaci贸n. e.g. Alejandro Magno",
|
| 41 |
+
},
|
| 42 |
},
|
| 43 |
+
"required": ["busqueda"],
|
| 44 |
+
}}
|
|
|
|
| 45 |
}
|
| 46 |
|
| 47 |
def ejecutar(busqueda):
|
chat_functions/leer_pagina_web.py
CHANGED
|
@@ -7,17 +7,20 @@ activo = False
|
|
| 7 |
user_text = "Leyendo pagina web"
|
| 8 |
|
| 9 |
info = {
|
| 10 |
-
"
|
| 11 |
-
"
|
| 12 |
-
|
| 13 |
-
"
|
| 14 |
-
"
|
| 15 |
-
"
|
| 16 |
-
|
| 17 |
-
"
|
|
|
|
|
|
|
|
|
|
| 18 |
},
|
| 19 |
-
|
| 20 |
-
|
| 21 |
}
|
| 22 |
}
|
| 23 |
|
|
|
|
| 7 |
user_text = "Leyendo pagina web"
|
| 8 |
|
| 9 |
info = {
|
| 10 |
+
"type": "function",
|
| 11 |
+
"function":{
|
| 12 |
+
"name": "leer_pagina_web",
|
| 13 |
+
"description": "Un portal hacia Internet. 脷salo cuando necesites obtener contenido espec铆fico de un sitio web. La entrada debe ser una URL (por ejemplo, https://www.google.com). La salida ser谩 la respuesta en texto de la solicitud GET.",
|
| 14 |
+
"parameters": {
|
| 15 |
+
"type": "object",
|
| 16 |
+
"properties": {
|
| 17 |
+
"url": {
|
| 18 |
+
"type": "string",
|
| 19 |
+
"description": "el url a consultar",
|
| 20 |
+
},
|
| 21 |
},
|
| 22 |
+
"required": ["url"],
|
| 23 |
+
}
|
| 24 |
}
|
| 25 |
}
|
| 26 |
|
chat_functions/obtener_clima.py
CHANGED
|
@@ -13,21 +13,24 @@ if not api_key:
|
|
| 13 |
user_text = "Consultando el clima"
|
| 14 |
|
| 15 |
info = {
|
| 16 |
-
"
|
| 17 |
-
"
|
| 18 |
-
|
| 19 |
-
"
|
| 20 |
-
"
|
| 21 |
-
"
|
| 22 |
-
|
| 23 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
},
|
| 25 |
-
"
|
| 26 |
-
|
| 27 |
-
"enum": ["celsius"]
|
| 28 |
-
},
|
| 29 |
-
},
|
| 30 |
-
"required": ["ubicacion", "unidad"],
|
| 31 |
}
|
| 32 |
}
|
| 33 |
|
|
|
|
| 13 |
user_text = "Consultando el clima"
|
| 14 |
|
| 15 |
info = {
|
| 16 |
+
"type": "function",
|
| 17 |
+
"function": {
|
| 18 |
+
"name": "obtener_clima",
|
| 19 |
+
"description": "Obtiene el clima de una ubicaci贸n",
|
| 20 |
+
"parameters": {
|
| 21 |
+
"type": "object",
|
| 22 |
+
"properties": {
|
| 23 |
+
"ubicacion": {
|
| 24 |
+
"type": "string",
|
| 25 |
+
"description": "La ciudad, estado y pais, e.g. Caracas, Distrito Capital, Venezuela",
|
| 26 |
+
},
|
| 27 |
+
"unidad": {
|
| 28 |
+
"type": "string",
|
| 29 |
+
"enum": ["celsius"]
|
| 30 |
+
},
|
| 31 |
},
|
| 32 |
+
"required": ["ubicacion", "unidad"],
|
| 33 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
}
|
| 35 |
}
|
| 36 |
|
error_map.py
CHANGED
|
@@ -1,26 +1,41 @@
|
|
| 1 |
-
from openai import
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
"
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
|
|
|
| 1 |
+
from openai._exceptions import (
|
| 2 |
+
APIError,
|
| 3 |
+
OpenAIError,
|
| 4 |
+
ConflictError,
|
| 5 |
+
NotFoundError,
|
| 6 |
+
APIStatusError,
|
| 7 |
+
RateLimitError,
|
| 8 |
+
APITimeoutError,
|
| 9 |
+
BadRequestError,
|
| 10 |
+
APIConnectionError,
|
| 11 |
+
AuthenticationError,
|
| 12 |
+
InternalServerError,
|
| 13 |
+
PermissionDeniedError,
|
| 14 |
+
UnprocessableEntityError,
|
| 15 |
+
APIResponseValidationError,
|
| 16 |
+
)
|
| 17 |
+
from fastapi import status
|
| 18 |
+
from requests.exceptions import RequestException
|
| 19 |
+
error_table = {
|
| 20 |
+
RequestException: {
|
| 21 |
+
"status_code": status.HTTP_408_REQUEST_TIMEOUT,
|
| 22 |
+
"detail": "Los servidores tardaron mucho en responder, puede haber sobrecarga en OpenAI, reintenta luego (error 1)"
|
| 23 |
+
},
|
| 24 |
+
APIConnectionError: {
|
| 25 |
+
"status_code": status.HTTP_408_REQUEST_TIMEOUT,
|
| 26 |
+
"detail": "El servidor no respondi贸, hubo un error de API"
|
| 27 |
+
},
|
| 28 |
+
APITimeoutError: {
|
| 29 |
+
"status_code": status.HTTP_408_REQUEST_TIMEOUT,
|
| 30 |
+
"detail": "El servidor tard贸 demasiado en responder"
|
| 31 |
+
},
|
| 32 |
+
RateLimitError: {
|
| 33 |
+
"status_code": status.HTTP_408_REQUEST_TIMEOUT,
|
| 34 |
+
"detail": "ChatGPT se gomit贸 馃ぎ, este chat ya es muy largo, limpia el chat y reintenta."
|
| 35 |
+
},
|
| 36 |
+
"undefined": {
|
| 37 |
+
"status_code": status.HTTP_408_REQUEST_TIMEOUT,
|
| 38 |
+
"detail": "Error no definido 馃檮"
|
| 39 |
+
}
|
| 40 |
+
}
|
| 41 |
|
main.py
CHANGED
|
@@ -6,7 +6,7 @@ import os, json
|
|
| 6 |
from datetime import datetime, timedelta
|
| 7 |
import time
|
| 8 |
import jwt
|
| 9 |
-
|
| 10 |
from hashlib import sha256
|
| 11 |
from error_map import error_table
|
| 12 |
from logger import log_write, logger
|
|
@@ -88,26 +88,25 @@ async def validate_token(request: Request):
|
|
| 88 |
|
| 89 |
def ejecutar_llm(data):
|
| 90 |
messages = data["messages"]
|
| 91 |
-
try:
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
}
|
| 97 |
-
return openai.ChatCompletion.create(
|
| 98 |
-
model=model,
|
| 99 |
-
messages=messages,
|
| 100 |
-
temperature=config["temperature"],
|
| 101 |
-
frequency_penalty=config["frequency_penalty"],
|
| 102 |
-
presence_penalty=config["presence_penalty"],
|
| 103 |
-
request_timeout = 5,
|
| 104 |
-
functions=chat_functions.functions,
|
| 105 |
-
function_call="auto",
|
| 106 |
-
stream=True
|
| 107 |
)
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
def manejar_funciones(chunk, response_async, data):
|
| 113 |
f_cb = dict(chunk["choices"][0]["delta"]["function_call"])
|
|
@@ -136,8 +135,8 @@ async def root(request: Request, credentials: HTTPBasicCredentials = Depends(sec
|
|
| 136 |
|
| 137 |
|
| 138 |
|
| 139 |
-
@app.post("/
|
| 140 |
-
async def
|
| 141 |
messages = data.get("messages", "")
|
| 142 |
|
| 143 |
|
|
@@ -149,7 +148,6 @@ async def chat_async(data = Depends(validate_token)):
|
|
| 149 |
status_code=status.HTTP_418_IM_A_TEAPOT,
|
| 150 |
detail= error
|
| 151 |
)
|
| 152 |
-
log_write(data["token_data"]["user"], "Mensaje RQ", messages[-1]["content"])
|
| 153 |
response_async = ejecutar_llm(data)
|
| 154 |
|
| 155 |
async def __streamer(response_async, data):
|
|
|
|
| 6 |
from datetime import datetime, timedelta
|
| 7 |
import time
|
| 8 |
import jwt
|
| 9 |
+
from openai import OpenAI
|
| 10 |
from hashlib import sha256
|
| 11 |
from error_map import error_table
|
| 12 |
from logger import log_write, logger
|
|
|
|
| 88 |
|
| 89 |
def ejecutar_llm(data):
|
| 90 |
messages = data["messages"]
|
| 91 |
+
# try:
|
| 92 |
+
client = OpenAI(
|
| 93 |
+
api_key=os.environ['OPENAI_API_KEY'],
|
| 94 |
+
timeout=5.0,
|
| 95 |
+
max_retries=3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
)
|
| 97 |
+
|
| 98 |
+
return client.chat.completions.create(
|
| 99 |
+
model=model,
|
| 100 |
+
messages=messages,
|
| 101 |
+
tools=chat_functions.functions,
|
| 102 |
+
function_call="auto",
|
| 103 |
+
stream=False,
|
| 104 |
+
user=sha256(data["token_data"]["user"].encode('UTF-8')).hexdigest()
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
# except Exception as error:
|
| 108 |
+
# logger.error(repr(error) + " - " + str(data))
|
| 109 |
+
# raise HTTPException( **error_table.get(type(error), error_table["undefined"]))
|
| 110 |
|
| 111 |
def manejar_funciones(chunk, response_async, data):
|
| 112 |
f_cb = dict(chunk["choices"][0]["delta"]["function_call"])
|
|
|
|
| 135 |
|
| 136 |
|
| 137 |
|
| 138 |
+
@app.post("/chat")
|
| 139 |
+
async def chat(data = Depends(validate_token)):
|
| 140 |
messages = data.get("messages", "")
|
| 141 |
|
| 142 |
|
|
|
|
| 148 |
status_code=status.HTTP_418_IM_A_TEAPOT,
|
| 149 |
detail= error
|
| 150 |
)
|
|
|
|
| 151 |
response_async = ejecutar_llm(data)
|
| 152 |
|
| 153 |
async def __streamer(response_async, data):
|
requirements.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
fastapi==0.103.*
|
| 2 |
oauthlib==3.2.*
|
| 3 |
requests==2.31.*
|
| 4 |
-
openai==
|
| 5 |
uvicorn[standard]==0.23.*
|
| 6 |
PyJWT==2.8.*
|
| 7 |
hypercorn>=0.14.*
|
|
|
|
| 1 |
fastapi==0.103.*
|
| 2 |
oauthlib==3.2.*
|
| 3 |
requests==2.31.*
|
| 4 |
+
openai==1.2.*
|
| 5 |
uvicorn[standard]==0.23.*
|
| 6 |
PyJWT==2.8.*
|
| 7 |
hypercorn>=0.14.*
|
static/css/app.css
CHANGED
|
@@ -1,252 +1,252 @@
|
|
| 1 |
-
html,
|
| 2 |
-
body {
|
| 3 |
-
margin: 0;
|
| 4 |
-
padding: 0;
|
| 5 |
-
width: 100%;
|
| 6 |
-
height: 100svh;
|
| 7 |
-
font-family: Monospace;
|
| 8 |
-
font-size: 15px;
|
| 9 |
-
}
|
| 10 |
-
body {
|
| 11 |
-
display: flex;
|
| 12 |
-
}
|
| 13 |
-
button{
|
| 14 |
-
cursor: pointer;
|
| 15 |
-
}
|
| 16 |
-
.wrapper {
|
| 17 |
-
background: #34495e;
|
| 18 |
-
margin: 0;
|
| 19 |
-
min-width: 320px;
|
| 20 |
-
width: 100%;
|
| 21 |
-
display: grid;
|
| 22 |
-
grid-template-rows: 40px auto;
|
| 23 |
-
height: 100%;
|
| 24 |
-
padding: 0px 20px;
|
| 25 |
-
}
|
| 26 |
-
.chat {
|
| 27 |
-
--textarea: 0px;
|
| 28 |
-
border-radius: 5px;
|
| 29 |
-
display: block;
|
| 30 |
-
width: 100%;
|
| 31 |
-
overflow-y: scroll;
|
| 32 |
-
overflow-x: hidden;
|
| 33 |
-
background: rgb(161, 161, 161);
|
| 34 |
-
padding: 10px 0;
|
| 35 |
-
height: max( calc( 100svh - 120px - var(--textarea) ), calc(50svh - 90px) );
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
.chat .message {
|
| 39 |
-
display: flex;
|
| 40 |
-
margin: 5px 20px 5px 10px;
|
| 41 |
-
filter: opacity(0.9);
|
| 42 |
-
}
|
| 43 |
-
.chat .message.me {
|
| 44 |
-
margin: 5px 10px 5px 20px;
|
| 45 |
-
}
|
| 46 |
-
.chat .message.comando {
|
| 47 |
-
margin: 5px auto;
|
| 48 |
-
display: table;
|
| 49 |
-
}
|
| 50 |
-
.chat .message:last-child {
|
| 51 |
-
filter: opacity(1);
|
| 52 |
-
}
|
| 53 |
-
|
| 54 |
-
.chat .message.no-opacity {
|
| 55 |
-
display: flex;
|
| 56 |
-
margin: 10px 0 0 10px;
|
| 57 |
-
filter: opacity(1);
|
| 58 |
-
}
|
| 59 |
-
|
| 60 |
-
.chat .message img {
|
| 61 |
-
margin: 0 10px 0 0;
|
| 62 |
-
height: 30px;
|
| 63 |
-
border-radius: 50%;
|
| 64 |
-
}
|
| 65 |
-
|
| 66 |
-
.chat .message.me img {
|
| 67 |
-
order: 2;
|
| 68 |
-
margin: 0 0 0 3px;
|
| 69 |
-
}
|
| 70 |
-
|
| 71 |
-
.chat .message div {
|
| 72 |
-
flex: 1;
|
| 73 |
-
max-width: 100%;
|
| 74 |
-
}
|
| 75 |
-
|
| 76 |
-
.chat .message div p {
|
| 77 |
-
max-width: calc( 100% - 20px );
|
| 78 |
-
display: inline-block;
|
| 79 |
-
margin: 0;
|
| 80 |
-
padding: 8px 10px 8px 10px;
|
| 81 |
-
background: #fff;
|
| 82 |
-
border-radius: 3px;
|
| 83 |
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
| 84 |
-
min-width: 40%;
|
| 85 |
-
transition: 0.5s height;
|
| 86 |
-
}
|
| 87 |
-
|
| 88 |
-
.chat .message.me div p {
|
| 89 |
-
float: right;
|
| 90 |
-
background: #b4c2ff;
|
| 91 |
-
}
|
| 92 |
-
.chat .message.comando div p {
|
| 93 |
-
background: #d0a8ff;
|
| 94 |
-
}
|
| 95 |
-
.chat .message.warning div p {
|
| 96 |
-
background: #f0e370;
|
| 97 |
-
}
|
| 98 |
-
.chat .message.error div p {
|
| 99 |
-
background: #f09470;
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
.chat .message div p ul {
|
| 103 |
-
list-style: none;
|
| 104 |
-
color: #555;
|
| 105 |
-
padding-right: 10px;
|
| 106 |
-
}
|
| 107 |
-
|
| 108 |
-
.chat .message:last-child div p ul {
|
| 109 |
-
list-style: none;
|
| 110 |
-
color: blue;
|
| 111 |
-
}
|
| 112 |
-
|
| 113 |
-
.chat .message div p ul.ultotal {
|
| 114 |
-
list-style: none;
|
| 115 |
-
color: #34495e;
|
| 116 |
-
font-size: 12px;
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
.chat .message pre {
|
| 120 |
-
overflow-x: scroll;
|
| 121 |
-
border: solid 1px #e5e4e4;
|
| 122 |
-
padding: 10px;
|
| 123 |
-
}
|
| 124 |
-
|
| 125 |
-
.input-box {
|
| 126 |
-
background: #222f3d;
|
| 127 |
-
margin: 10px 0;
|
| 128 |
-
height: 30px;
|
| 129 |
-
display: flex;
|
| 130 |
-
border-radius: 5px;
|
| 131 |
-
max-height: 50svh;
|
| 132 |
-
}
|
| 133 |
-
|
| 134 |
-
.input-box textarea,
|
| 135 |
-
.input-box button {
|
| 136 |
-
height: 100%;
|
| 137 |
-
margin: 0;
|
| 138 |
-
border: none;
|
| 139 |
-
padding: 0 15px;
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
.input-box button:focus, .input-box textarea:focus {
|
| 143 |
-
outline: none;
|
| 144 |
-
}
|
| 145 |
-
|
| 146 |
-
.input-box .input-text {
|
| 147 |
-
width: 100%;
|
| 148 |
-
border-radius: 5px 0 0 5px;
|
| 149 |
-
resize: none;
|
| 150 |
-
border-top: solid 7px #fff;
|
| 151 |
-
border-bottom: solid 7px #fff;
|
| 152 |
-
|
| 153 |
-
}
|
| 154 |
-
.input-box button{
|
| 155 |
-
width: 30px;
|
| 156 |
-
background-size: 20px;
|
| 157 |
-
background-color: #ddd;
|
| 158 |
-
background-repeat: no-repeat;
|
| 159 |
-
background-position: center;
|
| 160 |
-
border-left: solid 1px #555;
|
| 161 |
-
}
|
| 162 |
-
.input-box .input-send {
|
| 163 |
-
background-image: url(/static/img/send.png);
|
| 164 |
-
}
|
| 165 |
-
.input-box .input-delete {
|
| 166 |
-
background-image: url(/static/img/delete.png);
|
| 167 |
-
}
|
| 168 |
-
.input-box .input-menu {
|
| 169 |
-
background-image: url(/static/img/menu.svg);
|
| 170 |
-
}
|
| 171 |
-
.input-box button:first-child{
|
| 172 |
-
border-left: none;
|
| 173 |
-
}
|
| 174 |
-
.input-box button:last-child{
|
| 175 |
-
border-radius: 0 5px 5px 0;
|
| 176 |
-
}
|
| 177 |
-
.input-box button:disabled, .input-box textarea:disabled{
|
| 178 |
-
background-color: #8b8b8b;
|
| 179 |
-
border-color: #8b8b8b;
|
| 180 |
-
|
| 181 |
-
}
|
| 182 |
-
|
| 183 |
-
#message-template{
|
| 184 |
-
display: none;
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
.loader-wrap {
|
| 188 |
-
display: flex;
|
| 189 |
-
}
|
| 190 |
-
.loader {
|
| 191 |
-
margin: auto;
|
| 192 |
-
width: 48px;
|
| 193 |
-
height: 48px;
|
| 194 |
-
border: 3px dotted #476380;
|
| 195 |
-
border-style: solid solid dotted dotted;
|
| 196 |
-
border-radius: 50%;
|
| 197 |
-
display: inline-block;
|
| 198 |
-
position: relative;
|
| 199 |
-
box-sizing: border-box;
|
| 200 |
-
animation: rotation 2s linear infinite;
|
| 201 |
-
}
|
| 202 |
-
.loader.firststage{
|
| 203 |
-
border: 3px dotted #49b359;
|
| 204 |
-
border-style: solid solid dotted dotted;
|
| 205 |
-
transition:all 1s;
|
| 206 |
-
}
|
| 207 |
-
.loader::after {
|
| 208 |
-
content: '';
|
| 209 |
-
box-sizing: border-box;
|
| 210 |
-
position: absolute;
|
| 211 |
-
left: 0;
|
| 212 |
-
right: 0;
|
| 213 |
-
top: 0;
|
| 214 |
-
bottom: 0;
|
| 215 |
-
margin: auto;
|
| 216 |
-
border: 3px dotted #445464;
|
| 217 |
-
border-style: solid solid dotted;
|
| 218 |
-
width: 24px;
|
| 219 |
-
height: 24px;
|
| 220 |
-
border-radius: 50%;
|
| 221 |
-
animation: rotationBack 1s linear infinite;
|
| 222 |
-
transform-origin: center center;
|
| 223 |
-
}
|
| 224 |
-
.loader.firststage::after {
|
| 225 |
-
border: 3px dotted #49b359;
|
| 226 |
-
border-style: solid solid dotted;
|
| 227 |
-
transition:all 1s;
|
| 228 |
-
}
|
| 229 |
-
|
| 230 |
-
@keyframes rotation {
|
| 231 |
-
0% {
|
| 232 |
-
transform: rotate(0deg);
|
| 233 |
-
}
|
| 234 |
-
100% {
|
| 235 |
-
transform: rotate(360deg);
|
| 236 |
-
}
|
| 237 |
-
}
|
| 238 |
-
@keyframes rotationBack {
|
| 239 |
-
0% {
|
| 240 |
-
transform: rotate(0deg);
|
| 241 |
-
}
|
| 242 |
-
100% {
|
| 243 |
-
transform: rotate(-360deg);
|
| 244 |
-
}
|
| 245 |
-
}
|
| 246 |
-
.loader-wrap ~ div {
|
| 247 |
-
text-align: center;
|
| 248 |
-
margin-top: 10px;
|
| 249 |
-
}
|
| 250 |
-
dialog{
|
| 251 |
-
margin: auto;
|
| 252 |
-
}
|
|
|
|
| 1 |
+
html,
|
| 2 |
+
body {
|
| 3 |
+
margin: 0;
|
| 4 |
+
padding: 0;
|
| 5 |
+
width: 100%;
|
| 6 |
+
height: 100svh;
|
| 7 |
+
font-family: Monospace;
|
| 8 |
+
font-size: 15px;
|
| 9 |
+
}
|
| 10 |
+
body {
|
| 11 |
+
display: flex;
|
| 12 |
+
}
|
| 13 |
+
button{
|
| 14 |
+
cursor: pointer;
|
| 15 |
+
}
|
| 16 |
+
.wrapper {
|
| 17 |
+
background: #34495e;
|
| 18 |
+
margin: 0;
|
| 19 |
+
min-width: 320px;
|
| 20 |
+
width: 100%;
|
| 21 |
+
display: grid;
|
| 22 |
+
grid-template-rows: 40px auto;
|
| 23 |
+
height: 100%;
|
| 24 |
+
padding: 0px 20px;
|
| 25 |
+
}
|
| 26 |
+
.chat {
|
| 27 |
+
--textarea: 0px;
|
| 28 |
+
border-radius: 5px;
|
| 29 |
+
display: block;
|
| 30 |
+
width: 100%;
|
| 31 |
+
overflow-y: scroll;
|
| 32 |
+
overflow-x: hidden;
|
| 33 |
+
background: rgb(161, 161, 161);
|
| 34 |
+
padding: 10px 0;
|
| 35 |
+
height: max( calc( 100svh - 120px - var(--textarea) ), calc(50svh - 90px) );
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.chat .message {
|
| 39 |
+
display: flex;
|
| 40 |
+
margin: 5px 20px 5px 10px;
|
| 41 |
+
filter: opacity(0.9);
|
| 42 |
+
}
|
| 43 |
+
.chat .message.me {
|
| 44 |
+
margin: 5px 10px 5px 20px;
|
| 45 |
+
}
|
| 46 |
+
.chat .message.comando {
|
| 47 |
+
margin: 5px auto;
|
| 48 |
+
display: table;
|
| 49 |
+
}
|
| 50 |
+
.chat .message:last-child {
|
| 51 |
+
filter: opacity(1);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.chat .message.no-opacity {
|
| 55 |
+
display: flex;
|
| 56 |
+
margin: 10px 0 0 10px;
|
| 57 |
+
filter: opacity(1);
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
.chat .message img {
|
| 61 |
+
margin: 0 10px 0 0;
|
| 62 |
+
height: 30px;
|
| 63 |
+
border-radius: 50%;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
.chat .message.me img {
|
| 67 |
+
order: 2;
|
| 68 |
+
margin: 0 0 0 3px;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.chat .message div {
|
| 72 |
+
flex: 1;
|
| 73 |
+
max-width: 100%;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.chat .message div p {
|
| 77 |
+
max-width: calc( 100% - 20px );
|
| 78 |
+
display: inline-block;
|
| 79 |
+
margin: 0;
|
| 80 |
+
padding: 8px 10px 8px 10px;
|
| 81 |
+
background: #fff;
|
| 82 |
+
border-radius: 3px;
|
| 83 |
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
| 84 |
+
min-width: 40%;
|
| 85 |
+
transition: 0.5s height;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.chat .message.me div p {
|
| 89 |
+
float: right;
|
| 90 |
+
background: #b4c2ff;
|
| 91 |
+
}
|
| 92 |
+
.chat .message.comando div p {
|
| 93 |
+
background: #d0a8ff;
|
| 94 |
+
}
|
| 95 |
+
.chat .message.warning div p {
|
| 96 |
+
background: #f0e370;
|
| 97 |
+
}
|
| 98 |
+
.chat .message.error div p {
|
| 99 |
+
background: #f09470;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.chat .message div p ul {
|
| 103 |
+
list-style: none;
|
| 104 |
+
color: #555;
|
| 105 |
+
padding-right: 10px;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
.chat .message:last-child div p ul {
|
| 109 |
+
list-style: none;
|
| 110 |
+
color: blue;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
.chat .message div p ul.ultotal {
|
| 114 |
+
list-style: none;
|
| 115 |
+
color: #34495e;
|
| 116 |
+
font-size: 12px;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.chat .message pre {
|
| 120 |
+
overflow-x: scroll;
|
| 121 |
+
border: solid 1px #e5e4e4;
|
| 122 |
+
padding: 10px;
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.input-box {
|
| 126 |
+
background: #222f3d;
|
| 127 |
+
margin: 10px 0;
|
| 128 |
+
height: 30px;
|
| 129 |
+
display: flex;
|
| 130 |
+
border-radius: 5px;
|
| 131 |
+
max-height: 50svh;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
.input-box textarea,
|
| 135 |
+
.input-box button {
|
| 136 |
+
height: 100%;
|
| 137 |
+
margin: 0;
|
| 138 |
+
border: none;
|
| 139 |
+
padding: 0 15px;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
.input-box button:focus, .input-box textarea:focus {
|
| 143 |
+
outline: none;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.input-box .input-text {
|
| 147 |
+
width: 100%;
|
| 148 |
+
border-radius: 5px 0 0 5px;
|
| 149 |
+
resize: none;
|
| 150 |
+
border-top: solid 7px #fff;
|
| 151 |
+
border-bottom: solid 7px #fff;
|
| 152 |
+
|
| 153 |
+
}
|
| 154 |
+
.input-box button{
|
| 155 |
+
width: 30px;
|
| 156 |
+
background-size: 20px;
|
| 157 |
+
background-color: #ddd;
|
| 158 |
+
background-repeat: no-repeat;
|
| 159 |
+
background-position: center;
|
| 160 |
+
border-left: solid 1px #555;
|
| 161 |
+
}
|
| 162 |
+
.input-box .input-send {
|
| 163 |
+
background-image: url(/static/img/send.png);
|
| 164 |
+
}
|
| 165 |
+
.input-box .input-delete {
|
| 166 |
+
background-image: url(/static/img/delete.png);
|
| 167 |
+
}
|
| 168 |
+
.input-box .input-menu {
|
| 169 |
+
background-image: url(/static/img/menu.svg);
|
| 170 |
+
}
|
| 171 |
+
.input-box button:first-child{
|
| 172 |
+
border-left: none;
|
| 173 |
+
}
|
| 174 |
+
.input-box button:last-child{
|
| 175 |
+
border-radius: 0 5px 5px 0;
|
| 176 |
+
}
|
| 177 |
+
.input-box button:disabled, .input-box textarea:disabled{
|
| 178 |
+
background-color: #8b8b8b;
|
| 179 |
+
border-color: #8b8b8b;
|
| 180 |
+
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
#message-template{
|
| 184 |
+
display: none;
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
.loader-wrap {
|
| 188 |
+
display: flex;
|
| 189 |
+
}
|
| 190 |
+
.loader {
|
| 191 |
+
margin: auto;
|
| 192 |
+
width: 48px;
|
| 193 |
+
height: 48px;
|
| 194 |
+
border: 3px dotted #476380;
|
| 195 |
+
border-style: solid solid dotted dotted;
|
| 196 |
+
border-radius: 50%;
|
| 197 |
+
display: inline-block;
|
| 198 |
+
position: relative;
|
| 199 |
+
box-sizing: border-box;
|
| 200 |
+
animation: rotation 2s linear infinite;
|
| 201 |
+
}
|
| 202 |
+
.loader.firststage{
|
| 203 |
+
border: 3px dotted #49b359;
|
| 204 |
+
border-style: solid solid dotted dotted;
|
| 205 |
+
transition:all 1s;
|
| 206 |
+
}
|
| 207 |
+
.loader::after {
|
| 208 |
+
content: '';
|
| 209 |
+
box-sizing: border-box;
|
| 210 |
+
position: absolute;
|
| 211 |
+
left: 0;
|
| 212 |
+
right: 0;
|
| 213 |
+
top: 0;
|
| 214 |
+
bottom: 0;
|
| 215 |
+
margin: auto;
|
| 216 |
+
border: 3px dotted #445464;
|
| 217 |
+
border-style: solid solid dotted;
|
| 218 |
+
width: 24px;
|
| 219 |
+
height: 24px;
|
| 220 |
+
border-radius: 50%;
|
| 221 |
+
animation: rotationBack 1s linear infinite;
|
| 222 |
+
transform-origin: center center;
|
| 223 |
+
}
|
| 224 |
+
.loader.firststage::after {
|
| 225 |
+
border: 3px dotted #49b359;
|
| 226 |
+
border-style: solid solid dotted;
|
| 227 |
+
transition:all 1s;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
@keyframes rotation {
|
| 231 |
+
0% {
|
| 232 |
+
transform: rotate(0deg);
|
| 233 |
+
}
|
| 234 |
+
100% {
|
| 235 |
+
transform: rotate(360deg);
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
@keyframes rotationBack {
|
| 239 |
+
0% {
|
| 240 |
+
transform: rotate(0deg);
|
| 241 |
+
}
|
| 242 |
+
100% {
|
| 243 |
+
transform: rotate(-360deg);
|
| 244 |
+
}
|
| 245 |
+
}
|
| 246 |
+
.loader-wrap ~ div {
|
| 247 |
+
text-align: center;
|
| 248 |
+
margin-top: 10px;
|
| 249 |
+
}
|
| 250 |
+
dialog{
|
| 251 |
+
margin: auto;
|
| 252 |
+
}
|
static/js/chatHandler.js
CHANGED
|
@@ -1,77 +1,48 @@
|
|
| 1 |
class ChatGPT{
|
| 2 |
-
definicion =
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
constructor(token){
|
| 11 |
-
|
| 12 |
-
// Parametros de ejecuci贸n del chatbot
|
| 13 |
-
let fecha = new Date().toJSON().slice(0, 10);
|
| 14 |
-
this.definicion = this.definicion.replace("{date}", fecha)
|
| 15 |
-
this.definicion = {role: "system", content: this.definicion, tokens: 100};
|
| 16 |
-
|
| 17 |
-
// Carga el historial de chats almacenados en el navegador
|
| 18 |
-
this.cargarHistorial()
|
| 19 |
-
|
| 20 |
-
// Enpoint
|
| 21 |
-
this.endpointChat = "/chat_async";
|
| 22 |
-
|
| 23 |
// Token JWT de ejecuci贸n
|
| 24 |
-
this.token = token
|
| 25 |
-
|
| 26 |
-
// Reintentos
|
| 27 |
-
this.reintentos = 0
|
| 28 |
-
|
| 29 |
-
$(document).on("chat:enviar", (event, params) => {
|
| 30 |
-
// Al enviar un mensaje, reintentos vuelve a 0
|
| 31 |
-
this.reintentos = 0;
|
| 32 |
-
this.enviar(params.mensaje, params.ctx);
|
| 33 |
-
});
|
| 34 |
|
| 35 |
-
|
| 36 |
-
$(document).on("enviar:error", (event, params) => this.reenviar(params));
|
| 37 |
|
| 38 |
-
|
| 39 |
-
$(document).on("chat:crear", () => this.crearChat())
|
| 40 |
-
|
| 41 |
-
// Eliminar Chat
|
| 42 |
-
$(document).on("chat:eliminar", (event, params) => this.eliminarChat(params.ctx, params.index))
|
| 43 |
|
| 44 |
-
|
| 45 |
-
}
|
| 46 |
-
|
| 47 |
-
cargarHistorial(){
|
| 48 |
-
// Carga el historial almacenado
|
| 49 |
-
|
| 50 |
-
// Si existe conversaciones almacenadas
|
| 51 |
-
if (
|
| 52 |
-
localStorage.getItem("conversaciones") !== null &&
|
| 53 |
-
JSON.parse(localStorage.getItem("conversaciones")).length!=0
|
| 54 |
-
) {
|
| 55 |
-
// Se carga en el espacio local
|
| 56 |
-
this.conversaciones = JSON.parse(localStorage.getItem("conversaciones"));
|
| 57 |
-
}else{
|
| 58 |
-
// Se crea una conversa con la definici贸n
|
| 59 |
-
this.conversaciones = [[this.definicion]];
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
// Array de windowHandlers
|
| 63 |
-
this.wHand = []
|
| 64 |
-
|
| 65 |
// Se crea un windowHandler por conversa
|
| 66 |
for(let conversacion of this.conversaciones){
|
| 67 |
this.wHand.push(new WindowHandler(conversacion, this.wHand.length));
|
| 68 |
}
|
| 69 |
|
| 70 |
-
//
|
| 71 |
$(document).trigger("chat:creado");
|
| 72 |
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
}
|
| 76 |
|
| 77 |
crearChat(){
|
|
@@ -92,6 +63,22 @@ class ChatGPT{
|
|
| 92 |
|
| 93 |
}
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
eliminarChat(ctx, index){
|
| 96 |
// Elimina un chat
|
| 97 |
|
|
|
|
| 1 |
class ChatGPT{
|
| 2 |
+
definicion = {
|
| 3 |
+
role: "system",
|
| 4 |
+
content: "Te llamas Chatsito, eres un asistente de apoyo a los amigos de " +
|
| 5 |
+
"MIA, tu objetivo principal es responder preguntas de manera puntual y " +
|
| 6 |
+
"objetiva a tu interlocutor.\n" +
|
| 7 |
+
"Si requieres ejecutar m谩s funciones, ejecuta tantas veces como lo " +
|
| 8 |
+
"necesites\n" +
|
| 9 |
+
"Responde de manera amistosa con en el texto m谩s corto y objetivo posible.\n" +
|
| 10 |
+
"Knowledge cutoff: " +
|
| 11 |
+
"2021-09-01\nCurrent date: {date}".definicion.replace("{date}", fecha)
|
| 12 |
+
};
|
| 13 |
+
|
| 14 |
+
// Enpoint
|
| 15 |
+
endpointChat = "/chat";
|
| 16 |
+
token = null;
|
| 17 |
+
conversaciones = [[definicion]];
|
| 18 |
+
|
| 19 |
constructor(token){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
// Token JWT de ejecuci贸n
|
| 21 |
+
this.token = token;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
this.cargarEventos();
|
|
|
|
| 24 |
|
| 25 |
+
try{this.conversaciones = JSON.parse(localStorage.getItem("conversaciones"))}catch{}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
// Se crea un windowHandler por conversa
|
| 28 |
for(let conversacion of this.conversaciones){
|
| 29 |
this.wHand.push(new WindowHandler(conversacion, this.wHand.length));
|
| 30 |
}
|
| 31 |
|
| 32 |
+
// Anucia chats creados
|
| 33 |
$(document).trigger("chat:creado");
|
| 34 |
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
cargarEventos(){
|
| 38 |
+
$(document).on("chat:crear", () => this.crearChat())
|
| 39 |
+
$(document).on("chat:enviar", (event, params) => {
|
| 40 |
+
// Al enviar un mensaje, reintentos vuelve a 0
|
| 41 |
+
this.reintentos = 0;
|
| 42 |
+
this.enviar(params.mensaje, params.ctx);
|
| 43 |
+
});
|
| 44 |
+
$(document).on("enviar:error", (event, params) => this.reenviar(params));
|
| 45 |
+
$(document).on("chat:eliminar", (event, params) => this.eliminarChat(params.ctx, params.index))
|
| 46 |
}
|
| 47 |
|
| 48 |
crearChat(){
|
|
|
|
| 63 |
|
| 64 |
}
|
| 65 |
|
| 66 |
+
cargarHistorial(){
|
| 67 |
+
// Carga el historial almacenado
|
| 68 |
+
|
| 69 |
+
// Si existe conversaciones almacenadas
|
| 70 |
+
|
| 71 |
+
// Array de windowHandlers
|
| 72 |
+
this.wHand = []
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
|
| 82 |
eliminarChat(ctx, index){
|
| 83 |
// Elimina un chat
|
| 84 |
|
static/js/inputboxHandler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
class
|
| 2 |
isOpen = false;
|
| 3 |
textarea = null;
|
| 4 |
sendButton = null;
|
|
|
|
| 1 |
+
class InputBox{
|
| 2 |
isOpen = false;
|
| 3 |
textarea = null;
|
| 4 |
sendButton = null;
|
static/main.html
CHANGED
|
@@ -77,7 +77,7 @@
|
|
| 77 |
var cHand;
|
| 78 |
$(document).ready(function() {
|
| 79 |
cHand = new ChatGPT("{% token %}");
|
| 80 |
-
|
| 81 |
});
|
| 82 |
let versionLocal = localStorage.getItem("version")
|
| 83 |
let versionRemota = "{% version %}"
|
|
|
|
| 77 |
var cHand;
|
| 78 |
$(document).ready(function() {
|
| 79 |
cHand = new ChatGPT("{% token %}");
|
| 80 |
+
new InputBox();
|
| 81 |
});
|
| 82 |
let versionLocal = localStorage.getItem("version")
|
| 83 |
let versionRemota = "{% version %}"
|