-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Use the official Python base image | ||
FROM python:3.11-slim | ||
|
||
# Set the working directory in the container | ||
WORKDIR /app | ||
|
||
# Expose port 8080 for running the website | ||
EXPOSE 8080 | ||
|
||
# Copy the required files | ||
COPY app.py footer.py requirements.txt robots.txt sitemap.xml ./ | ||
COPY assets assets | ||
COPY callbacks callbacks | ||
COPY pages pages | ||
|
||
# Create a virtual environment and activate it | ||
RUN python -m venv venv | ||
ENV PATH="/app/venv/bin:$PATH" | ||
|
||
RUN pip3 install --no-cache-dir -r requirements.txt | ||
|
||
# Specify the command to run the app | ||
CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0", "--port=8080"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import dash_bootstrap_components as dbc | ||
from dash import Dash, html, page_container | ||
from flask import send_from_directory | ||
|
||
from footer import footer | ||
|
||
app = Dash( | ||
__name__, | ||
use_pages=True, | ||
pages_folder="pages", | ||
external_stylesheets=[dbc.icons.BOOTSTRAP, dbc.themes.BOOTSTRAP], | ||
) | ||
app.config.suppress_callback_exceptions = True | ||
server = app.server | ||
|
||
|
||
@server.route("/robots.txt") | ||
def serve_robots(): | ||
return send_from_directory(".", "robots.txt", mimetype="text/plain") | ||
|
||
|
||
@server.route("/sitemap.xml") | ||
def serve_sitemap(): | ||
return send_from_directory(".", "sitemap.xml", mimetype="application/xml") | ||
|
||
|
||
app.index_string = """<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<!-- Global site tag (gtag.js) - Google Analytics --> | ||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-THNE3MSS49"></script> | ||
<script> | ||
window.dataLayer = window.dataLayer || []; | ||
function gtag(){dataLayer.push(arguments);} | ||
gtag('js', new Date()); | ||
gtag('config', 'G-THNE3MSS49'); | ||
</script> | ||
{%metas%} | ||
<title>{%title%}</title> | ||
{%favicon%} | ||
{%css%} | ||
</head> | ||
<body> | ||
{%app_entry%} | ||
<footer> | ||
{%config%} | ||
{%scripts%} | ||
{%renderer%} | ||
</footer> | ||
</body> | ||
</html>""" | ||
|
||
app.layout = html.Div( | ||
[ | ||
html.Div( | ||
className="container", | ||
children=[ | ||
page_container, | ||
footer, | ||
], | ||
) | ||
] | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
app.run_server(debug=True, port=8080) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
html { | ||
margin: 0px; | ||
} | ||
body { | ||
font-family: Georgia, 'Times New Roman', Times, serif; | ||
} | ||
#button-play-audio { | ||
cursor: pointer; | ||
} | ||
.button-play-audio-wrapper { | ||
clear: both; | ||
font-size: 22px; | ||
margin-left: 10px; | ||
} | ||
#button-start-conversation { | ||
background-color: #0061F3; | ||
color: white; | ||
} | ||
#button-start-conversation:hover { | ||
background-color: #003d9b; | ||
} | ||
.container { | ||
margin: 0px; | ||
min-width: 100%; | ||
padding: 0px; | ||
} | ||
#content { | ||
margin: auto; | ||
max-width: 600px; | ||
min-height: 470px; | ||
padding: 0px 20px; | ||
} | ||
#conversation { | ||
display: block; | ||
min-height: fit-content; | ||
min-width: 100%; | ||
} | ||
#conversation-id { | ||
height: 10px; | ||
min-width: 100%; | ||
} | ||
.conversation-setting-custom-input { | ||
padding: 10px 0px; | ||
} | ||
#conversation-setting-custom::placeholder { | ||
color: #aaa; | ||
} | ||
.conversation-setting-menu { | ||
padding: 10px 0px 0px; | ||
} | ||
.conversation-setting-wrapper { | ||
min-width: 100%; | ||
} | ||
#header { | ||
background-color: #003d9b; | ||
color: white; | ||
margin-bottom: 40px; | ||
padding: 10px 10px; | ||
text-align: center; | ||
} | ||
#help-highlight-for-translation { | ||
color: #aaa; | ||
font-size: 13px; | ||
font-style: italic; | ||
margin: 10px 0px -15px; | ||
width: fit-content; | ||
} | ||
.languages { | ||
display: flex; | ||
min-width: 100%; | ||
} | ||
#language-menu-known { | ||
min-width: 50%; | ||
padding-right: 10px; | ||
} | ||
#language-menu-learn { | ||
min-width: 50%; | ||
padding-left: 10px; | ||
} | ||
#loading { | ||
align-items: center; | ||
justify-content: center; | ||
margin: 20px auto; | ||
} | ||
.loading-icon { | ||
margin: 10px; | ||
} | ||
.message-ai-wrapper { | ||
align-items: center; | ||
display: flex; | ||
margin: 15px 0px; | ||
width: 100%; | ||
} | ||
.message-ai { | ||
border: 1px solid #87b7ff; | ||
border-radius: 0px 4px 4px 4px; | ||
clear: both; | ||
color: black; | ||
float: left; | ||
max-width: 75%; | ||
padding: 5px 10px; | ||
width: fit-content; | ||
} | ||
.message-user { | ||
background-color: #87b7ff; | ||
border-radius: 4px 0px 4px 4px; | ||
clear: both; | ||
padding: 5px 10px; | ||
width: fit-content; | ||
} | ||
.message-user-wrapper { | ||
display: flex; | ||
justify-content: flex-end; | ||
margin: 15px 0px; | ||
width: 100%; | ||
} | ||
#toggle-play-audio-text { | ||
color: #aaa; | ||
font-size: 14px; | ||
font-style: italic; | ||
margin-right: 10px; | ||
padding-top: 2px; | ||
} | ||
#toggle-play-audio-wrapper { | ||
display: flex; | ||
} | ||
#translation { | ||
clear: both; | ||
display: block; | ||
font-style: italic; | ||
width: 100%; | ||
} | ||
#title { | ||
margin: 0px; | ||
} | ||
#user-input { | ||
margin: 0px 0px 30px; | ||
width: 100%; | ||
} | ||
#user-input.form-control { | ||
border: 1px solid rgba(7, 76, 179, 0.9); | ||
} | ||
#user-input::placeholder { | ||
color: #aaa; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import base64 | ||
|
||
from gtts import gTTS | ||
|
||
|
||
def get_audio_file(text: str, language: str) -> str: | ||
""" | ||
Create and return an mp3 file that contains the audio | ||
for a message to be played in the desired language's accent. | ||
Params: | ||
text: The text for the audio | ||
language: The language for the accent of the audio | ||
Returns: | ||
A path to the mp3 file | ||
""" | ||
|
||
# Perform text-to-speech conversion | ||
tts = gTTS(text, lang=language) | ||
audio_path = "temp_audio.mp3" | ||
tts.save(audio_path) | ||
|
||
# Read and encode the audio file | ||
with open(audio_path, "rb") as audio_file: | ||
audio_data = audio_file.read() | ||
audio_base64 = base64.b64encode(audio_data).decode("utf-8") | ||
audio_src = f"data:audio/mpeg;base64,{audio_base64}" | ||
|
||
return audio_src |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import os | ||
import re | ||
|
||
import openai | ||
import requests | ||
from tenacity import retry, stop_after_attempt, wait_random_exponential | ||
|
||
openai.api_key = os.environ.get("OPENAI_KEY") | ||
|
||
|
||
def get_assistant_message(messages): | ||
|
||
chat_response = chat_completion_request(messages) | ||
message_assistant = chat_response.json()["choices"][0]["message"]["content"] | ||
|
||
# Remove space before "!" or "?" | ||
message_assistant = re.sub(r"\s+([!?])", r"\1", message_assistant) | ||
|
||
return message_assistant | ||
|
||
|
||
@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3)) | ||
def chat_completion_request(messages, model="gpt-3.5-turbo-0613"): | ||
headers = { | ||
"Content-Type": "application/json", | ||
"Authorization": "Bearer " + openai.api_key, | ||
} | ||
json_data = {"model": model, "messages": messages, "temperature": 1.5} | ||
try: | ||
response = requests.post( | ||
"https://api.openai.com/v1/chat/completions", | ||
headers=headers, | ||
json=json_data, | ||
) | ||
return response | ||
except Exception as e: | ||
print("Unable to generate ChatCompletion response") | ||
print(f"Exception: {e}") | ||
return e | ||
|
||
|
||
def system_content( | ||
language_learn, language_known, setting, point_in_conversation="Start" | ||
): | ||
|
||
content = f"{point_in_conversation} a conversation about {setting} in {language_learn}. \ | ||
Provide one statement in {language_learn}, then wait for my response. \ | ||
Do not write in {language_known}. \ | ||
Always finish your response with a question. \ | ||
Example response: Bonjour, qu'est-ce que je peux vous servir aujourd'hui?" | ||
|
||
content = re.sub(r"\s+", " ", content) | ||
|
||
return content |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#buy-me-a-coffee-logo { | ||
max-width: 100px; | ||
} | ||
#email { | ||
font-size: 14px; | ||
text-align: center; | ||
} | ||
#footer { | ||
border-top: 1px solid #cccccc; | ||
display: flex; | ||
justify-content: center; | ||
margin: 20px auto 0px; | ||
width: 100%; | ||
} | ||
#footer a { | ||
margin: 23px 15px 10px; | ||
} | ||
#footer p { | ||
margin: 25px 15px 10px; | ||
} | ||
.footer-pipe { | ||
color: #cccccc; | ||
margin-top: 25px; | ||
} | ||
@media (max-width: 800px) { | ||
#footer { | ||
display: block; | ||
padding: 20px; | ||
} | ||
#footer a, #footer p { | ||
display: block; | ||
margin: 0px auto 5px; | ||
} | ||
.footer-pipe { | ||
display: none; | ||
} | ||
} |
Oops, something went wrong.