Skip to content

Commit

Permalink
Create v1 (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
Currie32 authored Aug 16, 2023
1 parent 36b276d commit 5ee528d
Show file tree
Hide file tree
Showing 20 changed files with 1,124 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,8 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Custom
.DS_Store
*.ipynb
temp_audio.mp3
23 changes: 23 additions & 0 deletions Dockerfile
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"]
68 changes: 68 additions & 0 deletions app.py
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)
145 changes: 145 additions & 0 deletions assets/app.css
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;
}
30 changes: 30 additions & 0 deletions assets/audio.py
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
Binary file added assets/buyMeACoffee.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions assets/chat_request.py
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 added assets/favicon.ico
Binary file not shown.
37 changes: 37 additions & 0 deletions assets/footer.css
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;
}
}
Loading

0 comments on commit 5ee528d

Please sign in to comment.