k96beni commited on
Commit
d59a72d
·
verified ·
1 Parent(s): b0117f1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -47
app.py CHANGED
@@ -1,41 +1,33 @@
1
  import os
 
2
  import pandas as pd
3
  import torch
4
  import gradio as gr
5
- import json # För att hantera JSON-data i loggfilen
6
 
7
  from huggingface_hub import login, Repository
8
  from sentence_transformers import SentenceTransformer, util
9
 
10
- # -------------------------------
11
- # SÄTT GLOBAL GIT-IDENTITET
12
- # -------------------------------
13
- os.system('git config --global user.email "niklas.berg@chargenode.eu"')
14
- os.system('git config --global user.name "Niklas Berg"')
15
-
16
- # -------------------------------
17
  # KONFIG & INIT
18
- # -------------------------------
19
  HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
20
  if not HF_TOKEN:
21
  raise ValueError("HUGGINGFACE_TOKEN miljövariabel saknas!")
22
 
23
- # Logga in mot Hugging Face
24
  login(token=HF_TOKEN)
25
 
26
- # Repo-detaljer
27
- REPO_ID = "ChargeNodeEurope/Chatbot_4o_mini"
28
  REPO_LOCAL_PATH = "chatbot_faq_repo"
29
- FAQ_XLSX_PATH = "FAQ stadat.xlsx" # Excel-filen med FAQ-information
30
 
31
  repo = Repository(
32
  local_dir=REPO_LOCAL_PATH,
33
  clone_from=REPO_ID,
34
- repo_type="space", # Ange "space" om det är en Hugging Face Space
35
  use_auth_token=HF_TOKEN
36
  )
37
 
38
- # Ladda in FAQ-data från Excel-filen
39
  faq_path = os.path.join(REPO_LOCAL_PATH, FAQ_XLSX_PATH)
40
  try:
41
  df = pd.read_excel(faq_path)
@@ -43,17 +35,20 @@ try:
43
  except Exception as e:
44
  raise FileNotFoundError(f"Kunde inte ladda FAQ-filen: {str(e)}")
45
 
46
- # Ladda Sentence Transformer-modellen för semantiska embeddings
47
  model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
 
 
48
  faq_questions = df["Fråga"].tolist()
49
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
50
 
51
- # -------------------------------
52
- # HJÄLPFUNKTIONER
53
- # -------------------------------
 
54
  def uppdatera_embeddings():
55
  """
56
- Uppdaterar FAQ-embeddings efter att FAQ-data har ändrats.
57
  """
58
  global faq_questions, faq_embeddings, df
59
  faq_questions = df["Fråga"].tolist()
@@ -61,19 +56,21 @@ def uppdatera_embeddings():
61
 
62
  def sök_faq(fråga):
63
  """
64
- Utför en semantisk sökning i FAQ och returnerar de tre bästa resultaten.
65
  """
66
  fråga = fråga.strip()
67
  if not fråga:
68
  return pd.DataFrame(columns=["Liknande fråga", "Svar", "Kategori", "Confidence"])
69
-
 
70
  query_emb = model.encode(fråga, convert_to_tensor=True)
71
  cos_scores = util.cos_sim(query_emb, faq_embeddings)[0]
72
-
 
73
  top_results = torch.topk(cos_scores, k=3)
74
  indices = top_results.indices.tolist()
75
  scores = top_results.values.tolist()
76
-
77
  data = []
78
  for idx, score in zip(indices, scores):
79
  row = df.iloc[idx]
@@ -87,8 +84,7 @@ def sök_faq(fråga):
87
 
88
  def lägg_till_faq(fråga, svar, kategori):
89
  """
90
- Lägger till en ny FAQ-post, uppdaterar Excel-filen, skapar nya embeddings
91
- samt pushar ändringen till Hugging Face-repo:t.
92
  """
93
  global df
94
  fråga = fråga.strip()
@@ -99,11 +95,13 @@ def lägg_till_faq(fråga, svar, kategori):
99
  return "Fråga, svar och kategori får inte vara tomma!"
100
 
101
  try:
 
102
  ny_rad = pd.DataFrame([[fråga, svar, kategori]], columns=["Fråga", "Svar", "Kategori"])
103
  df = pd.concat([df, ny_rad], ignore_index=True)
104
 
 
105
  df.to_excel(faq_path, index=False)
106
- uppdatera_embeddings()
107
 
108
  repo.git_add()
109
  repo.git_commit(f"Lade till FAQ: {fråga[:50]}...")
@@ -115,13 +113,13 @@ def lägg_till_faq(fråga, svar, kategori):
115
 
116
  def visa_senaste_faq(antal=10):
117
  """
118
- Returnerar de senaste 'antal' FAQ-posterna.
119
  """
120
  return df.tail(antal)
121
 
122
  def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
123
  """
124
- Uppdaterar en befintlig FAQ-post (baserat exakt matchning av 'Fråga').
125
  """
126
  global df
127
  gammal_fråga = gammal_fråga.strip()
@@ -153,7 +151,7 @@ def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
153
 
154
  def ta_bort_faq(fråga_att_radera):
155
  """
156
- Tar bort en FAQ-post baserat på en exakt matchning av 'Fråga'.
157
  """
158
  global df
159
  fråga_att_radera = fråga_att_radera.strip()
@@ -203,22 +201,32 @@ def visa_logfil():
203
  except Exception as e:
204
  return pd.DataFrame({"Fel": [f"Fel vid inläsning av loggfil: {e}"]})
205
 
206
- # -------------------------------
 
207
  # GRADIO-GRÄNSSNITT
208
- # -------------------------------
209
  with gr.Blocks() as demo:
210
- gr.Markdown("# Enkel FAQ Admin")
211
- gr.Markdown("Administrera FAQ-poster: Sök, lägg till, uppdatera eller ta bort FAQ samt visa loggposter.")
212
-
213
- with gr.Tab("FAQ"):
214
- # --- Sök i FAQ ---
 
 
 
 
 
 
 
 
 
215
  gr.Markdown("## Sök i FAQ")
216
  inp_question = gr.Textbox(label="Din fråga", placeholder="Ex: Hur startar jag en laddning?")
217
  btn_search = gr.Button("Sök")
218
  out_search = gr.Dataframe(label="Topp 3 resultat")
219
  btn_search.click(fn=sök_faq, inputs=inp_question, outputs=out_search)
220
 
221
- # --- Lägg till FAQ ---
222
  gr.Markdown("## Lägg till FAQ")
223
  add_question = gr.Textbox(label="Ny fråga")
224
  add_answer = gr.Textbox(label="Nytt svar")
@@ -227,7 +235,7 @@ with gr.Blocks() as demo:
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
- # --- Redigera / Ta bort FAQ ---
231
  gr.Markdown("## Redigera / Ta bort FAQ")
232
  existing_quests = gr.Dropdown(choices=df["Fråga"].tolist(), label="Befintliga frågor")
233
  new_answer = gr.Textbox(label="Nytt svar (valfritt)")
@@ -239,19 +247,33 @@ with gr.Blocks() as demo:
239
  btn_update.click(fn=uppdatera_faq, inputs=[existing_quests, new_answer, new_cat], outputs=out_update)
240
  btn_delete.click(fn=ta_bort_faq, inputs=existing_quests, outputs=out_delete)
241
 
242
- # --- Visa senaste FAQ-poster ---
243
  gr.Markdown("## Visa senaste FAQ-poster")
244
  btn_show = gr.Button("Visa senaste 10")
245
- out_log = gr.Dataframe(label="Senaste poster")
246
- btn_show.click(fn=visa_senaste_faq, inputs=[], outputs=out_log)
247
 
248
- with gr.Tab("Logg"):
249
- # --- Visa loggfilen ---
250
- gr.Markdown("## Visa senast 10 loggposter")
251
  btn_log = gr.Button("Visa loggfil")
252
  out_logfil = gr.Dataframe(label="Senaste loggar")
253
  btn_log.click(fn=visa_logfil, inputs=[], outputs=out_logfil)
254
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  if __name__ == "__main__":
256
- # Ange autentisering: username: ChargeNode, password: wer123
257
- demo.launch(auth=[("ChargeNode", "wer123")])
 
1
  import os
2
+ import json
3
  import pandas as pd
4
  import torch
5
  import gradio as gr
6
+ import datetime
7
 
8
  from huggingface_hub import login, Repository
9
  from sentence_transformers import SentenceTransformer, util
10
 
11
+ # ================================
 
 
 
 
 
 
12
  # KONFIG & INIT
13
+ # ================================
14
  HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
15
  if not HF_TOKEN:
16
  raise ValueError("HUGGINGFACE_TOKEN miljövariabel saknas!")
17
 
 
18
  login(token=HF_TOKEN)
19
 
20
+ REPO_ID = "ChargeNodeEurope/Chatbot_4o_mini" # Exempel-ID
 
21
  REPO_LOCAL_PATH = "chatbot_faq_repo"
22
+ FAQ_XLSX_PATH = "FAQ stadat.xlsx"
23
 
24
  repo = Repository(
25
  local_dir=REPO_LOCAL_PATH,
26
  clone_from=REPO_ID,
27
+ repo_type="space", # Viktigt om det är en Space
28
  use_auth_token=HF_TOKEN
29
  )
30
 
 
31
  faq_path = os.path.join(REPO_LOCAL_PATH, FAQ_XLSX_PATH)
32
  try:
33
  df = pd.read_excel(faq_path)
 
35
  except Exception as e:
36
  raise FileNotFoundError(f"Kunde inte ladda FAQ-filen: {str(e)}")
37
 
38
+ # Ladda Sentence Transformer-modellen
39
  model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
40
+
41
+ # Skapa embeddings av alla FAQ-frågor en gång
42
  faq_questions = df["Fråga"].tolist()
43
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
44
 
45
+
46
+ # ================================
47
+ # HJÄLPFUNKTIONER
48
+ # ================================
49
  def uppdatera_embeddings():
50
  """
51
+ Uppdatera FAQ-embeddings om FAQ-DataFrame ändras.
52
  """
53
  global faq_questions, faq_embeddings, df
54
  faq_questions = df["Fråga"].tolist()
 
56
 
57
  def sök_faq(fråga):
58
  """
59
+ Gör en semantisk sökning i FAQ och returnerar topp 3 resultat.
60
  """
61
  fråga = fråga.strip()
62
  if not fråga:
63
  return pd.DataFrame(columns=["Liknande fråga", "Svar", "Kategori", "Confidence"])
64
+
65
+ # Skapa embedding för sökfrågan
66
  query_emb = model.encode(fråga, convert_to_tensor=True)
67
  cos_scores = util.cos_sim(query_emb, faq_embeddings)[0]
68
+
69
+ # Hämta de 3 bästa resultaten
70
  top_results = torch.topk(cos_scores, k=3)
71
  indices = top_results.indices.tolist()
72
  scores = top_results.values.tolist()
73
+
74
  data = []
75
  for idx, score in zip(indices, scores):
76
  row = df.iloc[idx]
 
84
 
85
  def lägg_till_faq(fråga, svar, kategori):
86
  """
87
+ Lägger till en ny FAQ-post, sparar och synkroniserar med Hugging Face-repot.
 
88
  """
89
  global df
90
  fråga = fråga.strip()
 
95
  return "Fråga, svar och kategori får inte vara tomma!"
96
 
97
  try:
98
+ # Lägg till den nya FAQ-posten i DataFrame
99
  ny_rad = pd.DataFrame([[fråga, svar, kategori]], columns=["Fråga", "Svar", "Kategori"])
100
  df = pd.concat([df, ny_rad], ignore_index=True)
101
 
102
+ # Spara ändringar till Excel-filen
103
  df.to_excel(faq_path, index=False)
104
+ uppdatera_embeddings() # Uppdatera embeddings
105
 
106
  repo.git_add()
107
  repo.git_commit(f"Lade till FAQ: {fråga[:50]}...")
 
113
 
114
  def visa_senaste_faq(antal=10):
115
  """
116
+ Returnerar de senaste {antal} FAQ-posterna (från Excel-filen).
117
  """
118
  return df.tail(antal)
119
 
120
  def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
121
  """
122
+ Uppdaterar FAQ-posten med ny information.
123
  """
124
  global df
125
  gammal_fråga = gammal_fråga.strip()
 
151
 
152
  def ta_bort_faq(fråga_att_radera):
153
  """
154
+ Tar bort en vald FAQ-post.
155
  """
156
  global df
157
  fråga_att_radera = fråga_att_radera.strip()
 
201
  except Exception as e:
202
  return pd.DataFrame({"Fel": [f"Fel vid inläsning av loggfil: {e}"]})
203
 
204
+
205
+ # ================================
206
  # GRADIO-GRÄNSSNITT
207
+ # ================================
208
  with gr.Blocks() as demo:
209
+ # --- Login-sektionen ---
210
+ with gr.Column(visible=True) as login_container:
211
+ gr.Markdown("## Logga in")
212
+ login_username = gr.Textbox(label="Användarnamn")
213
+ login_password = gr.Textbox(label="Lösenord", type="password")
214
+ login_button = gr.Button("Logga in")
215
+ login_status = gr.Textbox(label="Status")
216
+
217
+ # --- Huvudapplikationen (gömmer tills inloggning lyckas) ---
218
+ with gr.Column(visible=False) as main_container:
219
+ gr.Markdown("# Enkel FAQ Admin")
220
+ gr.Markdown("Administrera FAQ-poster, sök i befintliga frågor, lägg till, uppdatera eller ta bort.")
221
+
222
+ # ---- Sök i FAQ ----
223
  gr.Markdown("## Sök i FAQ")
224
  inp_question = gr.Textbox(label="Din fråga", placeholder="Ex: Hur startar jag en laddning?")
225
  btn_search = gr.Button("Sök")
226
  out_search = gr.Dataframe(label="Topp 3 resultat")
227
  btn_search.click(fn=sök_faq, inputs=inp_question, outputs=out_search)
228
 
229
+ # ---- Lägg till FAQ ----
230
  gr.Markdown("## Lägg till FAQ")
231
  add_question = gr.Textbox(label="Ny fråga")
232
  add_answer = gr.Textbox(label="Nytt svar")
 
235
  out_add = gr.Textbox(label="Status")
236
  btn_add.click(fn=lägg_till_faq, inputs=[add_question, add_answer, add_cat], outputs=out_add)
237
 
238
+ # ---- Redigera / Ta bort FAQ ----
239
  gr.Markdown("## Redigera / Ta bort FAQ")
240
  existing_quests = gr.Dropdown(choices=df["Fråga"].tolist(), label="Befintliga frågor")
241
  new_answer = gr.Textbox(label="Nytt svar (valfritt)")
 
247
  btn_update.click(fn=uppdatera_faq, inputs=[existing_quests, new_answer, new_cat], outputs=out_update)
248
  btn_delete.click(fn=ta_bort_faq, inputs=existing_quests, outputs=out_delete)
249
 
250
+ # ---- Visa senaste FAQ-poster ----
251
  gr.Markdown("## Visa senaste FAQ-poster")
252
  btn_show = gr.Button("Visa senaste 10")
253
+ out_faq_log = gr.Dataframe(label="Senaste poster")
254
+ btn_show.click(fn=visa_senaste_faq, inputs=[], outputs=out_faq_log)
255
 
256
+ # ---- Visa loggfil (senaste 10 konversationer) ----
257
+ gr.Markdown("## Visa loggfil")
 
258
  btn_log = gr.Button("Visa loggfil")
259
  out_logfil = gr.Dataframe(label="Senaste loggar")
260
  btn_log.click(fn=visa_logfil, inputs=[], outputs=out_logfil)
261
 
262
+ # --- Inloggningsverifiering ---
263
+ def verify_login(username, password):
264
+ """
265
+ Verifierar inloggningsuppgifterna mot miljövariablerna APP_USERNAME och APP_PASSWORD.
266
+ """
267
+ valid_username = os.getenv("APP_USERNAME")
268
+ valid_password = os.getenv("APP_PASSWORD")
269
+ if username == valid_username and password == valid_password:
270
+ return "Inloggning lyckades!", gr.update(visible=False), gr.update(visible=True)
271
+ else:
272
+ return "Felaktiga inloggningsuppgifter!", gr.update(visible=True), gr.update(visible=False)
273
+
274
+ login_button.click(fn=verify_login,
275
+ inputs=[login_username, login_password],
276
+ outputs=[login_status, login_container, main_container])
277
+
278
  if __name__ == "__main__":
279
+ demo.launch()