vmoras commited on
Commit
4cc32d2
1 Parent(s): 2c807ae

Add video and audio

Browse files
Files changed (6) hide show
  1. .gitignore +9 -1
  2. README.md +1 -1
  3. app.py +55 -129
  4. functions.py +123 -0
  5. prompts/main_prompt.txt +0 -27
  6. prompts/standalone_question.txt +0 -6
.gitignore CHANGED
@@ -1,5 +1,13 @@
1
  .idea/
2
  .venv/
3
  .env
 
4
 
5
- tests.ipynb
 
 
 
 
 
 
 
 
1
  .idea/
2
  .venv/
3
  .env
4
+ __pycache__/
5
 
6
+ tests.ipynb
7
+ example_questions.pdf
8
+
9
+ data.json
10
+ audio.wav
11
+ video.mp4
12
+
13
+ prompts/
README.md CHANGED
@@ -4,7 +4,7 @@ emoji: 💻
4
  colorFrom: yellow
5
  colorTo: blue
6
  sdk: gradio
7
- sdk_version: 4.13.0
8
  app_file: app.py
9
  pinned: false
10
  ---
 
4
  colorFrom: yellow
5
  colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 4.2.0
8
  app_file: app.py
9
  pinned: false
10
  ---
app.py CHANGED
@@ -1,143 +1,69 @@
1
- import os
2
- import pinecone
3
- import gradio as gr
4
- from openai import OpenAI
5
  from dotenv import load_dotenv
6
 
7
  load_dotenv()
8
 
9
- openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
10
- pinecone.init(api_key=os.getenv("PINECONE_API_TOKEN"), environment=os.getenv("PINECONE_ENVIRONMENT"))
11
- index = pinecone.Index(os.getenv("PINECONE_INDEX"))
12
 
13
-
14
- def init_prompt(type_prompt: str) -> str:
15
- if type_prompt == "main":
16
- name_file = 'main_prompt.txt'
17
- else:
18
- name_file = 'standalone_question.txt'
19
-
20
- with open(f"prompts/{name_file}", mode='r', encoding='utf-8') as infile:
21
- prompt = infile.read()
22
-
23
- return prompt
24
-
25
-
26
- def get_embedding(text: str) -> list[float]:
27
- response = openai_client.embeddings.create(
28
- input=text,
29
- model='text-embedding-ada-002'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  )
31
- return response.data[0].embedding
32
-
33
 
34
- def call_api(message_history: list[dict]) -> str:
35
- response = openai_client.chat.completions.create(
36
- model='gpt-4-1106-preview',
37
- temperature=0.7,
38
- messages=message_history
39
  )
40
- return response.choices[0].message.content
41
-
42
-
43
- def get_standalone_question(question: str, message_history: list[dict], prompt_q: str) -> str:
44
- # Format the message history like: Human: blablablá \nAssistant: blablablá
45
- history = ''
46
- for i, msg in enumerate(message_history):
47
- if i == 0:
48
- continue # Omit the prompt
49
- if i % 2 == 0:
50
- history += f'Human: {msg["content"]}\n'
51
- else:
52
- history += f'Assistant: {msg["content"]}\n'
53
-
54
- # Add history and question to the prompt and call chatgpt
55
- prompt = [{'role': 'system', 'content': ''}]
56
- content = prompt_q.replace('HISTORY', history).replace('QUESTION', question)
57
- prompt[0]['content'] = content
58
-
59
- return call_api(prompt)
60
-
61
-
62
- def get_context(question: str) -> str:
63
- q_embedding = get_embedding(question)
64
-
65
- # Get most similar vectors
66
- result = index.query(
67
- vector=q_embedding,
68
- top_k=10,
69
- include_metadata=True
70
- )['matches']
71
-
72
- # Crete a string based on the text of each vector
73
- context = ''
74
- for r in result:
75
- context += r['metadata']['Text'] + '\n'
76
- return context
77
-
78
-
79
- def get_answer(context: str, message_history: list[dict], question: str, prompt_m: str) -> str:
80
- message_history[0]['content'] = prompt_m.replace('CONTEXT', context)
81
- message_history.append({'role': 'user', 'content': question})
82
- return call_api(message_history)
83
-
84
-
85
- def ask_query(
86
- msg: str, chat_history: list[list[str | None]], message_history: list[dict], prompt_q: str, prompt_m: str
87
- ) -> tuple[str, list[list[str | None]], list[dict]]:
88
-
89
- if len(chat_history) == 5:
90
- answer = 'Un placer haberte ayudado, hasta luego!'
91
-
92
- else:
93
- question = get_standalone_question(msg, message_history, prompt_q)
94
- print(question)
95
- context = get_context(question)
96
- print(context)
97
- answer = get_answer(context, message_history, question, prompt_m)
98
-
99
- message_history.append({'role': 'assistant', 'content': answer})
100
- chat_history.append([msg, answer])
101
-
102
- return "", chat_history, message_history
103
-
104
-
105
- def start_chat(chat_history: list[list[str | None]], prompt_m: str):
106
- greeting = ('Hola 👋, ¡estoy encantada de conversar contigo! Antes de empezar, quiero asegurarte algo '
107
- 'importante: tu privacidad y confidencialidad son mi máxima prioridad. Puedes estar '
108
- 'tranquila sabiendo que nuestras conversaciones son completamente seguras y nunca '
109
- 'serán compartidas con terceros. ¿En qué puedo ayudarte hoy?')
110
-
111
- message_history = [
112
- {'role': 'system', 'content': prompt_m},
113
- {'role': 'assistant', 'content': greeting}
114
- ]
115
-
116
- chat_history.append(['', greeting])
117
-
118
- return message_history, chat_history, gr.Button(visible=False), gr.Text(visible=True)
119
-
120
-
121
- with gr.Blocks() as app:
122
- prompt_questions = gr.State(init_prompt('questions'))
123
- prompt_main = gr.State(init_prompt('main'))
124
- msg_history = gr.State([])
125
-
126
- chatbot = gr.Chatbot(label='Bella Nosotras')
127
- start_button = gr.Button()
128
- message = gr.Textbox(visible=False)
129
 
130
- start_button.click(
131
- start_chat,
132
- [chatbot, prompt_main],
133
- [msg_history, chatbot, start_button, message]
134
  )
135
 
136
- message.submit(
137
- ask_query,
138
- [message, chatbot, msg_history, prompt_questions, prompt_main],
139
- [message, chatbot, msg_history]
140
  )
141
 
142
 
143
- app.launch(debug=True, auth=(os.environ.get("SPACE_USERNAME"), os.environ.get("SPACE_PASSWORD")))
 
 
1
+ from functions import *
 
 
 
2
  from dotenv import load_dotenv
3
 
4
  load_dotenv()
5
 
 
 
 
6
 
7
+ with (gr.Blocks() as app):
8
+ user_id = gr.State('') # id used to find the chat into the database
9
+
10
+ with gr.Tab('Test Chats'):
11
+ with gr.Row() as select_author:
12
+ chat_btn = gr.Button(value='Start chat')
13
+
14
+ # ------------------------------------- Chat -------------------------------------------
15
+ with gr.Row(visible=False) as chatbot:
16
+ with gr.Column():
17
+ with gr.Row():
18
+ video = gr.Video(interactive=False, label='Video', autoplay=True)
19
+ with gr.Row():
20
+ output_audio = gr.Audio(interactive=False, label='Audio', autoplay=True)
21
+ with gr.Row():
22
+ checkbox_video = gr.Checkbox(
23
+ label='Get video', info='Remember that this has a cost'
24
+ )
25
+ checkbox_audio = gr.Checkbox(
26
+ label='Get only audio', info='This is free but makes API slower'
27
+ )
28
+ radio = gr.Radio(
29
+ choices=['local', 'remote'], value='remote', label='Backend used', visible=False
30
+ )
31
+
32
+ with gr.Column():
33
+ with gr.Row():
34
+ chat = gr.Chatbot(label='Chat')
35
+ with gr.Row():
36
+ with gr.Column():
37
+ text = gr.Text(label='Write your question')
38
+ with gr.Column():
39
+ audio = gr.Audio(sources=['microphone'], type='filepath', label='Tell me your question')
40
+ button_audio = gr.Button(value='Submit audio')
41
+
42
+ # -------------------------------------- Actions -----------------------------------------
43
+ chat_btn.click(
44
+ make_invisible, None, select_author
45
+ ).then(
46
+ make_visible, None, chatbot
47
+ ).then(
48
+ init_chatbot, [chat, radio], [video, chat, user_id]
49
  )
 
 
50
 
51
+ text.submit(
52
+ get_answer_text,
53
+ [text, chat, user_id, checkbox_video, checkbox_audio, radio],
54
+ [video, output_audio, chat, text]
 
55
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
+ button_audio.click(
58
+ get_answer_audio,
59
+ [audio, chat, user_id, checkbox_video, checkbox_audio, radio],
60
+ [video, output_audio, chat, audio]
61
  )
62
 
63
+ output_audio.stop(
64
+ lambda: None, None, output_audio
 
 
65
  )
66
 
67
 
68
+ app.queue()
69
+ app.launch(debug=True, auth=(os.environ.get('SPACE_USERNAME'), os.environ.get('SPACE_PASSWORD')))
functions.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import base64
3
+ import shutil
4
+ import requests
5
+ import gradio as gr
6
+ from datetime import datetime
7
+
8
+
9
+ def make_invisible():
10
+ """
11
+ Makes visible a row
12
+ """
13
+ return gr.Row.update(visible=False)
14
+
15
+
16
+ def make_visible():
17
+ """
18
+ Makes visibles a rows
19
+ """
20
+ return gr.Row.update(visible=True)
21
+
22
+
23
+ def _query(payload, backend_location: str, type_query: str):
24
+ """
25
+ Returns the json from a post request. It is done to the BellaAPI
26
+ """
27
+ API_TOKEN = os.getenv(f'API_TOKEN')
28
+ API_URL = os.getenv(f'API_URL_{backend_location}') + f'{type_query}/'
29
+
30
+ headers = {
31
+ "Authorization": f"Bearer {API_TOKEN}",
32
+ "Content-Type": "application/json"
33
+ }
34
+
35
+ response = requests.post(API_URL, headers=headers, json=payload)
36
+ return response.json()
37
+
38
+
39
+ def _download_media(url: str, type_media: str) -> None:
40
+ """
41
+ Downloads a video or audio (depending on the type_media) that can be
42
+ used inside a gr.Video or gr.Audio
43
+ """
44
+ name = 'video.mp4' if type_media == 'video' else 'audio.wav'
45
+ with requests.get(url, stream=True) as r, open(name, "wb") as f:
46
+ shutil.copyfileobj(r.raw, f)
47
+
48
+
49
+ def init_chatbot(chatbot: list[tuple[str, str]], backend_location: str):
50
+ """
51
+ Returns a greeting video, with its transcription and the user_id that
52
+ will be used later in the other requests
53
+ """
54
+ l = 'es'
55
+
56
+ # Call API with the following json
57
+ inputs = {
58
+ "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
59
+ 'language': l,
60
+ 'get_video': True
61
+ }
62
+ output = _query(inputs, backend_location, 'start_chat')
63
+
64
+ chatbot.append(('', output['answer']))
65
+ _download_media(output['link_media'], 'video')
66
+
67
+ return 'video.mp4', chatbot, output['user_id']
68
+
69
+
70
+ def get_answer_text(
71
+ question: str, chatbot: list[tuple[str, str]], user_id: str, checkbox_video: bool, checkbox_audio: bool,
72
+ backend_location: str
73
+ ):
74
+ """
75
+ Gets the answer of the chatbot
76
+ """
77
+
78
+ # Create json and send it to the API
79
+ inputs = {
80
+ 'text': question, 'user_id': user_id, 'get_video': checkbox_video, 'get_audio': checkbox_audio,
81
+ }
82
+ output = _query(inputs, backend_location, 'get_answer')
83
+ return _update_elements(question, chatbot, output, checkbox_video, checkbox_audio, '')
84
+
85
+
86
+ def get_answer_audio(
87
+ audio_path, chatbot: list[tuple[str, str]], user_id: str, checkbox_video: bool, checkbox_audio: bool,
88
+ backend_location: str
89
+ ):
90
+ """
91
+ Gets the answer of the chatbot
92
+ """
93
+ # Encode audio data to Base64
94
+ with open(audio_path, 'rb') as audio_file:
95
+ audio_data = audio_file.read()
96
+ encoded_audio = base64.b64encode(audio_data).decode('utf-8')
97
+
98
+ # Create json and send it to the API
99
+ inputs = {
100
+ 'is_audio': True, 'audio': encoded_audio, 'user_id': user_id, 'get_video': checkbox_video,
101
+ 'get_audio': checkbox_audio
102
+ }
103
+ output = _query(inputs, backend_location, 'get_answer')
104
+
105
+ # Transcription of the audio
106
+ question = output['question']
107
+ return _update_elements(question, chatbot, output, checkbox_video, checkbox_audio, None)
108
+
109
+
110
+ def _update_elements(question, chatbot, output, checkbox_video, checkbox_audio, clean):
111
+ """
112
+ Adds the video, output audio, interaction and cleans the text or audio
113
+ """
114
+ chatbot.append((question, output['answer']))
115
+ link_media = output['link_media']
116
+ if checkbox_video:
117
+ _download_media(link_media, 'video')
118
+ return 'video.mp4', None, chatbot, clean
119
+ elif checkbox_audio:
120
+ _download_media(link_media, 'audio')
121
+ return None, 'audio.wav', chatbot, clean
122
+ else:
123
+ return None, None, chatbot, clean
prompts/main_prompt.txt DELETED
@@ -1,27 +0,0 @@
1
- Tu eres Bella es una mujer de 32 años, amigable, sensible y comprensiva. Eres una confidente que entiende todo lo relacionado con el tema de la menstruación y la higiene íntima de la marca Nosotras, también comprendes las emociones de las mujeres durante la menstruación y el ciclo menstrual. Eres la amiga que necesita cualquier mujer para ser escuchada y validada en cualquier momento de tu ciclo menstrual, y a la que le consultan sobre productos de higiene menstrual e íntima de la marca Nosotras, cuáles son los mejores y se adecuan a sus necesidades.
2
-
3
- Tono de Comunicación: Tu tono debe ser amigable, empático y sensible. Debes comunicarte de manera natural y fácil de entender. Usa palabras simples y un lenguaje que se sienta cercano. Además, no repites información dada anteriormente.
4
- Objetivo de Bella: Tu objetivo es brindar información y apoyo relacionado con productos de higiene menstrual e higiene íntima, recomendando productos específicos de la marca Nosotras.
5
-
6
- Si te preguntan sobre situaciones donde se requiera asesoramiento médico o psicológico e invita a la usuaria a visitar el consultorio virtual de Nosotras: https://www.nosotrasonline.com.co/entre-nosotras/consultorios/ . Evita dar consejos o información relacionados con prácticas médicas, remite a profesionales de la salud.
7
-
8
- Instrucciones para tener cualquier conversación. Debes hacer siempre lo siguiente:
9
-
10
- Describe los diferentes tipos de productos de higiene menstrual disponibles hablando de sus materiales, beneficios, para qué sirven y en qué tiendas comprarlos según la información de www.nosotrasonline.com.co . Explica todo máximo en 5 frases.
11
- Pregunta a las usuarias sobre sus alergias o sensibilidades relacionadas con ciertos materiales y evita recomendarles productos que contengan dichos materiales cuando te digan que son alérgicas a ellos.
12
- Promueve el respeto a la autonomía y decisiones individuales de las usuarias.
13
- Muéstrate sensible a la diversidad de experiencias y circunstancias de las usuarias.
14
-
15
- Estos son algunos ejemplos de los usuarios que tendrías:
16
-
17
- Soy una mujer adolescente entre los 12 y los 18 que menstrua por primera vez, tengo muchas dudas sobre qué productos usar y preguntas sobre la menstruación y el ciclo menstrual.
18
- Soy una mujer entre los 18 y los 40 años que lleva un tiempo menstruando, quiere mejorar mi calidad de vida con productos cómodos y que me protejan de manchas en cualquier momento del día. También tengo preguntas y dudas relacionadas con mitos o tabúes que quiero desvirtuar o cambios en mi ciclo menstrual.
19
- Soy una mujer entre los 40 y 55 años que está cerca de la menopausia o está pasando por una, y tengo dudas sobre qué productos de higiene menstrual e íntima debería comenzar a usar, además de preguntas relacionadas con los diferentes cambios que vienen con la menopausia.
20
-
21
-
22
- Para responder las preguntas, utiliza la siguiente información. Si la informacion dada no es suficiente, no inventes información y dile al usuario que visite esta página: https://www.nosotrasonline.com.co/
23
-
24
- =========
25
- Contexto:
26
- CONTEXT
27
- =========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
prompts/standalone_question.txt DELETED
@@ -1,6 +0,0 @@
1
- Your goal is to rephrase questions related to the brand Nosotras (which is a brand for feminine hygiene products) to show what is the best advice for the customer. Given the following conversation and a follow up question, rephrase the follow up question to be a standalone phrase where you show the best recommendation for the customer. Always include all the important information, specially all name of the nouns and the intention of the customer. For example, if the user says "Me siento incomoda con las toallas gruesas, cual me recomiendas?" The standalone phrase should me something like "necesito toallas menos gruesas y más cómodas". There might be moments when there isn't a question in those cases return a standalone phrase: for example if the user says "hello" (or something similar) then the output would be "the user wants to say hello", or if the user says "thank you" (or something similar) then it would be "the user is saying thank you", or if the user says "great", "it is very helpfully" (or something similar) then it would be "user thinks the recommendation is great". Your answer will always be in spanish.
2
- Chat History:
3
-
4
- HISTORY
5
- Follow-up Input: QUESTION
6
- Standalone question: