testDB / library_app.py
jaannawaz
πŸš€ Modern Library Management UI with HF Secrets support
84d3b50
import gradio as gr
import pandas as pd
from datetime import datetime, date
from supabase import create_client, Client
class LibraryManagement:
def __init__(self):
"""Initialize Supabase connection for library management"""
self.url = "https://bnjblzcqaumctpehgoid.supabase.co"
self.key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJuamJsemNxYXVtY3RwZWhnb2lkIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTgyOTA0OTQsImV4cCI6MjA3Mzg2NjQ5NH0.L4wPzuBj9dlSKpYxO1eDX-57KcP0mbNfN8stmTB-STM"
try:
self.supabase: Client = create_client(self.url, self.key)
self.connection_status = "βœ… Connected to Library Database!"
except Exception as e:
self.supabase = None
self.connection_status = f"❌ Connection failed: {str(e)}"
def get_all_members(self):
"""Get all library members"""
try:
result = self.supabase.table("member").select("*").order("name").execute()
return pd.DataFrame(result.data)
except Exception as e:
return pd.DataFrame([{"Error": str(e)}])
def get_all_books(self):
"""Get all books"""
try:
result = self.supabase.table("book").select("*").order("title").execute()
return pd.DataFrame(result.data)
except Exception as e:
return pd.DataFrame([{"Error": str(e)}])
def get_current_borrows(self):
"""Get all current (unreturned) book borrows with member and book details"""
try:
# Note: Supabase doesn't support complex JOINs in the Python client directly
# We'll get the data separately and merge it
# Get active borrows
borrows = self.supabase.table("borrow").select("*").is_("return_date", "null").execute()
if not borrows.data:
return pd.DataFrame([{"Message": "No current borrows"}])
# Get members and books to join the data
members = self.supabase.table("member").select("*").execute()
books = self.supabase.table("book").select("*").execute()
# Create lookup dictionaries
member_dict = {m['id']: m for m in members.data}
book_dict = {b['id']: b for b in books.data}
# Build the result
result_data = []
for borrow in borrows.data:
member = member_dict.get(borrow['member_id'], {})
book = book_dict.get(borrow['book_id'], {})
result_data.append({
'borrow_id': borrow['id'],
'member_name': member.get('name', 'Unknown'),
'member_email': member.get('email', 'Unknown'),
'book_title': book.get('title', 'Unknown'),
'book_author': book.get('author', 'Unknown'),
'borrow_date': borrow['borrow_date']
})
return pd.DataFrame(result_data)
except Exception as e:
return pd.DataFrame([{"Error": str(e)}])
def add_member(self, name: str, email: str):
"""Add a new member"""
try:
if not name or not email:
return "❌ Name and email are required"
data = {"name": name, "email": email}
result = self.supabase.table("member").insert(data).execute()
if result.data:
return f"βœ… Successfully added member: {name}"
else:
return "❌ Failed to add member"
except Exception as e:
if "duplicate key" in str(e):
return "❌ Email already exists"
return f"❌ Error: {str(e)}"
def add_book(self, title: str, author: str, year: int):
"""Add a new book"""
try:
if not title or not author:
return "❌ Title and author are required"
if year < 0 or year > datetime.now().year + 1:
return "❌ Invalid year"
data = {"title": title, "author": author, "year": year}
result = self.supabase.table("book").insert(data).execute()
if result.data:
return f"βœ… Successfully added book: {title}"
else:
return "❌ Failed to add book"
except Exception as e:
return f"❌ Error: {str(e)}"
def borrow_book(self, member_id: int, book_id: int):
"""Create a new borrow record"""
try:
if not member_id or not book_id:
return "❌ Please select both member and book"
# Check if book is already borrowed
existing = self.supabase.table("borrow").select("*").eq("book_id", book_id).is_("return_date", "null").execute()
if existing.data:
return "❌ Book is already borrowed and not returned"
data = {
"member_id": member_id,
"book_id": book_id,
"borrow_date": date.today().isoformat()
}
result = self.supabase.table("borrow").insert(data).execute()
if result.data:
return f"βœ… Book borrowed successfully!"
else:
return "❌ Failed to create borrow record"
except Exception as e:
return f"❌ Error: {str(e)}"
def return_book(self, borrow_id: int):
"""Return a borrowed book"""
try:
if not borrow_id:
return "❌ Please select a borrow record"
# Update the borrow record with return date
data = {"return_date": date.today().isoformat()}
result = self.supabase.table("borrow").update(data).eq("id", borrow_id).execute()
if result.data:
return f"βœ… Book returned successfully!"
else:
return "❌ Failed to return book"
except Exception as e:
return f"❌ Error: {str(e)}"
def get_member_choices(self):
"""Get member choices for dropdown"""
try:
result = self.supabase.table("member").select("id, name").order("name").execute()
return [(f"{m['name']} (ID: {m['id']})", m['id']) for m in result.data]
except:
return [("No members found", 0)]
def get_book_choices(self):
"""Get book choices for dropdown"""
try:
result = self.supabase.table("book").select("id, title, author").order("title").execute()
return [(f"{b['title']} by {b['author']} (ID: {b['id']})", b['id']) for b in result.data]
except:
return [("No books found", 0)]
def get_borrow_choices(self):
"""Get active borrow choices for dropdown"""
try:
# Get active borrows with member and book info
borrows = self.supabase.table("borrow").select("*").is_("return_date", "null").execute()
if not borrows.data:
return [("No active borrows", 0)]
# Get members and books for display
members = self.supabase.table("member").select("*").execute()
books = self.supabase.table("book").select("*").execute()
member_dict = {m['id']: m for m in members.data}
book_dict = {b['id']: b for b in books.data}
choices = []
for borrow in borrows.data:
member = member_dict.get(borrow['member_id'], {})
book = book_dict.get(borrow['book_id'], {})
label = f"{member.get('name', 'Unknown')} - {book.get('title', 'Unknown')} (Borrow ID: {borrow['id']})"
choices.append((label, borrow['id']))
return choices
except:
return [("Error loading borrows", 0)]
# Initialize the library management system
library = LibraryManagement()
# Gradio interface functions
def refresh_members():
return library.get_all_members()
def refresh_books():
return library.get_all_books()
def refresh_borrows():
return library.get_current_borrows()
def add_new_member(name, email):
status = library.add_member(name, email)
return status, library.get_all_members()
def add_new_book(title, author, year):
status = library.add_book(title, author, year)
return status, library.get_all_books()
def create_borrow(member_choice, book_choice):
member_id = member_choice if isinstance(member_choice, int) else 0
book_id = book_choice if isinstance(book_choice, int) else 0
status = library.borrow_book(member_id, book_id)
return status, library.get_current_borrows()
def process_return(borrow_choice):
borrow_id = borrow_choice if isinstance(borrow_choice, int) else 0
status = library.return_book(borrow_id)
return status, library.get_current_borrows()
def refresh_member_dropdown():
return gr.Dropdown(choices=library.get_member_choices())
def refresh_book_dropdown():
return gr.Dropdown(choices=library.get_book_choices())
def refresh_borrow_dropdown():
return gr.Dropdown(choices=library.get_borrow_choices())
# Create the Gradio interface
with gr.Blocks(title="Library Management System", theme=gr.themes.Soft()) as app:
gr.Markdown("# πŸ“š Library Management System")
gr.Markdown("Manage your library members, books, and borrowing records")
# Connection status
with gr.Row():
gr.Markdown(f"**Status:** {library.connection_status}")
with gr.Tabs():
# Members Tab
with gr.Tab("πŸ‘₯ Members"):
gr.Markdown("### Library Members")
with gr.Row():
refresh_members_btn = gr.Button("πŸ”„ Refresh Members", size="sm")
members_table = gr.Dataframe(label="All Members", value=library.get_all_members())
gr.Markdown("---")
gr.Markdown("**Add New Member:**")
with gr.Row():
member_name = gr.Textbox(label="Name", placeholder="Enter member name")
member_email = gr.Textbox(label="Email", placeholder="Enter email address")
add_member_btn = gr.Button("βž• Add Member", variant="primary")
member_status = gr.Textbox(label="Status", interactive=False)
refresh_members_btn.click(refresh_members, outputs=members_table)
add_member_btn.click(
add_new_member,
inputs=[member_name, member_email],
outputs=[member_status, members_table]
)
# Books Tab
with gr.Tab("πŸ“– Books"):
gr.Markdown("### Library Books")
with gr.Row():
refresh_books_btn = gr.Button("πŸ”„ Refresh Books", size="sm")
books_table = gr.Dataframe(label="All Books", value=library.get_all_books())
gr.Markdown("---")
gr.Markdown("**Add New Book:**")
with gr.Row():
book_title = gr.Textbox(label="Title", placeholder="Enter book title")
book_author = gr.Textbox(label="Author", placeholder="Enter author name")
book_year = gr.Number(label="Year", value=2024, minimum=1900, maximum=2030)
add_book_btn = gr.Button("βž• Add Book", variant="primary")
book_status = gr.Textbox(label="Status", interactive=False)
refresh_books_btn.click(refresh_books, outputs=books_table)
add_book_btn.click(
add_new_book,
inputs=[book_title, book_author, book_year],
outputs=[book_status, books_table]
)
# Borrowing Tab
with gr.Tab("πŸ“ Borrowing"):
gr.Markdown("### Current Borrows")
with gr.Row():
refresh_borrows_btn = gr.Button("πŸ”„ Refresh Borrows", size="sm")
borrows_table = gr.Dataframe(label="Current Borrows", value=library.get_current_borrows())
gr.Markdown("---")
gr.Markdown("**Borrow a Book:**")
with gr.Row():
member_dropdown = gr.Dropdown(
choices=library.get_member_choices(),
label="Select Member"
)
book_dropdown = gr.Dropdown(
choices=library.get_book_choices(),
label="Select Book"
)
refresh_dropdowns_btn = gr.Button("πŸ”„", size="sm")
borrow_btn = gr.Button("πŸ“š Borrow Book", variant="primary")
borrow_status = gr.Textbox(label="Borrow Status", interactive=False)
gr.Markdown("---")
gr.Markdown("**Return a Book:**")
with gr.Row():
borrow_dropdown = gr.Dropdown(
choices=library.get_borrow_choices(),
label="Select Borrow Record to Return"
)
refresh_return_btn = gr.Button("πŸ”„", size="sm")
return_btn = gr.Button("↩️ Return Book", variant="secondary")
return_status = gr.Textbox(label="Return Status", interactive=False)
# Event handlers
refresh_borrows_btn.click(refresh_borrows, outputs=borrows_table)
refresh_dropdowns_btn.click(
lambda: [gr.Dropdown(choices=library.get_member_choices()),
gr.Dropdown(choices=library.get_book_choices())],
outputs=[member_dropdown, book_dropdown]
)
refresh_return_btn.click(
lambda: gr.Dropdown(choices=library.get_borrow_choices()),
outputs=borrow_dropdown
)
borrow_btn.click(
create_borrow,
inputs=[member_dropdown, book_dropdown],
outputs=[borrow_status, borrows_table]
)
return_btn.click(
process_return,
inputs=[borrow_dropdown],
outputs=[return_status, borrows_table]
)
# Reports Tab
with gr.Tab("πŸ“Š Reports"):
gr.Markdown("### Library Reports")
with gr.Row():
gr.Markdown("""
**Available Data:**
- Members: View and manage library members
- Books: Browse the book collection
- Current Borrows: See who has borrowed what
- Add/Return: Manage borrowing transactions
**Database Tables:**
- `member`: Library members with contact info
- `book`: Book catalog with title, author, year
- `borrow`: Borrowing records with dates
""")
gr.Markdown("---")
gr.Markdown("πŸ’‘ **Your Library Database is Ready!** Use the tabs above to manage members, books, and borrowing.")
# Launch the app
if __name__ == "__main__":
app.launch(
server_name="0.0.0.0",
server_port=7860,
share=False
)