File size: 5,187 Bytes
f0018cc
 
df3812c
 
 
 
 
 
f0018cc
df3812c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f0018cc
df3812c
 
f0018cc
df3812c
f0018cc
df3812c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f0018cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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="/")