k96beni commited on
Commit
e4bb8ca
·
verified ·
1 Parent(s): 44000f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -92
app.py CHANGED
@@ -3,27 +3,41 @@ import json
3
  import pandas as pd
4
  import torch
5
  import gradio as gr
6
-
7
  from huggingface_hub import login, Repository
8
  from sentence_transformers import SentenceTransformer, util
9
 
10
- # ================================
11
- # KONFIG & INIT
12
- # ================================
 
 
 
 
 
 
13
  HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
 
 
 
14
  if not HF_TOKEN:
15
  raise ValueError("HUGGINGFACE_TOKEN miljövariabel saknas!")
 
 
16
 
 
17
  login(token=HF_TOKEN)
18
 
19
- REPO_ID = "ChargeNodeEurope/Chatbot_4o_mini" # Exempel
 
 
 
20
  REPO_LOCAL_PATH = "chatbot_faq_repo"
21
  FAQ_XLSX_PATH = "FAQ stadat.xlsx"
22
 
23
  repo = Repository(
24
  local_dir=REPO_LOCAL_PATH,
25
  clone_from=REPO_ID,
26
- repo_type="space", # Viktigt om det är en Space
27
  use_auth_token=HF_TOKEN
28
  )
29
 
@@ -34,41 +48,34 @@ try:
34
  except Exception as e:
35
  raise FileNotFoundError(f"Kunde inte ladda FAQ-filen: {str(e)}")
36
 
37
- # Ladda Sentence Transformer
 
 
38
  model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
39
-
40
- # Skapa embeddings av alla FAQ-frågor en gång
41
  faq_questions = df["Fråga"].tolist()
42
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
43
 
44
- # ================================
45
- # HJÄLPFUNKTIONER
46
- # ================================
47
  def uppdatera_embeddings():
48
- """
49
- Uppdatera embeddings efter att FAQ-DataFrame har ändrats.
50
- """
51
  global faq_questions, faq_embeddings, df
52
  faq_questions = df["Fråga"].tolist()
53
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
54
 
 
 
 
55
  def sök_faq(fråga):
56
  """
57
- Gör en enkel semantisk sökning i FAQ och returnerar topp 3 resultat.
58
  """
59
  fråga = fråga.strip()
60
  if not fråga:
61
  return pd.DataFrame(columns=["Liknande fråga", "Svar", "Kategori", "Confidence"])
62
-
63
- # Skapa embedding för query
64
  query_emb = model.encode(fråga, convert_to_tensor=True)
65
  cos_scores = util.cos_sim(query_emb, faq_embeddings)[0]
66
-
67
- # Hämta topp 3
68
  top_results = torch.topk(cos_scores, k=3)
69
  indices = top_results.indices.tolist()
70
  scores = top_results.values.tolist()
71
-
72
  data = []
73
  for idx, score in zip(indices, scores):
74
  row = df.iloc[idx]
@@ -82,58 +89,50 @@ def sök_faq(fråga):
82
 
83
  def lägg_till_faq(fråga, svar, kategori):
84
  """
85
- Lägger till en ny fråga i df, sparar och pushar, uppdaterar embeddings.
86
  """
87
  global df
88
  fråga = fråga.strip()
89
  svar = svar.strip()
90
  kategori = kategori.strip()
91
-
92
  if not fråga or not svar or not kategori:
93
  return "Fråga, svar och kategori får inte vara tomma!"
94
-
95
  try:
96
- # Lägg till i DataFrame
97
  ny_rad = pd.DataFrame([[fråga, svar, kategori]], columns=["Fråga", "Svar", "Kategori"])
98
  df = pd.concat([df, ny_rad], ignore_index=True)
99
-
100
- # Spara och pusha
101
  df.to_excel(faq_path, index=False)
102
- uppdatera_embeddings() # Skapa nya embeddings
103
-
104
  repo.git_add()
105
  repo.git_commit(f"Lade till FAQ: {fråga[:50]}...")
106
  repo.git_push()
107
-
108
  return "Fråga tillagd och synkad med Hugging Face!"
109
  except Exception as e:
110
  return f"Fel vid uppdatering: {str(e)}"
111
 
112
  def visa_senaste_faq(antal=10):
 
113
  return df.tail(antal)
114
 
115
  def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
 
 
 
116
  global df
117
  gammal_fråga = gammal_fråga.strip()
118
  nytt_svar = nytt_svar.strip()
119
  ny_kategori = ny_kategori.strip()
120
-
121
  if not gammal_fråga:
122
  return "Ingen fråga vald."
123
-
124
  match_index = df.index[df["Fråga"] == gammal_fråga]
125
  if len(match_index) == 0:
126
  return "Ingen matchande FAQ-fråga hittad."
127
-
128
  if nytt_svar:
129
  df.loc[match_index, "Svar"] = nytt_svar
130
  if ny_kategori:
131
  df.loc[match_index, "Kategori"] = ny_kategori
132
-
133
  try:
134
  df.to_excel(faq_path, index=False)
135
  uppdatera_embeddings()
136
-
137
  repo.git_add()
138
  repo.git_commit(f"Uppdaterade FAQ: {gammal_fråga[:50]}...")
139
  repo.git_push()
@@ -142,21 +141,20 @@ def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
142
  return f"Fel vid uppdatering: {str(e)}"
143
 
144
  def ta_bort_faq(fråga_att_radera):
 
 
 
145
  global df
146
  fråga_att_radera = fråga_att_radera.strip()
147
  if not fråga_att_radera:
148
  return "Ingen fråga vald."
149
-
150
  match_index = df.index[df["Fråga"] == fråga_att_radera]
151
  if len(match_index) == 0:
152
  return "Ingen matchande FAQ-fråga hittad."
153
-
154
  df.drop(match_index, inplace=True)
155
-
156
  try:
157
  df.to_excel(faq_path, index=False)
158
  uppdatera_embeddings()
159
-
160
  repo.git_add()
161
  repo.git_commit(f"Raderade FAQ: {fråga_att_radera[:50]}...")
162
  repo.git_push()
@@ -164,12 +162,18 @@ def ta_bort_faq(fråga_att_radera):
164
  except Exception as e:
165
  return f"Fel vid borttagning: {str(e)}"
166
 
 
 
 
167
  def visa_logfil():
168
  """
169
  Läser in loggfilen och returnerar en DataFrame med de senaste 10 posterna:
170
  Datum, UserID, Fråga (user_message) och Svar (bot_reply).
171
  """
172
- log_file_path = os.path.join("ChargeNodeEurope", "logfiles", "logs_v2", "conversation_log_v2.txt")
 
 
 
173
  logs = []
174
  try:
175
  with open(log_file_path, "r", encoding="utf-8") as f:
@@ -178,77 +182,83 @@ def visa_logfil():
178
  if line:
179
  log_entry = json.loads(line)
180
  logs.append(log_entry)
181
- # Sortera loggarna med nyaste först (baserat på timestamp)
182
  logs_sorted = sorted(logs, key=lambda x: x["timestamp"], reverse=True)
183
  latest10 = logs_sorted[:10]
184
  df_logs = pd.DataFrame(latest10)
185
  if not df_logs.empty:
186
- # Välj och döp om de kolumner som ska visas
187
  df_logs = df_logs[["timestamp", "user_id", "user_message", "bot_reply"]]
188
  df_logs.columns = ["Datum", "UserID", "Fråga", "Svar"]
189
  return df_logs
190
  except Exception as e:
191
  return pd.DataFrame({"Fel": [f"Fel vid inläsning av loggfil: {e}"]})
192
 
193
- # ================================
194
- # GRADIO-GRÄNSSNITT
195
- # ================================
196
-
197
- # Anpassad CSS för att göra gränssnittet snyggare
198
- custom_css = """
199
- body {background-color: #f7f7f7; font-family: Arial, sans-serif;}
200
- h1, h2, h3 {font-family: Helvetica, sans-serif; color: #2a9d8f; text-align: center;}
201
- .gradio-container {max-width: 900px; margin: auto; padding: 20px;}
202
- .gr-button {background-color: #264653; color: #fff;}
203
- """
204
-
205
- with gr.Blocks(css=custom_css, title="Enkel FAQ Admin") as demo:
206
- gr.Markdown("<h1>Enkel FAQ Admin</h1>")
207
- gr.Markdown("<p style='text-align: center;'>Administrera FAQ-poster: sök i befintliga frågor, lägg till, uppdatera, ta bort och visa loggfil.</p>")
208
-
209
- with gr.Tabs():
210
- # Tab: Sök i FAQ
211
- with gr.TabItem("Sök i FAQ"):
212
- with gr.Row():
213
- inp_question = gr.Textbox(label="Din fråga", placeholder="Ex: Hur startar jag en laddning?")
 
 
 
 
 
 
 
 
 
 
 
 
214
  btn_search = gr.Button("Sök")
215
  out_search = gr.Dataframe(label="Topp 3 resultat")
216
  btn_search.click(fn=sök_faq, inputs=inp_question, outputs=out_search)
217
-
218
- # Tab: Lägg till FAQ
219
- with gr.TabItem("Lägg till FAQ"):
220
- with gr.Row():
221
- add_question = gr.Textbox(label="Ny fråga")
222
- with gr.Row():
223
- add_answer = gr.Textbox(label="Nytt svar")
224
- with gr.Row():
225
- add_cat = gr.Textbox(label="Ny kategori")
226
  btn_add = gr.Button("Lägg till")
227
  out_add = gr.Textbox(label="Status")
228
  btn_add.click(fn=lägg_till_faq, inputs=[add_question, add_answer, add_cat], outputs=out_add)
229
-
230
- # Tab: Redigera / Ta bort FAQ
231
- with gr.TabItem("Redigera / Ta bort FAQ"):
232
- with gr.Row():
233
- existing_quests = gr.Dropdown(choices=df["Fråga"].tolist(), label="Befintliga frågor")
234
- with gr.Row():
235
- new_answer = gr.Textbox(label="Nytt svar (valfritt)")
236
- with gr.Row():
237
- new_cat = gr.Textbox(label="Ny kategori (valfritt)")
238
  btn_update = gr.Button("Uppdatera")
239
  out_update = gr.Textbox(label="Status")
240
  btn_update.click(fn=uppdatera_faq, inputs=[existing_quests, new_answer, new_cat], outputs=out_update)
241
-
242
- gr.Markdown("#### Eller ta bort en FAQ-post:")
243
  btn_delete = gr.Button("Ta bort")
244
  out_delete = gr.Textbox(label="Status")
245
  btn_delete.click(fn=ta_bort_faq, inputs=existing_quests, outputs=out_delete)
246
-
247
- # Tab: Visa FAQ-loggfilen
248
- with gr.TabItem("Loggfil"):
249
- btn_show_log = gr.Button("Visa senaste 10 poster")
250
- out_log = gr.Dataframe(label="Loggfil")
251
- btn_show_log.click(fn=visa_logfil, inputs=[], outputs=out_log)
252
-
253
- if __name__ == "__main__":
254
- demo.launch()
 
 
 
 
 
 
3
  import pandas as pd
4
  import torch
5
  import gradio as gr
 
6
  from huggingface_hub import login, Repository
7
  from sentence_transformers import SentenceTransformer, util
8
 
9
+ # -------------------------------
10
+ # Global Git-konfiguration
11
+ # -------------------------------
12
+ os.system('git config --global user.email "niklas.berg@chargenode.eu"')
13
+ os.system('git config --global user.name "Niklas Berg"')
14
+
15
+ # -------------------------------
16
+ # Miljövariabler
17
+ # -------------------------------
18
  HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
19
+ APP_USERNAME = os.getenv("APP_USERNAME")
20
+ APP_PASSWORD = os.getenv("APP_PASSWORD")
21
+
22
  if not HF_TOKEN:
23
  raise ValueError("HUGGINGFACE_TOKEN miljövariabel saknas!")
24
+ if not APP_USERNAME or not APP_PASSWORD:
25
+ raise ValueError("APP_USERNAME eller APP_PASSWORD miljövariabel saknas!")
26
 
27
+ # Logga in på Hugging Face
28
  login(token=HF_TOKEN)
29
 
30
+ # -------------------------------
31
+ # Repo & FAQ-konfiguration
32
+ # -------------------------------
33
+ REPO_ID = "ChargeNodeEurope/Chatbot_4o_mini" # Exempel-ID
34
  REPO_LOCAL_PATH = "chatbot_faq_repo"
35
  FAQ_XLSX_PATH = "FAQ stadat.xlsx"
36
 
37
  repo = Repository(
38
  local_dir=REPO_LOCAL_PATH,
39
  clone_from=REPO_ID,
40
+ repo_type="space", # Viktigt om det är en Space
41
  use_auth_token=HF_TOKEN
42
  )
43
 
 
48
  except Exception as e:
49
  raise FileNotFoundError(f"Kunde inte ladda FAQ-filen: {str(e)}")
50
 
51
+ # -------------------------------
52
+ # Ladda Modell & Embeddings
53
+ # -------------------------------
54
  model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
 
 
55
  faq_questions = df["Fråga"].tolist()
56
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
57
 
 
 
 
58
  def uppdatera_embeddings():
59
+ """Uppdatera FAQ-embeddings efter att FAQ-DataFrame har ändrats."""
 
 
60
  global faq_questions, faq_embeddings, df
61
  faq_questions = df["Fråga"].tolist()
62
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
63
 
64
+ # -------------------------------
65
+ # FAQ-funktioner
66
+ # -------------------------------
67
  def sök_faq(fråga):
68
  """
69
+ Gör en semantisk sökning i FAQ och returnerar topp 3 resultat.
70
  """
71
  fråga = fråga.strip()
72
  if not fråga:
73
  return pd.DataFrame(columns=["Liknande fråga", "Svar", "Kategori", "Confidence"])
 
 
74
  query_emb = model.encode(fråga, convert_to_tensor=True)
75
  cos_scores = util.cos_sim(query_emb, faq_embeddings)[0]
 
 
76
  top_results = torch.topk(cos_scores, k=3)
77
  indices = top_results.indices.tolist()
78
  scores = top_results.values.tolist()
 
79
  data = []
80
  for idx, score in zip(indices, scores):
81
  row = df.iloc[idx]
 
89
 
90
  def lägg_till_faq(fråga, svar, kategori):
91
  """
92
+ Lägger till en FAQ-post, sparar lokalt och pushar till Hugging Face.
93
  """
94
  global df
95
  fråga = fråga.strip()
96
  svar = svar.strip()
97
  kategori = kategori.strip()
 
98
  if not fråga or not svar or not kategori:
99
  return "Fråga, svar och kategori får inte vara tomma!"
 
100
  try:
 
101
  ny_rad = pd.DataFrame([[fråga, svar, kategori]], columns=["Fråga", "Svar", "Kategori"])
102
  df = pd.concat([df, ny_rad], ignore_index=True)
 
 
103
  df.to_excel(faq_path, index=False)
104
+ uppdatera_embeddings()
 
105
  repo.git_add()
106
  repo.git_commit(f"Lade till FAQ: {fråga[:50]}...")
107
  repo.git_push()
 
108
  return "Fråga tillagd och synkad med Hugging Face!"
109
  except Exception as e:
110
  return f"Fel vid uppdatering: {str(e)}"
111
 
112
  def visa_senaste_faq(antal=10):
113
+ """Returnerar de 10 senaste FAQ-posterna."""
114
  return df.tail(antal)
115
 
116
  def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
117
+ """
118
+ Uppdaterar en befintlig FAQ-post.
119
+ """
120
  global df
121
  gammal_fråga = gammal_fråga.strip()
122
  nytt_svar = nytt_svar.strip()
123
  ny_kategori = ny_kategori.strip()
 
124
  if not gammal_fråga:
125
  return "Ingen fråga vald."
 
126
  match_index = df.index[df["Fråga"] == gammal_fråga]
127
  if len(match_index) == 0:
128
  return "Ingen matchande FAQ-fråga hittad."
 
129
  if nytt_svar:
130
  df.loc[match_index, "Svar"] = nytt_svar
131
  if ny_kategori:
132
  df.loc[match_index, "Kategori"] = ny_kategori
 
133
  try:
134
  df.to_excel(faq_path, index=False)
135
  uppdatera_embeddings()
 
136
  repo.git_add()
137
  repo.git_commit(f"Uppdaterade FAQ: {gammal_fråga[:50]}...")
138
  repo.git_push()
 
141
  return f"Fel vid uppdatering: {str(e)}"
142
 
143
  def ta_bort_faq(fråga_att_radera):
144
+ """
145
+ Tar bort en FAQ-post.
146
+ """
147
  global df
148
  fråga_att_radera = fråga_att_radera.strip()
149
  if not fråga_att_radera:
150
  return "Ingen fråga vald."
 
151
  match_index = df.index[df["Fråga"] == fråga_att_radera]
152
  if len(match_index) == 0:
153
  return "Ingen matchande FAQ-fråga hittad."
 
154
  df.drop(match_index, inplace=True)
 
155
  try:
156
  df.to_excel(faq_path, index=False)
157
  uppdatera_embeddings()
 
158
  repo.git_add()
159
  repo.git_commit(f"Raderade FAQ: {fråga_att_radera[:50]}...")
160
  repo.git_push()
 
162
  except Exception as e:
163
  return f"Fel vid borttagning: {str(e)}"
164
 
165
+ # -------------------------------
166
+ # Loggfilsfunktion
167
+ # -------------------------------
168
  def visa_logfil():
169
  """
170
  Läser in loggfilen och returnerar en DataFrame med de senaste 10 posterna:
171
  Datum, UserID, Fråga (user_message) och Svar (bot_reply).
172
  """
173
+ # Uppdaterad sökväg till loggfilen
174
+ log_file_path = os.path.join("/datasets/ChargeNodeEurope/logfiles/logs_v2", "conversation_log_v2.txt")
175
+ if not os.path.exists(log_file_path):
176
+ return pd.DataFrame({"Fel": ["Loggfilen hittades inte."]})
177
  logs = []
178
  try:
179
  with open(log_file_path, "r", encoding="utf-8") as f:
 
182
  if line:
183
  log_entry = json.loads(line)
184
  logs.append(log_entry)
185
+ # Sortera med nyaste posten först
186
  logs_sorted = sorted(logs, key=lambda x: x["timestamp"], reverse=True)
187
  latest10 = logs_sorted[:10]
188
  df_logs = pd.DataFrame(latest10)
189
  if not df_logs.empty:
 
190
  df_logs = df_logs[["timestamp", "user_id", "user_message", "bot_reply"]]
191
  df_logs.columns = ["Datum", "UserID", "Fråga", "Svar"]
192
  return df_logs
193
  except Exception as e:
194
  return pd.DataFrame({"Fel": [f"Fel vid inläsning av loggfil: {e}"]})
195
 
196
+ # -------------------------------
197
+ # Inloggningsfunktion
198
+ # -------------------------------
199
+ def logga_in(user, pwd):
200
+ """
201
+ Verifierar inloggningsuppgifter mot APP_USERNAME och APP_PASSWORD.
202
+ """
203
+ if user == APP_USERNAME and pwd == APP_PASSWORD:
204
+ return "Inloggning lyckades!"
205
+ else:
206
+ return "Felaktiga inloggningsuppgifter!"
207
+
208
+ # -------------------------------
209
+ # Gradio-gränssnittet
210
+ # -------------------------------
211
+ with gr.Blocks() as demo:
212
+ gr.Markdown("# Enkel FAQ Admin")
213
+ gr.Markdown("Administrera FAQ-poster, sök i befintliga frågor, lägg till, uppdatera eller ta bort.")
214
+
215
+ # Inloggningsflik
216
+ with gr.Tab("Inloggning"):
217
+ gr.Markdown("## Logga in")
218
+ username_input = gr.Textbox(label="Användarnamn", placeholder="Ange användarnamn")
219
+ password_input = gr.Textbox(label="Lösenord", placeholder="Ange lösenord", type="password")
220
+ login_button = gr.Button("Logga in")
221
+ login_status = gr.Textbox(label="Inloggningsstatus")
222
+ login_button.click(fn=logga_in, inputs=[username_input, password_input], outputs=login_status)
223
+
224
+ # FAQ-hantering
225
+ with gr.Tab("FAQ Management"):
226
+ with gr.Row():
227
+ gr.Markdown("### Sök i FAQ")
228
+ inp_question = gr.Textbox(label="Din fråga", placeholder="Ex: Hur startar jag en laddning?")
229
  btn_search = gr.Button("Sök")
230
  out_search = gr.Dataframe(label="Topp 3 resultat")
231
  btn_search.click(fn=sök_faq, inputs=inp_question, outputs=out_search)
232
+ with gr.Row():
233
+ gr.Markdown("### Lägg till FAQ")
234
+ add_question = gr.Textbox(label="Ny fråga")
235
+ add_answer = gr.Textbox(label="Nytt svar")
236
+ add_cat = gr.Textbox(label="Ny kategori")
 
 
 
 
237
  btn_add = gr.Button("Lägg till")
238
  out_add = gr.Textbox(label="Status")
239
  btn_add.click(fn=lägg_till_faq, inputs=[add_question, add_answer, add_cat], outputs=out_add)
240
+ with gr.Row():
241
+ gr.Markdown("### Redigera / Ta bort FAQ")
242
+ existing_quests = gr.Dropdown(choices=df["Fråga"].tolist(), label="Befintliga frågor")
243
+ new_answer = gr.Textbox(label="Nytt svar (valfritt)")
244
+ new_cat = gr.Textbox(label="Ny kategori (valfritt)")
 
 
 
 
245
  btn_update = gr.Button("Uppdatera")
246
  out_update = gr.Textbox(label="Status")
247
  btn_update.click(fn=uppdatera_faq, inputs=[existing_quests, new_answer, new_cat], outputs=out_update)
 
 
248
  btn_delete = gr.Button("Ta bort")
249
  out_delete = gr.Textbox(label="Status")
250
  btn_delete.click(fn=ta_bort_faq, inputs=existing_quests, outputs=out_delete)
251
+ with gr.Row():
252
+ gr.Markdown("### Visa senaste FAQ-poster")
253
+ btn_show = gr.Button("Visa senaste 10")
254
+ out_log = gr.Dataframe(label="Senaste poster")
255
+ btn_show.click(fn=visa_senaste_faq, inputs=[], outputs=out_log)
256
+
257
+ # Loggflik
258
+ with gr.Tab("Loggfil"):
259
+ gr.Markdown("## Visa loggfil (senaste 10 poster)")
260
+ btn_log = gr.Button("Läs loggfil")
261
+ out_logfile = gr.Dataframe(label="Loggfil")
262
+ btn_log.click(fn=visa_logfil, inputs=[], outputs=out_logfile)
263
+
264
+ demo.launch()