MGLDZM commited on
Commit
48c5bc4
·
1 Parent(s): c800f4d

Mejoras generales y pruebas

Browse files
.gitattributes CHANGED
@@ -1,34 +1,34 @@
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
- *.tflite filter=lfs diff=lfs merge=lfs -text
29
- *.tgz filter=lfs diff=lfs merge=lfs -text
30
- *.wasm filter=lfs diff=lfs merge=lfs -text
31
- *.xz filter=lfs diff=lfs merge=lfs -text
32
- *.zip filter=lfs diff=lfs merge=lfs -text
33
- *.zst filter=lfs diff=lfs merge=lfs -text
34
- *tfevents* 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
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
@@ -1,4 +1,5 @@
1
- .history/
2
- .vscode/
3
- __pycache__/
4
- keys/
 
 
1
+ .history/
2
+ .vscode/
3
+ __pycache__/
4
+ keys/
5
+ .env
Dockerfile CHANGED
@@ -1,21 +1,21 @@
1
- FROM python:3.9
2
-
3
- WORKDIR /code
4
- COPY ./requirements.txt /code/requirements.txt
5
-
6
-
7
- RUN useradd -m -u 1000 user
8
-
9
- USER user
10
-
11
- ENV HOME=/home/user \
12
- PATH=/home/user/.local/bin:$PATH
13
-
14
- WORKDIR $HOME/app
15
-
16
-
17
- COPY --chown=user . $HOME/app
18
- RUN pip install --user --no-cache-dir --upgrade -r /code/requirements.txt
19
- #CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
20
- CMD ["hypercorn", "main:app", "--workers", "6", "--bind", "0.0.0.0:7860"]
21
-
 
1
+ FROM python:3.11
2
+
3
+ WORKDIR /code
4
+ COPY ./requirements.txt /code/requirements.txt
5
+
6
+
7
+ RUN useradd -m -u 1000 user
8
+
9
+ USER user
10
+
11
+ ENV HOME=/home/user \
12
+ PATH=/home/user/.local/bin:$PATH
13
+
14
+ WORKDIR $HOME/app
15
+
16
+
17
+ COPY --chown=user . $HOME/app
18
+ RUN pip install --user --no-cache-dir --upgrade -r /code/requirements.txt
19
+ #CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
20
+ CMD ["hypercorn", "main:app", "--workers", "6", "--bind", "0.0.0.0:7860"]
21
+
chat_functions/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ functions = []
2
+ function_callbacks = {}
3
+ function_user_text = {}
4
+ import importlib
5
+ import glob
6
+
7
+
8
+ # Obtiene la lista de archivos .py en la carpeta actual
9
+ archivos = glob.glob("*.py", root_dir=__path__[0])
10
+
11
+ # Recorre cada archivo y lee la variable "info" dentro de ellos
12
+ for archivo in archivos:
13
+ if "__" in archivo[:-3]:
14
+ continue
15
+ # Importa el módulo del archivo
16
+ modulo = importlib.import_module('.'+archivo[:-3], "chat_functions")
17
+ if not modulo.activo:
18
+ continue
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
chat_functions/buscar_google.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ from googleapiclient.discovery import build
4
+ from logger import logger
5
+
6
+ activo = True
7
+ try:
8
+ api_key = os.getenv("GOOGLE_API_KEY")
9
+ cse_id = os.getenv("GOOGLE_CSE_ID")
10
+ except:
11
+ api_key = False
12
+ cse_id = False
13
+ if not api_key or not cse_id:
14
+ activo = False
15
+
16
+ user_text = "Buscando en google"
17
+
18
+ info = {
19
+ "name": "buscar_google",
20
+ "description": "Un API de Búsqueda de Google. Útil cuando necesitas responder preguntas sobre\
21
+ eventos actuales, personas o noticias. Utiliza esta herramienta especialmente cuando busques\
22
+ información sobre eventos o personas. El resultado será un JSON { \n\
23
+ \"conseguidos\": [\n\
24
+ { \n\
25
+ \"titulo\": este contendrá el titulo del enlace , \n\
26
+ \"link\": este contendrá el enlace a la pagina donde está la información, puedes usar este enlace en \
27
+ la herramienta leer_pagina_web si está disponible para obtener más información, \n\
28
+ \"resumen\": este contendrá un resumen del contenido de la pagina \n\
29
+ },\n\
30
+ ...\n\
31
+ ] \n\
32
+ }",
33
+ "parameters": {
34
+ "type": "object",
35
+ "properties": {
36
+ "busqueda": {
37
+ "type": "string",
38
+ "description": "El termino a buscar en google para obtener información. e.g. Alejandro Magno",
39
+ },
40
+ },
41
+ "required": ["busqueda"],
42
+ }
43
+ }
44
+
45
+ def ejecutar(busqueda):
46
+ try:
47
+ service = build("customsearch", "v1", developerKey=api_key)
48
+ results = service.cse().list(q=busqueda, cx=cse_id).execute()
49
+ retorno = {}
50
+ retorno["conseguidos"] = []
51
+ for result in results["items"]:
52
+ retorno["conseguidos"].append({
53
+ "titulo": result["title"],
54
+ "link": result["link"],
55
+ "resumen": result["snippet"]
56
+ })
57
+ return json.dumps(retorno)
58
+ except Exception as e:
59
+ logger.error(repr(e))
60
+ return json.dumps({"status": "api failed"})
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+ def google_search(search_term, api_key, cse_id, **kwargs):
74
+
75
+
76
+ return res
chat_functions/leer_pagina_web.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import requests
4
+ from logger import logger
5
+ activo = False
6
+
7
+ user_text = "Leyendo pagina web"
8
+
9
+ info = {
10
+ "name": "leer_pagina_web",
11
+ "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.",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {
15
+ "url": {
16
+ "type": "string",
17
+ "description": "el url a consultar",
18
+ },
19
+ },
20
+ "required": ["url"],
21
+ }
22
+ }
23
+
24
+ def ejecutar(url):
25
+ try:
26
+ req = requests.get(url=url, timeout=5)
27
+ retorno = {
28
+ "data": req.text
29
+ }
30
+ return json.dumps(retorno)
31
+ except Exception as e:
32
+ logger.error(repr(e))
33
+ return json.dumps({"status": "api failed"})
34
+
35
+
36
+ # def ejecutar(ubicacion, unidad="celsius"):
37
+ # url = f"https://api.weatherapi.com/v1/current.json?key={api_key}&q={ubicacion}&aqi=no"
38
+ # elementos = ["temp_c", "is_day", "condition", "wind_kph", "wind_dir", "precip_mm", "humidity", "cloud", "feelslike_c", "vis_km"]
39
+ # try:
40
+ # rq = requests.get(url, timeout=3)
41
+ # if rq.status_code!=200:
42
+ # return json.dumps({"status": "api failed"})
43
+ # clima = json.loads(rq.text)
44
+ # clima = {k: v for k, v in clima["current"].items() if k in elementos}
45
+ # return json.dumps(clima)
46
+ # except Exception as e:
47
+ # logger.error(repr(e))
48
+ # return json.dumps({"status": "api failed"})
chat_functions/obtener_clima.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+ import requests
4
+ from logger import logger
5
+ activo = True
6
+ try:
7
+ api_key = os.getenv("WEATHERAPI_KEY")
8
+ except:
9
+ api_key = False
10
+ if not api_key:
11
+ activo = False
12
+
13
+ user_text = "Consultando el clima"
14
+
15
+ info = {
16
+ "name": "obtener_clima",
17
+ "description": "Obtiene el clima de una ubicación",
18
+ "parameters": {
19
+ "type": "object",
20
+ "properties": {
21
+ "ubicacion": {
22
+ "type": "string",
23
+ "description": "La ciudad, estado y pais, e.g. Caracas, Distrito Capital, Venezuela",
24
+ },
25
+ "unidad": {
26
+ "type": "string",
27
+ "enum": ["celsius"]
28
+ },
29
+ },
30
+ "required": ["ubicacion", "unidad"],
31
+ }
32
+ }
33
+
34
+ def ejecutar(ubicacion, unidad="celsius"):
35
+ url = f"https://api.weatherapi.com/v1/current.json?key={api_key}&q={ubicacion}&aqi=no"
36
+ elementos = ["temp_c", "is_day", "condition", "wind_kph", "wind_dir", "precip_mm", "humidity", "cloud", "feelslike_c", "vis_km"]
37
+ try:
38
+ rq = requests.get(url, timeout=3)
39
+ if rq.status_code!=200:
40
+ return json.dumps({"status": "api failed"})
41
+ clima = json.loads(rq.text)
42
+ clima = {k: v for k, v in clima["current"].items() if k in elementos}
43
+ return json.dumps(clima)
44
+ except Exception as e:
45
+ logger.error(repr(e))
46
+ return json.dumps({"status": "api failed"})
error_map.py CHANGED
@@ -1,26 +1,26 @@
1
- from openai import error as openai_error
2
- from fastapi import status
3
- import requests
4
- error_table = {
5
- requests.exceptions.RequestException: {
6
- "status_code": status.HTTP_408_REQUEST_TIMEOUT,
7
- "detail": "Los servidores tardaron mucho en responder, puede haber sobrecarga en OpenAI, reintenta luego (error 1)"
8
- },
9
- openai_error.APIConnectionError: {
10
- "status_code": status.HTTP_408_REQUEST_TIMEOUT,
11
- "detail": "El servidor no respondió, hubo un error de API"
12
- },
13
- openai_error.Timeout: {
14
- "status_code": status.HTTP_408_REQUEST_TIMEOUT,
15
- "detail": "El servidor tardó demasiado en responder"
16
- },
17
- openai_error.InvalidRequestError: {
18
- "status_code": status.HTTP_408_REQUEST_TIMEOUT,
19
- "detail": "ChatGPT se gomitó 🤮, este chat ya es muy largo, limpia el chat y reintenta."
20
- },
21
- "undefined": {
22
- "status_code": status.HTTP_408_REQUEST_TIMEOUT,
23
- "detail": "Error no definido 🙄"
24
- }
25
- }
26
 
 
1
+ from openai import error as openai_error
2
+ from fastapi import status
3
+ import requests
4
+ error_table = {
5
+ requests.exceptions.RequestException: {
6
+ "status_code": status.HTTP_408_REQUEST_TIMEOUT,
7
+ "detail": "Los servidores tardaron mucho en responder, puede haber sobrecarga en OpenAI, reintenta luego (error 1)"
8
+ },
9
+ openai_error.APIConnectionError: {
10
+ "status_code": status.HTTP_408_REQUEST_TIMEOUT,
11
+ "detail": "El servidor no respondió, hubo un error de API"
12
+ },
13
+ openai_error.Timeout: {
14
+ "status_code": status.HTTP_408_REQUEST_TIMEOUT,
15
+ "detail": "El servidor tardó demasiado en responder"
16
+ },
17
+ openai_error.InvalidRequestError: {
18
+ "status_code": status.HTTP_408_REQUEST_TIMEOUT,
19
+ "detail": "ChatGPT se gomitó 🤮, este chat ya es muy largo, limpia el chat y reintenta."
20
+ },
21
+ "undefined": {
22
+ "status_code": status.HTTP_408_REQUEST_TIMEOUT,
23
+ "detail": "Error no definido 🙄"
24
+ }
25
+ }
26
 
logger.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+
3
+ _logger = logging.getLogger(__name__)
4
+ _logger.setLevel(logging.DEBUG)
5
+ # Configura el archivo donde se guardarán los eventos
6
+ file_handler = logging.FileHandler('logs/eventos.log')
7
+ file_handler.setLevel(logging.DEBUG)
8
+
9
+ stream_handler = logging.StreamHandler()
10
+ stream_handler.setLevel(logging.DEBUG)
11
+
12
+ # Define el formato de los mensajes de log
13
+ formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(user)s - %(action)s - %(message)s')
14
+
15
+ file_handler.setFormatter(formatter)
16
+ stream_handler.setFormatter(formatter)
17
+
18
+ # Agrega el handler al logger
19
+ _logger.addHandler(file_handler)
20
+ _logger.addHandler(stream_handler)
21
+
22
+
23
+ logger = logging.LoggerAdapter(_logger, extra={'user': "system", 'action': ""})
24
+
25
+ def log_write(user, action, data):
26
+ logger_l = logging.LoggerAdapter(_logger, extra={'user': user, 'action': action})
27
+ logger_l.info(data)
main.py CHANGED
@@ -9,31 +9,32 @@ import jwt
9
  import openai
10
  from hashlib import sha256
11
  from error_map import error_table
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- #from token_counter import count_tokens
14
 
15
  app = FastAPI()
16
  security = HTTPBasic()
17
  model = "gpt-3.5-turbo-16k"
18
  app.mount("/static", staticfiles.StaticFiles(directory="static"), name="static")
19
  users = json.loads(str(os.getenv("USER_KEYS")).replace("\n", ""))
 
 
20
  for key in users:
21
  if key == "master": continue
22
  password = key+users[key]+users["master"]
23
  users[key] = sha256(password.encode('UTF-8')).hexdigest()
24
 
25
- def write_line(line):
26
- with open("log.txt", "a") as f:
27
- f.write(line)
28
- f.write("\n")
29
-
30
- def write_multi_line(list_text):
31
- for line in list_text:
32
- write_line(line)
33
- write_line("---------------------------")
34
-
35
-
36
- write_multi_line(["inicio"])
37
 
38
  fecha_unix = str(int(time.time()))
39
 
@@ -41,6 +42,29 @@ JWT_SECRET = users["master"]
41
  JWT_ALGORITHM = "HS256"
42
  JWT_EXPIRATION_TIME_MINUTES = 30
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  def create_jwt_token(data):
45
  to_encode = {"data": data}
46
  expire = datetime.utcnow() + timedelta(minutes=JWT_EXPIRATION_TIME_MINUTES)
@@ -56,131 +80,114 @@ async def validate_token(request: Request):
56
  payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
57
  data["token_data"] = payload["data"]
58
  except Exception as e:
59
- raise HTTPException(status_code=404, detail="Datos no válidos")
 
60
  return data
61
 
62
- def authenticate_user(credentials: HTTPBasicCredentials):
63
 
64
- password = credentials.username+credentials.password+users["master"]
65
- password = sha256(password.encode('UTF-8')).hexdigest()
66
 
67
- if credentials.username not in users or password != users[credentials.username]:
68
- raise HTTPException(
69
- status_code=status.HTTP_401_UNAUTHORIZED,
70
- detail="Incorrect username or password",
71
- headers={"WWW-Authenticate": "Basic"},
72
- )
73
-
74
- return True
75
-
76
-
77
- @app.get("/", response_class=HTMLResponse)
78
- async def root(request: Request, credentials: HTTPBasicCredentials = Depends(security)):
79
- if authenticate_user(credentials):
80
- token = create_jwt_token({"user":credentials.username})
81
- with open(os.path.join("static", "main.html")) as f:
82
- return HTMLResponse(f.read().replace("{% token %}", token).replace("{% version %}", fecha_unix))
83
-
84
- @app.post("/chat_sync")
85
- async def chat_sync(data = Depends(validate_token)):
86
- messages = data.get("messages", "")
87
- if not messages:
88
- print("Empty message")
89
- error = "What ??"
90
- raise HTTPException(
91
- status_code=status.HTTP_418_IM_A_TEAPOT,
92
- detail= error
93
- )
94
- config = {
95
- "temperature": float(data.get("config", []).get("temperature", 1)),
96
- "frequency_penalty": float(data.get("config", []).get("frequency_penalty", 1)),
97
- "presence_penalty": float(data.get("config", []).get("presence_penalty", 1))
98
- }
99
  try:
100
- t_s = time.time()
101
- response_sync = openai.ChatCompletion.create(
 
 
 
 
102
  model=model,
103
  messages=messages,
104
  temperature=config["temperature"],
105
  frequency_penalty=config["frequency_penalty"],
106
  presence_penalty=config["presence_penalty"],
107
  request_timeout = 5,
108
- stream=False
 
 
109
  )
110
- print("time:", time.time() - t_s)
111
  except Exception as error:
 
112
  raise HTTPException( **error_table.get(type(error), error_table["undefined"]))
 
 
 
 
 
 
 
 
113
 
114
- response = {"role":"", "content":""}
115
-
116
- response["role"] = response_sync["choices"][0]["delta"]["role"]
117
- response["content"] = response_sync["choices"][0]["delta"]["content"]
118
- token = create_jwt_token(data.pop("token_data"))
119
- response["token"] = token
120
- return JSONResponse(response)
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  @app.post("/chat_async")
123
  async def chat_async(data = Depends(validate_token)):
124
  messages = data.get("messages", "")
125
- print("recibido:", messages)
 
126
  if not messages:
127
  print("Empty message")
128
  error = "What ??"
 
129
  raise HTTPException(
130
  status_code=status.HTTP_418_IM_A_TEAPOT,
131
  detail= error
132
  )
133
- config = {
134
- "temperature": float(data.get("config", []).get("temperature", 1)),
135
- "frequency_penalty": float(data.get("config", []).get("frequency_penalty", 1)),
136
- "presence_penalty": float(data.get("config", []).get("presence_penalty", 1))
137
- }
138
- try:
139
- st = time.time()
140
- response_async = openai.ChatCompletion.create(
141
- model=model,
142
- messages=messages,
143
- temperature=config["temperature"],
144
- frequency_penalty=config["frequency_penalty"],
145
- presence_penalty=config["presence_penalty"],
146
- request_timeout = 5,
147
- stream=True
148
- )
149
- print("time:", time.time() - st)
150
- except Exception as error:
151
- raise HTTPException( **error_table.get(type(error), error_table["undefined"]))
152
- async def __streamer():
153
- yield json.dumps({"comando": "token", "token":create_jwt_token(data.pop("token_data"))})
154
- yield json.dumps({"comando": "status", "status":{"mensaje":"Cargando", "modo": "reemplazar"}})
155
 
 
156
  chunk = next(response_async)
157
- mensaje = {"role": chunk["choices"][0]["delta"]["role"], "content":""}
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- st = time.time()
160
- st_times = 0
161
  for chunk in response_async:
162
  if chunk["choices"][0]["finish_reason"]:
163
  break
164
-
165
- mensaje["content"] += chunk["choices"][0]["delta"]["content"]
166
-
167
- if time.time() - st > 3:
168
- if st_times > 2:
169
- yield json.dumps({"comando": "status", "status":{"mensaje":"Cargando", "modo": "reemplazar"}})
170
- st_times = 0
171
- else:
172
- yield json.dumps({"comando": "status", "status":{"mensaje":".", "modo": "enlinea"}})
173
- st_times += 1
174
- st = time.time()
175
 
176
-
177
  yield json.dumps({"comando": "mensaje", "mensaje": mensaje})
178
- return StreamingResponse(__streamer(), media_type="application/json")
 
179
 
180
 
181
  @app.get("/read_log", response_class=HTMLResponse)
182
  async def read_log(request: Request, credentials: HTTPBasicCredentials = Depends(security)):
183
- if authenticate_user(credentials):
184
- with open("log.txt", "r") as f:
 
185
  return HTMLResponse(f.read())
186
-
 
 
9
  import openai
10
  from hashlib import sha256
11
  from error_map import error_table
12
+ from logger import log_write, logger
13
+ from oauthlib.oauth2 import WebApplicationClient
14
+ GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CSE_ID", None)
15
+ GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_API_KEY", None)
16
+ GOOGLE_DISCOVERY_URL = (
17
+ "https://accounts.google.com/.well-known/openid-configuration"
18
+ )
19
+
20
+
21
+ import chat_functions
22
+
23
+
24
 
 
25
 
26
  app = FastAPI()
27
  security = HTTPBasic()
28
  model = "gpt-3.5-turbo-16k"
29
  app.mount("/static", staticfiles.StaticFiles(directory="static"), name="static")
30
  users = json.loads(str(os.getenv("USER_KEYS")).replace("\n", ""))
31
+
32
+
33
  for key in users:
34
  if key == "master": continue
35
  password = key+users[key]+users["master"]
36
  users[key] = sha256(password.encode('UTF-8')).hexdigest()
37
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  fecha_unix = str(int(time.time()))
40
 
 
42
  JWT_ALGORITHM = "HS256"
43
  JWT_EXPIRATION_TIME_MINUTES = 30
44
 
45
+
46
+ log_write("master", "iniciado", "-")
47
+
48
+ ### Login stuff
49
+
50
+ def authenticate_user(credentials: HTTPBasicCredentials) -> bool:
51
+ username = credentials.username
52
+ password = credentials.password
53
+ password = username+password+users["master"]
54
+ password = sha256(password.encode('UTF-8')).hexdigest()
55
+
56
+ if credentials.username not in users or password != users[credentials.username]:
57
+ log_write(credentials.username, "Autenticacion usuario fallida", "")
58
+ raise HTTPException(
59
+ status_code=status.HTTP_401_UNAUTHORIZED,
60
+ detail="Incorrect username or password",
61
+ headers={"WWW-Authenticate": "Basic"},
62
+ )
63
+
64
+ log_write(credentials.username, "Usuario autenticado", "")
65
+ return True
66
+
67
+
68
  def create_jwt_token(data):
69
  to_encode = {"data": data}
70
  expire = datetime.utcnow() + timedelta(minutes=JWT_EXPIRATION_TIME_MINUTES)
 
80
  payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
81
  data["token_data"] = payload["data"]
82
  except Exception as e:
83
+ logger.error(repr(e) + " - " + str(data))
84
+ raise HTTPException(status_code=404, detail="Token inválido")
85
  return data
86
 
 
87
 
 
 
88
 
89
+ def ejecutar_llm(data):
90
+ messages = data["messages"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  try:
92
+ config = {
93
+ "temperature": float(data.get("config", []).get("temperature", 1)),
94
+ "frequency_penalty": float(data.get("config", []).get("frequency_penalty", 1)),
95
+ "presence_penalty": float(data.get("config", []).get("presence_penalty", 1))
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
  except Exception as error:
109
+ logger.error(repr(error) + " - " + str(data))
110
  raise HTTPException( **error_table.get(type(error), error_table["undefined"]))
111
+
112
+ def manejar_funciones(chunk, response_async, data):
113
+ f_cb = dict(chunk["choices"][0]["delta"]["function_call"])
114
+ for chunk in response_async:
115
+ if chunk["choices"][0]["finish_reason"]:
116
+ break
117
+ for k, v in chunk["choices"][0]["delta"]["function_call"].items():
118
+ f_cb[k] += v
119
 
120
+ f_cb["arguments"] = json.loads(f_cb["arguments"])
121
+ log_write(data["token_data"]["user"], "Funcion ejecutada RQ", json.dumps(f_cb))
122
+ resultado_funcion = chat_functions.function_callbacks[f_cb["name"]](**f_cb["arguments"])
123
+ log_write(data["token_data"]["user"], "Funcion ejecutada RS", json.dumps(resultado_funcion))
124
+ data["messages"].append({"role": "function",
125
+ "name": f_cb["name"],
126
+ "content": resultado_funcion,
127
+ })
128
+ return json.dumps(f_cb), ejecutar_llm(data)
129
+
130
+ @app.get("/", response_class=HTMLResponse)
131
+ async def root(request: Request, credentials: HTTPBasicCredentials = Depends(security)):
132
+ if authenticate_user(credentials):
133
+ token = create_jwt_token({"user":credentials.username})
134
+ with open(os.path.join("static", "main.html")) as f:
135
+ return HTMLResponse(f.read().replace("{% token %}", token).replace("{% version %}", fecha_unix))
136
+
137
+
138
 
139
  @app.post("/chat_async")
140
  async def chat_async(data = Depends(validate_token)):
141
  messages = data.get("messages", "")
142
+
143
+
144
  if not messages:
145
  print("Empty message")
146
  error = "What ??"
147
+ log_write(data["token_data"]["user"], "Mensaje RQ", "error, mensajes vacios")
148
  raise HTTPException(
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):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
+ # Verificar function_calls
158
  chunk = next(response_async)
159
+
160
+ yield json.dumps({"comando": "status", "status":{"mensaje":"Cargando", "modo": "reemplazar"}})
161
+
162
+ maximo_uso = 3
163
+ while chunk["choices"][0]["delta"].get("function_call") and maximo_uso:
164
+ nombre = chunk["choices"][0]["delta"]["function_call"]["name"]
165
+ yield json.dumps({"comando": "status", "status":{"mensaje": chat_functions.function_user_text[nombre] }})
166
+ mensaje_funcion, response_async = manejar_funciones(chunk, response_async, data)
167
+ yield json.dumps({"comando": "function", "function": {"role": "assistant", "content": mensaje_funcion} })
168
+ chunk = next(response_async)
169
+ maximo_uso -= 1
170
+
171
+ mensaje = {"role": "assistant", "content":""}
172
 
173
+
 
174
  for chunk in response_async:
175
  if chunk["choices"][0]["finish_reason"]:
176
  break
177
+ if "content" in chunk["choices"][0]["delta"]:
178
+ mensaje["content"] += chunk["choices"][0]["delta"]["content"]
 
 
 
 
 
 
 
 
 
179
 
180
+ log_write(data["token_data"]["user"], "Mensaje Rs", mensaje["content"])
181
  yield json.dumps({"comando": "mensaje", "mensaje": mensaje})
182
+ yield json.dumps({"comando": "token", "token":create_jwt_token(data["token_data"])})
183
+ return StreamingResponse(__streamer(response_async, data), media_type="application/json")
184
 
185
 
186
  @app.get("/read_log", response_class=HTMLResponse)
187
  async def read_log(request: Request, credentials: HTTPBasicCredentials = Depends(security)):
188
+ if sha256(credentials.username.encode()).hexdigest()=="bc1c32d709aef061bbde4fc848421cdb933e8a9f391c3a089f2861ac0772c168" and authenticate_user(credentials):
189
+ log_write(credentials.username, "Log Accesado", "")
190
+ with open("logs/eventos.log", "r") as f:
191
  return HTMLResponse(f.read())
192
+ log_write(credentials.username, "Intento acceder logs", f"{request.client.host}:{request.client.port} - {str(dict(request.headers))}")
193
+ raise HTTPException(status_code=404)
requirements.txt CHANGED
@@ -1,7 +1,7 @@
1
- fastapi==0.74.*
2
- requests==2.27.*
3
- openai==0.27.*
4
- uvicorn[standard]==0.17.*
5
- PyJWT==2.6.0
6
- hypercorn>=0.14.3
7
- tiktoken>=0.3.0
 
1
+ fastapi==0.103.*
2
+ oauthlib==3.2.*
3
+ requests==2.31.*
4
+ openai==0.28.*
5
+ uvicorn[standard]==0.23.*
6
+ PyJWT==2.8.*
7
+ hypercorn>=0.14.*
static/css/app.css CHANGED
@@ -1,248 +1,251 @@
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
- }
25
- .chat {
26
- --textarea: 0px;
27
- border-radius: 5px;
28
- display: block;
29
- width: 100%;
30
- overflow-y: scroll;
31
- overflow-x: hidden;
32
- background: rgb(161, 161, 161);
33
- padding: 10px 0;
34
- height: max( calc( 100svh - 120px - var(--textarea) ), calc(50svh - 90px) );
35
- }
36
-
37
- .chat .message {
38
- display: flex;
39
- margin: 5px 20px 5px 10px;
40
- filter: opacity(0.9);
41
- }
42
- .chat .message.me {
43
- margin: 5px 10px 5px 20px;
44
- }
45
- .chat .message.comando {
46
- margin: 5px auto;
47
- display: table;
48
- }
49
- .chat .message:last-child {
50
- filter: opacity(1);
51
- }
52
-
53
- .chat .message.no-opacity {
54
- display: flex;
55
- margin: 10px 0 0 10px;
56
- filter: opacity(1);
57
- }
58
-
59
- .chat .message img {
60
- margin: 0 10px 0 0;
61
- height: 30px;
62
- border-radius: 50%;
63
- }
64
-
65
- .chat .message.me img {
66
- order: 2;
67
- margin: 0 0 0 3px;
68
- }
69
-
70
- .chat .message div {
71
- flex: 1;
72
- max-width: 100%;
73
- }
74
-
75
- .chat .message div p {
76
- max-width: calc( 100% - 20px );
77
- display: inline-block;
78
- margin: 0;
79
- padding: 8px 10px 8px 10px;
80
- background: #fff;
81
- border-radius: 3px;
82
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
83
- min-width: 40%;
84
- transition: 0.5s height;
85
- }
86
-
87
- .chat .message.me div p {
88
- float: right;
89
- background: #b4c2ff;
90
- }
91
- .chat .message.comando div p {
92
- background: #d0a8ff;
93
- }
94
- .chat .message.warning div p {
95
- background: #f0e370;
96
- }
97
- .chat .message.error div p {
98
- background: #f09470;
99
- }
100
-
101
- .chat .message div p ul {
102
- list-style: none;
103
- color: #555;
104
- padding-right: 10px;
105
- }
106
-
107
- .chat .message:last-child div p ul {
108
- list-style: none;
109
- color: blue;
110
- }
111
-
112
- .chat .message div p ul.ultotal {
113
- list-style: none;
114
- color: #34495e;
115
- font-size: 12px;
116
- }
117
-
118
- .chat .message pre {
119
- overflow-x: scroll;
120
- border: solid 1px #e5e4e4;
121
- padding: 10px;
122
- }
123
-
124
- .input-box {
125
- background: #222f3d;
126
- margin: 10px 0;
127
- height: 30px;
128
- display: flex;
129
- border-radius: 5px;
130
- max-height: 50svh;
131
- }
132
-
133
- .input-box textarea,
134
- .input-box button {
135
- height: 100%;
136
- margin: 0;
137
- border: none;
138
- padding: 0 15px;
139
- }
140
-
141
- .input-box button:focus, .input-box textarea:focus {
142
- outline: none;
143
- }
144
-
145
- .input-box .input-text {
146
- width: 100%;
147
- border-radius: 5px 0 0 5px;
148
- resize: none;
149
- border-top: solid 7px #fff;
150
- border-bottom: solid 7px #fff;
151
-
152
- }
153
- .input-box button{
154
- width: 30px;
155
- background-size: 20px;
156
- background-color: #ddd;
157
- background-repeat: no-repeat;
158
- background-position: center;
159
- border-left: solid 1px #555;
160
- }
161
- .input-box .input-send {
162
- background-image: url(/static/img/send.png);
163
- }
164
- .input-box .input-delete {
165
- background-image: url(/static/img/delete.png);
166
- }
167
- .input-box button:first-child{
168
- border-left: none;
169
- }
170
- .input-box button:last-child{
171
- border-radius: 0 5px 5px 0;
172
- }
173
- .input-box button:disabled, .input-box textarea:disabled{
174
- background-color: #8b8b8b;
175
- border-color: #8b8b8b;
176
-
177
- }
178
-
179
- #message-template{
180
- display: none;
181
- }
182
-
183
- .loader-wrap {
184
- display: flex;
185
- }
186
- .loader {
187
- margin: auto;
188
- width: 48px;
189
- height: 48px;
190
- border: 3px dotted #476380;
191
- border-style: solid solid dotted dotted;
192
- border-radius: 50%;
193
- display: inline-block;
194
- position: relative;
195
- box-sizing: border-box;
196
- animation: rotation 2s linear infinite;
197
- }
198
- .loader.firststage{
199
- border: 3px dotted #49b359;
200
- border-style: solid solid dotted dotted;
201
- transition:all 1s;
202
- }
203
- .loader::after {
204
- content: '';
205
- box-sizing: border-box;
206
- position: absolute;
207
- left: 0;
208
- right: 0;
209
- top: 0;
210
- bottom: 0;
211
- margin: auto;
212
- border: 3px dotted #445464;
213
- border-style: solid solid dotted;
214
- width: 24px;
215
- height: 24px;
216
- border-radius: 50%;
217
- animation: rotationBack 1s linear infinite;
218
- transform-origin: center center;
219
- }
220
- .loader.firststage::after {
221
- border: 3px dotted #49b359;
222
- border-style: solid solid dotted;
223
- transition:all 1s;
224
- }
225
-
226
- @keyframes rotation {
227
- 0% {
228
- transform: rotate(0deg);
229
- }
230
- 100% {
231
- transform: rotate(360deg);
232
- }
233
- }
234
- @keyframes rotationBack {
235
- 0% {
236
- transform: rotate(0deg);
237
- }
238
- 100% {
239
- transform: rotate(-360deg);
240
- }
241
- }
242
- .loader-wrap ~ div {
243
- text-align: center;
244
- margin-top: 10px;
245
- }
246
- dialog{
247
- margin: auto;
248
- }
 
 
 
 
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
+ }
25
+ .chat {
26
+ --textarea: 0px;
27
+ border-radius: 5px;
28
+ display: block;
29
+ width: 100%;
30
+ overflow-y: scroll;
31
+ overflow-x: hidden;
32
+ background: rgb(161, 161, 161);
33
+ padding: 10px 0;
34
+ height: max( calc( 100svh - 120px - var(--textarea) ), calc(50svh - 90px) );
35
+ }
36
+
37
+ .chat .message {
38
+ display: flex;
39
+ margin: 5px 20px 5px 10px;
40
+ filter: opacity(0.9);
41
+ }
42
+ .chat .message.me {
43
+ margin: 5px 10px 5px 20px;
44
+ }
45
+ .chat .message.comando {
46
+ margin: 5px auto;
47
+ display: table;
48
+ }
49
+ .chat .message:last-child {
50
+ filter: opacity(1);
51
+ }
52
+
53
+ .chat .message.no-opacity {
54
+ display: flex;
55
+ margin: 10px 0 0 10px;
56
+ filter: opacity(1);
57
+ }
58
+
59
+ .chat .message img {
60
+ margin: 0 10px 0 0;
61
+ height: 30px;
62
+ border-radius: 50%;
63
+ }
64
+
65
+ .chat .message.me img {
66
+ order: 2;
67
+ margin: 0 0 0 3px;
68
+ }
69
+
70
+ .chat .message div {
71
+ flex: 1;
72
+ max-width: 100%;
73
+ }
74
+
75
+ .chat .message div p {
76
+ max-width: calc( 100% - 20px );
77
+ display: inline-block;
78
+ margin: 0;
79
+ padding: 8px 10px 8px 10px;
80
+ background: #fff;
81
+ border-radius: 3px;
82
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
83
+ min-width: 40%;
84
+ transition: 0.5s height;
85
+ }
86
+
87
+ .chat .message.me div p {
88
+ float: right;
89
+ background: #b4c2ff;
90
+ }
91
+ .chat .message.comando div p {
92
+ background: #d0a8ff;
93
+ }
94
+ .chat .message.warning div p {
95
+ background: #f0e370;
96
+ }
97
+ .chat .message.error div p {
98
+ background: #f09470;
99
+ }
100
+
101
+ .chat .message div p ul {
102
+ list-style: none;
103
+ color: #555;
104
+ padding-right: 10px;
105
+ }
106
+
107
+ .chat .message:last-child div p ul {
108
+ list-style: none;
109
+ color: blue;
110
+ }
111
+
112
+ .chat .message div p ul.ultotal {
113
+ list-style: none;
114
+ color: #34495e;
115
+ font-size: 12px;
116
+ }
117
+
118
+ .chat .message pre {
119
+ overflow-x: scroll;
120
+ border: solid 1px #e5e4e4;
121
+ padding: 10px;
122
+ }
123
+
124
+ .input-box {
125
+ background: #222f3d;
126
+ margin: 10px 0;
127
+ height: 30px;
128
+ display: flex;
129
+ border-radius: 5px;
130
+ max-height: 50svh;
131
+ }
132
+
133
+ .input-box textarea,
134
+ .input-box button {
135
+ height: 100%;
136
+ margin: 0;
137
+ border: none;
138
+ padding: 0 15px;
139
+ }
140
+
141
+ .input-box button:focus, .input-box textarea:focus {
142
+ outline: none;
143
+ }
144
+
145
+ .input-box .input-text {
146
+ width: 100%;
147
+ border-radius: 5px 0 0 5px;
148
+ resize: none;
149
+ border-top: solid 7px #fff;
150
+ border-bottom: solid 7px #fff;
151
+
152
+ }
153
+ .input-box button{
154
+ width: 30px;
155
+ background-size: 20px;
156
+ background-color: #ddd;
157
+ background-repeat: no-repeat;
158
+ background-position: center;
159
+ border-left: solid 1px #555;
160
+ }
161
+ .input-box .input-send {
162
+ background-image: url(/static/img/send.png);
163
+ }
164
+ .input-box .input-delete {
165
+ background-image: url(/static/img/delete.png);
166
+ }
167
+ .input-box .input-menu {
168
+ background-image: url(/static/img/menu.svg);
169
+ }
170
+ .input-box button:first-child{
171
+ border-left: none;
172
+ }
173
+ .input-box button:last-child{
174
+ border-radius: 0 5px 5px 0;
175
+ }
176
+ .input-box button:disabled, .input-box textarea:disabled{
177
+ background-color: #8b8b8b;
178
+ border-color: #8b8b8b;
179
+
180
+ }
181
+
182
+ #message-template{
183
+ display: none;
184
+ }
185
+
186
+ .loader-wrap {
187
+ display: flex;
188
+ }
189
+ .loader {
190
+ margin: auto;
191
+ width: 48px;
192
+ height: 48px;
193
+ border: 3px dotted #476380;
194
+ border-style: solid solid dotted dotted;
195
+ border-radius: 50%;
196
+ display: inline-block;
197
+ position: relative;
198
+ box-sizing: border-box;
199
+ animation: rotation 2s linear infinite;
200
+ }
201
+ .loader.firststage{
202
+ border: 3px dotted #49b359;
203
+ border-style: solid solid dotted dotted;
204
+ transition:all 1s;
205
+ }
206
+ .loader::after {
207
+ content: '';
208
+ box-sizing: border-box;
209
+ position: absolute;
210
+ left: 0;
211
+ right: 0;
212
+ top: 0;
213
+ bottom: 0;
214
+ margin: auto;
215
+ border: 3px dotted #445464;
216
+ border-style: solid solid dotted;
217
+ width: 24px;
218
+ height: 24px;
219
+ border-radius: 50%;
220
+ animation: rotationBack 1s linear infinite;
221
+ transform-origin: center center;
222
+ }
223
+ .loader.firststage::after {
224
+ border: 3px dotted #49b359;
225
+ border-style: solid solid dotted;
226
+ transition:all 1s;
227
+ }
228
+
229
+ @keyframes rotation {
230
+ 0% {
231
+ transform: rotate(0deg);
232
+ }
233
+ 100% {
234
+ transform: rotate(360deg);
235
+ }
236
+ }
237
+ @keyframes rotationBack {
238
+ 0% {
239
+ transform: rotate(0deg);
240
+ }
241
+ 100% {
242
+ transform: rotate(-360deg);
243
+ }
244
+ }
245
+ .loader-wrap ~ div {
246
+ text-align: center;
247
+ margin-top: 10px;
248
+ }
249
+ dialog{
250
+ margin: auto;
251
+ }
static/css/tabs.css CHANGED
@@ -36,6 +36,7 @@
36
  margin-right: 4px;
37
  border-radius: 0px 0px 10px 10px;
38
  transition: 0.2s background-color;
 
39
  }
40
  .tab-label-add {
41
  background: #3b74ad;
 
36
  margin-right: 4px;
37
  border-radius: 0px 0px 10px 10px;
38
  transition: 0.2s background-color;
39
+ background: #7d9dbd;
40
  }
41
  .tab-label-add {
42
  background: #3b74ad;
static/img/menu.svg CHANGED
static/js/chatHandler.js CHANGED
@@ -2,6 +2,7 @@ class ChatGPT{
2
  definicion = "Te llamas Chatsito, eres un asistente de apoyo a los amigos de MIA, " +
3
  "tu objetivo principal es responder preguntas de manera puntual y objetiva " +
4
  "a tu interlocutor.\n" +
 
5
  "Responde de manera amistosa con en el texto más corto y objetivo posible.\n" +
6
  "Knowledge cutoff: 2021-09-01\nCurrent date: {date}";
7
  constructor(token){
@@ -144,6 +145,10 @@ class ChatGPT{
144
  localStorage.setItem("conversaciones", JSON.stringify(self.conversaciones))
145
  ctx.trigger("precarga:mensaje", response.mensaje.content);
146
  break;
 
 
 
 
147
  default:
148
  console.log("???")
149
  }
 
2
  definicion = "Te llamas Chatsito, eres un asistente de apoyo a los amigos de MIA, " +
3
  "tu objetivo principal es responder preguntas de manera puntual y objetiva " +
4
  "a tu interlocutor.\n" +
5
+ "Si requieres ejecutar más funciones, ejecuta tantas veces como lo necesites" +
6
  "Responde de manera amistosa con en el texto más corto y objetivo posible.\n" +
7
  "Knowledge cutoff: 2021-09-01\nCurrent date: {date}";
8
  constructor(token){
 
145
  localStorage.setItem("conversaciones", JSON.stringify(self.conversaciones))
146
  ctx.trigger("precarga:mensaje", response.mensaje.content);
147
  break;
148
+ case "function":
149
+ conversacion.push(response.function);
150
+ localStorage.setItem("conversaciones", JSON.stringify(self.conversaciones))
151
+ break;
152
  default:
153
  console.log("???")
154
  }
static/main.html CHANGED
@@ -40,6 +40,7 @@
40
  <div class='input-box'>
41
  <textarea class='input-text' placeholder="Escribe aquí" type="text" autofocus=""></textarea>
42
  <button class='input-send' ></button>
 
43
  <button class='input-delete' ></button>
44
  </div>
45
  </div>
 
40
  <div class='input-box'>
41
  <textarea class='input-text' placeholder="Escribe aquí" type="text" autofocus=""></textarea>
42
  <button class='input-send' ></button>
43
+ <button class='input-menu' ></button>
44
  <button class='input-delete' ></button>
45
  </div>
46
  </div>
token_counter.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tiktoken
2
+ def count_tokens(messages, model="gpt-3.5-turbo-16k"):
3
+ """Returns the number of tokens used by a list of messages."""
4
+ try:
5
+ encoding = tiktoken.encoding_for_model(model)
6
+ except KeyError:
7
+ encoding = tiktoken.get_encoding("cl100k_base")
8
+
9
+ num_tokens = 0
10
+ for message in messages:
11
+ num_tokens += 4 # every message follows <im_start>{role/name}\n{content}<im_end>\n
12
+ for key, value in message.items():
13
+ num_tokens += len(encoding.encode(value))
14
+ if key == "name": # if there's a name, the role is omitted
15
+ num_tokens += -1 # role is always required and always 1 token
16
+ num_tokens += 2 # every reply is primed with <im_start>assistant
17
+ return num_tokens