Keeby-smilyai commited on
Commit
dbe4e96
·
verified ·
1 Parent(s): 881cef4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +644 -268
app.py CHANGED
@@ -806,16 +806,16 @@ def generate_response_stream(prompt, temperature=0.7, backend=None, max_tokens=2
806
  final_tokens_per_sec = tokens_generated / elapsed if elapsed > 0 else 0
807
  yield "", False, final_tokens_per_sec, final_tokens_per_sec, False
808
 
809
- # PART 3 - Continue from Part 2 - SESSION CODE VERSION (FIXED)
 
810
 
811
  import secrets
812
 
813
- # Global session codes storage
814
- active_sessions = {} # {session_code: user_data}
815
  session_lock = threading.Lock()
816
 
817
  def generate_session_code():
818
- """Generate a unique 4-digit session code."""
819
  with session_lock:
820
  while True:
821
  code = ''.join([str(secrets.randbelow(10)) for _ in range(4)])
@@ -823,10 +823,8 @@ def generate_session_code():
823
  return code
824
 
825
  def create_session(user_data):
826
- """Create a new session and return the code."""
827
  code = generate_session_code()
828
  with session_lock:
829
- # Normalize the user_data to always use 'user_id'
830
  normalized_data = {
831
  'user_id': user_data.get('id') or user_data.get('user_id'),
832
  'username': user_data.get('username'),
@@ -837,12 +835,10 @@ def create_session(user_data):
837
  return code
838
 
839
  def validate_session(code):
840
- """Validate a session code and return user data."""
841
  with session_lock:
842
  return active_sessions.get(code, None)
843
 
844
  def invalidate_session(code):
845
- """Remove a session code."""
846
  with session_lock:
847
  if code in active_sessions:
848
  del active_sessions[code]
@@ -853,38 +849,297 @@ if __name__ == "__main__":
853
  import gradio as gr
854
 
855
  custom_css = """
856
- .plan-explore { background: #d8b4fe; color: #7e22ce; }
857
- .plan-research { background: #a5f3fc; color: #0e7490; }
858
- .plan-VIP { background: #fbbf24; color: #92400e; }
859
- .chat-container { height: 500px; overflow-y: auto; padding: 20px; background: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; }
860
- .user-message { background: #f7f7f8; padding: 16px; margin: 12px 0; border-radius: 8px; }
861
- .assistant-message { background: #ffffff; padding: 16px; margin: 12px 0; border-radius: 8px; border-left: 3px solid #10a37f; }
862
- .message-content { color: #353740; line-height: 1.6; font-size: 15px; }
863
- .message-header { font-weight: 600; margin-bottom: 8px; color: #353740; font-size: 14px; }
864
- .thinking-content { color: #6b7280; font-style: italic; border-left: 3px solid #d1d5db; padding-left: 12px; margin: 8px 0; background: #f9fafb; padding: 8px 12px; border-radius: 4px; }
865
- .plan-badge { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 600; margin-left: 8px; }
866
- .plan-free { background: #e0e7ff; color: #3730a3; }
867
- .plan-plus { background: #dbeafe; color: #1e40af; }
868
- .plan-pro { background: #fef3c7; color: #92400e; }
869
- .limits-panel { background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; margin: 12px 0; }
870
- .limit-item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #e5e7eb; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
871
  .limit-item:last-child { border-bottom: none; }
872
  .limit-exceeded { color: #dc2626; font-weight: 600; }
873
- .limit-ok { color: #059669; }
874
- .circular-btn { width: 48px !important; height: 48px !important; min-width: 48px !important; border-radius: 50% !important; padding: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 20px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.15) !important; transition: all 0.2s ease !important; }
875
- .circular-btn:hover:not(:disabled) { transform: scale(1.05) !important; box-shadow: 0 4px 12px rgba(0,0,0,0.2) !important; }
876
- .send-btn { background: linear-gradient(135deg, #10a37f 0%, #0d8c6c 100%) !important; border: none !important; }
877
- .stop-btn { background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important; border: none !important; }
878
- .announcement-banner { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px 28px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); text-align: center; font-size: 16px; font-weight: 500; line-height: 1.6; }
879
- .session-code-box { background: linear-gradient(135deg, #10a37f 0%, #0d8c6c 100%); color: white; padding: 20px; border-radius: 12px; text-align: center; margin: 20px 0; box-shadow: 0 4px 12px rgba(0,0,0,0.2); }
880
- .session-code-display { font-size: 32px; font-weight: 700; letter-spacing: 8px; margin: 10px 0; font-family: monospace; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
881
  """
882
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
883
  def format_message_html(role, content, show_thinking=True):
884
  role_class = "user-message" if role == "user" else "assistant-message"
885
- role_name = "You" if role == "user" else "SAM-X-1"
886
  thinking = ""
887
  answer = ""
 
888
  if "<think>" in content:
889
  parts = content.split("<think>", 1)
890
  before_think = parts[0].strip()
@@ -905,7 +1160,8 @@ if __name__ == "__main__":
905
  answer = before_think
906
  else:
907
  answer = content
908
- html = f'<div class="{role_class}"><div class="message-header">{role_name}</div><div class="message-content">'
 
909
  if thinking and show_thinking:
910
  html += f'<div class="thinking-content">💭 {thinking}</div>'
911
  if answer:
@@ -925,213 +1181,329 @@ if __name__ == "__main__":
925
  info = get_user_limits_info(user_data['user_id'])
926
  if not info:
927
  return ""
928
- plan_badge_class = f"plan-{info['plan']}"
929
- html = f'<div class="limits-panel"><div style="font-weight: 600; margin-bottom: 12px; font-size: 16px;">Your Plan: <span class="plan-badge {plan_badge_class}">{info["plan"].upper()}</span></div><div style="font-size: 13px; color: #6b7280; margin-bottom: 12px;">⏰ Limits reset in: <strong>{info["reset_in"]}</strong></div>'
930
- models_info = [('NANO ⚡⚡', info['nano_used'], info['nano_limit']), ('MINI 🚀', info['mini_used'], info['mini_limit']), ('FAST ⚡', info['fast_used'], info['fast_limit']), ('LARGE 💎', info['large_used'], info['large_limit'])]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
  for model_name, used, limit in models_info:
932
  if limit == -1:
933
- status = f'<span class="limit-ok">{used} messages (Unlimited)</span>'
934
  else:
935
  remaining = limit - used
936
  if remaining <= 0:
937
- status = f'<span class="limit-exceeded">{used}/{limit} (LIMIT REACHED)</span>'
938
  elif remaining <= 2:
939
- status = f'<span style="color: #f59e0b; font-weight: 600;">{used}/{limit} ({remaining} left)</span>'
940
  else:
941
- status = f'<span class="limit-ok">{used}/{limit} ({remaining} left)</span>'
942
- html += f'<div class="limit-item"><span style="font-weight: 500;">{model_name}</span><span>{status}</span></div>'
 
943
  html += '</div>'
944
  return html
945
 
946
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="slate")) as demo:
947
 
948
- gr.HTML('<div class="announcement-banner">🔐 <strong>SAM-X-1 V3.0 - SESSION CODE ACCESS</strong> 🔐<br>✨ Sign in to get your 4-digit session code!<br>🆓 FREE: Nano & Mini unlimited, Fast 10/3h, Large 8/3h<br>⭐ PLUS: Nano/Mini/Fast unlimited, Large 20/3h<br>💎 PRO: Everything unlimited!</div>')
 
 
 
949
 
950
- with gr.Tabs() as main_tabs:
951
- with gr.Tab("🔐 Sign In"):
952
- with gr.Column():
953
- login_username = gr.Textbox(label="Username", placeholder="Enter username")
954
- login_password = gr.Textbox(label="Password", type="password", placeholder="Enter password")
955
- login_btn = gr.Button("Sign In", variant="primary", size="lg")
956
- login_msg = gr.Markdown("")
957
- session_code_display = gr.HTML("")
958
-
959
- with gr.Tab("📝 Sign Up"):
960
- with gr.Column():
961
- signup_username = gr.Textbox(label="Username", placeholder="Choose a username")
962
- signup_email = gr.Textbox(label="Email (optional)", placeholder="your@email.com")
963
- signup_password = gr.Textbox(label="Password", type="password", placeholder="Choose a password")
964
- signup_btn = gr.Button("Create Account", variant="primary", size="lg")
965
- signup_msg = gr.Markdown("")
966
-
967
- with gr.Tab("💬 Chat") as chat_tab:
968
- with gr.Row():
969
- chat_session_code = gr.Textbox(label="🔑 Enter Your 4-Digit Session Code", placeholder="0000", max_lines=1, scale=3)
970
- verify_session_btn = gr.Button("✅ Verify", variant="primary", scale=1)
971
-
972
- with gr.Row():
973
- with gr.Column(scale=4):
974
- user_info = gr.Markdown("❌ Not authenticated - Enter your session code above")
975
- with gr.Column(scale=1):
976
- logout_btn = gr.Button("🚪 Logout", size="sm")
977
 
978
- limits_display = gr.HTML("")
 
 
979
 
980
- with gr.Accordion("⚙️ Settings", open=False):
981
- with gr.Row():
982
- model_selector = gr.Dropdown(choices=["🤖 Auto (Recommended)"], value="🤖 Auto (Recommended)", label="Model Selection", info="FREE users: Auto only. PLUS/PRO: Choose manually")
983
- max_tokens_slider = gr.Slider(minimum=64, maximum=512, value=256, step=64, label="Max Tokens")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
984
  with gr.Row():
985
- temperature_slider = gr.Slider(minimum=0.0, maximum=2.0, value=0.7, step=0.1, label="Temperature")
986
- show_thinking_checkbox = gr.Checkbox(label="Show Thinking", value=True)
987
 
988
- speed_display = gr.Textbox(label="Generation Speed", value="⚡ Ready", interactive=False)
989
- chat_html = gr.HTML(value="", elem_classes=["chat-container"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
990
 
991
- with gr.Row():
992
- msg_input = gr.Textbox(placeholder="Enter session code first to chat...", show_label=False, scale=8, interactive=False)
993
- with gr.Column(scale=1, min_width=120):
 
 
 
 
994
  with gr.Row():
995
- send_btn = gr.Button("▶", variant="primary", elem_classes=["circular-btn", "send-btn"], interactive=False)
996
- stop_btn = gr.Button("⏹", variant="stop", elem_classes=["circular-btn", "stop-btn"], interactive=False)
997
-
998
- with gr.Row():
999
- clear_btn = gr.Button("🗑️ Clear", size="sm")
1000
- upgrade_btn = gr.Button("⭐ Request Upgrade", size="sm", variant="primary")
1001
-
1002
- with gr.Accordion("🔐 Admin Panel", visible=False, open=False) as admin_panel:
1003
- gr.Markdown("### 👨‍💼 User Management Dashboard")
1004
- with gr.Tabs():
1005
- with gr.Tab("👥 All Users"):
1006
- users_table = gr.Dataframe(headers=["ID", "Username", "Email", "Plan", "Created", "Admin"])
1007
- refresh_users_btn = gr.Button("🔄 Refresh Users")
1008
- with gr.Row():
1009
- admin_username = gr.Textbox(label="Username to Update")
1010
- admin_new_plan = gr.Dropdown(choices=["free", "plus", "pro", "explore", "Research", "VIP(hyper)"], label="New Plan", value="free")
1011
- update_plan_btn = gr.Button("✏️ Update Plan", variant="primary")
1012
- admin_msg = gr.Markdown("")
1013
 
1014
- with gr.Tab("📋 Upgrade Requests"):
1015
- gr.Markdown("**Review and approve/deny user upgrade requests below:**")
1016
- requests_table = gr.Dataframe(headers=["ID", "Username", "Requested Plan", "Reason", "Date"])
1017
- refresh_requests_btn = gr.Button("🔄 Refresh Requests")
1018
- with gr.Row():
1019
- request_id_input = gr.Number(label="Request ID (from table above)", precision=0, minimum=1)
1020
- with gr.Row():
1021
- approve_req_btn = gr.Button("✅ Approve Request", variant="primary", size="lg")
1022
- deny_req_btn = gr.Button("❌ Deny Request", variant="stop", size="lg")
1023
- request_msg = gr.Markdown("")
1024
-
1025
- with gr.Accordion("⭐ Request Plan Upgrade", visible=False, open=False) as upgrade_panel:
1026
- upgrade_session_code = gr.Textbox(label="Your Session Code", placeholder="0000")
1027
- upgrade_plan_choice = gr.Radio(choices=["plus", "pro", "explore", "Research"], label="Select Plan", value="plus")
1028
- upgrade_reason = gr.Textbox(label="Reason for Upgrade", placeholder="Why do you need this upgrade?", lines=3)
1029
- submit_upgrade_btn = gr.Button("Submit Request", variant="primary")
1030
- upgrade_msg = gr.Markdown("")
1031
-
1032
- with gr.Tab("👨‍💼 Admin Access") as admin_tab:
1033
- admin_session_code = gr.Textbox(label="🔑 Enter Your Admin Session Code", placeholder="0000", max_lines=1)
1034
- verify_admin_btn = gr.Button("✅ Verify Admin", variant="primary", size="lg")
1035
- admin_verify_msg = gr.Markdown("")
1036
- admin_logout_btn = gr.Button("🚪 Logout", size="sm")
1037
 
1038
- # Event handlers
1039
- def handle_login(username, password):
1040
- success, user_data = authenticate_user(username, password)
1041
- if success:
1042
- session_code = create_session(user_data)
1043
- code_html = f'<div class="session-code-box"><div style="font-size: 18px; margin-bottom: 10px;">✅ Login Successful!</div><div style="font-size: 16px; margin-bottom: 5px;">Your Session Code:</div><div class="session-code-display">{session_code}</div><div style="font-size: 14px; margin-top: 10px;">💡 Use this code in the Chat or Admin tab</div><div style="font-size: 13px; margin-top: 5px; opacity: 0.9;">⚠️ Keep this code private!</div></div>'
1044
- return f"✅ Welcome back, **{username}**! Use your session code above to access chat.", code_html
1045
- return "❌ Invalid credentials!", ""
1046
 
1047
- def handle_signup(username, email, password):
 
1048
  if len(username) < 3:
1049
- return "❌ Username must be at least 3 characters!"
1050
  if len(password) < 6:
1051
- return "❌ Password must be at least 6 characters!"
1052
- success, message = create_user(username, password, email)
1053
- if success:
1054
- return f"✅ {message} Now sign in to get your session code!"
1055
- return f"❌ {message}"
1056
-
1057
- def verify_session_code(code):
1058
- if not code or len(code) != 4 or not code.isdigit():
1059
- return "❌ Invalid code format", "", gr.update(visible=False), gr.update(), gr.update(), gr.update(interactive=False, placeholder="Enter valid session code first..."), gr.update(interactive=False)
1060
 
1061
- user_data = validate_session(code)
1062
- if not user_data:
1063
- return "❌ Invalid or expired session code", "", gr.update(visible=False), gr.update(), gr.update(), gr.update(interactive=False, placeholder="Enter valid session code first..."), gr.update(interactive=False)
1064
 
1065
- info = get_user_limits_info(user_data['user_id'])
1066
- if not info:
1067
- return "❌ Could not load user info", "", gr.update(visible=False), gr.update(), gr.update(), gr.update(interactive=False), gr.update(interactive=False)
 
 
 
 
 
 
 
1068
 
1069
- plan_badge = f'<span class="plan-badge plan-{info["plan"]}">{info["plan"].upper()}</span>'
1070
- user_info_text = f"✅ **Authenticated as: {user_data['username']}** {plan_badge}"
1071
- limits_html = render_limits_panel(user_data)
1072
 
 
 
 
 
 
 
1073
  if info['can_choose_model']:
1074
- available_model_names = list(available_models.keys())
1075
- choices = ["🤖 Auto (Recommended)"] + available_model_names
1076
  else:
1077
- choices = ["🤖 Auto (Recommended)"]
1078
 
1079
- is_admin = user_data.get('is_admin', False)
1080
 
1081
  return (
1082
- user_info_text,
1083
- limits_html,
1084
- gr.update(visible=is_admin),
1085
- gr.update(choices=choices, value="🤖 Auto (Recommended)"),
1086
- gr.update(maximum=info['max_tokens'], value=min(256, info['max_tokens'])),
1087
- gr.update(interactive=True, placeholder="Ask me anything..."),
1088
- gr.update(interactive=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1089
  )
1090
 
1091
- def send_message_handler(message, show_thinking, temperature, model_choice, max_tokens, session_code):
1092
  global stop_generation
1093
  stop_generation.clear()
1094
 
1095
- if not session_code or len(session_code) != 4:
1096
- return "", "", " Invalid session code", gr.update(), gr.update()
1097
 
1098
- user_data = validate_session(session_code)
1099
- if not user_data:
1100
- return "", "", " Session expired - please re-enter your code", gr.update(), gr.update()
1101
 
1102
  if not message.strip():
1103
- return "", "", " Ready", gr.update(interactive=True), gr.update(interactive=False)
1104
 
1105
- info = get_user_limits_info(user_data['user_id'])
1106
 
1107
- # Auto or manual model selection
1108
  if model_choice == "🤖 Auto (Recommended)" or not info['can_choose_model']:
1109
- user_available = get_available_models_for_user(user_data['user_id'])
1110
  if not user_available:
1111
- return "", "", " No models available (limits reached)", gr.update(interactive=True), gr.update(interactive=False)
1112
  backend = select_model_auto(message, available_models, user_available)
1113
  if not backend:
1114
- return "", "", " Could not select model", gr.update(interactive=True), gr.update(interactive=False)
1115
  model_name = backend.get_name()
1116
  else:
1117
  model_name = model_choice
1118
- can_use, msg = can_use_model(user_data['user_id'], model_name)
1119
  if not can_use:
1120
- return "", "", f" {msg}", gr.update(interactive=True), gr.update(interactive=False)
1121
  backend = available_models[model_name]
1122
 
1123
  # Final check
1124
- can_use, msg = can_use_model(user_data['user_id'], model_name)
1125
  if not can_use:
1126
- return "", "", f" {msg}", gr.update(interactive=True), gr.update(interactive=False)
1127
 
1128
  # Increment usage
1129
- increment_model_usage(user_data['user_id'], model_name)
1130
 
1131
- yield "", "", f" Using {model_name}...", gr.update(interactive=False), gr.update(interactive=True)
1132
 
1133
  history = [{"role": "user", "content": message}]
1134
- yield "", render_history(history, show_thinking), f" Generating...", gr.update(interactive=False), gr.update(interactive=True)
1135
 
1136
  prompt = f"User: {message}\nSam: <think>"
1137
  history.append({"role": "assistant", "content": "<think>"})
@@ -1153,153 +1525,157 @@ if __name__ == "__main__":
1153
  history[-1]["content"] += new_chunk
1154
 
1155
  last_speed = avg_speed
1156
- yield "", render_history(history, show_thinking), f" {tokens_per_sec:.1f} tok/s", gr.update(interactive=False), gr.update(interactive=True)
1157
 
1158
- final = f"{'🛑 Stopped' if was_stopped else '✅ Done'} - {last_speed:.1f} tok/s"
1159
- yield "", render_history(history, show_thinking), final, gr.update(interactive=True), gr.update(interactive=False)
1160
 
1161
  def stop_generation_handler():
1162
  global stop_generation
1163
  stop_generation.set()
1164
- return "🛑 Stopping...", gr.update(interactive=False), gr.update(interactive=False)
1165
 
1166
  def clear_chat():
1167
- return "", " Ready", gr.update(interactive=True), gr.update(interactive=False)
1168
 
1169
- def show_upgrade_panel():
1170
- return gr.update(visible=True, open=True)
1171
-
1172
- def submit_upgrade_request(session_code, plan, reason):
1173
- if not session_code or len(session_code) != 4:
1174
- return "❌ Invalid session code"
1175
 
1176
- user_data = validate_session(session_code)
1177
- if not user_data:
1178
  return "❌ Session expired"
1179
 
1180
  if not reason.strip():
1181
  return "❌ Please provide a reason"
1182
 
1183
- success, msg = request_upgrade(user_data['user_id'], plan, reason)
1184
  return f"{'✅' if success else '❌'} {msg}"
1185
 
1186
- def handle_logout(session_code):
1187
- if session_code and len(session_code) == 4:
1188
- invalidate_session(session_code)
1189
- return (
1190
- "",
1191
- "❌ Logged out - Session code invalidated",
1192
- "",
1193
- gr.update(visible=False),
1194
- gr.update(choices=["🤖 Auto (Recommended)"], value="🤖 Auto (Recommended)"),
1195
- gr.update(value=256),
1196
- gr.update(interactive=False, placeholder="Enter session code first..."),
1197
- gr.update(interactive=False)
1198
- )
1199
-
1200
- def verify_admin_session(code):
1201
- if not code or len(code) != 4 or not code.isdigit():
1202
- return "❌ Invalid code format", gr.update(visible=False)
1203
-
1204
- user_data = validate_session(code)
1205
- if not user_data:
1206
- return "❌ Invalid or expired session code", gr.update(visible=False)
1207
-
1208
- if not user_data.get('is_admin', False):
1209
- return "❌ Access denied - Admin privileges required", gr.update(visible=False)
1210
-
1211
- return f"✅ Admin access granted for **{user_data['username']}**", gr.update(visible=True, open=True)
1212
-
1213
- def admin_logout_handler(code):
1214
- if code and len(code) == 4:
1215
- invalidate_session(code)
1216
- return "", "❌ Logged out", gr.update(visible=False)
1217
-
1218
  def load_all_users():
1219
  users = get_all_users()
1220
  formatted = []
1221
  for user in users:
1222
- formatted.append([user[0], user[1], user[2] or "N/A", user[3], user[4][:10] if user[4] else "N/A", "Yes" if user[5] else "No"])
 
 
 
 
 
 
 
1223
  return formatted
1224
 
1225
  def load_pending_requests():
1226
  requests = get_pending_requests()
1227
  formatted = []
1228
  for req in requests:
1229
- formatted.append([req[0], req[1], req[2], req[3], req[4][:10] if req[4] else "N/A"])
 
 
 
 
 
 
1230
  return formatted
1231
 
1232
- def admin_update_plan(username, new_plan):
1233
  if not username or not new_plan:
1234
  return "❌ Please fill all fields"
1235
  success, msg = update_user_plan(username, new_plan)
1236
  return f"{'✅' if success else '❌'} {msg}"
1237
 
1238
- def admin_approve_request(request_id):
1239
  if not request_id:
1240
  return "❌ Please enter request ID"
1241
  success, msg = approve_request(int(request_id))
1242
  return f"{'✅' if success else '❌'} {msg}"
1243
 
1244
- def admin_deny_request(request_id):
1245
  if not request_id:
1246
  return "❌ Please enter request ID"
1247
  success, msg = deny_request(int(request_id))
1248
  return f"{'✅' if success else '❌'} {msg}"
1249
 
1250
- # Wire up events
1251
- login_btn.click(handle_login, [login_username, login_password], [login_msg, session_code_display])
1252
- signup_btn.click(handle_signup, [signup_username, signup_email, signup_password], [signup_msg])
 
 
 
 
 
 
 
 
 
 
1253
 
1254
- # Session verification
1255
- verify_outputs = [user_info, limits_display, admin_panel, model_selector, max_tokens_slider, msg_input, send_btn]
1256
- verify_session_btn.click(verify_session_code, [chat_session_code], verify_outputs)
1257
 
1258
- # Chat functionality
1259
- send_outputs = [msg_input, chat_html, speed_display, send_btn, stop_btn]
1260
- send_btn.click(send_message_handler, [msg_input, show_thinking_checkbox, temperature_slider, model_selector, max_tokens_slider, chat_session_code], send_outputs)
1261
- msg_input.submit(send_message_handler, [msg_input, show_thinking_checkbox, temperature_slider, model_selector, max_tokens_slider, chat_session_code], send_outputs)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1262
 
1263
  stop_btn.click(stop_generation_handler, outputs=[speed_display, send_btn, stop_btn])
1264
  clear_btn.click(clear_chat, outputs=[chat_html, speed_display, send_btn, stop_btn])
1265
- upgrade_btn.click(show_upgrade_panel, outputs=[upgrade_panel])
1266
- submit_upgrade_btn.click(submit_upgrade_request, [upgrade_session_code, upgrade_plan_choice, upgrade_reason], [upgrade_msg])
1267
-
1268
- logout_outputs = [chat_session_code, user_info, limits_display, admin_panel, model_selector, max_tokens_slider, msg_input, send_btn]
1269
- logout_btn.click(handle_logout, [chat_session_code], logout_outputs)
1270
 
1271
- # Admin panel events
1272
- verify_admin_btn.click(verify_admin_session, [admin_session_code], [admin_verify_msg, admin_panel])
1273
- admin_logout_btn.click(admin_logout_handler, [admin_session_code], [admin_session_code, admin_verify_msg, admin_panel])
 
 
 
1274
 
 
1275
  refresh_users_btn.click(load_all_users, outputs=[users_table])
1276
  refresh_requests_btn.click(load_pending_requests, outputs=[requests_table])
1277
- update_plan_btn.click(admin_update_plan, [admin_username, admin_new_plan], [admin_msg])
1278
- approve_req_btn.click(admin_approve_request, [request_id_input], [request_msg])
1279
- deny_req_btn.click(admin_deny_request, [request_id_input], [request_msg])
1280
 
 
1281
  gr.Markdown("""
1282
  ---
1283
- ### 🔑 How Session Codes Work
 
 
 
 
1284
 
1285
- 1. **Sign In** on the "Sign In" tab to get your unique 4-digit code
1286
- 2. **Copy** your session code (displayed after login)
1287
- 3. **Enter** the code in the Chat or Admin tab to access features
1288
- 4. **Logout** invalidates your code (you'll need to sign in again)
1289
 
1290
- ### 📊 Plan Comparison
 
 
1291
 
1292
- | Feature | FREE | PLUS ⭐ | PRO 💎 |
1293
- |---------|------|---------|--------|
1294
- | **Nano Model** | Unlimited | Unlimited | Unlimited |
1295
- | **Mini Model** | Unlimited | Unlimited | ✅ Unlimited |
1296
- | **Fast Model** | 10 msgs/3h | ✅ Unlimited | ✅ Unlimited |
1297
- | **Large Model** | 8 msgs/3h | 20 msgs/3h | ✅ Unlimited |
1298
- | **Model Selection** | 🤖 Auto only | ✅ Manual choice | ✅ Manual choice |
1299
- | **Max Tokens** | 256 | 384 | 512 |
1300
 
1301
- ### 🆓 Sign up for FREE account - Nano & Mini unlimited!
1302
- ### 👨‍💼 Admins: Use your session code in the Admin Access tab
1303
  """)
1304
 
1305
  demo.launch(debug=True, share=False, server_name="0.0.0.0", server_port=7860)
 
806
  final_tokens_per_sec = tokens_generated / elapsed if elapsed > 0 else 0
807
  yield "", False, final_tokens_per_sec, final_tokens_per_sec, False
808
 
809
+
810
+ # PART 3 - Multi-Page Website UI (No Backend Changes)
811
 
812
  import secrets
813
 
814
+ # Global session storage (unchanged from original)
815
+ active_sessions = {}
816
  session_lock = threading.Lock()
817
 
818
  def generate_session_code():
 
819
  with session_lock:
820
  while True:
821
  code = ''.join([str(secrets.randbelow(10)) for _ in range(4)])
 
823
  return code
824
 
825
  def create_session(user_data):
 
826
  code = generate_session_code()
827
  with session_lock:
 
828
  normalized_data = {
829
  'user_id': user_data.get('id') or user_data.get('user_id'),
830
  'username': user_data.get('username'),
 
835
  return code
836
 
837
  def validate_session(code):
 
838
  with session_lock:
839
  return active_sessions.get(code, None)
840
 
841
  def invalidate_session(code):
 
842
  with session_lock:
843
  if code in active_sessions:
844
  del active_sessions[code]
 
849
  import gradio as gr
850
 
851
  custom_css = """
852
+ /* Modern Website Styling */
853
+ .app-container { max-width: 1400px; margin: 0 auto; }
854
+
855
+ /* Navigation Bar */
856
+ .nav-bar {
857
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
858
+ padding: 16px 32px;
859
+ border-radius: 12px;
860
+ margin-bottom: 24px;
861
+ display: flex;
862
+ justify-content: space-between;
863
+ align-items: center;
864
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
865
+ }
866
+ .nav-left { display: flex; align-items: center; gap: 24px; }
867
+ .nav-brand { font-size: 24px; font-weight: 700; color: white; }
868
+ .nav-links { display: flex; gap: 16px; }
869
+ .nav-link {
870
+ color: white;
871
+ padding: 8px 16px;
872
+ border-radius: 8px;
873
+ cursor: pointer;
874
+ transition: all 0.2s;
875
+ background: rgba(255,255,255,0.1);
876
+ }
877
+ .nav-link:hover { background: rgba(255,255,255,0.2); transform: translateY(-2px); }
878
+ .nav-link.active { background: rgba(255,255,255,0.3); font-weight: 600; }
879
+ .nav-right { display: flex; align-items: center; gap: 16px; }
880
+ .user-greeting { color: white; font-weight: 500; font-size: 15px; }
881
+
882
+ /* Plan Badge */
883
+ .plan-badge {
884
+ display: inline-block;
885
+ padding: 6px 14px;
886
+ border-radius: 16px;
887
+ font-size: 12px;
888
+ font-weight: 700;
889
+ margin-left: 8px;
890
+ text-transform: uppercase;
891
+ letter-spacing: 0.5px;
892
+ }
893
+ .plan-free { background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%); color: #3730a3; }
894
+ .plan-plus { background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); color: #1e40af; }
895
+ .plan-pro { background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%); color: #92400e; }
896
+ .plan-explore { background: linear-gradient(135deg, #d8b4fe 0%, #c4b5fd 100%); color: #7e22ce; }
897
+ .plan-research { background: linear-gradient(135deg, #a5f3fc 0%, #67e8f9 100%); color: #0e7490; }
898
+ .plan-vip { background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%); color: #78350f; }
899
+
900
+ /* Auth Page */
901
+ .auth-container {
902
+ max-width: 480px;
903
+ margin: 60px auto;
904
+ background: white;
905
+ padding: 40px;
906
+ border-radius: 16px;
907
+ box-shadow: 0 8px 24px rgba(0,0,0,0.1);
908
+ }
909
+ .auth-title {
910
+ font-size: 32px;
911
+ font-weight: 700;
912
+ text-align: center;
913
+ margin-bottom: 8px;
914
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
915
+ -webkit-background-clip: text;
916
+ -webkit-text-fill-color: transparent;
917
+ }
918
+ .auth-subtitle {
919
+ text-align: center;
920
+ color: #6b7280;
921
+ margin-bottom: 32px;
922
+ font-size: 14px;
923
+ }
924
+
925
+ /* Chat Interface */
926
+ .chat-container {
927
+ height: 520px;
928
+ overflow-y: auto;
929
+ padding: 24px;
930
+ background: #f9fafb;
931
+ border: 1px solid #e5e7eb;
932
+ border-radius: 12px;
933
+ margin-bottom: 16px;
934
+ }
935
+ .user-message {
936
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
937
+ color: white;
938
+ padding: 16px 20px;
939
+ margin: 12px 0;
940
+ border-radius: 16px 16px 4px 16px;
941
+ max-width: 80%;
942
+ margin-left: auto;
943
+ }
944
+ .assistant-message {
945
+ background: white;
946
+ padding: 16px 20px;
947
+ margin: 12px 0;
948
+ border-radius: 16px 16px 16px 4px;
949
+ border-left: 4px solid #10a37f;
950
+ max-width: 80%;
951
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
952
+ }
953
+ .message-content { color: #353740; line-height: 1.7; font-size: 15px; }
954
+ .user-message .message-content { color: white; }
955
+ .thinking-content {
956
+ color: #6b7280;
957
+ font-style: italic;
958
+ border-left: 3px solid #d1d5db;
959
+ padding-left: 12px;
960
+ margin: 12px 0;
961
+ background: #f9fafb;
962
+ padding: 12px;
963
+ border-radius: 8px;
964
+ }
965
+
966
+ /* Input Area */
967
+ .input-row {
968
+ display: flex;
969
+ gap: 12px;
970
+ align-items: flex-end;
971
+ }
972
+ .circular-btn {
973
+ width: 52px !important;
974
+ height: 52px !important;
975
+ min-width: 52px !important;
976
+ border-radius: 50% !important;
977
+ padding: 0 !important;
978
+ font-size: 22px !important;
979
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
980
+ transition: all 0.2s ease !important;
981
+ border: none !important;
982
+ }
983
+ .circular-btn:hover:not(:disabled) {
984
+ transform: scale(1.08) !important;
985
+ box-shadow: 0 6px 16px rgba(0,0,0,0.2) !important;
986
+ }
987
+ .send-btn {
988
+ background: linear-gradient(135deg, #10a37f 0%, #0d8c6c 100%) !important;
989
+ }
990
+ .stop-btn {
991
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
992
+ }
993
+
994
+ /* Sidebar/Limits Panel */
995
+ .limits-panel {
996
+ background: white;
997
+ border: 1px solid #e5e7eb;
998
+ border-radius: 12px;
999
+ padding: 20px;
1000
+ margin-bottom: 16px;
1001
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
1002
+ }
1003
+ .limit-item {
1004
+ display: flex;
1005
+ justify-content: space-between;
1006
+ padding: 12px 0;
1007
+ border-bottom: 1px solid #f3f4f6;
1008
+ align-items: center;
1009
+ }
1010
  .limit-item:last-child { border-bottom: none; }
1011
  .limit-exceeded { color: #dc2626; font-weight: 600; }
1012
+ .limit-ok { color: #059669; font-weight: 500; }
1013
+ .limit-warning { color: #f59e0b; font-weight: 600; }
1014
+
1015
+ /* Plans Section */
1016
+ .plans-grid {
1017
+ display: grid;
1018
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
1019
+ gap: 24px;
1020
+ margin-top: 24px;
1021
+ }
1022
+ .plan-card {
1023
+ background: white;
1024
+ border: 2px solid #e5e7eb;
1025
+ border-radius: 16px;
1026
+ padding: 28px;
1027
+ transition: all 0.3s;
1028
+ position: relative;
1029
+ overflow: hidden;
1030
+ }
1031
+ .plan-card:hover {
1032
+ transform: translateY(-4px);
1033
+ box-shadow: 0 12px 24px rgba(0,0,0,0.12);
1034
+ border-color: #667eea;
1035
+ }
1036
+ .plan-card.featured {
1037
+ border: 3px solid #667eea;
1038
+ box-shadow: 0 8px 24px rgba(102, 126, 234, 0.2);
1039
+ }
1040
+ .plan-card.featured::before {
1041
+ content: '⭐ POPULAR';
1042
+ position: absolute;
1043
+ top: 16px;
1044
+ right: -32px;
1045
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1046
+ color: white;
1047
+ padding: 4px 40px;
1048
+ font-size: 11px;
1049
+ font-weight: 700;
1050
+ letter-spacing: 1px;
1051
+ transform: rotate(45deg);
1052
+ }
1053
+ .plan-name {
1054
+ font-size: 24px;
1055
+ font-weight: 700;
1056
+ margin-bottom: 8px;
1057
+ color: #1f2937;
1058
+ }
1059
+ .plan-price {
1060
+ font-size: 14px;
1061
+ color: #6b7280;
1062
+ margin-bottom: 20px;
1063
+ }
1064
+ .plan-features {
1065
+ list-style: none;
1066
+ padding: 0;
1067
+ margin: 20px 0;
1068
+ }
1069
+ .plan-features li {
1070
+ padding: 8px 0;
1071
+ color: #4b5563;
1072
+ font-size: 14px;
1073
+ }
1074
+ .plan-features li::before {
1075
+ content: '✓ ';
1076
+ color: #10a37f;
1077
+ font-weight: 700;
1078
+ margin-right: 8px;
1079
+ }
1080
+
1081
+ /* Admin Dashboard */
1082
+ .admin-dashboard {
1083
+ background: white;
1084
+ border-radius: 12px;
1085
+ padding: 24px;
1086
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
1087
+ }
1088
+ .dashboard-header {
1089
+ font-size: 24px;
1090
+ font-weight: 700;
1091
+ margin-bottom: 24px;
1092
+ color: #1f2937;
1093
+ }
1094
+
1095
+ /* Settings Panel */
1096
+ .settings-panel {
1097
+ background: white;
1098
+ border: 1px solid #e5e7eb;
1099
+ border-radius: 12px;
1100
+ padding: 20px;
1101
+ margin-bottom: 16px;
1102
+ }
1103
+
1104
+ /* Speed indicator */
1105
+ .speed-indicator {
1106
+ text-align: center;
1107
+ padding: 12px;
1108
+ background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
1109
+ border-radius: 8px;
1110
+ font-weight: 600;
1111
+ color: #166534;
1112
+ margin-bottom: 12px;
1113
+ }
1114
+
1115
+ /* Responsive */
1116
+ @media (max-width: 768px) {
1117
+ .nav-bar { flex-direction: column; gap: 16px; }
1118
+ .nav-left, .nav-right { width: 100%; justify-content: center; }
1119
+ .chat-container { height: 400px; }
1120
+ .plans-grid { grid-template-columns: 1fr; }
1121
+ }
1122
  """
1123
 
1124
+ # User greeting variations
1125
+ def get_greeting(username):
1126
+ import random
1127
+ greetings = [
1128
+ f"Hey {username}! 👋",
1129
+ f"Welcome back, {username}! ✨",
1130
+ f"Hi {username}! 🚀",
1131
+ f"Hello {username}! 😊",
1132
+ f"Great to see you, {username}! 🎉",
1133
+ f"What's up, {username}? 💫"
1134
+ ]
1135
+ return random.choice(greetings)
1136
+
1137
+ # Format message HTML
1138
  def format_message_html(role, content, show_thinking=True):
1139
  role_class = "user-message" if role == "user" else "assistant-message"
 
1140
  thinking = ""
1141
  answer = ""
1142
+
1143
  if "<think>" in content:
1144
  parts = content.split("<think>", 1)
1145
  before_think = parts[0].strip()
 
1160
  answer = before_think
1161
  else:
1162
  answer = content
1163
+
1164
+ html = f'<div class="{role_class}"><div class="message-content">'
1165
  if thinking and show_thinking:
1166
  html += f'<div class="thinking-content">💭 {thinking}</div>'
1167
  if answer:
 
1181
  info = get_user_limits_info(user_data['user_id'])
1182
  if not info:
1183
  return ""
1184
+
1185
+ plan_class = f"plan-{info['plan'].lower()}"
1186
+ html = f'''<div class="limits-panel">
1187
+ <div style="font-weight: 700; margin-bottom: 16px; font-size: 18px; color: #1f2937;">
1188
+ Usage Limits
1189
+ <span class="plan-badge {plan_class}">{info["plan"]}</span>
1190
+ </div>
1191
+ <div style="font-size: 13px; color: #6b7280; margin-bottom: 16px; padding: 8px; background: #f9fafb; border-radius: 6px;">
1192
+ ⏰ Resets in: <strong>{info["reset_in"]}</strong>
1193
+ </div>'''
1194
+
1195
+ models_info = [
1196
+ ('Nano ⚡⚡', info['nano_used'], info['nano_limit']),
1197
+ ('Mini 🚀', info['mini_used'], info['mini_limit']),
1198
+ ('Fast ⚡', info['fast_used'], info['fast_limit']),
1199
+ ('Large 💎', info['large_used'], info['large_limit'])
1200
+ ]
1201
+
1202
  for model_name, used, limit in models_info:
1203
  if limit == -1:
1204
+ status = f'<span class="limit-ok">{used} / ∞</span>'
1205
  else:
1206
  remaining = limit - used
1207
  if remaining <= 0:
1208
+ status = f'<span class="limit-exceeded">{used}/{limit}</span>'
1209
  elif remaining <= 2:
1210
+ status = f'<span class="limit-warning">{used}/{limit}</span>'
1211
  else:
1212
+ status = f'<span class="limit-ok">{used}/{limit}</span>'
1213
+ html += f'<div class="limit-item"><span style="font-weight: 500;">{model_name}</span>{status}</div>'
1214
+
1215
  html += '</div>'
1216
  return html
1217
 
1218
  with gr.Blocks(css=custom_css, theme=gr.themes.Soft(primary_hue="slate")) as demo:
1219
 
1220
+ # State to track current page and session
1221
+ current_page = gr.State("auth") # auth, chat, admin
1222
+ session_code = gr.State("")
1223
+ user_data = gr.State(None)
1224
 
1225
+ # Navigation Bar
1226
+ with gr.Row(elem_classes="nav-bar"):
1227
+ with gr.Column(scale=1, elem_classes="nav-left"):
1228
+ gr.HTML('<div class="nav-brand">🤖 SAM-X-1</div>')
1229
+ with gr.Column(scale=2, elem_classes="nav-right"):
1230
+ user_greeting = gr.HTML('<div class="user-greeting">Please sign in</div>')
1231
+ upgrade_nav_btn = gr.Button("⭐ Upgrade", size="sm", visible=False)
1232
+ logout_nav_btn = gr.Button("🚪 Logout", size="sm", visible=False)
1233
+
1234
+ # AUTH PAGE
1235
+ with gr.Group(visible=True) as auth_page:
1236
+ with gr.Column(elem_classes="auth-container"):
1237
+ gr.HTML('<div class="auth-title">Welcome to SAM-X-1</div>')
1238
+ gr.HTML('<div class="auth-subtitle">Sign in or create a new account</div>')
 
 
 
 
 
 
 
 
 
 
 
 
 
1239
 
1240
+ auth_username = gr.Textbox(label="Username", placeholder="Enter your username")
1241
+ auth_password = gr.Textbox(label="Password", type="password", placeholder="Enter your password")
1242
+ auth_email = gr.Textbox(label="Email (optional, for new accounts)", placeholder="your@email.com")
1243
 
1244
+ auth_btn = gr.Button("Continue ", variant="primary", size="lg")
1245
+ auth_msg = gr.Markdown("")
1246
+
1247
+ # CHAT PAGE
1248
+ with gr.Group(visible=False) as chat_page:
1249
+ with gr.Row():
1250
+ with gr.Column(scale=3):
1251
+ chat_html = gr.HTML(value='<div class="chat-container"></div>')
1252
+
1253
+ with gr.Row(elem_classes="input-row"):
1254
+ msg_input = gr.Textbox(
1255
+ placeholder="Ask me anything...",
1256
+ show_label=False,
1257
+ scale=10,
1258
+ lines=1
1259
+ )
1260
+ send_btn = gr.Button("▶", elem_classes=["circular-btn", "send-btn"])
1261
+ stop_btn = gr.Button("⏹", elem_classes=["circular-btn", "stop-btn"], visible=False)
1262
+
1263
+ speed_display = gr.HTML('<div class="speed-indicator">⚡ Ready</div>')
1264
+
1265
  with gr.Row():
1266
+ clear_btn = gr.Button("🗑️ Clear", size="sm")
1267
+ new_chat_btn = gr.Button(" New Chat", size="sm", variant="primary")
1268
 
1269
+ with gr.Column(scale=1):
1270
+ limits_display = gr.HTML("")
1271
+
1272
+ with gr.Accordion("⚙️ Settings", open=False, elem_classes="settings-panel"):
1273
+ model_selector = gr.Dropdown(
1274
+ choices=["🤖 Auto (Recommended)"],
1275
+ value="🤖 Auto (Recommended)",
1276
+ label="Model Selection"
1277
+ )
1278
+ max_tokens_slider = gr.Slider(
1279
+ minimum=64, maximum=512, value=256, step=64,
1280
+ label="Max Tokens"
1281
+ )
1282
+ temperature_slider = gr.Slider(
1283
+ minimum=0.0, maximum=2.0, value=0.7, step=0.1,
1284
+ label="Temperature"
1285
+ )
1286
+ show_thinking_checkbox = gr.Checkbox(
1287
+ label="Show Thinking Process",
1288
+ value=True
1289
+ )
1290
+
1291
+ # UPGRADE PAGE (Plans)
1292
+ with gr.Group(visible=False) as upgrade_page:
1293
+ gr.HTML('<div class="dashboard-header" style="text-align: center;">Choose Your Plan</div>')
1294
+ gr.Markdown("**Select the perfect plan for your needs**", elem_classes="text-center")
1295
+
1296
+ with gr.Column(elem_classes="plans-grid"):
1297
+ gr.HTML('''
1298
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 24px; margin-top: 24px;">
1299
+ <div class="plan-card">
1300
+ <div class="plan-name">Free</div>
1301
+ <div class="plan-price">Perfect for getting started</div>
1302
+ <ul class="plan-features">
1303
+ <li>Nano: Unlimited messages</li>
1304
+ <li>Mini: Unlimited messages</li>
1305
+ <li>Fast: 10 messages/3h</li>
1306
+ <li>Large: 8 messages/3h</li>
1307
+ <li>Auto model selection</li>
1308
+ <li>256 max tokens</li>
1309
+ </ul>
1310
+ </div>
1311
+
1312
+ <div class="plan-card featured">
1313
+ <div class="plan-name">Plus ⭐</div>
1314
+ <div class="plan-price">Great for power users</div>
1315
+ <ul class="plan-features">
1316
+ <li>Everything in Free</li>
1317
+ <li>Fast: Unlimited messages</li>
1318
+ <li>Large: 20 messages/3h</li>
1319
+ <li>Manual model selection</li>
1320
+ <li>384 max tokens</li>
1321
+ <li>Priority support</li>
1322
+ </ul>
1323
+ </div>
1324
+
1325
+ <div class="plan-card">
1326
+ <div class="plan-name">Pro 💎</div>
1327
+ <div class="plan-price">For professionals</div>
1328
+ <ul class="plan-features">
1329
+ <li>Everything in Plus</li>
1330
+ <li>All models unlimited</li>
1331
+ <li>512 max tokens</li>
1332
+ <li>Fastest reset (3h)</li>
1333
+ <li>24/7 premium support</li>
1334
+ <li>Early feature access</li>
1335
+ </ul>
1336
+ </div>
1337
+ </div>
1338
+ ''')
1339
+
1340
+ upgrade_plan_choice = gr.Radio(
1341
+ choices=["plus", "pro", "explore", "Research"],
1342
+ label="Select Plan to Request",
1343
+ value="plus"
1344
+ )
1345
+ upgrade_reason = gr.Textbox(
1346
+ label="Why do you need this upgrade?",
1347
+ placeholder="Tell us about your use case...",
1348
+ lines=3
1349
+ )
1350
+ submit_upgrade_btn = gr.Button("Submit Upgrade Request", variant="primary", size="lg")
1351
+ upgrade_msg = gr.Markdown("")
1352
+ back_to_chat_btn = gr.Button("← Back to Chat", size="sm")
1353
+
1354
+ # ADMIN PAGE
1355
+ with gr.Group(visible=False) as admin_page:
1356
+ with gr.Column(elem_classes="admin-dashboard"):
1357
+ gr.HTML('<div class="dashboard-header">👨‍💼 Admin Dashboard</div>')
1358
 
1359
+ with gr.Tabs():
1360
+ with gr.Tab("👥 Users"):
1361
+ users_table = gr.Dataframe(
1362
+ headers=["ID", "Username", "Email", "Plan", "Created", "Admin"]
1363
+ )
1364
+ refresh_users_btn = gr.Button("🔄 Refresh", size="sm")
1365
+
1366
  with gr.Row():
1367
+ admin_username = gr.Textbox(label="Username", scale=2)
1368
+ admin_new_plan = gr.Dropdown(
1369
+ choices=["free", "plus", "pro", "explore", "Research", "VIP"],
1370
+ label="New Plan",
1371
+ scale=1
1372
+ )
1373
+ update_plan_btn = gr.Button("Update", variant="primary", scale=1)
1374
+ admin_msg = gr.Markdown("")
1375
+
1376
+ with gr.Tab("📋 Requests"):
1377
+ requests_table = gr.Dataframe(
1378
+ headers=["ID", "Username", "Plan", "Reason", "Date"]
1379
+ )
1380
+ refresh_requests_btn = gr.Button("🔄 Refresh", size="sm")
 
 
 
 
1381
 
1382
+ with gr.Row():
1383
+ request_id_input = gr.Number(label="Request ID", precision=0)
1384
+ approve_req_btn = gr.Button(" Approve", variant="primary")
1385
+ deny_req_btn = gr.Button(" Deny", variant="stop")
1386
+ request_msg = gr.Markdown("")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1387
 
1388
+ # ==================== EVENT HANDLERS ====================
 
 
 
 
 
 
 
1389
 
1390
+ def handle_auth(username, password, email):
1391
+ """Unified auth handler - auto signup if new user"""
1392
  if len(username) < 3:
1393
+ return None, "❌ Username must be at least 3 characters", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1394
  if len(password) < 6:
1395
+ return None, "❌ Password must be at least 6 characters", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
 
 
 
 
 
 
 
 
1396
 
1397
+ # Try login first
1398
+ success, data = authenticate_user(username, password)
 
1399
 
1400
+ if not success:
1401
+ # Try signup
1402
+ success, message = create_user(username, password, email)
1403
+ if success:
1404
+ # Auto-login after signup
1405
+ success, data = authenticate_user(username, password)
1406
+ if not success:
1407
+ return None, "❌ Account created but login failed", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1408
+ else:
1409
+ return None, f"❌ {message}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
1410
 
1411
+ # Generate session code
1412
+ code = create_session(data)
 
1413
 
1414
+ # Get user info
1415
+ info = get_user_limits_info(data['user_id'])
1416
+ plan_class = f"plan-{info['plan'].lower()}"
1417
+ greeting_html = f'<div class="user-greeting">{get_greeting(username)} <span class="plan-badge {plan_class}">{info["plan"]}</span></div>'
1418
+
1419
+ # Set model choices
1420
  if info['can_choose_model']:
1421
+ model_choices = ["🤖 Auto (Recommended)"] + list(available_models.keys())
 
1422
  else:
1423
+ model_choices = ["🤖 Auto (Recommended)"]
1424
 
1425
+ limits_html = render_limits_panel(data)
1426
 
1427
  return (
1428
+ code,
1429
+ f"✅ Welcome, {username}!",
1430
+ gr.update(visible=False), # auth_page
1431
+ gr.update(visible=True), # chat_page
1432
+ gr.update(visible=data.get('is_admin', False)), # admin_page
1433
+ greeting_html,
1434
+ gr.update(visible=True), # upgrade_nav_btn
1435
+ gr.update(visible=True), # logout_nav_btn
1436
+ model_choices,
1437
+ info['max_tokens'],
1438
+ limits_html
1439
+ )
1440
+
1441
+ def show_upgrade_page():
1442
+ return gr.update(visible=False), gr.update(visible=True)
1443
+
1444
+ def back_to_chat():
1445
+ return gr.update(visible=True), gr.update(visible=False)
1446
+
1447
+ def handle_logout(code):
1448
+ if code:
1449
+ invalidate_session(code)
1450
+ return (
1451
+ "",
1452
+ gr.update(visible=True), # auth_page
1453
+ gr.update(visible=False), # chat_page
1454
+ gr.update(visible=False), # admin_page
1455
+ gr.update(visible=False), # upgrade_page
1456
+ '<div class="user-greeting">Please sign in</div>',
1457
+ gr.update(visible=False), # upgrade_nav_btn
1458
+ gr.update(visible=False), # logout_nav_btn
1459
+ "",
1460
+ ""
1461
  )
1462
 
1463
+ def send_message_handler(message, show_thinking, temperature, model_choice, max_tokens, code):
1464
  global stop_generation
1465
  stop_generation.clear()
1466
 
1467
+ if not code:
1468
+ return "", "", '<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ Session expired</div>', gr.update(), gr.update(), ""
1469
 
1470
+ data = validate_session(code)
1471
+ if not data:
1472
+ return "", "", '<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ Session expired</div>', gr.update(), gr.update(), ""
1473
 
1474
  if not message.strip():
1475
+ return "", "", '<div class="speed-indicator">⚡ Ready</div>', gr.update(), gr.update(), ""
1476
 
1477
+ info = get_user_limits_info(data['user_id'])
1478
 
1479
+ # Model selection logic
1480
  if model_choice == "🤖 Auto (Recommended)" or not info['can_choose_model']:
1481
+ user_available = get_available_models_for_user(data['user_id'])
1482
  if not user_available:
1483
+ return "", "", '<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ No models available</div>', gr.update(), gr.update(), render_limits_panel(data)
1484
  backend = select_model_auto(message, available_models, user_available)
1485
  if not backend:
1486
+ return "", "", '<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ Could not select model</div>', gr.update(), gr.update(), render_limits_panel(data)
1487
  model_name = backend.get_name()
1488
  else:
1489
  model_name = model_choice
1490
+ can_use, msg = can_use_model(data['user_id'], model_name)
1491
  if not can_use:
1492
+ return "", "", f'<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ {msg}</div>', gr.update(), gr.update(), render_limits_panel(data)
1493
  backend = available_models[model_name]
1494
 
1495
  # Final check
1496
+ can_use, msg = can_use_model(data['user_id'], model_name)
1497
  if not can_use:
1498
+ return "", "", f'<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">❌ {msg}</div>', gr.update(), gr.update(), render_limits_panel(data)
1499
 
1500
  # Increment usage
1501
+ increment_model_usage(data['user_id'], model_name)
1502
 
1503
+ yield "", "", f'<div class="speed-indicator" style="background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); color: #1e40af;">⚡ Using {model_name}...</div>', gr.update(interactive=False), gr.update(visible=True), render_limits_panel(data)
1504
 
1505
  history = [{"role": "user", "content": message}]
1506
+ yield "", render_history(history, show_thinking), '<div class="speed-indicator" style="background: linear-gradient(135deg, #dbeafe 0%, #bfdbfe 100%); color: #1e40af;">⚡ Generating...</div>', gr.update(interactive=False), gr.update(visible=True), render_limits_panel(data)
1507
 
1508
  prompt = f"User: {message}\nSam: <think>"
1509
  history.append({"role": "assistant", "content": "<think>"})
 
1525
  history[-1]["content"] += new_chunk
1526
 
1527
  last_speed = avg_speed
1528
+ yield "", render_history(history, show_thinking), f'<div class="speed-indicator" style="background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); color: #166534;">⚡ {tokens_per_sec:.1f} tok/s</div>', gr.update(interactive=False), gr.update(visible=True), render_limits_panel(data)
1529
 
1530
+ final_html = f'<div class="speed-indicator" style="background: linear-gradient(135deg, {"#fee2e2 0%, #fecaca 100%); color: #991b1b;" if was_stopped else "#dcfce7 0%, #bbf7d0 100%); color: #166534;"}>{"🛑 Stopped" if was_stopped else "✅ Done"} - {last_speed:.1f} tok/s</div>'
1531
+ yield "", render_history(history, show_thinking), final_html, gr.update(interactive=True), gr.update(visible=False), render_limits_panel(data)
1532
 
1533
  def stop_generation_handler():
1534
  global stop_generation
1535
  stop_generation.set()
1536
+ return '<div class="speed-indicator" style="background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); color: #991b1b;">🛑 Stopping...</div>', gr.update(interactive=False), gr.update(visible=False)
1537
 
1538
  def clear_chat():
1539
+ return '<div class="chat-container"></div>', '<div class="speed-indicator">⚡ Ready</div>', gr.update(interactive=True), gr.update(visible=False)
1540
 
1541
+ def submit_upgrade_request(code, plan, reason):
1542
+ if not code:
1543
+ return "❌ Session expired"
 
 
 
1544
 
1545
+ data = validate_session(code)
1546
+ if not data:
1547
  return "❌ Session expired"
1548
 
1549
  if not reason.strip():
1550
  return "❌ Please provide a reason"
1551
 
1552
+ success, msg = request_upgrade(data['user_id'], plan, reason)
1553
  return f"{'✅' if success else '❌'} {msg}"
1554
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1555
  def load_all_users():
1556
  users = get_all_users()
1557
  formatted = []
1558
  for user in users:
1559
+ formatted.append([
1560
+ user[0],
1561
+ user[1],
1562
+ user[2] or "N/A",
1563
+ user[3],
1564
+ user[4][:10] if user[4] else "N/A",
1565
+ "Yes" if user[5] else "No"
1566
+ ])
1567
  return formatted
1568
 
1569
  def load_pending_requests():
1570
  requests = get_pending_requests()
1571
  formatted = []
1572
  for req in requests:
1573
+ formatted.append([
1574
+ req[0],
1575
+ req[1],
1576
+ req[2],
1577
+ req[3],
1578
+ req[4][:10] if req[4] else "N/A"
1579
+ ])
1580
  return formatted
1581
 
1582
+ def admin_update_plan_handler(username, new_plan):
1583
  if not username or not new_plan:
1584
  return "❌ Please fill all fields"
1585
  success, msg = update_user_plan(username, new_plan)
1586
  return f"{'✅' if success else '❌'} {msg}"
1587
 
1588
+ def admin_approve_request_handler(request_id):
1589
  if not request_id:
1590
  return "❌ Please enter request ID"
1591
  success, msg = approve_request(int(request_id))
1592
  return f"{'✅' if success else '❌'} {msg}"
1593
 
1594
+ def admin_deny_request_handler(request_id):
1595
  if not request_id:
1596
  return "❌ Please enter request ID"
1597
  success, msg = deny_request(int(request_id))
1598
  return f"{'✅' if success else '❌'} {msg}"
1599
 
1600
+ # ==================== WIRE UP EVENTS ====================
1601
+
1602
+ # Auth
1603
+ auth_outputs = [
1604
+ session_code, auth_msg, auth_page, chat_page, admin_page,
1605
+ user_greeting, upgrade_nav_btn, logout_nav_btn,
1606
+ model_selector, max_tokens_slider, limits_display
1607
+ ]
1608
+ auth_btn.click(
1609
+ handle_auth,
1610
+ [auth_username, auth_password, auth_email],
1611
+ auth_outputs
1612
+ )
1613
 
1614
+ # Navigation
1615
+ upgrade_nav_btn.click(show_upgrade_page, outputs=[chat_page, upgrade_page])
1616
+ back_to_chat_btn.click(back_to_chat, outputs=[chat_page, upgrade_page])
1617
 
1618
+ logout_outputs = [
1619
+ session_code, auth_page, chat_page, admin_page, upgrade_page,
1620
+ user_greeting, upgrade_nav_btn, logout_nav_btn, chat_html, limits_display
1621
+ ]
1622
+ logout_nav_btn.click(handle_logout, [session_code], logout_outputs)
1623
+
1624
+ # Chat
1625
+ send_outputs = [msg_input, chat_html, speed_display, send_btn, stop_btn, limits_display]
1626
+ send_btn.click(
1627
+ send_message_handler,
1628
+ [msg_input, show_thinking_checkbox, temperature_slider, model_selector, max_tokens_slider, session_code],
1629
+ send_outputs
1630
+ )
1631
+ msg_input.submit(
1632
+ send_message_handler,
1633
+ [msg_input, show_thinking_checkbox, temperature_slider, model_selector, max_tokens_slider, session_code],
1634
+ send_outputs
1635
+ )
1636
 
1637
  stop_btn.click(stop_generation_handler, outputs=[speed_display, send_btn, stop_btn])
1638
  clear_btn.click(clear_chat, outputs=[chat_html, speed_display, send_btn, stop_btn])
1639
+ new_chat_btn.click(clear_chat, outputs=[chat_html, speed_display, send_btn, stop_btn])
 
 
 
 
1640
 
1641
+ # Upgrade
1642
+ submit_upgrade_btn.click(
1643
+ submit_upgrade_request,
1644
+ [session_code, upgrade_plan_choice, upgrade_reason],
1645
+ [upgrade_msg]
1646
+ )
1647
 
1648
+ # Admin
1649
  refresh_users_btn.click(load_all_users, outputs=[users_table])
1650
  refresh_requests_btn.click(load_pending_requests, outputs=[requests_table])
1651
+ update_plan_btn.click(admin_update_plan_handler, [admin_username, admin_new_plan], [admin_msg])
1652
+ approve_req_btn.click(admin_approve_request_handler, [request_id_input], [request_msg])
1653
+ deny_req_btn.click(admin_deny_request_handler, [request_id_input], [request_msg])
1654
 
1655
+ # Footer
1656
  gr.Markdown("""
1657
  ---
1658
+ ### 🚀 Getting Started
1659
+
1660
+ 1. **Enter your username and password** - We'll automatically create an account if you're new!
1661
+ 2. **Start chatting** - Ask anything and SAM-X-1 will help you
1662
+ 3. **Need more?** - Click the ⭐ Upgrade button to see plans and request an upgrade
1663
 
1664
+ ### 📊 Quick Plan Overview
 
 
 
1665
 
1666
+ - **Free**: Nano & Mini unlimited, Fast 10/3h, Large 8/3h
1667
+ - **Plus**: Fast unlimited, Large 20/3h + manual model selection
1668
+ - **Pro**: Everything unlimited + 512 tokens + priority support
1669
 
1670
+ ### 💡 Tips
1671
+
1672
+ - Use **Auto mode** for best results - SAM will pick the right model for you
1673
+ - Watch the **limits panel** on the right to track your usage
1674
+ - Enable **Show Thinking** to see SAM's reasoning process
1675
+
1676
+ ---
 
1677
 
1678
+ Made with ❤️ by the SAM-X-1 Team | Powered by Keras & TensorFlow
 
1679
  """)
1680
 
1681
  demo.launch(debug=True, share=False, server_name="0.0.0.0", server_port=7860)