Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI | |
| import gradio as gr | |
| import os | |
| import sqlalchemy | |
| from sqlalchemy import create_engine, text, Column, Integer, String, DateTime | |
| from sqlalchemy.orm import sessionmaker, declarative_base | |
| from datetime import datetime | |
| import time | |
| # --- Cấu hình Biến Database (PHẢI KHỚP VỚI run.sh) --- | |
| DB_USER="gradio_user" | |
| DB_PASS="local_password_123" | |
| DB_NAME="gradio_db" | |
| DB_HOST="localhost" # Kết nối cục bộ | |
| DB_PORT="5432" | |
| # --- Thiết lập Cơ sở dữ liệu (Database Setup) --- | |
| # 1. Tạo chuỗi kết nối cục bộ | |
| DATABASE_URL = f"postgresql://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}" | |
| DB_IS_LOCAL = True | |
| # 2. Tạo kết nối | |
| print("Đang kết nối tới cơ sở dữ liệu PostgreSQL cục bộ...") | |
| try: | |
| engine = create_engine(DATABASE_URL) | |
| # Thử kết nối nhanh | |
| with engine.connect() as connection: | |
| print("Kết nối PostgreSQL cục bộ thành công.") | |
| except Exception as e: | |
| print(f"LỖI NGHIÊM TRỌNG: Không thể kết nối tới DB cục bộ: {e}") | |
| print("Sử dụng cơ sở dữ liệu SQLite trong bộ nhớ để demo.") | |
| engine = create_engine("sqlite:///:memory:") | |
| DB_IS_LOCAL = False # Đánh dấu là đang chạy demo | |
| Base = declarative_base() | |
| # 3. Định nghĩa mô hình bảng (Table Model) | |
| class Note(Base): | |
| __tablename__ = 'notes' | |
| id = Column(Integer, primary_key=True, autoincrement=True) | |
| username = Column(String(100), nullable=False) | |
| message = Column(String(500), nullable=False) | |
| created_at = Column(DateTime, default=datetime.utcnow) | |
| # 4. Tạo bảng (nếu chưa tồn tại) | |
| try: | |
| Base.metadata.create_all(engine) | |
| print("Bảng 'notes' đã được kiểm tra/tạo thành công.") | |
| except Exception as e: | |
| print(f"Lỗi khi tạo bảng (có thể bảng đã tồn tại): {e}") | |
| # 5. Tạo một Session để tương tác với DB | |
| SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) | |
| # --- Hàm xử lý Gradio --- | |
| def add_entry(username, message): | |
| """Thêm một mục mới vào cơ sở dữ liệu.""" | |
| if not DB_IS_LOCAL: | |
| print("Chạy ở chế độ demo (SQLite), không thêm vào DB.") | |
| return get_entries() | |
| if not username or not message: | |
| return get_entries() # Chỉ tải lại, không thêm gì | |
| try: | |
| db = SessionLocal() | |
| new_note = Note(username=username, message=message) | |
| db.add(new_note) | |
| db.commit() | |
| print(f"Đã thêm mục mới từ: {username}") | |
| except Exception as e: | |
| print(f"Lỗi khi thêm mục: {e}") | |
| db.rollback() | |
| return f"Lỗi khi thêm mục: {e}" | |
| finally: | |
| db.close() | |
| # Sau khi thêm, tải lại các mục | |
| return get_entries() | |
| def get_entries(): | |
| """Lấy tất cả các mục từ cơ sở dữ liệu và định dạng chúng.""" | |
| if not DB_IS_LOCAL: | |
| return "Ứng dụng đang chạy ở chế độ demo (SQLite). Không thể kết nối với DB cục bộ." | |
| output = "" | |
| try: | |
| db = SessionLocal() | |
| # Lấy 20 mục gần nhất | |
| notes = db.query(Note).order_by(Note.created_at.desc()).limit(20).all() | |
| if not notes: | |
| output = "Chưa có tin nhắn nào. Hãy là người đầu tiên!" | |
| else: | |
| # Định dạng đầu ra (hiển thị từ mới nhất) | |
| for note in notes: | |
| time_str = note.created_at.strftime('%Y-%m-%d %H:%M') | |
| output += f"[{time_str}] {note.username}:\n{note.message}\n" + "-"*20 + "\n" | |
| except Exception as e: | |
| print(f"Lỗi khi tải mục: {e}") | |
| output = f"Lỗi khi tải mục: {e}" | |
| finally: | |
| db.close() | |
| return output | |
| with gr.Blocks(title="Gradio + PG (Local)") as gr_interface: | |
| gr.Markdown("# Sổ khách (Gradio + PostgreSQL Cục bộ)") | |
| gr.Markdown("Để lại tin nhắn và xem các tin nhắn trước đó. CẢNH BÁO: Dữ liệu sẽ bị mất khi Space khởi động lại!") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| username_input = gr.Textbox(label="Tên của bạn") | |
| message_input = gr.Textbox(label="Tin nhắn của bạn", lines=4, placeholder="Viết gì đó...") | |
| submit_button = gr.Button("Gửi tin nhắn", variant="primary") | |
| with gr.Column(scale=2): | |
| output_display = gr.Textbox( | |
| label="Tin nhắn đã lưu (Tải lại tự động)", | |
| lines=12, | |
| interactive=False | |
| ) | |
| # Tải các mục khi giao diện khởi động | |
| gr_interface.load(get_entries, outputs=output_display) | |
| # Liên kết nút Gửi | |
| submit_button.click( | |
| fn=add_entry, | |
| inputs=[username_input, message_input], | |
| outputs=output_display | |
| ).then( | |
| # Xóa các ô input sau khi gửi | |
| lambda: (gr.update(value=""), gr.update(value="")), | |
| outputs=[username_input, message_input] | |
| ) | |
| app = FastAPI() | |
| app = gr.mount_gradio_app(app, gr_interface, path="/") |