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