add locales

This commit is contained in:
if 2023-03-22 19:13:02 +03:00
parent dc335dd789
commit 07ebe8b291
12 changed files with 217 additions and 117 deletions

View File

@ -29,6 +29,11 @@ repos:
- id: requirements-txt-fixer - id: requirements-txt-fixer
- id: debug-statements - id: debug-statements
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/charliermarsh/ruff-pre-commit - repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.254 rev: v0.0.254
hooks: hooks:

84
chat.py
View File

@ -1,10 +1,9 @@
from openai.error import OpenAIError from streamlit_option_menu import option_menu
from pathlib import Path from pathlib import Path
from src.utils.ai import ai_settings, send_ai_request from src.utils.lang import en, ru
from src.utils.tts import show_player
from src.utils.donates import show_donates from src.utils.donates import show_donates
from src.utils.conversation import get_user_input, clear_chat, show_conversation from src.utils.conversation import get_user_input, show_chat_buttons, show_conversation
import streamlit as st import streamlit as st
@ -17,6 +16,11 @@ icons_dir = assets_dir / "icons"
# --- GENERAL SETTINGS --- # --- GENERAL SETTINGS ---
PAGE_TITLE = "AI Talks" PAGE_TITLE = "AI Talks"
PAGE_ICON = "🤖" PAGE_ICON = "🤖"
AI_MODEL_OPTIONS = [
"gpt-3.5-turbo",
"gpt-4",
"gpt-4-32k",
]
st.set_page_config(page_title=PAGE_TITLE, page_icon=PAGE_ICON) st.set_page_config(page_title=PAGE_TITLE, page_icon=PAGE_ICON)
@ -24,8 +28,38 @@ st.set_page_config(page_title=PAGE_TITLE, page_icon=PAGE_ICON)
with open(css_file) as f: with open(css_file) as f:
st.markdown("<style>{}</style>".format(f.read()), unsafe_allow_html=True) st.markdown("<style>{}</style>".format(f.read()), unsafe_allow_html=True)
st.markdown(f"<h1 style='text-align: center;'>{PAGE_TITLE}</h1>", unsafe_allow_html=True) selected_lang = option_menu(
st.markdown("---") menu_title=None,
options=["En", "Ru", ],
icons=["flag_en", "flag_ru"],
menu_icon="cast",
default_index=0,
orientation="horizontal",
styles={
"container": {"padding": "0px",
"display": "grid",
"margin": "0!important",
"background-color": "#23212c"
},
"icon": {"color": "#8bff80", "font-size": "14px"},
"nav-link": {
"font-size": "14px",
"text-align": "center",
"margin": "auto",
"background-color": "#23212c",
"height": "30px",
"width": "13rem",
"color": "#7970a9",
"border-radius": "5px"
},
"nav-link-selected": {
"background-color": "#454158",
"font-weight": "300",
"color": "#f7f8f2",
"border": "1px solid #fe80bf"
}
}
)
# Storing The Context # Storing The Context
if "generated" not in st.session_state: if "generated" not in st.session_state:
@ -40,34 +74,28 @@ if "user_text" not in st.session_state:
def main() -> None: def main() -> None:
user_content = get_user_input() user_content = get_user_input()
b1, b2 = st.columns(2) show_chat_buttons()
with b1, b2:
b1.button("Rerun", on_click=st.cache_data.clear)
b2.button("Clear Conversation", on_click=clear_chat)
model, role = ai_settings() c1, c2 = st.columns(2)
with c1, c2:
model = c1.selectbox(label=st.session_state.locale.select_placeholder1, options=AI_MODEL_OPTIONS)
role = c2.selectbox(label=st.session_state.locale.select_placeholder2,
options=st.session_state.locale.ai_role_options)
if user_content: if user_content:
if st.session_state["messages"]: show_conversation(user_content, model, role)
st.session_state["messages"].append({"role": "user", "content": user_content})
else:
st.session_state["messages"] = [
{"role": "system", "content": f"You are a {role}."},
{"role": "user", "content": user_content},
]
try:
completion = send_ai_request(model, st.session_state["messages"])
ai_content = completion.get("choices")[0].get("message").get("content")
st.session_state["messages"].append({"role": "assistant", "content": ai_content})
if ai_content:
show_conversation(ai_content, user_content)
st.markdown("---")
show_player(ai_content)
except (OpenAIError, UnboundLocalError) as err:
st.error(err)
if __name__ == "__main__": if __name__ == "__main__":
match selected_lang:
case "En":
st.session_state.locale = en
case "Ru":
st.session_state.locale = ru
case _:
locale = en
st.markdown(f"<h1 style='text-align: center;'>{st.session_state.locale.title}</h1>", unsafe_allow_html=True)
st.markdown("---")
main() main()
st.markdown("---") st.markdown("---")
st.image("assets/ai.jpg") st.image("assets/ai.jpg")

View File

@ -2,8 +2,8 @@
line-length = 120 line-length = 120
# Enable Flake's "E" and "F" codes by default. # Enable Flake's "E" and "F" codes by default.
select = ["E", "F", "U", "N", "S", "C", "B", "A", "Q", "A", "YTT", "RUF", "M", "W", "I" ] select = ["E", "F", "U", "N", "S", "C", "B", "A", "Q", "A", "YTT", "RUF", "RUF100", "W", "I", ]
ignore = ["N806", "S101", "A003", "N815", "S104"] ignore = ["N806", "S101", "A003", "N815", "S104", "UP006", "RUF001"]
# Exclude a variety of commonly ignored directories. # Exclude a variety of commonly ignored directories.
exclude = [".bzr", exclude = [".bzr",

View File

@ -1,5 +1,6 @@
streamlit==1.20.0 streamlit==1.20.0
streamlit-chat==0.0.2.2 streamlit-chat==0.0.2.2
streamlit_option_menu==0.3.2
openai==0.27.2 openai==0.27.2
gtts==2.3.1 gtts==2.3.1
pip==23.0.1 pip==23.0.1

0
src/__init__.py Normal file
View File

0
src/utils/__init__.py Normal file
View File

View File

@ -1,40 +0,0 @@
from typing import List, Dict, Tuple
import streamlit as st
import openai
AI_MODEL_OPTIONS = [
"gpt-3.5-turbo",
"gpt-4",
"gpt-4-32k",
]
AI_ROLE_OPTIONS = [
"helpful assistant",
"code assistant",
"code reviewer",
"text improver",
"cinema expert",
"sport expert",
"online games expert",
"food recipes expert",
"English grammar expert",
]
def ai_settings() -> Tuple[str, str]:
c1, c2 = st.columns(2)
with c1, c2:
model = c1.selectbox(label="Select AI Model", options=AI_MODEL_OPTIONS)
role = c2.selectbox(label="Select AI Role", options=AI_ROLE_OPTIONS)
return model, role
@st.cache_data()
def send_ai_request(ai_model: str, messages: List[Dict]) -> Dict:
openai.api_key = st.secrets.api_credentials.api_key
completion = openai.ChatCompletion.create(
model=ai_model,
messages=messages,
)
return completion

View File

@ -0,0 +1,19 @@
from typing import List
import openai
import streamlit as st
@st.cache_data()
def send_ai_request(ai_model: str, messages: List[dict]) -> dict:
openai.api_key = st.secrets.api_credentials.api_key
import logging
logging.warning("messages:")
logging.warning(messages)
completion = openai.ChatCompletion.create(
model=ai_model,
messages=messages,
)
logging.warning("completion:")
logging.warning(completion)
return completion

View File

@ -1,6 +1,10 @@
import streamlit as st import streamlit as st
from openai.error import OpenAIError
from streamlit_chat import message from streamlit_chat import message
from src.utils.ai_interaction import send_ai_request
from src.utils.tts import show_player
def clear_chat() -> None: def clear_chat() -> None:
st.session_state["generated"] = [] st.session_state["generated"] = []
@ -10,11 +14,18 @@ def clear_chat() -> None:
def get_user_input() -> str: def get_user_input() -> str:
user_text = st.text_area(label="Start Your Conversation With AI:", key="user_text") user_text = st.text_area(label=st.session_state.locale.chat_placeholder, key="user_text")
return user_text return user_text
def show_conversation(ai_content: str, user_text: str) -> None: def show_chat_buttons() -> None:
b1, b2 = st.columns(2)
with b1, b2:
b1.button(st.session_state.locale.chat_btn1, on_click=st.cache_data.clear)
b2.button(st.session_state.locale.chat_btn2, on_click=clear_chat)
def show_chat(ai_content: str, user_text: str) -> None:
if ai_content not in st.session_state.generated: if ai_content not in st.session_state.generated:
# store the ai content # store the ai content
st.session_state.past.append(user_text) st.session_state.past.append(user_text)
@ -24,3 +35,23 @@ def show_conversation(ai_content: str, user_text: str) -> None:
message("", key=str(i)) message("", key=str(i))
st.markdown(st.session_state["generated"][i]) st.markdown(st.session_state["generated"][i])
message(st.session_state["past"][i], is_user=True, key=str(i) + "_user", avatar_style="micah") message(st.session_state["past"][i], is_user=True, key=str(i) + "_user", avatar_style="micah")
def show_conversation(user_content: str, model: str, role: str) -> None:
if st.session_state["messages"]:
st.session_state["messages"].append({"role": "user", "content": user_content})
else:
st.session_state["messages"] = [
{"role": "system", "content": f"{st.session_state.locale.ai_role_prefix} {role}."},
{"role": "user", "content": user_content},
]
try:
completion = send_ai_request(model, st.session_state["messages"])
ai_content = completion.get("choices")[0].get("message").get("content")
st.session_state["messages"].append({"role": "assistant", "content": ai_content})
if ai_content:
show_chat(ai_content, user_content)
st.markdown("---")
show_player(ai_content)
except (OpenAIError, UnboundLocalError) as err:
st.error(err)

View File

@ -3,12 +3,12 @@ import streamlit as st
def show_donates() -> None: def show_donates() -> None:
st.markdown("---") st.markdown("---")
st.markdown(""" st.markdown(f"""
### :moneybag: Donates ### :moneybag: {st.session_state.locale.donates}
**Russia:** **{st.session_state.locale.donates1}:**
- [CloudTips (Tinkoff)](https://pay.cloudtips.ru/p/eafa15b2) - [CloudTips (Tinkoff)](https://pay.cloudtips.ru/p/eafa15b2)
**World:** **{st.session_state.locale.donates2}:**
- [Buy Me A Coffee](https://www.buymeacoffee.com/aitalks) - [Buy Me A Coffee](https://www.buymeacoffee.com/aitalks)
- [ko-fi](https://ko-fi.com/ai_talks) - [ko-fi](https://ko-fi.com/ai_talks)
- [PayPal](https://www.paypal.com/paypalme/aitalks) - [PayPal](https://www.paypal.com/paypalme/aitalks)

94
src/utils/lang.py Normal file
View File

@ -0,0 +1,94 @@
from dataclasses import dataclass
from typing import List
# Parent data class
@dataclass
class Locale:
ai_role_options: List[str]
ai_role_prefix: str
title: str
language: str
lang_code: str
donates: str
donates1: str
donates2: str
chat_placeholder: str
chat_btn1: str
chat_btn2: str
select_placeholder1: str
select_placeholder2: str
stt_placeholder: str
# Child data class for English
@dataclass
class EnLocale(Locale):
ai_role_prefix: str = "You are a"
title: str = "AI Talks"
language: str = "English"
lang_code: str = "en"
donates: str = "Donates"
donates1: str = "Russia"
donates2: str = "World"
chat_placeholder: str = "Start Your Conversation With AI:"
chat_btn1: str = "Rerun"
chat_btn2: str = "Clear Conversation"
select_placeholder1: str = "Select AI Model"
select_placeholder2: str = "Select AI Role"
stt_placeholder: str = "To Hear The Voice Of AI, Press Play"
# Child data class for Russian
@dataclass
class RuLocale(Locale):
ai_role_prefix: str = "Вы"
title: str = "Разговорчики с ИИ"
language: str = "Russian"
lang_code: str = "ru"
donates: str = "Поддержать Проект"
donates1: str = "Россия"
donates2: str = "Остальной Мир"
chat_placeholder: str = "Начните Вашу Беседу с ИИ:"
chat_btn1: str = "Перезапустить"
chat_btn2: str = "Очистить Беседу"
select_placeholder1: str = "Выберите Модель ИИ"
select_placeholder2: str = "Выберите Роль ИИ"
stt_placeholder: str = "Чтобы Услышать ИИ Нажми Кнопку Проигрывателя"
AI_ROLE_OPTIONS_EN = [
"helpful assistant",
"code assistant",
"code reviewer",
"text improver",
"cinema expert",
"sport expert",
"online games expert",
"food recipes expert",
"English grammar expert",
"friendly and helpful teaching assistant. You explain concepts in great depth using simple terms, and you give examples to help people learn. At the end of each explanation, you ask a question to check for understanding", # NOQA: E501
"laconic assistant. You reply with brief, to-the-point answers with no elaboration",
"helpful, pattern-following assistant",
"helpful, pattern-following assistant that translates corporate jargon into plain English",
]
AI_ROLE_OPTIONS_RU = [
"ассистент, который готов помочь",
"ассистент программиста",
"рецензент кода программиста",
"эксперт по улучшению текста",
"эксперт по кинематографу",
"эксперт в области спорта",
"эксперт в онлайн-играх",
"эксперт по рецептам блюд",
"эксперт по английской грамматике",
"эксперт по русской грамматике",
"дружелюбный и полезный помощник преподавателя. Вы объясняете концепции в подробностях, используя простые термины, и даёте примеры, чтобы помочь людям научиться. В конце каждого объяснения вы задаете вопрос, чтобы проверить понимание", # NOQA: E501
"лаконичный помощник. Вы отвечаете краткими, по существу ответами без лишних слов",
"полезный помощник, следующий шаблонам",
"полезный помощник, следующий шаблонам, который переводит корпоративный жаргон на простой английский",
]
en = EnLocale(ai_role_options=AI_ROLE_OPTIONS_EN)
ru = RuLocale(ai_role_options=AI_ROLE_OPTIONS_RU)

View File

@ -1,53 +1,15 @@
from typing import Any, Dict, Optional
from gtts import gTTS, gTTSError, lang
from io import BytesIO from io import BytesIO
import streamlit as st import streamlit as st
from gtts import gTTS, gTTSError
DEFAULT_SPEECH_LANG = "English"
def get_dict_key(dictionary: Dict, value: Any) -> Optional[Any]:
for key, val in dictionary.items():
if val == value:
return key
def lang_selector() -> str:
languages = lang.tts_langs()
lang_options = list(lang.tts_langs().values())
default_index = lang_options.index(DEFAULT_SPEECH_LANG)
lang_name = st.selectbox(
label="Select Speech Language",
options=lang_options,
index=default_index
)
return get_dict_key(languages, lang_name)
def speech_speed_radio() -> bool:
speed_options = {
"Normal": False,
"Slow": True
}
speed_speech = st.radio(
label="Select Speech Speed",
options=speed_options.keys(),
)
return speed_options.get(speed_speech)
def show_player(ai_content: str) -> None: def show_player(ai_content: str) -> None:
sound_file = BytesIO() sound_file = BytesIO()
col1, col2 = st.columns(2)
with col1:
lang_code = lang_selector()
with col2:
is_speech_slow = speech_speed_radio()
try: try:
tts = gTTS(text=ai_content, lang=lang_code, slow=is_speech_slow) tts = gTTS(text=ai_content, lang=st.session_state.locale.lang_code)
tts.write_to_fp(sound_file) tts.write_to_fp(sound_file)
st.write("To Hear The Voice Of AI, Press Play.") st.write(st.session_state.locale.stt_placeholder)
st.audio(sound_file) st.audio(sound_file)
except gTTSError as err: except gTTSError as err:
st.error(err) st.error(err)