0qwpifs's picture
Update app.py from anycoder
bd94d91 verified
import gradio as gr
import random
import time
from datetime import datetime
from typing import List, Dict, Tuple
# Данные друзей и чатов
friends_data = {
"AlexGamer": {"status": "online", "avatar": "🎮", "last_seen": "Сейчас"},
"ProPlayer": {"status": "online", "avatar": "🏆", "last_seen": "Сейчас"},
"BuilderMaster": {"status": "away", "avatar": "🏗️", "last_seen": "5 мин назад"},
"SpeedRunner": {"status": "offline", "avatar": "⚡", "last_seen": "1 час назад"},
"CreativeMind": {"status": "online", "avatar": "🎨", "last_seen": "Сейчас"},
"TeamLeader": {"status": "online", "avatar": "👑", "last_seen": "Сейчас"},
"NinjaWarrior": {"status": "offline", "avatar": "🥷", "last_seen": "2 часа назад"},
"MysteryPlayer": {"status": "away", "avatar": "🎭", "last_seen": "15 мин назад"}
}
# История чатов
chat_history = {
"AlexGamer": [
{"role": "user", "content": "Привет! Как игра?", "time": "14:30"},
{"role": "friend", "content": "Привет! Отлично, новый рекорд поставил!", "time": "14:31"},
{"role": "user", "content": "Круто! В какую играл?", "time": "14:32"},
{"role": "friend", "content": "Tower of Hell, дошел до 15 уровня", "time": "14:33"}
],
"ProPlayer": [
{"role": "friend", "content": "Готов к турниру сегодня?", "time": "13:45"},
{"role": "user", "content": "Да, жду не дождусь!", "time": "13:50"},
{"role": "friend", "content": "Встречаемся в 7 по серверу", "time": "13:52"}
],
"BuilderMaster": [
{"role": "friend", "content": "Посмотри мой новый мир!", "time": "12:00"},
{"role": "user", "content": "Вау, это потрясающе!", "time": "12:15"}
]
}
def get_status_color(status: str) -> str:
colors = {
"online": "#00ff00",
"away": "#ffaa00",
"offline": "#666666"
}
return colors.get(status, "#666666")
def format_chat_history(history: List[Dict]) -> List[Tuple[str, str]]:
formatted = []
for msg in history:
if msg["role"] == "user":
formatted.append((msg["content"], None))
else:
formatted.append((None, msg["content"]))
return formatted
def send_message(message: str, current_friend: str, history: List[Tuple[str, str]]) -> Tuple[List[Tuple[str, str]], str]:
if not message.strip():
return history, ""
current_time = datetime.now().strftime("%H:%M")
# Добавляем сообщение в историю
if current_friend not in chat_history:
chat_history[current_friend] = []
chat_history[current_friend].append({
"role": "user",
"content": message,
"time": current_time
})
# Форматируем для отображения
new_history = format_chat_history(chat_history[current_friend])
# Симулируем ответ друга
time.sleep(1)
responses = [
"Отлично! 👍",
"Понял, согласен!",
"Круто, давай так!",
"😄 Отличная идея!",
"Обязательно попробую!",
"Спасибо за информацию!",
"Погнали! 🚀",
"Это просто эпик!"
]
bot_response = random.choice(responses)
chat_history[current_friend].append({
"role": "friend",
"content": bot_response,
"time": current_time
})
final_history = format_chat_history(chat_history[current_friend])
return final_history, ""
def select_friend(friend_name: str) -> Tuple[List[Tuple[str, str]], str]:
if friend_name in chat_history:
return format_chat_history(chat_history[friend_name]), f"Чат с {friend_name}"
return [], f"Начните чат с {friend_name}"
def get_friends_list() -> List[Dict]:
friends_list = []
for name, info in friends_data.items():
status_color = get_status_color(info["status"])
friends_list.append({
"name": name,
"status": info["status"],
"avatar": info["avatar"],
"last_seen": info["last_seen"],
"status_color": status_color
})
return friends_list
def create_friends_html() -> str:
friends_html = ""
for name, info in friends_data.items():
status_color = get_status_color(info["status"])
status_icon = "🟢" if info["status"] == "online" else "🟡" if info["status"] == "away" else "🔴"
friends_html += f"""
<div class="friend-item" onclick="selectFriend('{name}')" style="cursor: pointer; padding: 12px; margin: 5px 0; border-radius: 10px; background: rgba(255, 255, 255, 0.05); transition: all 0.3s ease;">
<div style="display: flex; align-items: center; gap: 10px;">
<span style="font-size: 24px;">{info['avatar']}</span>
<div style="flex: 1;">
<div style="display: flex; align-items: center; gap: 5px;">
<span style="color: white; font-weight: bold;">{name}</span>
<span style="color: {status_color}; font-size: 12px;">{status_icon}</span>
</div>
<div style="color: #888; font-size: 12px;">{info['last_seen']}</div>
</div>
</div>
</div>
"""
return friends_html
# CSS для стилизации в стиле Roblox Aero
custom_css = """
/* Основные стили в стиле Roblox Aero */
.gradio-container {
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
color: #ffffff;
font-family: 'Kalam', cursive;
min-height: 100vh;
}
/* Glass эффект для компонентов */
.glass-effect {
background: rgba(20, 20, 20, 0.7) !important;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1) !important;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
/* Стили для чата */
.message-user {
background: linear-gradient(135deg, #ffd700, #ffed4e) !important;
color: #000000 !important;
border-radius: 18px 18px 4px 18px !important;
margin-left: auto !important;
font-weight: bold;
}
.message-friend {
background: rgba(255, 255, 255, 0.1) !important;
color: #ffffff !important;
border-radius: 18px 18px 18px 4px !important;
border: 1px solid rgba(255, 215, 0, 0.3);
}
/* Стили для кнопок */
.btn-primary {
background: linear-gradient(135deg, #ffd700, #ffed4e) !important;
color: #000000 !important;
border: none !important;
border-radius: 20px !important;
font-weight: bold !important;
transition: all 0.3s ease !important;
}
.btn-primary:hover {
transform: translateY(-2px) !important;
box-shadow: 0 6px 30px rgba(255, 215, 0, 0.5) !important;
}
/* Стили для друзей */
.friend-item:hover {
background: rgba(255, 215, 0, 0.1) !important;
border: 1px solid rgba(255, 215, 0, 0.3) !important;
transform: translateX(5px);
}
/* Заголовки */
.chat-header {
background: rgba(20, 20, 20, 0.9) !important;
border-bottom: 2px solid #ffd700 !important;
color: #ffd700 !important;
font-weight: bold !important;
}
/* Анимации */
@keyframes glow {
from { filter: drop-shadow(0 0 20px rgba(255, 215, 0, 0.5)); }
to { filter: drop-shadow(0 0 30px rgba(255, 215, 0, 0.8)); }
}
.glow-text {
animation: glow 2s ease-in-out infinite alternate;
}
/* Поле ввода */
.input-message {
background: rgba(255, 255, 255, 0.1) !important;
border: 1px solid rgba(255, 215, 0, 0.3) !important;
border-radius: 20px !important;
color: #ffffff !important;
}
.input-message::placeholder {
color: rgba(255, 255, 255, 0.5) !important;
}
/* Табы */
.tab-nav {
background: rgba(20, 20, 20, 0.8) !important;
border-bottom: 1px solid rgba(255, 215, 0, 0.3) !important;
}
.tab-nav button {
color: #ffffff !important;
border: none !important;
background: transparent !important;
}
.tab-nav button.selected {
color: #ffd700 !important;
border-bottom: 2px solid #ffd700 !important;
}
"""
# JavaScript для интерактивности
custom_js = """
function selectFriend(friendName) {
// Находим и кликаем на соответствующего друга в интерфейсе
const friendButtons = document.querySelectorAll('[data-testid="radio"]');
friendButtons.forEach(btn => {
if(btn.textContent.includes(friendName)) {
btn.click();
}
});
}
// Добавляем анимацию для новых сообщений
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
const newMessages = mutation.addedNodes;
newMessages.forEach(node => {
if(node.classList && node.classList.contains('message-user')) {
node.style.animation = 'slideInRight 0.3s ease';
} else if(node.classList && node.classList.contains('message-friend')) {
node.style.animation = 'slideInLeft 0.3s ease';
}
});
}
});
});
// Наблюдаем за изменениями в чате
const chatContainer = document.querySelector('[data-testid="chatbot"]');
if(chatContainer) {
observer.observe(chatContainer, { childList: true, subtree: true });
}
// Добавляем CSS анимации
const style = document.createElement('style');
style.textContent = `
@keyframes slideInRight {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideInLeft {
from { transform: translateX(-100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
`;
document.head.appendChild(style);
"""
with gr.Blocks() as demo:
gr.HTML("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Caveat:wght@400;700&display=swap');
</style>
""")
gr.HTML("""
<div style="text-align: center; padding: 20px; background: linear-gradient(135deg, rgba(20,20,20,0.9), rgba(10,10,10,0.9));
border-bottom: 2px solid #ffd700; margin-bottom: 20px; border-radius: 15px;">
<h1 style="color: #ffd700; font-family: 'Caveat', cursive; font-size: 48px; margin: 0; text-shadow: 0 0 20px rgba(255, 215, 0, 0.5);">
💬 Чат с друзьями
</h1>
<p style="color: #b0b0b0; font-family: 'Kalam', cursive; margin: 10px 0 0 0;">
Общайся с друзьями в реальном времени
</p>
<p style="margin-top: 10px;">
<a href="https://huggingface.co/spaces/akhaliq/anycoder"
style="color: #ffd700; text-decoration: none; font-size: 14px;">
Built with anycoder
</a>
</p>
</div>
""")
with gr.Row(equal_height=True):
# Список друзей
with gr.Column(scale=1):
gr.HTML('<h3 style="color: #ffd700; margin-bottom: 15px;">👥 Друзья</h3>')
with gr.Group(elem_classes=["glass-effect"]):
friends_html = gr.HTML(create_friends_html())
# Статистика
gr.HTML(f"""
<div style="margin-top: 20px; padding: 15px; background: rgba(255,215,0,0.1); border-radius: 10px;">
<div style="color: #ffd700; font-weight: bold; margin-bottom: 10px;">📊 Статистика</div>
<div style="color: #ffffff; font-size: 14px;">
<div>🟢 Онлайн: {sum(1 for f in friends_data.values() if f['status'] == 'online')}</div>
<div>🟡 Отошли: {sum(1 for f in friends_data.values() if f['status'] == 'away')}</div>
<div>🔴 Офлайн: {sum(1 for f in friends_data.values() if f['status'] == 'offline')}</div>
<div>📝 Всего друзей: {len(friends_data)}</div>
</div>
</div>
""")
# Основная область чата
with gr.Column(scale=2):
with gr.Row():
# Выбор друга
friend_choice = gr.Radio(
choices=list(friends_data.keys()),
value="AlexGamer",
label="Выберите друга для чата",
elem_classes=["glass-effect"],
interactive=True
)
# История чата
chatbot = gr.Chatbot(
value=format_chat_history(chat_history.get("AlexGamer", [])),
height=400,
show_copy_button=True,
bubble_full_width=False,
elem_classes=["glass-effect"],
avatar_images=(None, None)
)
# Поле ввода сообщения
with gr.Row():
msg_input = gr.Textbox(
placeholder="Введите сообщение...",
label="Сообщение",
elem_classes=["input-message"],
scale=4,
container=False
)
send_btn = gr.Button(
"➤",
elem_classes=["btn-primary"],
scale=1,
size="lg"
)
# Кнопки действий
with gr.Row():
emoji_btn = gr.Button("😊 Эмодзи", elem_classes=["btn-primary"], scale=1)
voice_btn = gr.Button("🎤 Голос", elem_classes=["btn-primary"], scale=1)
photo_btn = gr.Button("📷 Фото", elem_classes=["btn-primary"], scale=1)
clear_btn = gr.Button("🗑️ Очистить", elem_classes=["btn-primary"], scale=1)
# Обработчики событий
def handle_friend_change(friend_name):
return format_chat_history(chat_history.get(friend_name, []))
friend_choice.change(
handle_friend_change,
inputs=[friend_choice],
outputs=[chatbot]
)
def handle_send(message, friend, history):
if message.strip():
return send_message(message, friend, history)
return history, ""
send_btn.click(
handle_send,
inputs=[msg_input, friend_choice, chatbot],
outputs=[chatbot, msg_input]
)
msg_input.submit(
handle_send,
inputs=[msg_input, friend_choice, chatbot],
outputs=[chatbot, msg_input]
)
# Обработка кнопок эмодзи
def add_emoji(emoji_type):
emojis = {
"😊": "😊 😂 🤣 😍 😎 🤔 🤗 😴 🥳 🎉",
"🎮": "🎮 🎯 🎪 🎨 🎭 🎪 🎯 🎲",
"❤️": "❤️ 💛 💚 💙 💜 🖤 💔"
}
return emojis.get(emoji_type, "😊")
emoji_btn.click(
lambda: gr.Info("Выберите эмодзи: 😊 😂 🤣 😍 😎 🤔 🤗 😴 🥳 🎉"),
inputs=[],
outputs=[]
)
voice_btn.click(
lambda: gr.Info("🎤 Голосовые сообщения в разработке"),
inputs=[],
outputs=[]
)
photo_btn.click(
lambda: gr.Info("📷 Загрузка изображений в разработке"),
inputs=[],
outputs=[]
)
clear_btn.click(
lambda: ([], ""),
outputs=[chatbot, msg_input]
)
demo.launch(
theme=gr.themes.Soft(
primary_hue="yellow",
secondary_hue="orange",
neutral_hue="slate",
font=gr.themes.GoogleFont("Kalam"),
text_size="lg",
spacing_size="lg",
radius_size="md"
).set(
body_background_fill="*primary_950",
block_background_fill="*neutral_950",
block_border_width="1px",
block_border_color="*neutral_800",
block_radius="15px",
button_primary_background_fill="linear-gradient(135deg, *primary_600, *primary_400)",
button_primary_background_fill_hover="linear-gradient(135deg, *primary_500, *primary_300)",
button_primary_text_color="*neutral_950",
chatbot_background_fill="*neutral_950",
chatbot_message_user_background_fill="linear-gradient(135deg, *primary_600, *primary_400)",
chatbot_message_user_text_color="*neutral_950",
chatbot_message_assistant_background_fill="*neutral_800",
chatbot_message_assistant_text_color="*neutral_100"
),
css=custom_css,
js=custom_js,
footer_links=[
{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}
]
)