diff --git a/app/__init__.py b/app/__init__.py index faea43a6..98f6a34f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -10,6 +10,8 @@ def create_app(): load_configurations(app) configure_logging() + print("ACCESS_TOKEN desde config:", app.config["ACCESS_TOKEN"]) + # Import and register blueprints, if any app.register_blueprint(webhook_blueprint) diff --git a/app/config.py b/app/config.py index 310aa082..51e6ad56 100644 --- a/app/config.py +++ b/app/config.py @@ -6,6 +6,7 @@ def load_configurations(app): load_dotenv() + # app.config["ACCESS_TOKEN"] = 'EACZD' app.config["ACCESS_TOKEN"] = os.getenv("ACCESS_TOKEN") app.config["YOUR_PHONE_NUMBER"] = os.getenv("YOUR_PHONE_NUMBER") app.config["APP_ID"] = os.getenv("APP_ID") diff --git a/app/services/openai_service.py b/app/services/openai_service.py index 04f5829d..091a5d71 100644 --- a/app/services/openai_service.py +++ b/app/services/openai_service.py @@ -1,9 +1,11 @@ +import json from openai import OpenAI import shelve from dotenv import load_dotenv import os import time import logging +import requests load_dotenv() OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") @@ -14,7 +16,7 @@ def upload_file(path): # Upload a file with an "assistants" purpose file = client.files.create( - file=open("../../data/airbnb-faq.pdf", "rb"), purpose="assistants" + file=open("../../data/faq.pdf", "rb"), purpose="assistants" ) @@ -23,10 +25,10 @@ def create_assistant(file): You currently cannot set the temperature for Assistant via the API. """ assistant = client.beta.assistants.create( - name="WhatsApp AirBnb Assistant", - instructions="You're a helpful WhatsApp assistant that can assist guests that are staying in our Paris AirBnb. Use your knowledge base to best respond to customer queries. If you don't know the answer, say simply that you cannot help with question and advice to contact the host directly. Be friendly and funny.", + name="WhatsApp Murrah Assistant", + instructions="Eres un asistente útil de WhatsApp que puede ayudar a los clientes que quieren hacer un pedido en nuestro restaurante Murrah. Usa tu base de conocimientos para responder de la mejor manera posible a las preguntas de los clientes. Si no sabes la respuesta, simplemente di que no puedes ayudar con esa pregunta y aconseja contactar al anfitrión directamente. Sé amigable y divertido.", tools=[{"type": "retrieval"}], - model="gpt-4-1106-preview", + model="gpt-4o-mini", file_ids=[file.id], ) return assistant @@ -44,28 +46,97 @@ def store_thread(wa_id, thread_id): def run_assistant(thread, name): - # Retrieve the Assistant assistant = client.beta.assistants.retrieve(OPENAI_ASSISTANT_ID) - # Run the assistant + # Verificar si el menú ya ha sido enviado + if verificar_menu_enviado(thread.id): + menu_enviado = True + else: + menu_enviado = False + + # Definir la estructura del JSON que debe ser devuelta cuando el cliente termine + estructura_json = """ + { + "cliente": "nombre_del_cliente", + "pedido": [ + {"producto": "nombre_del_producto", "cantidad": cantidad}, + {"producto": "nombre_del_producto", "cantidad": cantidad} + ], + "hora_pedido": "2025-10-01T12:00:00Z (aqui va la hora del pedido)", + } + """ + + # Ejecutar el asistente run = client.beta.threads.runs.create( thread_id=thread.id, assistant_id=assistant.id, - # instructions=f"You are having a conversation with {name}", + instructions=f"Estás teniendo una conversación con {name}. Primero espera a que se muestre el menú, y luego espera las instrucciones del cliente sobre su pedido. \ + Y cuando el cliente diga explicitamente 'CONFIRMAR', pero tambien recuerdale que tiene que decir 'CONFIRMAR' para acabar el pedido, \ + finaliza el pedido y manda el siguiente json y solo el json:\n {estructura_json}\ + Ahora espera la respuesta del cliente.", ) - # Wait for completion - # https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps#:~:text=under%20failed_at.-,Polling%20for%20updates,-In%20order%20to + + # Esperar la finalización while run.status != "completed": - # Be nice to the API time.sleep(0.5) run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id) - # Retrieve the Messages + # Obtener los mensajes messages = client.beta.threads.messages.list(thread_id=thread.id) new_message = messages.data[0].content[0].text.value - logging.info(f"Generated message: {new_message}") - return new_message + logging.info(f"Mensaje generado: {new_message}") + response = new_message + + # Si es la primera interacción y el menú aún no ha sido enviado + if not menu_enviado: + # Cargar el menú desde el archivo o base de datos + menu = cargar_menu_desde_txt() # Cargar el menú del archivo de texto + response = f"¡Hola {name}! ¡Bienvenido a Murrah! \nAquí está el menú: \n{menu}" + + # Enviar el menú al cliente como el primer mensaje + message = client.beta.threads.messages.create( + thread_id=thread.id, + role="assistant", + content=response, + ) + + # Marcar que el menú ha sido enviado + marcar_menu_enviado(thread.id) + + # Si el cliente menciona que ha terminado el pedido + elif "json" in new_message.lower(): + # Persistir la confirmación del cliente + marcar_confirmacion(thread.id, True) + + import re + + try: + # Buscar el bloque entre ```json y ``` + match = re.search(r"```json\s*(\{.*?\})\s*```", new_message, re.DOTALL) + if match: + json_str = match.group(1) + comanda_extraida = json.loads(json_str) + estado_pedido[thread.id] = comanda_extraida["pedido"] + logging.info(f"✅ Pedido guardado para {thread.id}: {estado_pedido[thread.id]}") + else: + raise ValueError("No se encontró bloque JSON válido en el mensaje") + except Exception as e: + logging.error(f"❌ Error al extraer comanda JSON: {e}") + return "Hubo un error al procesar tu pedido. Por favor intenta nuevamente." + + # Finalizar el pedido y generar el JSON + comanda_json = finalizar_pedido(thread.id, name) + logging.info(f"Comanda finalizada: {json.dumps(comanda_json, indent=4)}") + estado_pedido[thread.id] = comanda_json + response = f"Gracias por tu pedido, {name}. ¡Lo estamos procesando!" + + # Si el cliente no ha confirmado, pero la confirmación persiste (por si el servicio se cae) + elif verificar_confirmacion(thread.id): + response = "Tu pedido ya fue confirmado. Estamos procesando tu pedido." + + # Devolver la respuesta generada + return response def generate_response(message_body, wa_id, name): @@ -95,3 +166,103 @@ def generate_response(message_body, wa_id, name): new_message = run_assistant(thread, name) return new_message + +# Diccionario que almacena el pedido del cliente +estado_pedido = {} + +def finalizar_pedido(wa_id, name): + """ + Función para finalizar el pedido del cliente y generar el JSON. + """ + if wa_id not in estado_pedido: + logging.warning(f"No hay pedido para {wa_id}") + return None + + # Generamos el JSON de la comanda + comanda_json = { + "cliente": name, + "pedido": estado_pedido[wa_id] + } + + try: + response = requests.post("http://localhost:5001/comandas", json=comanda_json, timeout=5) + response.raise_for_status() + logging.info("✅ Comanda enviada correctamente.") + except requests.exceptions.RequestException as e: + logging.error(f"❌ Error al enviar comanda: {e}") + return None + + logging.info(f"📦 Comanda generada:\n{json.dumps(comanda_json, indent=4)}") + return comanda_json + + +def agregar_producto_pedido(wa_id, producto, cantidad, precio): + """ + Función para agregar un producto al pedido del cliente. + Si el producto ya está en el pedido, actualiza la cantidad. + """ + if wa_id not in estado_pedido: + estado_pedido[wa_id] = [] + + # Buscar si el producto ya está en el pedido + producto_existente = next((item for item in estado_pedido[wa_id] if item['producto'] == producto), None) + + if producto_existente: + # Si el producto ya existe, actualizar la cantidad + producto_existente['cantidad'] += cantidad + else: + # Si el producto no existe, agregarlo + estado_pedido[wa_id].append({ + 'producto': producto, + 'cantidad': cantidad, + 'precio': precio + }) + + logging.info(f"Pedido actualizado para {wa_id}: {estado_pedido[wa_id]}") + +def cargar_menu_desde_txt(): + """ + Lee el contenido de un archivo .txt y lo retorna como un string. + + Parámetros: + ruta_archivo (str): Ruta del archivo de texto. + + Retorna: + str: Contenido del archivo. + """ + try: + with open("app/utils/menu.txt", 'r', encoding='utf-8') as archivo: + contenido = archivo.read() + return contenido + except FileNotFoundError: + return "Error: El archivo no se encontró." + except Exception as e: + return f"Error al leer el archivo: {str(e)}" + +def marcar_menu_enviado(thread_id): + """ + Guarda en un archivo la información de que el menú ya ha sido enviado para este hilo. + """ + with shelve.open('estado_conversacion.db', writeback=True) as db: + db[thread_id] = True + +def verificar_menu_enviado(thread_id): + """ + Verifica si el menú ya fue enviado para este hilo de conversación. + """ + with shelve.open('estado_conversacion.db') as db: + return db.get(thread_id, False) + +def marcar_confirmacion(wa_id, confirmado): + """ + Guarda en un archivo la información de si el cliente ha confirmado o no su pedido. + """ + with shelve.open('estado_confirmacion.db', writeback=True) as db: + db[wa_id] = confirmado + +def verificar_confirmacion(wa_id): + """ + Verifica si el cliente ha confirmado su pedido. + """ + with shelve.open('estado_confirmacion.db') as db: + return db.get(wa_id, False) \ No newline at end of file diff --git a/app/services/straico_service.py b/app/services/straico_service.py new file mode 100644 index 00000000..30b8177f --- /dev/null +++ b/app/services/straico_service.py @@ -0,0 +1,43 @@ +import requests +import json + +url = "https://api.straico.com/v1/prompt/completion" + + +headers = { + 'Authorization': 'Bearer TY-AX7LCpGWb1qEh7DSGOV1ucPX3EhV1YwNoANr2IY89j3J6B5C', + 'Content-Type': 'application/json' +} + + +def generate_response(message_body, wa_id, name): + payload = json.dumps({ + "models": [ + #"anthropic/claude-3.7-sonnet:thinking", + "meta-llama/llama-4-maverick" + ], + "message": "Contexto", + + + + + #Cargar archivo para contexto + "file_urls": [ + "url a reemplazar" + ] + }) + response = requests.request("POST", url, headers=headers, data=payload) + + return response.text + + +print(generate_response("Hola, que hora es", None, "Felipe")) + + +def generaurl(): + files=[ + ('file',('galaxy.jpg', open('C:/Users/GATOTEC18/Downloads/galaxy.jpg','rb'), 'image/jpeg')) +] +headers = { + # 'Content-Type': 'multipart/form-data' # Esta línea se comenta o elimina +} diff --git a/app/utils/__init__.py b/app/utils/__init__.py index e69de29b..cfb7840d 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -0,0 +1,9 @@ +from flask import Flask + +def create_app(): + app = Flask(__name__) + + from .views import webhook_blueprint # 👈 muévelo aquí + app.register_blueprint(webhook_blueprint, url_prefix="/webhook") + + return app \ No newline at end of file diff --git a/app/utils/app_mostrar_comandas.py b/app/utils/app_mostrar_comandas.py new file mode 100644 index 00000000..ec4a3a65 --- /dev/null +++ b/app/utils/app_mostrar_comandas.py @@ -0,0 +1,71 @@ +from flask import Flask, request, jsonify, render_template_string +from datetime import datetime + +app = Flask(__name__) +comandas = [] + +html_template = """ + + + + 🧾 Tablero de Comandas - Cocina + + + + + +

🧾 COMANDAS EN COCINA

+
+ {% for comanda in comandas %} +
+
👤 {{ comanda.cliente }}
+
🕒 {{ comanda.hora_pedido }}
+
📝 Pedido:
+ +
+ {% endfor %} +
+ + +""" + +@app.route("/", methods=["GET"]) +def ver_comandas(): + return render_template_string(html_template, comandas=comandas) + +@app.route("/comandas", methods=["POST"]) +def recibir_comanda(): + data = request.get_json() + if not data: + return jsonify({"error": "No data provided"}), 400 + + # Agregar hora si no viene incluida + if "hora_pedido" not in data: + data["hora_pedido"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + comandas.append(data) + return jsonify({"status": "comanda recibida"}), 200 + +if __name__ == "__main__": + app.run(port=5001) \ No newline at end of file diff --git a/app/utils/menu.txt b/app/utils/menu.txt new file mode 100644 index 00000000..4af04190 --- /dev/null +++ b/app/utils/menu.txt @@ -0,0 +1,83 @@ +🍔 **Hamburguesas**: + +1. **Tradición (Clásica)** – $23.500 + Pan artesanal, carne de búfalo 90g, lechuga, tomate. + - **Solo**: + - 90gr: 23.5K + - 120gr: 26.5K + - 150gr: 27.9K + - **Combo**: + - 90gr: 32.9K + - 120gr: 35.9K + - 150gr: 37.3K + +2. **Tropical (Artesanal)** – $27.500 + Carne de búfalo 90g, tocineta, piña, lechuga, cebolla caramelizada. + - **Solo**: + - 90gr: 27.5K + - 120gr: 29.5K + - 150gr: 31.9K + - ** En Combo**: + - 90gr: 36.9K + - 120gr: 38.9K + - 150gr: 41.3K + +3. **Antioqueña (Artesanal)** – $27.500 + Carne de búfalo 90g, lechuga, frijoles refritos, tomate, guacamole. + - **Solo**: + - 90gr: 27.5K + - 120gr: 29.5K + - 150gr: 31.9K + - **En Combo**: + - 90gr: 36.9K + - 120gr: 38.9K + - 150gr: 41.3K + +4. **Andina (Artesanal)** – $27.500 + Carne de búfalo 90g, huevo frito, plátano maduro. + - **Solo**: + - 90gr: 27.5K + - 120gr: 29.5K + - 150gr: 31.9K + - **En Combo**: + - 90gr: 36.9K + - 120gr: 38.9K + - 150gr: 41.3K + +5. **Crunchy (Signature)** – $27.500 + Carne de búfalo 90g, tocineta, cebolla caramelizada, cebolla frita, salsa BBQ. + - **Solo**: + - 90gr: 27.5K + - 120gr: 29.5K + - 150gr: 31.9K + - **En Combo**: + - 90gr: 36.9K + - 120gr: 38.9K + - 150gr: 41.3K + +6. **Chimichurri (Signature)** – $30.900 + Carne de búfalo 90g, chorizo, chimichurri. + - **Solo**: + - 90gr: 30.9K + - 120gr: 33.5K + - 150gr: 35.9K + - **En Combo**: + - 90gr: 40.3K + - 120gr: 42.9K + - 150gr: 45.3K + +--- + +🥤 **Bebidas**: + +1. **Gaseosa (Coca-Cola / Manzana / Schweppes)** – $4.000 +2. **Agua sin gas** – $3.000 +3. **Té frío artesanal** – $5.000 + +--- + +➕ **Acompañamientos**: + +• **Papas Casco** – $5.000 +• **Papas Francesas** – $5.000 +• **Yucas** – $5.000 diff --git a/app/utils/whatsapp_utils.py b/app/utils/whatsapp_utils.py index 78d25fa4..345a5140 100644 --- a/app/utils/whatsapp_utils.py +++ b/app/utils/whatsapp_utils.py @@ -3,7 +3,7 @@ import json import requests -# from app.services.openai_service import generate_response +from app.services.openai_service import generate_response import re @@ -13,22 +13,40 @@ def log_http_response(response): logging.info(f"Body: {response.text}") -def get_text_message_input(recipient, text): - return json.dumps( - { - "messaging_product": "whatsapp", - "recipient_type": "individual", - "to": recipient, - "type": "text", - "text": {"preview_url": False, "body": text}, +def get_text_message_input(recipient, text="Hola"): + return { + "messaging_product": "whatsapp", + "to": recipient, + "type": "text", + "text": { + "body": text } - ) - + } +''' def generate_response(response): - # Return text in uppercase + # Return text in uppercase return response.upper() +''' + +def cargar_menu_desde_txt(): + """ + Lee el contenido de un archivo .txt y lo retorna como un string. + + Parámetros: + ruta_archivo (str): Ruta del archivo de texto. + Retorna: + str: Contenido del archivo. + """ + try: + with open("app/utils/menu.txt", 'r', encoding='utf-8') as archivo: + contenido = archivo.read() + return contenido + except FileNotFoundError: + return "Error: El archivo no se encontró." + except Exception as e: + return f"Error al leer el archivo: {str(e)}" def send_message(data): headers = { @@ -39,24 +57,29 @@ def send_message(data): url = f"https://graph.facebook.com/{current_app.config['VERSION']}/{current_app.config['PHONE_NUMBER_ID']}/messages" try: + # usamos json=data para que requests lo serialice correctamente response = requests.post( - url, data=data, headers=headers, timeout=10 - ) # 10 seconds timeout as an example - response.raise_for_status() # Raises an HTTPError if the HTTP request returned an unsuccessful status code + url, + json=data, + headers=headers, + timeout=10 + ) + response.raise_for_status() except requests.Timeout: logging.error("Timeout occurred while sending message") return jsonify({"status": "error", "message": "Request timed out"}), 408 - except ( - requests.RequestException - ) as e: # This will catch any general request exception + except requests.RequestException as e: logging.error(f"Request failed due to: {e}") + if e.response is not None: + try: + logging.error(f"Meta response body: {e.response.text}") + except Exception as decode_error: + logging.error(f"Could not decode error body: {decode_error}") return jsonify({"status": "error", "message": "Failed to send message"}), 500 else: - # Process the response as normal log_http_response(response) return response - def process_text_for_whatsapp(text): # Remove brackets pattern = r"\【.*?\】" @@ -83,13 +106,14 @@ def process_whatsapp_message(body): message_body = message["text"]["body"] # TODO: implement custom function here - response = generate_response(message_body) - - # OpenAI Integration - # response = generate_response(message_body, wa_id, name) + # response = cargar_menu_desde_txt() # response = process_text_for_whatsapp(response) - data = get_text_message_input(current_app.config["RECIPIENT_WAID"], response) + # OpenAI Integration + response = generate_response(message_body, wa_id, name) + response = process_text_for_whatsapp(response) + + data = get_text_message_input(wa_id, response) send_message(data) diff --git a/data/airbnb-faq.pdf b/data/airbnb-faq.pdf deleted file mode 100644 index 44ae60d7..00000000 Binary files a/data/airbnb-faq.pdf and /dev/null differ diff --git a/run.py b/run.py index 7f03426c..4f4084c9 100644 --- a/run.py +++ b/run.py @@ -1,10 +1,12 @@ import logging - from app import create_app +from dotenv import load_dotenv +import os +load_dotenv() app = create_app() if __name__ == "__main__": logging.info("Flask app started") - app.run(host="0.0.0.0", port=8000) + app.run(host="0.0.0.0", port=int(os.getenv("PORT", 8000))) \ No newline at end of file diff --git a/start/assistants_quickstart.py b/start/assistants_quickstart.py index 85c21bc0..8a19f722 100644 --- a/start/assistants_quickstart.py +++ b/start/assistants_quickstart.py @@ -18,7 +18,7 @@ def upload_file(path): return file -file = upload_file("../data/airbnb-faq.pdf") +file = upload_file("../data/faq.pdf") # -------------------------------------------------------------- @@ -29,8 +29,8 @@ def create_assistant(file): You currently cannot set the temperature for Assistant via the API. """ assistant = client.beta.assistants.create( - name="WhatsApp AirBnb Assistant", - instructions="You're a helpful WhatsApp assistant that can assist guests that are staying in our Paris AirBnb. Use your knowledge base to best respond to customer queries. If you don't know the answer, say simply that you cannot help with question and advice to contact the host directly. Be friendly and funny.", + name="WhatsApp Murrah Assistant", + instructions="You're a helpful WhatsApp assistant that can assist clients that want to order in our restaurant Murrah. Use your knowledge base to best respond to customer queries. If you don't know the answer, say simply that you cannot help with question and advice to contact the host directly. Be friendly and funny.", tools=[{"type": "retrieval"}], model="gpt-4-1106-preview", file_ids=[file.id], diff --git a/start/whatsapp_quickstart.py b/start/whatsapp_quickstart.py index 668159e0..1f989b35 100644 --- a/start/whatsapp_quickstart.py +++ b/start/whatsapp_quickstart.py @@ -40,9 +40,10 @@ def send_whatsapp_message(): # Call the function -response = send_whatsapp_message() -print(response.status_code) -print(response.json()) +# response = send_whatsapp_message() +# print(response.status_code) +# print(response.json()) + # -------------------------------------------------------------- # Send a custom text WhatsApp message @@ -64,13 +65,13 @@ def get_text_message_input(recipient, text): def send_message(data): + url = f"https://graph.facebook.com/{VERSION}/{PHONE_NUMBER_ID}/messages" + headers = { - "Content-type": "application/json", "Authorization": f"Bearer {ACCESS_TOKEN}", + "Content-type": "application/json", } - url = f"https://graph.facebook.com/{VERSION}/{PHONE_NUMBER_ID}/messages" - response = requests.post(url, data=data, headers=headers) if response.status_code == 200: print("Status:", response.status_code) @@ -83,11 +84,15 @@ def send_message(data): return response -data = get_text_message_input( - recipient=RECIPIENT_WAID, text="Hello, this is a test message." -) +# data = get_text_message_input( +# recipient=RECIPIENT_WAID, text="¡Bienvenido a Murrah! " +# "Aquí las hamburguesas no son cualquier cosa... son totalmente carne de búfalo 🦬" +# "¿Antojo de algo diferente y brutalmente sabroso?" +# "🍔 Escríbenos y déjate tentar por el sabor salvaje." +# ) + -response = send_message(data) +# response = send_message(data) # -------------------------------------------------------------- # Send a custom text WhatsApp message asynchronously @@ -102,7 +107,8 @@ async def send_message(data): } async with aiohttp.ClientSession() as session: - url = "https://graph.facebook.com" + f"/{VERSION}/{PHONE_NUMBER_ID}/messages" + url = "https://graph.facebook.com" + \ + f"/{VERSION}/{PHONE_NUMBER_ID}/messages" try: async with session.post(url, data=data, headers=headers) as response: if response.status == 200: @@ -130,6 +136,7 @@ def get_text_message_input(recipient, text): ) +''' data = get_text_message_input( recipient=RECIPIENT_WAID, text="Hello, this is a test message." ) @@ -137,3 +144,4 @@ def get_text_message_input(recipient, text): loop = asyncio.get_event_loop() loop.run_until_complete(send_message(data)) loop.close() +''' diff --git a/whatsapp/Scripts/Activate.ps1 b/whatsapp/Scripts/Activate.ps1 new file mode 100644 index 00000000..dbbf985c --- /dev/null +++ b/whatsapp/Scripts/Activate.ps1 @@ -0,0 +1,502 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" + +# SIG # Begin signature block +# MIIvIwYJKoZIhvcNAQcCoIIvFDCCLxACAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk +# dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCE8MwggWQMIIDeKADAgECAhAFmxtXno4h +# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV +# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z +# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ +# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 +# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z +# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ +# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s +# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL +# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb +# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 +# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c +# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx +# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 +# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL +# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud +# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf +# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk +# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS +# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK +# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB +# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp +# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg +# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri +# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 +# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 +# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 +# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H +# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G +# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ +# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 +# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla +# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE +# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz +# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C +# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce +# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da +# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T +# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA +# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh +# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM +# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z +# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 +# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY +# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP +# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T +# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD +# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG +# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY +# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj +# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV +# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU +# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN +# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry +# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL +# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf +# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh +# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh +# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV +# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j +# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH +# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC +# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l +# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW +# eE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0GCSqGSIb3DQEBCwUA +# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE +# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz +# ODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1MjM1OTU5WjB8MQsw +# CQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQHEwlCZWF2ZXJ0b24x +# IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQDExpQ +# eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +# ADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiSYgDFfwhjQy89koM7 +# uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi0GGAZUegEAeRlSXx +# xhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN16yS8skFa3IHyvWdb +# D9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGuppxcia6a7xCyKoOA +# GjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu352diDY+iCMpk9Zanm +# SjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0ZFYKeb6BLA66d2GA +# LwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oERzTzEiV6nCO1M3U1 +# HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZI7IWe7JKhHohqKuc +# eQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16xot2KVPdfyPAWd81w +# tZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapPUnwo8ygflJJ74J+B +# Yxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3ZIly+qIqDAgMBAAGj +# ggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAdBgNVHQ4E +# FgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM +# MAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRp +# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI +# QTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v +# RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex +# LmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v +# d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUF +# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6 +# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu +# aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZI +# hvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcWTiNc2rskrNLrfH1N +# s0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+VVzxC88pOEvz68nA +# 82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfLIJQsAHBla0i7QRF2 +# de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izWOXM95BSkFSKdE45O +# q3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86WmjRUqbrnvdyR2yd +# I5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+W1scCpnA8YTs2d50 +# jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM58WEDkbeoriDk3hxU +# 8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMfZOm5cuclMnUHs2uq +# rRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw/TKqVL4Oaz3bkMSs +# M46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3r7bjyHTxOgqxRCVa +# 18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VHxaZg2unjHY3rMYIa +# tjCCGrICAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu +# Yy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJT +# QTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM0NHdMA0GCWCGSAFl +# AwQCAQUAoIHIMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC +# AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBnAZ6P7YvTwq0fbF62 +# o7E75R0LxsW5OtyYiFESQckLhjBcBgorBgEEAYI3AgEMMU4wTKBGgEQAQgB1AGkA +# bAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAxAC4AOQBfADIAMAAyADQA +# MAA0ADAAMgAuADAAMqECgAAwDQYJKoZIhvcNAQEBBQAEggIAg5wQO5NiKFirm9vr +# 1//X5G4t+z318Uagu8vJT/vTjkMTau86CF+SwP3pqC1H2ZMUyVYmVHae5dswKAMR +# hHY1VJV/0lJI+LdYcaxHI/WYzaFLbDrQI/Mty5cabjveG6geMlcJG4nYZlyQX+fJ +# 1k0ogeIF1owldecXP8t5e10WlHBlWb8IBnIPwMtJVZ2/y8NASxsnSJE7pEe7ijGe +# 5Bv9DXvoltKnMSVYv9u2vn7PeIq+Jm3n3kOGSIYtfdytEd1Fd6spfdcmIhqyzVk0 +# Hslq7Aqd7soT0xdmNa/amzEA4HRHpWGUhzOtcC+EqEIIJk9kTjyVgCiyWaB5gGko +# OAZfsxQn+a916iWwA7RrQ+TzBZq/pleUTLZzJmI3DXFjuJ1NDP6Sdw6KREgx6Yw4 +# q2NnnodKlGZkMDcGYPTM2sA4i6i6FsznWY4d8wE4J261YeUrVfIyTx+Q81W4KXoi +# C0x7Pe9Bjh4oJGM3YiLyhVL56sXZWxAC2C/vD3nvIvra9EpvlMvQh6b0xl0V4TSN +# dJ7T7VttR/WNjau46JIgbGZWCDBTTUAydQNoAZ4KnCrcIZCN6Y0qVokXsYHsVIto +# TsnM2+Ca09wxuOIfCOSKpAmqdJ/w2NwLwp+0gwrO2uzpCfbSbkAd+UQNv0joPyUp +# ywmsQndxqA8TaADp8TfkkpJywJGhghc/MIIXOwYKKwYBBAGCNwMDATGCFyswghcn +# BgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqGSIb3 +# DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQg+Jhe +# IOzOttA8vliuL+r3CiY4EJTzfvPasXkI/vwkoI8CEHZ95Ht1TmSmU8+fM0kIG00Y +# DzIwMjQwNDAyMTIzMjEwWqCCEwkwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f +# 5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp +# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2 +# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEz +# MjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x +# IDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0B +# AQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6 +# OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp +# 52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF +# 6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G4 +# 5lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7p +# Be6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAs +# NJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU +# 6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwK +# WEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFx +# smxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbR +# yV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPL +# QHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYG +# A1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCG +# SAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4E +# FgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov +# L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1 +# NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUH +# MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDov +# L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNI +# QTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCp +# tZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX +# 4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoF +# eoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+nji +# kxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBB +# Jt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJ +# A+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcs +# QdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE +# 5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS +# 2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3 +# CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUb +# c7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqADAgECAhAHNje3JFR8 +# 2Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV +# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0z +# NzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg +# SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1 +# NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +# AQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI +# 82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9 +# xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ +# 3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5Emfv +# DqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDET +# qVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHe +# IhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jo +# n7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ +# 9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/T +# Xkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJg +# o1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkw +# EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+e +# yG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQD +# AgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEF +# BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRw +# Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy +# dDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln +# aUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg +# hkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGw +# GC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0 +# MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1D +# X+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw +# 1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY +# +/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0I +# SQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr +# 5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7y +# Rp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDop +# hrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/ +# AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMO +# Hds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkq +# hkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j +# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB +# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5 +# WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +# ExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJv +# b3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1K +# PDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2r +# snnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C +# 8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBf +# sXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +# QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8 +# rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaY +# dj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+ +# wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw +# ++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+N +# P8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7F +# wI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUw +# AwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAU +# Reuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEB +# BG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsG +# AQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 +# cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp +# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAow +# CDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/ +# Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLe +# JLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE +# 1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9Hda +# XFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbO +# byMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYID +# djCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu +# Yy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYg +# VGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUA +# oIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcN +# MjQwNDAyMTIzMjEwWjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRm8CsywsLJD4Jd +# zqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQg58bvIvjFkyBb2O0xwLgtU8RJLcMV +# kvIdXiq3TCLuhq4wNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg0vbkbe10IszR1EBX +# aEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAEggIAhU3imuIvql4+ +# IqPz0Anf0ZIB5hbafNTx1WEVhPEG9iJr24gpjbWvepQrbWJf0FBj8wY9GeRab6iv +# 79MMxZkPpR/DMK1qFr1vIlw67JhpqqNkaNIa5G3pAHDYdHYcB+Utw1p5XPOBRu0A +# f4wQ5fwWugys4CGGAboq4prLNRKeUGVexMDK7Eorsv9xmzK0tE9QSMA3SxLCcSIX +# mrMkKzTR3vn0dqaDG4Ge7U2w7dVnQYGBX+s6C9CCjvCtenCAQLbF+OyYhkMNDVtJ +# lTmzxxwyyA5fFZJpG/Wfo/84/P8lQXUTuwOBpFoLE65OqNEG03SoqKsW4aTqkVM7 +# b6fKLsygm1w23+UlHGF/fbExeqxgOZiuJWWt/OFy9T3HIcAF1SMh7mot5ciu7btS +# xjkr/fhsi1M3M1g/giyn0I8N24mgaICPtXAzAbZW7GSC0R5T2qnW6gYoAcY62Qdz +# jl/Ey1rnOQ26TuQODyPVHhfhoIBbdIDpDJ2Vu2mxyxUnjATbizphcBgsU1fBYvZR +# v+SuK1MYZOGqgzugfiufdeFAlBDA/e64yRkJvDBEkcyGvj6FS6nVm7ekJpJhLU3z +# sSSmcYwdx1YQCr48HEjcmGrj5sAzzg4U4WU/GrLWz2sSRmh5rKcDAa0ewfYi13Z2 +# a/cdr8Or2RQ5ZSQ8OHgr3GBw7koDWR8= +# SIG # End signature block diff --git a/whatsapp/Scripts/activate b/whatsapp/Scripts/activate new file mode 100644 index 00000000..52fc070c --- /dev/null +++ b/whatsapp/Scripts/activate @@ -0,0 +1,63 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="C:\Users\juand\OneDrive - Universidad de los andes\Semestre 7\PMC\python-whatsapp-bot\whatsapp" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(whatsapp) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(whatsapp) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/whatsapp/Scripts/activate.bat b/whatsapp/Scripts/activate.bat new file mode 100644 index 00000000..567af582 --- /dev/null +++ b/whatsapp/Scripts/activate.bat @@ -0,0 +1,34 @@ +@echo off + +rem This file is UTF-8 encoded, so we need to update the current code page while executing it +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=C:\Users\juand\OneDrive - Universidad de los andes\Semestre 7\PMC\python-whatsapp-bot\whatsapp + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(whatsapp) %PROMPT% + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=(whatsapp) + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/whatsapp/Scripts/deactivate.bat b/whatsapp/Scripts/deactivate.bat new file mode 100644 index 00000000..62a39a75 --- /dev/null +++ b/whatsapp/Scripts/deactivate.bat @@ -0,0 +1,22 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) + +set _OLD_VIRTUAL_PATH= + +set VIRTUAL_ENV= +set VIRTUAL_ENV_PROMPT= + +:END diff --git a/whatsapp/Scripts/distro.exe b/whatsapp/Scripts/distro.exe new file mode 100644 index 00000000..18d8eb68 Binary files /dev/null and b/whatsapp/Scripts/distro.exe differ diff --git a/whatsapp/Scripts/dotenv.exe b/whatsapp/Scripts/dotenv.exe new file mode 100644 index 00000000..e2496263 Binary files /dev/null and b/whatsapp/Scripts/dotenv.exe differ diff --git a/whatsapp/Scripts/flask.exe b/whatsapp/Scripts/flask.exe new file mode 100644 index 00000000..60040aa6 Binary files /dev/null and b/whatsapp/Scripts/flask.exe differ diff --git a/whatsapp/Scripts/httpx.exe b/whatsapp/Scripts/httpx.exe new file mode 100644 index 00000000..bd75d005 Binary files /dev/null and b/whatsapp/Scripts/httpx.exe differ diff --git a/whatsapp/Scripts/normalizer.exe b/whatsapp/Scripts/normalizer.exe new file mode 100644 index 00000000..f5e92254 Binary files /dev/null and b/whatsapp/Scripts/normalizer.exe differ diff --git a/whatsapp/Scripts/openai.exe b/whatsapp/Scripts/openai.exe new file mode 100644 index 00000000..9cd9c2d5 Binary files /dev/null and b/whatsapp/Scripts/openai.exe differ diff --git a/whatsapp/Scripts/pip.exe b/whatsapp/Scripts/pip.exe new file mode 100644 index 00000000..deec182d Binary files /dev/null and b/whatsapp/Scripts/pip.exe differ diff --git a/whatsapp/Scripts/pip3.11.exe b/whatsapp/Scripts/pip3.11.exe new file mode 100644 index 00000000..deec182d Binary files /dev/null and b/whatsapp/Scripts/pip3.11.exe differ diff --git a/whatsapp/Scripts/pip3.exe b/whatsapp/Scripts/pip3.exe new file mode 100644 index 00000000..deec182d Binary files /dev/null and b/whatsapp/Scripts/pip3.exe differ diff --git a/whatsapp/Scripts/python.exe b/whatsapp/Scripts/python.exe new file mode 100644 index 00000000..f7cb1e38 Binary files /dev/null and b/whatsapp/Scripts/python.exe differ diff --git a/whatsapp/Scripts/pythonw.exe b/whatsapp/Scripts/pythonw.exe new file mode 100644 index 00000000..4fc3f909 Binary files /dev/null and b/whatsapp/Scripts/pythonw.exe differ diff --git a/whatsapp/Scripts/tqdm.exe b/whatsapp/Scripts/tqdm.exe new file mode 100644 index 00000000..c096a5eb Binary files /dev/null and b/whatsapp/Scripts/tqdm.exe differ diff --git a/whatsapp/pyvenv.cfg b/whatsapp/pyvenv.cfg new file mode 100644 index 00000000..8c1223e0 --- /dev/null +++ b/whatsapp/pyvenv.cfg @@ -0,0 +1,5 @@ +home = C:\Users\juand\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0 +include-system-site-packages = false +version = 3.11.9 +executable = C:\Users\juand\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\python.exe +command = C:\Users\juand\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\python.exe -m venv C:\Users\juand\OneDrive - Universidad de los andes\Semestre 7\PMC\python-whatsapp-bot\whatsapp