Spaces:
Sleeping
Sleeping
| import uuid | |
| import sqlite3 | |
| import gradio as gr | |
| from datetime import datetime | |
| from passlib.context import CryptContext | |
| # ================= DATABASE ================= | |
| conn = sqlite3.connect("chat.db", check_same_thread=False) | |
| cursor = conn.cursor() | |
| cursor.execute("""CREATE TABLE IF NOT EXISTS users(email TEXT PRIMARY KEY,password TEXT)""") | |
| cursor.execute("""CREATE TABLE IF NOT EXISTS invites(code TEXT PRIMARY KEY,user1 TEXT,user2 TEXT)""") | |
| cursor.execute("""CREATE TABLE IF NOT EXISTS messages(id TEXT PRIMARY KEY,room TEXT,sender TEXT,message TEXT,time TEXT)""") | |
| conn.commit() | |
| pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") | |
| # ================= AUTH ================= | |
| def register_or_login(email, password): | |
| cursor.execute("SELECT password FROM users WHERE email=?", (email,)) | |
| data = cursor.fetchone() | |
| if data: | |
| if pwd_context.verify(password, data[0]): | |
| return email, "Welcome back β " | |
| return None, "Wrong password β" | |
| hashed = pwd_context.hash(password) | |
| cursor.execute("INSERT INTO users VALUES (?,?)", (email, hashed)) | |
| conn.commit() | |
| return email, "Account created β " | |
| # ================= INVITES ================= | |
| def create_invite(user): | |
| code = str(uuid.uuid4())[:8] | |
| cursor.execute("INSERT INTO invites VALUES (?,?,?)", (code, user, "")) | |
| conn.commit() | |
| return code, f"Invite Code: {code}" | |
| def join_invite(user, code): | |
| cursor.execute("SELECT user1,user2 FROM invites WHERE code=?", (code,)) | |
| data = cursor.fetchone() | |
| if not data: | |
| return None, "Invalid Code" | |
| if data[1]: | |
| return None, "Room already full" | |
| cursor.execute("UPDATE invites SET user2=? WHERE code=?", (user, code)) | |
| conn.commit() | |
| return code, f"Connected with {data[0]}" | |
| # ================= CHAT ================= | |
| def send_message(user, room, msg): | |
| if not msg or not room: | |
| return | |
| cursor.execute("INSERT INTO messages VALUES (?,?,?,?,?)", | |
| (str(uuid.uuid4()), room, user, msg, | |
| datetime.now().strftime("%H:%M"))) | |
| conn.commit() | |
| def fetch_messages(room, current_user): | |
| if not room: | |
| return "<div class='system'>Join a room to start chatting.</div>" | |
| cursor.execute("SELECT sender,message,time FROM messages WHERE room=? ORDER BY rowid", (room,)) | |
| chats = cursor.fetchall() | |
| html = "" | |
| for sender, msg, t in chats: | |
| side = "me" if sender == current_user else "other" | |
| html += f""" | |
| <div class='msg {side}'> | |
| <div class='bubble'> | |
| <div class='text'>{msg}</div> | |
| <div class='time'>{t}</div> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| # ================= UI ================= | |
| custom_css = """ | |
| body {background:#0f172a;} | |
| .container {max-width:900px;margin:auto;} | |
| .header {text-align:center;color:white;font-size:26px;font-weight:600;margin-bottom:10px;} | |
| .msg {display:flex;margin:8px;} | |
| .msg.me {justify-content:flex-end;} | |
| .msg.other {justify-content:flex-start;} | |
| .bubble { | |
| padding:12px 16px; | |
| border-radius:18px; | |
| max-width:60%; | |
| box-shadow:0 4px 14px rgba(0,0,0,0.2); | |
| } | |
| .me .bubble {background:#22c55e;color:white;} | |
| .other .bubble {background:#1e293b;color:white;} | |
| .time {font-size:10px;opacity:0.6;margin-top:4px;text-align:right;} | |
| .chatbox { | |
| height:420px; | |
| overflow-y:auto; | |
| padding:10px; | |
| background:#020617; | |
| border-radius:14px; | |
| } | |
| .system {color:#94a3b8;text-align:center;margin-top:20px;} | |
| """ | |
| with gr.Blocks(css=custom_css) as app: | |
| user_state = gr.State() | |
| room_state = gr.State() | |
| gr.Markdown("<div class='header'>π DuoSecure β Private 2-Person Chat</div>") | |
| with gr.Tab("Login"): | |
| email = gr.Textbox(label="Email") | |
| password = gr.Textbox(type="password", label="Password") | |
| btn = gr.Button("Enter") | |
| status = gr.Markdown() | |
| btn.click(register_or_login, [email, password], [user_state, status]) | |
| with gr.Tab("Invitation"): | |
| create_btn = gr.Button("Create Private Room") | |
| code_box = gr.Textbox(label="Room Code") | |
| join_btn = gr.Button("Join Room") | |
| invite_status = gr.Markdown() | |
| create_btn.click(create_invite, user_state, [code_box, invite_status]) | |
| join_btn.click(join_invite, [user_state, code_box], [room_state, invite_status]) | |
| with gr.Tab("Chat"): | |
| chat_html = gr.HTML(elem_classes="chatbox") | |
| msg = gr.Textbox(placeholder="Type message and press Enter...", show_label=False) | |
| msg.submit(send_message, [user_state, room_state, msg], None) | |
| timer = gr.Timer(1) | |
| timer.tick(fetch_messages, [room_state, user_state], chat_html) | |
| with gr.Tab("Voice / Video"): | |
| gr.Markdown("Allow camera & microphone to start secure conversation.") | |
| gr.HTML(""" | |
| <video id="v" autoplay muted style="width:70%;border-radius:14px;"></video> | |
| <script> | |
| navigator.mediaDevices.getUserMedia({video:true,audio:true}) | |
| .then(s=>{document.getElementById("v").srcObject=s;}); | |
| </script> | |
| """) | |
| app.launch() | |