Spaces:
Running
Running
Upload log_viewer.py
Browse files- admin/log_viewer.py +82 -0
admin/log_viewer.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import pandas as pd
|
| 4 |
+
|
| 5 |
+
QUERY_LOG_JSONL = "logs/query_log.jsonl"
|
| 6 |
+
QUERY_LOG_CSV = "logs/query_log.csv"
|
| 7 |
+
FAILED_URLS_LOG = "logs/failed_urls.txt"
|
| 8 |
+
GLOSSARY_OVERFLOW_LOG = "logs/glossary_overflow.txt"
|
| 9 |
+
|
| 10 |
+
# ----------------------------
|
| 11 |
+
# Query Logs
|
| 12 |
+
# ----------------------------
|
| 13 |
+
|
| 14 |
+
def log_query(query: str, answer: str, source: str = "unknown"):
|
| 15 |
+
"""
|
| 16 |
+
Append query + answer to JSONL and CSV logs.
|
| 17 |
+
"""
|
| 18 |
+
entry = {"query": query, "answer": answer, "source": source}
|
| 19 |
+
|
| 20 |
+
os.makedirs(os.path.dirname(QUERY_LOG_JSONL), exist_ok=True)
|
| 21 |
+
with open(QUERY_LOG_JSONL, "a", encoding="utf-8") as f:
|
| 22 |
+
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
| 23 |
+
|
| 24 |
+
# Append to CSV
|
| 25 |
+
try:
|
| 26 |
+
df = pd.DataFrame([entry])
|
| 27 |
+
if os.path.exists(QUERY_LOG_CSV):
|
| 28 |
+
df.to_csv(QUERY_LOG_CSV, mode="a", index=False, header=False)
|
| 29 |
+
else:
|
| 30 |
+
df.to_csv(QUERY_LOG_CSV, index=False)
|
| 31 |
+
except Exception as e:
|
| 32 |
+
print(f"⚠️ Failed to write CSV log: {e}")
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def load_queries(limit: int = 20):
|
| 36 |
+
"""
|
| 37 |
+
Load last N query log entries.
|
| 38 |
+
"""
|
| 39 |
+
if not os.path.exists(QUERY_LOG_JSONL):
|
| 40 |
+
return []
|
| 41 |
+
with open(QUERY_LOG_JSONL, "r", encoding="utf-8") as f:
|
| 42 |
+
lines = f.readlines()
|
| 43 |
+
entries = [json.loads(line) for line in lines]
|
| 44 |
+
return entries[-limit:]
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# ----------------------------
|
| 48 |
+
# Failed URLs
|
| 49 |
+
# ----------------------------
|
| 50 |
+
|
| 51 |
+
def log_failed_url(url: str):
|
| 52 |
+
"""Log a failed URL fetch."""
|
| 53 |
+
os.makedirs(os.path.dirname(FAILED_URLS_LOG), exist_ok=True)
|
| 54 |
+
with open(FAILED_URLS_LOG, "a", encoding="utf-8") as f:
|
| 55 |
+
f.write(url + "\n")
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def load_failed_urls():
|
| 59 |
+
"""Load failed URLs."""
|
| 60 |
+
if not os.path.exists(FAILED_URLS_LOG):
|
| 61 |
+
return []
|
| 62 |
+
with open(FAILED_URLS_LOG, "r", encoding="utf-8") as f:
|
| 63 |
+
return [line.strip() for line in f.readlines()]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
# ----------------------------
|
| 67 |
+
# Glossary Overflow
|
| 68 |
+
# ----------------------------
|
| 69 |
+
|
| 70 |
+
def log_glossary_overflow(term: str, definition: str):
|
| 71 |
+
"""Save glossary entries that couldn’t be parsed properly."""
|
| 72 |
+
os.makedirs(os.path.dirname(GLOSSARY_OVERFLOW_LOG), exist_ok=True)
|
| 73 |
+
with open(GLOSSARY_OVERFLOW_LOG, "a", encoding="utf-8") as f:
|
| 74 |
+
f.write(f"{term}: {definition}\n")
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def load_glossary_overflow():
|
| 78 |
+
"""Load glossary overflow terms."""
|
| 79 |
+
if not os.path.exists(GLOSSARY_OVERFLOW_LOG):
|
| 80 |
+
return []
|
| 81 |
+
with open(GLOSSARY_OVERFLOW_LOG, "r", encoding="utf-8") as f:
|
| 82 |
+
return [line.strip() for line in f.readlines()]
|