book-chat / app.py
hajar-bettiche-07
another version of UI
d3227db
import gradio as gr
from backend.populate_vec_db_and_seach import create_populate_collection_if_not_exist
from backend.chatgpt import generate
BOOK_NAME = ""
def echo(message, history):
chat_response = generate(message, BOOK_NAME)
return chat_response
def show_loading_message():
return gr.update(value="Searching for your book...", visible=True)
def clickTrigger(book_name):
global BOOK_NAME
if not book_name or book_name.strip() == "":
return gr.update(value="Please enter a book title!", visible=True), gr.update(visible=False)
print(f"[DEBUG] Button clicked with book_name={book_name!r}")
BOOK_NAME = book_name
try:
create_populate_collection_if_not_exist(book_name)
except Exception as exc:
error_msg = f"Unable to prepare book data: {exc}"
print(f"[ERROR] {error_msg}")
return gr.update(value=error_msg, visible=True), gr.update(visible=False)
success_msg = f"Book '{BOOK_NAME}' is ready! Start chatting below."
return gr.update(value=success_msg, visible=True), gr.update(visible=True)
with gr.Blocks(
css="""
/* Global Styles - ELIMINER LES ESPACES */
.gradio-container {
max-width: 100% !important;
padding: 0 !important;
margin: 0 !important;
}
/* Supprimer TOUS les gaps et marges entre les sections */
.gradio-container > .contain {
gap: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
.contain > div {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
/* Header Section - COINS COURBÉS EN BAS */
.header-section {
background: linear-gradient(135deg, #d97706 0%, #dc2626 100%);
padding: 100px 0 80px 0 !important;
margin: 0 !important;
position: relative;
overflow: hidden;
border-radius: 0 0 30px 30px !important;
min-height: 300px;
}
.header-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: repeating-linear-gradient(
90deg,
rgba(255, 255, 255, 0.03) 0px,
rgba(255, 255, 255, 0.03) 2px,
transparent 2px,
transparent 20px
);
pointer-events: none;
}
.header-content {
display: flex;
align-items: center;
gap: 30px;
position: relative;
z-index: 1;
max-width: 1400px;
margin: 0 auto;
padding: 0 80px;
}
.header-icon {
width: 100px;
height: 100px;
background: rgba(255, 255, 255, 0.2);
border-radius: 25px;
display: flex;
align-items: center;
justify-content: center;
font-size: 60px;
backdrop-filter: blur(10px);
}
.header-text h1 {
color: white;
font-size: 56px;
font-weight: 700;
margin: 0 0 12px 0;
letter-spacing: -0.5px;
}
.header-text p {
color: rgba(255, 255, 255, 0.95);
font-size: 24px;
margin: 0;
font-weight: 400;
}
/* Feature Cards Section - COINS COURBÉS EN HAUT ET EN BAS */
.features-section {
background: linear-gradient(135deg, #f5e6d3 0%, #e8d4b8 100%);
padding: 60px 0 !important;
margin: 0 !important;
border-radius: 0 !important;
}
.features-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
max-width: 1400px;
margin: 0 auto;
padding: 0 80px;
}
.feature-card {
background: white;
border: 2px solid #d2b48c;
border-radius: 20px;
padding: 32px 24px;
text-align: center;
box-shadow: 0 4px 12px rgba(139, 69, 19, 0.1);
transition: all 0.3s ease;
}
.feature-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 20px rgba(139, 69, 19, 0.2);
border-color: #d2691e;
}
.feature-icon {
width: 56px;
height: 56px;
background: linear-gradient(135deg, #d2691e 0%, #a0522d 100%);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 20px auto;
font-size: 28px;
}
.feature-card h3 {
font-size: 18px;
font-weight: 600;
color: #1f2937;
margin: 0 0 12px 0;
}
.feature-card p {
font-size: 14px;
color: #6b7280;
line-height: 1.6;
margin: 0;
}
/* Search Section - COINS COURBÉS EN HAUT ET EN BAS */
.search-section-wrapper {
background: white;
padding: 80px 0 !important;
margin: 0 !important;
border-radius: 0 !important;
}
.search-section {
max-width: 1400px;
margin: 0 auto;
padding: 0 80px;
}
.search-card {
background: linear-gradient(135deg, #ffe4cc 0%, #ffd4a3 100%);
border: 2px solid #ffb366;
border-radius: 25px;
padding: 60px;
box-shadow: 0 6px 16px rgba(255, 140, 0, 0.2);
display: flex;
gap: 50px;
align-items: center;
min-height: 280px;
}
.search-image {
flex-shrink: 0;
width: 350px;
height: 240px;
border-radius: 20px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.search-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.search-content {
flex: 1;
}
.search-title {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.search-title h2 {
font-size: 38px;
font-weight: 700;
color: #8b4513;
margin: 0;
}
.search-subtitle {
color: #654321;
font-size: 18px;
margin-bottom: 0;
}
/* Search Inputs - MARGES ALIGNÉES */
.search-inputs {
max-width: 1400px !important;
margin: 30px auto 0 auto !important;
padding: 0 80px !important;
width: auto !important;
}
.search-box-container {
display: flex;
gap: 12px;
margin-bottom: 16px;
width: 100% !important;
max-width: 100% !important;
}
.search-box-container input {
flex: 1;
padding: 16px 24px !important;
border: 2px solid #d2691e !important;
border-radius: 15px !important;
font-size: 16px !important;
background: white !important;
width: 100% !important;
}
.search-box-container input:focus {
border-color: #8b4513 !important;
outline: none !important;
box-shadow: 0 0 0 3px rgba(139, 69, 19, 0.1) !important;
}
.search-button {
padding: 16px 40px !important;
background: linear-gradient(135deg, #8b4513 0%, #a0522d 100%) !important;
color: white !important;
border: none !important;
border-radius: 15px !important;
font-size: 16px !important;
font-weight: 600 !important;
cursor: pointer !important;
transition: all 0.3s ease !important;
box-shadow: 0 4px 12px rgba(139, 69, 19, 0.3) !important;
white-space: nowrap !important;
}
.search-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(139, 69, 19, 0.4) !important;
background: linear-gradient(135deg, #a0522d 0%, #8b4513 100%) !important;
}
.status-message {
padding: 12px 20px;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
max-width: 1400px !important;
margin: 0 auto !important;
width: auto !important;
}
/* Chat Section - COINS COURBÉS EN HAUT ET MARGES ALIGNÉES */
.chat-section-wrapper {
background: white;
padding: 60px 0 80px 0 !important;
margin: 0 !important;
border-radius: 30px 30px 0 0 !important;
}
.chat-section {
max-width: 1400px !important;
margin: 0 auto !important;
padding: 0 80px !important;
width: auto !important;
}
.chat-container {
background: white;
border: 2px solid #e5e7eb;
border-radius: 25px;
padding: 32px;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
}
.chat-header {
font-size: 24px;
font-weight: 700;
color: #1f2937;
margin-bottom: 24px;
width: 100% !important;
}
/* FORCER la suppression de tous les espaces entre les blocs Gradio */
div[data-testid]:has(.header-section) {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
border-radius: 0 0 30px 30px !important;
overflow: hidden !important;
}
div[data-testid]:has(.features-section) {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
div[data-testid]:has(.search-section-wrapper) {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
div[data-testid]:has(.search-inputs) {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
max-width: 1400px !important;
margin-left: auto !important;
margin-right: auto !important;
padding-left: 80px !important;
padding-right: 80px !important;
}
div[data-testid]:has(.chat-section-wrapper) {
margin-top: 0 !important;
margin-bottom: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
border-radius: 30px 30px 0 0 !important;
overflow: hidden !important;
}
/* Assurer l'alignement parfait de tous les conteneurs */
.header-content,
.features-grid,
.search-section,
.search-inputs,
.chat-section {
margin-left: auto !important;
margin-right: auto !important;
padding-left: 80px !important;
padding-right: 80px !important;
box-sizing: border-box !important;
}
/* Correction spécifique pour les inputs */
.gradio-row {
max-width: 1400px !important;
margin-left: auto !important;
margin-right: auto !important;
padding-left: 80px !important;
padding-right: 80px !important;
}
/* Pour le chatbot */
.gradio-chatbot {
max-width: 100% !important;
margin: 0 !important;
}
/* Pour la textbox du chat */
.gradio-textbox {
max-width: 100% !important;
margin: 0 !important;
}
"""
) as demo:
# Header - COINS COURBÉS EN BAS
gr.HTML("""
<div class="header-section">
<div class="header-content">
<div class="header-icon">📖</div>
<div class="header-text">
<h1>Welcome to ChatBook</h1>
<p>Your intelligent reading companion</p>
</div>
</div>
</div>
""")
# Feature Cards
gr.HTML("""
<div class="features-section">
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">💬</div>
<h3>Deep Discussions</h3>
<p>Ask complex questions about plot, themes, and characters</p>
</div>
<div class="feature-card">
<div class="feature-icon">⚡</div>
<h3>Instant Answers</h3>
<p>Get immediate AI-powered responses about any book</p>
</div>
<div class="feature-card">
<div class="feature-icon">⏱️</div>
<h3>Save Time</h3>
<p>No need to re-read - get quick summaries and insights</p>
</div>
<div class="feature-card">
<div class="feature-icon">📈</div>
<h3>Learn More</h3>
<p>Discover hidden meanings and literary analysis</p>
</div>
</div>
</div>
""")
# Search Section
gr.HTML("""
<div class="search-section-wrapper">
<div class="search-section">
<div class="search-card">
<div class="search-image">
<img src="https://images.unsplash.com/photo-1524995997946-a1c2e315a42f?w=600&h=400&fit=crop" alt="Person reading">
</div>
<div class="search-content">
<div class="search-title">
<span style="font-size: 38px;"></span>
<h2>Find Your Book</h2>
</div>
<p class="search-subtitle">Enter a book title and start an intelligent conversation about it</p>
</div>
</div>
</div>
</div>
""")
with gr.Group(elem_classes="search-inputs"):
with gr.Row(elem_classes="search-box-container"):
book_box = gr.Textbox(
placeholder="Enter book title (e.g, The Great Gatsby)...",
show_label=False,
container=False,
scale=5
)
search_btn = gr.Button("🔍 Search", elem_classes="search-button", scale=1)
status_text = gr.HTML("", visible=False)
# Chat Section - COINS COURBÉS EN HAUT
with gr.Group(visible=False) as chat_section:
gr.HTML("""
<div class="chat-section-wrapper">
<div class="chat-section">
<div class="chat-header">💬 Chat with Your Book</div>
<div class="chat-container">
""")
chat = gr.ChatInterface(
fn=echo,
type="messages",
chatbot=gr.Chatbot(height=500, type="messages"),
textbox=gr.Textbox(
placeholder="Ask anything about the book...",
container=False,
scale=7
)
)
gr.HTML("""
</div>
</div>
</div>
""")
# Event Handlers
search_btn.click(
fn=show_loading_message,
outputs=status_text,
queue=False
).then(
fn=clickTrigger,
inputs=book_box,
outputs=[status_text, chat_section]
)
demo.launch()