add locales
This commit is contained in:
parent
dc335dd789
commit
07ebe8b291
@ -29,6 +29,11 @@ repos:
|
||||
- id: requirements-txt-fixer
|
||||
- id: debug-statements
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||
rev: v0.0.254
|
||||
hooks:
|
||||
|
84
chat.py
84
chat.py
@ -1,10 +1,9 @@
|
||||
from openai.error import OpenAIError
|
||||
from streamlit_option_menu import option_menu
|
||||
from pathlib import Path
|
||||
|
||||
from src.utils.ai import ai_settings, send_ai_request
|
||||
from src.utils.tts import show_player
|
||||
from src.utils.lang import en, ru
|
||||
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
|
||||
|
||||
@ -17,6 +16,11 @@ icons_dir = assets_dir / "icons"
|
||||
# --- GENERAL SETTINGS ---
|
||||
PAGE_TITLE = "AI Talks"
|
||||
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)
|
||||
|
||||
@ -24,8 +28,38 @@ st.set_page_config(page_title=PAGE_TITLE, page_icon=PAGE_ICON)
|
||||
with open(css_file) as f:
|
||||
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)
|
||||
st.markdown("---")
|
||||
selected_lang = option_menu(
|
||||
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
|
||||
if "generated" not in st.session_state:
|
||||
@ -40,34 +74,28 @@ if "user_text" not in st.session_state:
|
||||
|
||||
def main() -> None:
|
||||
user_content = get_user_input()
|
||||
b1, b2 = st.columns(2)
|
||||
with b1, b2:
|
||||
b1.button("Rerun", on_click=st.cache_data.clear)
|
||||
b2.button("Clear Conversation", on_click=clear_chat)
|
||||
show_chat_buttons()
|
||||
|
||||
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 st.session_state["messages"]:
|
||||
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)
|
||||
show_conversation(user_content, model, role)
|
||||
|
||||
|
||||
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()
|
||||
st.markdown("---")
|
||||
st.image("assets/ai.jpg")
|
||||
|
@ -2,8 +2,8 @@
|
||||
line-length = 120
|
||||
|
||||
# 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" ]
|
||||
ignore = ["N806", "S101", "A003", "N815", "S104"]
|
||||
select = ["E", "F", "U", "N", "S", "C", "B", "A", "Q", "A", "YTT", "RUF", "RUF100", "W", "I", ]
|
||||
ignore = ["N806", "S101", "A003", "N815", "S104", "UP006", "RUF001"]
|
||||
|
||||
# Exclude a variety of commonly ignored directories.
|
||||
exclude = [".bzr",
|
||||
|
@ -1,5 +1,6 @@
|
||||
streamlit==1.20.0
|
||||
streamlit-chat==0.0.2.2
|
||||
streamlit_option_menu==0.3.2
|
||||
openai==0.27.2
|
||||
gtts==2.3.1
|
||||
pip==23.0.1
|
||||
|
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
0
src/utils/__init__.py
Normal file
0
src/utils/__init__.py
Normal 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
|
19
src/utils/ai_interaction.py
Normal file
19
src/utils/ai_interaction.py
Normal 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
|
@ -1,6 +1,10 @@
|
||||
import streamlit as st
|
||||
from openai.error import OpenAIError
|
||||
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:
|
||||
st.session_state["generated"] = []
|
||||
@ -10,11 +14,18 @@ def clear_chat() -> None:
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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:
|
||||
# store the ai content
|
||||
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))
|
||||
st.markdown(st.session_state["generated"][i])
|
||||
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)
|
||||
|
@ -3,12 +3,12 @@ import streamlit as st
|
||||
|
||||
def show_donates() -> None:
|
||||
st.markdown("---")
|
||||
st.markdown("""
|
||||
### :moneybag: Donates
|
||||
**Russia:**
|
||||
st.markdown(f"""
|
||||
### :moneybag: {st.session_state.locale.donates}
|
||||
**{st.session_state.locale.donates1}:**
|
||||
- [CloudTips (Tinkoff)](https://pay.cloudtips.ru/p/eafa15b2)
|
||||
|
||||
**World:**
|
||||
**{st.session_state.locale.donates2}:**
|
||||
- [Buy Me A Coffee](https://www.buymeacoffee.com/aitalks)
|
||||
- [ko-fi](https://ko-fi.com/ai_talks)
|
||||
- [PayPal](https://www.paypal.com/paypalme/aitalks)
|
||||
|
94
src/utils/lang.py
Normal file
94
src/utils/lang.py
Normal 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)
|
@ -1,53 +1,15 @@
|
||||
from typing import Any, Dict, Optional
|
||||
from gtts import gTTS, gTTSError, lang
|
||||
from io import BytesIO
|
||||
|
||||
import streamlit as st
|
||||
|
||||
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)
|
||||
from gtts import gTTS, gTTSError
|
||||
|
||||
|
||||
def show_player(ai_content: str) -> None:
|
||||
sound_file = BytesIO()
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
lang_code = lang_selector()
|
||||
with col2:
|
||||
is_speech_slow = speech_speed_radio()
|
||||
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)
|
||||
st.write("To Hear The Voice Of AI, Press Play.")
|
||||
st.write(st.session_state.locale.stt_placeholder)
|
||||
st.audio(sound_file)
|
||||
except gTTSError as err:
|
||||
st.error(err)
|
||||
|
Loading…
Reference in New Issue
Block a user