Create journal.py
Browse files- journal.py +80 -0
journal.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# journal.py
|
| 2 |
+
import os
|
| 3 |
+
import csv
|
| 4 |
+
import pandas as pd
|
| 5 |
+
from datetime import datetime
|
| 6 |
+
|
| 7 |
+
JOURNAL_FILE = "./lab_journal.csv"
|
| 8 |
+
JOURNAL_CATEGORIES = [
|
| 9 |
+
# S1-A Genomics
|
| 10 |
+
"S1-A·R1a", # OpenVariant
|
| 11 |
+
"S1-A·R1b", # Somatic Classifier (future)
|
| 12 |
+
"S1-A·R2e", # Research Assistant (RAG Chatbot)
|
| 13 |
+
# S1-B RNA
|
| 14 |
+
"S1-B·R1a", # BRCA2 miRNA
|
| 15 |
+
"S1-B·R2a", # TP53 siRNA
|
| 16 |
+
"S1-B·R3a", # lncRNA-TREM2
|
| 17 |
+
"S1-B·R3b", # ASO Designer
|
| 18 |
+
# S1-C Drug
|
| 19 |
+
"S1-C·R1a", # FGFR3 RNA Drug
|
| 20 |
+
"S1-C·R1b", # SL Drug Mapping (future)
|
| 21 |
+
"S1-C·R2a", # Frontier (future)
|
| 22 |
+
# S1-D LNP
|
| 23 |
+
"S1-D·R1a", # LNP Corona
|
| 24 |
+
"S1-D·R2a", # Flow Corona
|
| 25 |
+
"S1-D·R3a", # LNP Brain
|
| 26 |
+
"S1-D·R4a", # AutoCorona NLP
|
| 27 |
+
"S1-D·R5a", # CSF/Vitreous/BM (future)
|
| 28 |
+
"S1-D·R6a", # Corona Database
|
| 29 |
+
# S1-E Biomarkers
|
| 30 |
+
"S1-E·R1a", # Liquid Biopsy
|
| 31 |
+
"S1-E·R1b", # Protein Validator (future)
|
| 32 |
+
"S1-E·R2a", # Multi-protein Biomarkers
|
| 33 |
+
# S1-F Rare
|
| 34 |
+
"S1-F·R1a", # DIPG Toolkit
|
| 35 |
+
"S1-F·R2a", # UVM Toolkit
|
| 36 |
+
"S1-F·R3a", # pAML Toolkit
|
| 37 |
+
# S1-G 3D
|
| 38 |
+
"S1-G·General", # 3D Models
|
| 39 |
+
"Manual"
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
def journal_log(category: str, action: str, result: str, note: str = ""):
|
| 43 |
+
"""Log an entry with category."""
|
| 44 |
+
ts = datetime.now().isoformat()
|
| 45 |
+
row = [ts, category, action, result[:200], note]
|
| 46 |
+
write_header = not os.path.exists(JOURNAL_FILE)
|
| 47 |
+
with open(JOURNAL_FILE, "a", newline="", encoding="utf-8") as f:
|
| 48 |
+
w = csv.writer(f)
|
| 49 |
+
if write_header:
|
| 50 |
+
w.writerow(["timestamp", "category", "action", "result_summary", "note"])
|
| 51 |
+
w.writerow(row)
|
| 52 |
+
return ts
|
| 53 |
+
|
| 54 |
+
def journal_read(category: str = "All") -> str:
|
| 55 |
+
"""Read journal entries, optionally filtered by category. Returns markdown."""
|
| 56 |
+
if not os.path.exists(JOURNAL_FILE):
|
| 57 |
+
return "No entries yet."
|
| 58 |
+
try:
|
| 59 |
+
df = pd.read_csv(JOURNAL_FILE)
|
| 60 |
+
if df.empty:
|
| 61 |
+
return "No entries yet."
|
| 62 |
+
if category != "All":
|
| 63 |
+
df = df[df["category"] == category]
|
| 64 |
+
if df.empty:
|
| 65 |
+
return f"No entries for category: {category}"
|
| 66 |
+
df_display = df[["timestamp", "category", "action", "result_summary", "note"]].tail(50)
|
| 67 |
+
df_display.columns = ["Timestamp", "Category", "Action", "Result", "Observation"]
|
| 68 |
+
return df_display.to_markdown(index=False)
|
| 69 |
+
except Exception as e:
|
| 70 |
+
print(f"Journal read error: {e}")
|
| 71 |
+
return "Error reading journal."
|
| 72 |
+
|
| 73 |
+
def clear_journal():
|
| 74 |
+
try:
|
| 75 |
+
if os.path.exists(JOURNAL_FILE):
|
| 76 |
+
os.remove(JOURNAL_FILE)
|
| 77 |
+
return "Journal cleared."
|
| 78 |
+
except Exception as e:
|
| 79 |
+
print(f"Clear journal error: {e}")
|
| 80 |
+
return "Error clearing journal."
|