k96beni commited on
Commit
22a160b
·
verified ·
1 Parent(s): e4bb8ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -77
app.py CHANGED
@@ -3,17 +3,18 @@ import json
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")
@@ -24,20 +25,19 @@ if not HF_TOKEN:
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
 
@@ -49,33 +49,38 @@ 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,22 +94,26 @@ def sök_faq(fråga):
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)}"
@@ -114,25 +123,27 @@ def visa_senaste_faq(antal=10):
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,20 +152,21 @@ def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
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,27 +174,25 @@ def ta_bort_faq(fråga_att_radera):
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:
 
 
 
 
 
 
180
  for line in f:
181
  line = line.strip()
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)
@@ -193,9 +203,6 @@ def visa_logfil():
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.
@@ -206,59 +213,73 @@ def logga_in(user, pwd):
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()
 
3
  import pandas as pd
4
  import torch
5
  import gradio as gr
6
+
7
+ from huggingface_hub import login, Repository, hf_hub_download
8
  from sentence_transformers import SentenceTransformer, util
9
 
10
  # -------------------------------
11
+ # Global Git-konfiguration
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
+ # Miljövariabler & Inloggning
18
  # -------------------------------
19
  HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
20
  APP_USERNAME = os.getenv("APP_USERNAME")
 
25
  if not APP_USERNAME or not APP_PASSWORD:
26
  raise ValueError("APP_USERNAME eller APP_PASSWORD miljövariabel saknas!")
27
 
 
28
  login(token=HF_TOKEN)
29
 
30
  # -------------------------------
31
+ # Repo & FAQ-konfiguration
32
  # -------------------------------
33
+ REPO_ID = "ChargeNodeEurope/Chatbot_4o_mini" # Exempel
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
 
 
49
  raise FileNotFoundError(f"Kunde inte ladda FAQ-filen: {str(e)}")
50
 
51
  # -------------------------------
52
+ # 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
+ # -------------------------------
59
+ # Hjälpfunktioner
60
+ # -------------------------------
61
  def uppdatera_embeddings():
62
+ """
63
+ Uppdatera embeddings efter att FAQ-DataFrame har ändrats.
64
+ """
65
  global faq_questions, faq_embeddings, df
66
  faq_questions = df["Fråga"].tolist()
67
  faq_embeddings = model.encode(faq_questions, convert_to_tensor=True)
68
 
 
 
 
69
  def sök_faq(fråga):
70
  """
71
+ Gör en enkel semantisk sökning i FAQ och returnerar topp 3 resultat.
72
  """
73
  fråga = fråga.strip()
74
  if not fråga:
75
  return pd.DataFrame(columns=["Liknande fråga", "Svar", "Kategori", "Confidence"])
76
+
77
+ # Skapa embedding för query
78
  query_emb = model.encode(fråga, convert_to_tensor=True)
79
  cos_scores = util.cos_sim(query_emb, faq_embeddings)[0]
80
  top_results = torch.topk(cos_scores, k=3)
81
  indices = top_results.indices.tolist()
82
  scores = top_results.values.tolist()
83
+
84
  data = []
85
  for idx, score in zip(indices, scores):
86
  row = df.iloc[idx]
 
94
 
95
  def lägg_till_faq(fråga, svar, kategori):
96
  """
97
+ Lägger till en ny FAQ-post, sparar lokalt och pushar till Hugging Face.
98
  """
99
  global df
100
  fråga = fråga.strip()
101
  svar = svar.strip()
102
  kategori = kategori.strip()
103
+
104
  if not fråga or not svar or not kategori:
105
  return "Fråga, svar och kategori får inte vara tomma!"
106
+
107
  try:
108
  ny_rad = pd.DataFrame([[fråga, svar, kategori]], columns=["Fråga", "Svar", "Kategori"])
109
  df = pd.concat([df, ny_rad], ignore_index=True)
110
  df.to_excel(faq_path, index=False)
111
  uppdatera_embeddings()
112
+
113
  repo.git_add()
114
  repo.git_commit(f"Lade till FAQ: {fråga[:50]}...")
115
  repo.git_push()
116
+
117
  return "Fråga tillagd och synkad med Hugging Face!"
118
  except Exception as e:
119
  return f"Fel vid uppdatering: {str(e)}"
 
123
  return df.tail(antal)
124
 
125
  def uppdatera_faq(gammal_fråga, nytt_svar, ny_kategori):
 
 
 
126
  global df
127
  gammal_fråga = gammal_fråga.strip()
128
  nytt_svar = nytt_svar.strip()
129
  ny_kategori = ny_kategori.strip()
130
+
131
  if not gammal_fråga:
132
  return "Ingen fråga vald."
133
+
134
  match_index = df.index[df["Fråga"] == gammal_fråga]
135
  if len(match_index) == 0:
136
  return "Ingen matchande FAQ-fråga hittad."
137
+
138
  if nytt_svar:
139
  df.loc[match_index, "Svar"] = nytt_svar
140
  if ny_kategori:
141
  df.loc[match_index, "Kategori"] = ny_kategori
142
+
143
  try:
144
  df.to_excel(faq_path, index=False)
145
  uppdatera_embeddings()
146
+
147
  repo.git_add()
148
  repo.git_commit(f"Uppdaterade FAQ: {gammal_fråga[:50]}...")
149
  repo.git_push()
 
152
  return f"Fel vid uppdatering: {str(e)}"
153
 
154
  def ta_bort_faq(fråga_att_radera):
 
 
 
155
  global df
156
  fråga_att_radera = fråga_att_radera.strip()
157
  if not fråga_att_radera:
158
  return "Ingen fråga vald."
159
+
160
  match_index = df.index[df["Fråga"] == fråga_att_radera]
161
  if len(match_index) == 0:
162
  return "Ingen matchande FAQ-fråga hittad."
163
+
164
  df.drop(match_index, inplace=True)
165
+
166
  try:
167
  df.to_excel(faq_path, index=False)
168
  uppdatera_embeddings()
169
+
170
  repo.git_add()
171
  repo.git_commit(f"Raderade FAQ: {fråga_att_radera[:50]}...")
172
  repo.git_push()
 
174
  except Exception as e:
175
  return f"Fel vid borttagning: {str(e)}"
176
 
 
 
 
177
  def visa_logfil():
178
  """
179
+ Hämtar loggfilen från Hugging Face Hub och returnerar en DataFrame med de senaste 10 posterna:
180
  Datum, UserID, Fråga (user_message) och Svar (bot_reply).
181
  """
 
 
 
 
 
182
  try:
183
+ # Ange repo- och filsökväg enligt Hugging Face Hub
184
+ repo_id = "ChargeNodeEurope/logfiles"
185
+ filename = "logs_v2/conversation_log_v2.txt"
186
+ local_log_path = hf_hub_download(repo_id=repo_id, filename=filename, repo_type="dataset")
187
+
188
+ logs = []
189
+ with open(local_log_path, "r", encoding="utf-8") as f:
190
  for line in f:
191
  line = line.strip()
192
  if line:
193
  log_entry = json.loads(line)
194
  logs.append(log_entry)
195
+ # Sortera loggarna med nyaste först baserat på timestamp
196
  logs_sorted = sorted(logs, key=lambda x: x["timestamp"], reverse=True)
197
  latest10 = logs_sorted[:10]
198
  df_logs = pd.DataFrame(latest10)
 
203
  except Exception as e:
204
  return pd.DataFrame({"Fel": [f"Fel vid inläsning av loggfil: {e}"]})
205
 
 
 
 
206
  def logga_in(user, pwd):
207
  """
208
  Verifierar inloggningsuppgifter mot APP_USERNAME och APP_PASSWORD.
 
213
  return "Felaktiga inloggningsuppgifter!"
214
 
215
  # -------------------------------
216
+ # Gradio - Användargränssnitt med anpassad look & feel
217
  # -------------------------------
218
+
219
+ # Anpassad CSS enligt exemplet
220
+ custom_css = """
221
+ body {background-color: #f7f7f7; font-family: Arial, sans-serif;}
222
+ h1, h2, h3 {font-family: Helvetica, sans-serif; color: #2a9d8f; text-align: center;}
223
+ .gradio-container {max-width: 900px; margin: auto; padding: 20px;}
224
+ .gr-button {background-color: #264653; color: #fff;}
225
+ """
226
+
227
+ with gr.Blocks(css=custom_css, title="Enkel FAQ Admin") as demo:
228
+ gr.Markdown("<h1>Enkel FAQ Admin</h1>")
229
+ gr.Markdown("<p style='text-align: center;'>Administrera FAQ-poster: sök, lägg till, uppdatera, ta bort och visa loggfil.</p>")
230
+
231
+ with gr.Tabs():
232
+ # Flik: Inloggning
233
+ with gr.TabItem("Inloggning"):
234
+ with gr.Row():
235
+ username_input = gr.Textbox(label="Användarnamn", placeholder="Ange användarnamn")
236
+ with gr.Row():
237
+ password_input = gr.Textbox(label="Lösenord", placeholder="Ange lösenord", type="password")
238
+ login_button = gr.Button("Logga in")
239
+ login_status = gr.Textbox(label="Inloggningsstatus")
240
+ login_button.click(fn=logga_in, inputs=[username_input, password_input], outputs=login_status)
241
+
242
+ # Flik: Sök i FAQ
243
+ with gr.TabItem("Sök i FAQ"):
244
+ with gr.Row():
245
+ inp_question = gr.Textbox(label="Din fråga", placeholder="Ex: Hur startar jag en laddning?")
246
  btn_search = gr.Button("Sök")
247
  out_search = gr.Dataframe(label="Topp 3 resultat")
248
  btn_search.click(fn=sök_faq, inputs=inp_question, outputs=out_search)
249
+
250
+ # Flik: Lägg till FAQ
251
+ with gr.TabItem("Lägg till FAQ"):
252
+ with gr.Row():
253
+ add_question = gr.Textbox(label="Ny fråga")
254
+ with gr.Row():
255
+ add_answer = gr.Textbox(label="Nytt svar")
256
+ with gr.Row():
257
+ add_cat = gr.Textbox(label="Ny kategori")
258
  btn_add = gr.Button("Lägg till")
259
  out_add = gr.Textbox(label="Status")
260
  btn_add.click(fn=lägg_till_faq, inputs=[add_question, add_answer, add_cat], outputs=out_add)
261
+
262
+ # Flik: Redigera / Ta bort FAQ
263
+ with gr.TabItem("Redigera / Ta bort FAQ"):
264
+ with gr.Row():
265
+ existing_quests = gr.Dropdown(choices=df["Fråga"].tolist(), label="Befintliga frågor")
266
+ with gr.Row():
267
+ new_answer = gr.Textbox(label="Nytt svar (valfritt)")
268
+ with gr.Row():
269
+ new_cat = gr.Textbox(label="Ny kategori (valfritt)")
270
  btn_update = gr.Button("Uppdatera")
271
  out_update = gr.Textbox(label="Status")
272
  btn_update.click(fn=uppdatera_faq, inputs=[existing_quests, new_answer, new_cat], outputs=out_update)
273
+ gr.Markdown("#### Eller ta bort en FAQ-post:")
274
  btn_delete = gr.Button("Ta bort")
275
  out_delete = gr.Textbox(label="Status")
276
  btn_delete.click(fn=ta_bort_faq, inputs=existing_quests, outputs=out_delete)
277
+
278
+ # Flik: Loggfil
279
+ with gr.TabItem("Loggfil"):
280
+ btn_show_log = gr.Button("Visa senaste 10 poster")
281
+ out_log = gr.Dataframe(label="Loggfil")
282
+ btn_show_log.click(fn=visa_logfil, inputs=[], outputs=out_log)
283
+
284
+ if __name__ == "__main__":
285
+ demo.launch()