geeksiddhant commited on
Commit
45d0aa5
·
verified ·
1 Parent(s): 89adeb4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -6
app.py CHANGED
@@ -1,15 +1,102 @@
1
  import os
 
2
  import gradio as gr
3
  import requests
 
 
 
 
 
 
4
 
5
  BACKEND_URL = os.environ.get("BACKEND_URL", "http://127.0.0.1:8000/diagnose")
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
- def diagnose(message, history):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  try:
10
  response = requests.post(
11
  BACKEND_URL,
12
  json={"workflow_description": message},
 
 
 
13
  timeout=60,
14
  )
15
  response.raise_for_status()
@@ -18,11 +105,36 @@ def diagnose(message, history):
18
  return f"Could not reach the backend.\n\n{e}"
19
 
20
 
21
- demo = gr.ChatInterface(
22
- diagnose,
23
- title="Workflow Diagnoser",
24
- description="Describe one repeated task you do at work.",
25
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  if __name__ == "__main__":
28
  demo.launch()
 
1
  import os
2
+
3
  import gradio as gr
4
  import requests
5
+ from supabase import create_client
6
+
7
+ # The frontend runs on a machine the USER controls, so it only ever gets keys
8
+ # that are safe in a browser. SUPABASE_ANON_KEY is the public, publishable key —
9
+ # safe precisely because RLS guards every row (db/03_policies.sql). The
10
+ # service_role key never comes near this file.
11
 
12
  BACKEND_URL = os.environ.get("BACKEND_URL", "http://127.0.0.1:8000/diagnose")
13
 
14
+ supabase = create_client(
15
+ os.environ["SUPABASE_URL"],
16
+ os.environ["SUPABASE_ANON_KEY"],
17
+ )
18
+
19
+
20
+ # ---------------------------------------------------------------------------
21
+ # Auth: get the user a passport (JWT) before they can use the app.
22
+ #
23
+ # We do NOT build a users table or hash passwords — Supabase Auth does that.
24
+ # We just ask it to sign someone up or log them in, and keep the access_token
25
+ # it hands back. That token is the passport we attach to every backend call.
26
+ # ---------------------------------------------------------------------------
27
+
28
+ def _explain(error: Exception) -> str:
29
+ """Turn a Supabase auth error into one human sentence."""
30
+ message = getattr(error, "message", None) or str(error)
31
+ return f"That did not work: {message}"
32
+
33
 
34
+ def log_in(email, password):
35
+ """Exchange email + password for a session, then reveal the chat."""
36
+ if not email or not password:
37
+ return None, gr.update(), gr.update(), "Enter an email and a password."
38
+ try:
39
+ result = supabase.auth.sign_in_with_password(
40
+ {"email": email, "password": password}
41
+ )
42
+ except Exception as error: # wrong password, unknown user, etc.
43
+ return None, gr.update(), gr.update(), _explain(error)
44
+
45
+ session = result.session
46
+ if session is None:
47
+ return None, gr.update(), gr.update(), "Could not start a session."
48
+ # Logged in: stash the token, hide the login box, show the chat.
49
+ return (
50
+ session.access_token,
51
+ gr.update(visible=False),
52
+ gr.update(visible=True),
53
+ "",
54
+ )
55
+
56
+
57
+ def sign_up(email, password):
58
+ """Create the account. This project has 'Confirm email' ON, so no session
59
+ is returned yet — the user must click the link in their inbox first, then
60
+ log in. (If you turn confirmation OFF, a session comes straight back and the
61
+ `session is not None` branch below logs them in immediately.)"""
62
+ if not email or not password:
63
+ return None, gr.update(), gr.update(), "Enter an email and a password."
64
+ try:
65
+ result = supabase.auth.sign_up({"email": email, "password": password})
66
+ except Exception as error: # already registered, weak password, etc.
67
+ return None, gr.update(), gr.update(), _explain(error)
68
+
69
+ session = result.session
70
+ if session is None:
71
+ # Email confirmation is on: account made, but no passport until verified.
72
+ return (
73
+ None,
74
+ gr.update(),
75
+ gr.update(),
76
+ "Account created. Check your email to confirm, then log in.",
77
+ )
78
+ return (
79
+ session.access_token,
80
+ gr.update(visible=False),
81
+ gr.update(visible=True),
82
+ "",
83
+ )
84
+
85
+
86
+ # ---------------------------------------------------------------------------
87
+ # The chat, now carrying the passport.
88
+ # ---------------------------------------------------------------------------
89
+
90
+ def diagnose(message, history, token):
91
+ if not token:
92
+ return "Your session expired. Please reload and log in again."
93
  try:
94
  response = requests.post(
95
  BACKEND_URL,
96
  json={"workflow_description": message},
97
+ # The passport. The backend hands this straight to Supabase to learn
98
+ # who is asking — it never trusts a name in the request body.
99
+ headers={"Authorization": f"Bearer {token}"},
100
  timeout=60,
101
  )
102
  response.raise_for_status()
 
105
  return f"Could not reach the backend.\n\n{e}"
106
 
107
 
108
+ with gr.Blocks(title="Workflow Diagnoser") as demo:
109
+ # Holds the JWT for the length of the browser session.
110
+ token_state = gr.State(None)
111
+
112
+ # ---- Login view (what you see first) ----
113
+ with gr.Column(visible=True) as login_view:
114
+ gr.Markdown(
115
+ "# Workflow Diagnoser\n"
116
+ "Log in or sign up to start. Your conversations are private to you."
117
+ )
118
+ email = gr.Textbox(label="Email", placeholder="you@example.com")
119
+ password = gr.Textbox(label="Password", type="password")
120
+ with gr.Row():
121
+ login_btn = gr.Button("Log in", variant="primary")
122
+ signup_btn = gr.Button("Sign up")
123
+ status = gr.Markdown()
124
+
125
+ # ---- Chat view (hidden until you have a passport) ----
126
+ with gr.Column(visible=False) as chat_view:
127
+ gr.ChatInterface(
128
+ diagnose,
129
+ additional_inputs=[token_state],
130
+ title="Workflow Diagnoser",
131
+ description="Describe one repeated task you do at work.",
132
+ )
133
+
134
+ outputs = [token_state, login_view, chat_view, status]
135
+ login_btn.click(log_in, [email, password], outputs)
136
+ signup_btn.click(sign_up, [email, password], outputs)
137
+
138
 
139
  if __name__ == "__main__":
140
  demo.launch()