""" Manager Intelligence Agent Free HF Inference API (Llama-3-8B) — no paid API key needed Deploy on Hugging Face Spaces (Gradio) """ import os, re, json, shutil, pickle, hashlib, datetime, logging from pathlib import Path import gradio as gr logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") log = logging.getLogger(__name__) # ── CONFIG ─────────────────────────────────────────────────────── INDEX_DIR = os.path.join(os.path.expanduser("~"), "manager_agent_index") TASKS_FILE = os.path.join(INDEX_DIR, "_tasks.json") EVENTS_FILE = os.path.join(INDEX_DIR, "_events.json") os.makedirs(INDEX_DIR, exist_ok=True) SUPPORTED = {".pdf",".docx",".doc",".xlsx",".xls",".csv",".txt",".eml",".rtf",".pptx",".ppt"} MAX_MB = 50 ICONS = {".pdf":"📕",".docx":"📘",".doc":"📘",".xlsx":"📗",".xls":"📗", ".csv":"📊",".pptx":"📙",".ppt":"📙",".txt":"📄",".eml":"📧",".msg":"📧"} HF_TOKEN = os.environ.get("HF_TOKEN", "") # optional — removes rate limits HF_MODEL = "meta-llama/Meta-Llama-3-8B-Instruct" # ── AI BACKEND ─────────────────────────────────────────────────── def get_client(): try: from huggingface_hub import InferenceClient return InferenceClient(model=HF_MODEL, token=HF_TOKEN if HF_TOKEN else None) except Exception as e: log.error(f"InferenceClient init: {e}") return None def ai_status(): try: from huggingface_hub import InferenceClient return "✅ HF Inference (Llama-3-8B) — Free" except: return "⚠️ huggingface_hub not installed" def call_llm(prompt, system=None, history=None): client = get_client() if not client: return "❌ Could not connect to HF Inference API." messages = [] if system: messages.append({"role": "system", "content": system}) if history: for u, b in history[-6:]: messages += [{"role":"user","content":str(u)}, {"role":"assistant","content":str(b)}] messages.append({"role": "user", "content": prompt}) try: resp = client.chat_completion(messages=messages, max_tokens=1024, temperature=0.7) return resp.choices[0].message.content.strip() except Exception as e: log.error(f"call_llm: {e}") return f"❌ Inference error: {e}" def do_generate(prompt): return call_llm(prompt) def do_chat_llm(prompt, context, history): system = ("You are an elite executive assistant AI with access to the manager's document archive. " "Answer precisely using the provided context. Cite document names. " "Use bullet points. Flag deadlines and action items proactively.") return call_llm(f"{prompt}\n\n--- Document Context ---\n{context}", system=system, history=history) # ── TEXT EXTRACTION ────────────────────────────────────────────── def extract(fp): ext = Path(fp).suffix.lower() try: if ext == ".pdf": import pdfplumber with pdfplumber.open(fp) as pdf: return "\n".join(p.extract_text() or "" for p in pdf.pages) if ext in (".docx", ".doc"): from docx import Document doc = Document(fp) parts = [p.text for p in doc.paragraphs if p.text.strip()] for t in doc.tables: for row in t.rows: parts.append(" | ".join(c.text.strip() for c in row.cells if c.text.strip())) return "\n".join(parts) if ext in (".xlsx", ".xls"): import pandas as pd xl = pd.ExcelFile(fp) return "\n\n".join(f"[{s}]\n{xl.parse(s).head(200).to_string(index=False)}" for s in xl.sheet_names) if ext == ".csv": import pandas as pd return pd.read_csv(fp, encoding="utf-8", errors="ignore").to_string(index=False) if ext in (".pptx", ".ppt"): from pptx import Presentation prs = Presentation(fp) return "\n".join(" ".join(s.text for s in sl.shapes if hasattr(s,"text")) for sl in prs.slides) return open(fp, "r", encoding="utf-8", errors="ignore").read() except Exception as e: log.warning(f"extract({fp}): {e}") return "" # ── INDEXING ───────────────────────────────────────────────────── def fhash(fp): return hashlib.md5(f"{fp}{os.path.getmtime(fp)}".encode()).hexdigest()[:12] def is_indexed(fp): return os.path.exists(f"{INDEX_DIR}/{fhash(fp)}.pkl") def make_chunks(text, fname, size=350, overlap=70): words = re.sub(r'\s+', ' ', text).strip().split() chunks = [] for s in range(0, len(words), size - overlap): e = min(s + size, len(words)) c = " ".join(words[s:e]) if len(c) > 50: chunks.append({"text": c, "source": fname, "preview": c[:200]}) if e == len(words): break return chunks def index_file(fp): fname = Path(fp).name try: size_mb = os.path.getsize(fp) / (1024*1024) except Exception as e: return False, f"Cannot read: {e}" if size_mb > MAX_MB: return False, f">{MAX_MB}MB skipped" text = extract(fp) if not text or len(text.strip()) < 30: return False, "No text extracted" chunks = make_chunks(text, fname) if not chunks: return False, "No chunks" fh = fhash(fp) meta = {"filename": fname, "filepath": str(fp), "ftype": Path(fp).suffix.upper().strip("."), "words": len(text.split()), "mb": round(size_mb, 2), "date": datetime.datetime.fromtimestamp(os.path.getmtime(fp)).strftime("%Y-%m-%d")} with open(f"{INDEX_DIR}/{fh}.pkl", "wb") as f: pickle.dump({"chunks": chunks, "meta": meta}, f) return True, f"{len(chunks)} chunks indexed" # ── SEARCH ─────────────────────────────────────────────────────── def load_all(): chunks = [] for ff in os.listdir(INDEX_DIR): if not ff.endswith(".pkl") or ff.startswith("_"): continue try: with open(f"{INDEX_DIR}/{ff}", "rb") as f: data = pickle.load(f) for c in data["chunks"]: c = c.copy(); c["meta"] = data["meta"]; chunks.append(c) except Exception as e: log.warning(f"load_all {ff}: {e}") return chunks def keyword_search(query, chunks): stop = {"the","a","an","is","in","on","at","to","for","of","and","or","it","was","are","with","this","that"} kws = {w.lower() for w in re.findall(r'\w+', query) if len(w) > 2} - stop if not kws: return {} seen = {} for c in chunks: kh = sum(1 for kw in kws if kw in c["text"].lower()) if kh == 0: continue fn = c["source"] if fn not in seen or seen[fn]["kw"] < kh: seen[fn] = {"chunk": c, "score": kh * 0.1, "kw": kh} return seen def run_search(query): EMPTY = gr.Dropdown(choices=[], value=None, label="Select result") if not query.strip(): return "

Enter a search query.

", [], EMPTY chunks = load_all() if not chunks: return "

❌ No files indexed. Upload files in Documents tab.

", [], EMPTY stop = {"the","a","an","is","in","on","at","to","for","of","and","or","it","was","are","with","this","that"} kws = {w.lower() for w in re.findall(r'\w+', query) if len(w) > 2} - stop seen = keyword_search(query, chunks) if not seen: all_fnames = list(dict.fromkeys(c["source"] for c in chunks)) cards = "".join(f"""
📄 {fn}
""" for fn in all_fnames) return (f"
" f"No matches for: {query}
Try shorter words.
" f"

All indexed files ({len(all_fnames)}):

" + cards, all_fnames, gr.Dropdown(choices=all_fnames, value=None, label="Select a file")) results = sorted(seen.items(), key=lambda x: -x[1]["score"])[:8] html = f"

{len(results)} documents for: {query}

" choices = [] for fname, v in results: m = v["chunk"]["meta"] icon = ICONS.get("." + m.get("ftype","").lower(), "📄") prev = v["chunk"]["preview"] for kw in kws: prev = re.sub(f"({re.escape(kw)})", r"\1", prev, flags=re.IGNORECASE) html += f"""
{icon}
{fname}
{m.get("ftype","")} · {m.get("mb",0)} MB · {m.get("words",0):,} words · {m.get("date","")}
🔑 {v["kw"]} hits
{prev}…
""" choices.append(fname) return html, choices, gr.Dropdown(choices=choices, value=choices[0], label="📂 Select a file to preview") # ── DOCUMENT HELPERS ───────────────────────────────────────────── def get_text(fname): for ff in os.listdir(INDEX_DIR): if not ff.endswith(".pkl"): continue try: with open(f"{INDEX_DIR}/{ff}", "rb") as f: data = pickle.load(f) if data["meta"]["filename"] == fname: return "\n\n".join(c["text"] for c in data["chunks"]) except: pass return "" def all_meta(): docs = [] for ff in os.listdir(INDEX_DIR): if not ff.endswith(".pkl"): continue try: with open(f"{INDEX_DIR}/{ff}", "rb") as f: data = pickle.load(f) docs.append(data["meta"]) except: pass return sorted(docs, key=lambda x: x.get("date",""), reverse=True) def all_names(): return [d["filename"] for d in all_meta()] def lib_stats(): docs = all_meta() if not docs: return "*No files indexed yet.*" tw = sum(d.get("words",0) for d in docs) lines = [f"**📚 {len(docs)} files · {tw:,} words**\n"] for d in docs[:40]: icon = ICONS.get("." + d.get("ftype","").lower(), "📄") lines.append(f"{icon} **{d['filename']}** · {d.get('words',0):,}w · {d.get('date','')} · {d.get('ftype','')}") if len(docs) > 40: lines.append(f"*...and {len(docs)-40} more*") return "\n".join(lines) # ── TASKS ──────────────────────────────────────────────────────── def load_tasks(): try: if os.path.exists(TASKS_FILE): with open(TASKS_FILE) as f: return json.load(f) except: pass return [] def save_tasks(t): with open(TASKS_FILE, "w") as f: json.dump(t, f, indent=2) def tasks_html(): tasks = load_tasks(); today = datetime.date.today().isoformat() if not tasks: return "

No tasks yet.

" rows = "" for i, t in enumerate(tasks): done = t.get("done", False) due = t.get("due", "") ov = due and due < today and not done bg = "#fef2f2" if ov else ("#f9fafb" if done else "#fff") bl = "#dc2626" if ov else ("#d1d5db" if done else "#1d4ed8") pri = t.get("priority","medium") pc = {"high":"#dc2626","medium":"#d97706","low":"#15803d"}.get(pri,"#6b7280") rows += f"""
#{i}
{t['text']}
{f'
📅 {due}{" ⚠️ OVERDUE" if ov else ""}
' if due else ''}
{pri.upper()}
""" return rows + "

Use task # to toggle/delete

" # ── EVENTS ─────────────────────────────────────────────────────── def load_events(): try: if os.path.exists(EVENTS_FILE): with open(EVENTS_FILE) as f: return json.load(f) except: pass return [] def save_events(e): with open(EVENTS_FILE, "w") as f: json.dump(e, f, indent=2) def events_html(): evs = load_events(); today = datetime.date.today().isoformat() up = sorted([e for e in evs if e.get("date","") >= today], key=lambda x: x["date"]) past = sorted([e for e in evs if e.get("date","") < today], key=lambda x: x["date"], reverse=True)[:3] if not up and not past: return "

No events yet.

" def row(e, old=False): try: day=datetime.datetime.strptime(e["date"],"%Y-%m-%d").strftime("%d"); mon=datetime.datetime.strptime(e["date"],"%Y-%m-%d").strftime("%b %Y") except: day=e.get("date",""); mon="" return f"""
{day}
{mon}
{e['title']}
{f'
🕐 {e["time"]}
' if e.get("time") else ''} {f'
{e["note"]}
' if e.get("note") else ''}
""" html = "" if up: html += "

📅 Upcoming

" html += "".join(row(e) for e in up[:10]) if past: html += "

Past

" html += "".join(row(e, True) for e in past) return html # ── DASHBOARD ──────────────────────────────────────────────────── def dashboard_html(): tasks = load_tasks(); today = datetime.date.today().isoformat() today_s = datetime.date.today().strftime("%A, %B %d, %Y") hr = datetime.datetime.now().hour greet = "Good morning" if hr < 12 else "Good afternoon" if hr < 17 else "Good evening" pending = [t for t in tasks if not t.get("done")] overdue = [t for t in pending if t.get("due","") and t["due"] < today] hi = [t for t in pending if t.get("priority") == "high"] evs = load_events() up = sorted([e for e in evs if e.get("date","") >= today], key=lambda x: x["date"])[:5] docs = all_meta(); recent = docs[:6] def stat(n, lbl, bg, tc, bc): return f"""
{n}
{lbl}
""" stats = f"""
{stat(len(docs),"Indexed Docs","#eff6ff","#1d4ed8","#bfdbfe")} {stat(len(pending),"Pending Tasks","#fffbeb","#d97706","#fde68a")} {stat(len(overdue),"Overdue","#fef2f2" if overdue else "#f0fdf4","#dc2626" if overdue else "#15803d","#fecaca" if overdue else "#bbf7d0")} {stat(len(hi),"High Priority","#fef2f2" if hi else "#f0fdf4","#dc2626" if hi else "#15803d","#fecaca" if hi else "#bbf7d0")} {stat(len(up),"Upcoming Events","#f5f3ff","#7c3aed","#ddd6fe")}
""" def card(title, rows_html, empty_msg): return f"""
{title}
{rows_html or f'

{empty_msg}

'}
""" def drow(icon, text, meta): return f"""
{icon}{text} {meta}
""" task_rows = "".join(drow("⬜", t["text"][:45], t.get("due","")) for t in pending[:5]) ev_rows = "".join(drow("📅", e["title"][:45], e["date"]) for e in up) doc_rows = "".join(drow(ICONS.get("."+d.get("ftype","").lower(),"📄"), d["filename"][:45], d.get("date","")) for d in recent) return f"""
{greet}, Manager
{today_s}
{stats}
{card("📋 Active Tasks", task_rows, "All tasks complete! 🎉")} {card("🗓️ Upcoming Events", ev_rows, "No upcoming events")} {card("📁 Recent Documents", doc_rows, "No documents indexed yet")}
""" # ── CHAT ───────────────────────────────────────────────────────── def do_chat(message, history, focus): if not message.strip(): return history, "" ctx = [] if focus and focus not in ("", "— All Documents —"): t = get_text(focus) if t: ctx.append(f"[{focus}]\n{t[:3000]}") else: chunks = load_all() kw = keyword_search(message, chunks) for fn, v in sorted(kw.items(), key=lambda x:-x[1]["kw"])[:5]: t = get_text(fn) if t: ctx.append(f"[{fn}]\n{t[:800]}") context = "\n\n---\n\n".join(ctx) if ctx else "No documents indexed yet." try: ans = do_chat_llm(message, context, [(h[0],h[1]) for h in history[-8:]]) except Exception as e: ans = f"❌ {e}" return history + [[message, ans]], "" def do_analyze(filename): if not filename: return [["","⚠️ Select a document first."]], [] text = get_text(filename) if not text: return [[f'❌',f"'{filename}' not in index."]], [] prompt = f"""Analyze this document as an executive assistant. # {filename} ## Executive Summary ## Key People ## Important Dates ## Financial Data ## Decisions & Action Items ## Risks & Flags Document:\n{text[:4000]}""" try: return [[f"📊 {filename}", do_generate(prompt)]], [] except Exception as e: return [[f"📊 {filename}", f"❌ {e}"]], [] # ── EMAIL ──────────────────────────────────────────────────────── def do_email(instructions, doc, tone): if not instructions.strip(): return "⚠️ Describe the email first." ctx = "" if doc and doc not in ("", "— None —"): t = get_text(doc) if t: ctx = f"\n\nDocument context ({doc}):\n{t[:2000]}" tones = {"Formal & Executive":"formal, authoritative", "Professional & Warm":"professional, warm", "Concise & Direct":"very concise, direct", "Diplomatic":"diplomatic, nuanced"} prompt = f"""Write a complete professional business email. Tone: {tones.get(tone,"formal")} Instructions: {instructions}{ctx} Format: Subject: [subject] Dear [Recipient], [body] Best regards, [Manager Name]""" try: return do_generate(prompt) except Exception as e: return f"❌ {e}" # ── TASK HANDLERS ──────────────────────────────────────────────── def add_task(txt, due, pri, note): if not txt.strip(): return tasks_html(), "⚠️ Enter task text", "", "", "medium", "" t = load_tasks() t.append({"text":txt.strip(),"due":due.strip(),"priority":pri,"note":note, "done":False,"created":datetime.date.today().isoformat()}) save_tasks(t); return tasks_html(), "", "", "", "medium", "" def toggle_task(idx): t = load_tasks() try: i = int(idx.strip()) if 0 <= i < len(t): t[i]["done"] = not t[i]["done"] save_tasks(t) except: pass return tasks_html(), "" def delete_task(idx): t = load_tasks() try: i = int(idx.strip()) if 0 <= i < len(t): t.pop(i) save_tasks(t) except: pass return tasks_html(), "" # ── EVENT HANDLERS ─────────────────────────────────────────────── def add_event(title, date, time, note): if not title.strip() or not date.strip(): return events_html(), "⚠️ Title and date required", "", "", "", "" e = load_events() e.append({"title":title.strip(),"date":date.strip(),"time":time.strip(),"note":note.strip()}) save_events(e); return events_html(), "", "", "", "", "" def delete_event(idx): e = load_events() try: i = int(idx.strip()) if 0 <= i < len(e): e.pop(i) save_events(e) except: pass return events_html(), "" # ── INDEX HANDLERS ─────────────────────────────────────────────── def do_upload(files, progress=gr.Progress()): if not files: return "⚠️ No files selected.", lib_stats() results = [] for i, f in enumerate(files): progress(i / len(files), desc=f"Indexing {Path(f.name).name}") good, msg = index_file(f.name) results.append(f"{'✅' if good else '⚠️'} {Path(f.name).name} — {msg}") return "\n".join(results), lib_stats() def do_clear(): shutil.rmtree(INDEX_DIR, ignore_errors=True) os.makedirs(INDEX_DIR, exist_ok=True) return "🗑️ Index cleared.", lib_stats() def do_load(fname): if not fname: return "*Select a file.*", "" text = get_text(fname) if not text: return f"❌ '{fname}' not found.", "" for ff in os.listdir(INDEX_DIR): if not ff.endswith(".pkl"): continue try: with open(f"{INDEX_DIR}/{ff}", "rb") as f: data = pickle.load(f) if data["meta"]["filename"] == fname: m = data["meta"] return f"**{fname}** · {m.get('words',0):,} words · {m.get('mb',0)} MB · {m.get('date','')}", text except: pass return f"**{fname}**", text # ── CSS ────────────────────────────────────────────────────────── CSS = """ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'); body, .gradio-container{background:#f0f4f8!important;font-family:'Inter',sans-serif!important;color:#111827!important} .gradio-container{max-width:100%!important;padding:0!important} textarea,input[type=text]{background:#fff!important;border:1.5px solid #d1d5db!important;border-radius:8px!important;color:#111827!important;font-family:'Inter',sans-serif!important;font-size:.86rem!important} textarea:focus,input:focus{border-color:#1d4ed8!important;outline:none!important;box-shadow:0 0 0 3px rgba(29,78,216,.1)!important} .gr-button{font-family:'Inter',sans-serif!important;font-weight:600!important;border-radius:8px!important;font-size:.83rem!important} .gr-button.primary{background:#1d4ed8!important;color:#fff!important;border:none!important} .gr-button.primary:hover{background:#1e40af!important} .gr-button.secondary{background:#fff!important;color:#374151!important;border:1.5px solid #d1d5db!important} ::-webkit-scrollbar{width:5px;height:5px} ::-webkit-scrollbar-thumb{background:#d1d5db;border-radius:3px} """ # ── UI ─────────────────────────────────────────────────────────── _ok = True _badge = ai_status() with gr.Blocks(title="Manager Intelligence Agent", css=CSS) as demo: HIST = gr.State([]) gr.HTML(f"""
🧠
Manager Intelligence Agent
Executive OS · Free AI · Hugging Face Spaces
🦙 Llama-3-8B PDF · DOCX · XLSX · CSV · PPTX {_badge}
""") with gr.Tabs(): with gr.Tab("🏠 Dashboard"): dash = gr.HTML(dashboard_html()) gr.Button("🔄 Refresh", variant="secondary").click(dashboard_html, outputs=[dash]) gr.HTML("""
Getting started: Go to Documents → upload files → click Index. Then use Search or Chat to work with your documents.
""") with gr.Tab("🔍 Search"): with gr.Row(): s_q = gr.Textbox(label="Search", placeholder='"Ahmed Al-Rashidi 2023" · "Q3 budget" · "contract renewal"', lines=1, scale=5) s_btn = gr.Button("🔍 Search", variant="primary", scale=1) s_sum = gr.Markdown("*Enter a query and click Search.*") s_html = gr.HTML("") s_dd = gr.Dropdown(label="📂 Select a file to preview", choices=[], value=None) def do_search_all(q): html, choices, dd = run_search(q) return html, f"🔑 Found **{len(choices)}** results for: *{q}*" if choices else "*No results.*", dd s_btn.click(do_search_all, inputs=[s_q], outputs=[s_html, s_sum, s_dd]) s_q.submit(do_search_all, inputs=[s_q], outputs=[s_html, s_sum, s_dd]) with gr.Tab("💬 Chat & Intelligence"): with gr.Row(): with gr.Column(scale=1, min_width=260): c_focus = gr.Dropdown(label="Focus on file (optional)", choices=["— All Documents —"] + all_names(), value="— All Documents —") gr.Button("🔄 Refresh Files", variant="secondary").click( lambda: gr.Dropdown(choices=["— All Documents —"] + all_names()), outputs=[c_focus]) gr.HTML("""
Try asking:
• Find all records for Ahmed Hassan
• Summarize the Q3 financial report
• List all salary changes 2020–2024
• Who approved the merger?
• What contracts expire this year?
""") gr.HTML("
⚡ Document Analysis
") a_file = gr.Dropdown(label="Select document", choices=all_names()) gr.Button("🔄", variant="secondary").click(lambda: gr.Dropdown(choices=all_names()), outputs=[a_file]) a_btn = gr.Button("📊 Full Analysis", variant="primary") with gr.Column(scale=3): chatbot = gr.Chatbot(label="", height=460, show_label=False) with gr.Row(): c_in = gr.Textbox(label="", show_label=False, placeholder="Ask anything about your documents...", lines=2, scale=5) with gr.Column(scale=1, min_width=90): c_send = gr.Button("Send ↑", variant="primary") c_clear = gr.Button("Clear", variant="secondary") def chat_fn(msg, hist, focus): new_hist, _ = do_chat(msg, hist, focus) return new_hist, "", new_hist c_send.click(chat_fn, inputs=[c_in, HIST, c_focus], outputs=[HIST, c_in, chatbot]) c_in.submit(chat_fn, inputs=[c_in, HIST, c_focus], outputs=[HIST, c_in, chatbot]) c_clear.click(lambda: ([], []), outputs=[HIST, chatbot]) a_btn.click(do_analyze, inputs=[a_file], outputs=[chatbot, HIST]) with gr.Tab("✉️ Email Drafts"): with gr.Row(): with gr.Column(scale=1): e_tone = gr.Dropdown(label="Tone", choices=["Formal & Executive","Professional & Warm","Concise & Direct","Diplomatic"], value="Formal & Executive") e_doc = gr.Dropdown(label="Reference document (optional)", choices=["— None —"] + all_names(), value="— None —") gr.Button("🔄 Refresh", variant="secondary").click( lambda: gr.Dropdown(choices=["— None —"] + all_names()), outputs=[e_doc]) with gr.Column(scale=2): e_inst = gr.Textbox(label="Email instructions", placeholder="e.g. Write email to HR requesting 2 new engineers...", lines=5) e_btn = gr.Button("✉️ Draft Email", variant="primary") e_out = gr.Textbox(label="Email Draft — copy and send", lines=20, max_lines=35) e_btn.click(do_email, inputs=[e_inst, e_doc, e_tone], outputs=[e_out]) with gr.Tab("📋 Tasks & Calendar"): with gr.Row(): with gr.Column(scale=1): gr.HTML("
📋 Task Manager
") with gr.Row(): t_txt = gr.Textbox(label="Task", placeholder="What needs to be done?", scale=3) t_due = gr.Textbox(label="Due (YYYY-MM-DD)", placeholder="2025-12-31", scale=2) with gr.Row(): t_pri = gr.Dropdown(label="Priority", choices=["high","medium","low"], value="medium", scale=1) t_note = gr.Textbox(label="Note", scale=2) with gr.Row(): t_add = gr.Button("➕ Add Task", variant="primary") t_msg = gr.Markdown("") t_disp = gr.HTML(tasks_html()) with gr.Row(): t_idx = gr.Textbox(label="Task #", placeholder="0", scale=1) gr.Button("✅ Toggle", variant="secondary", scale=1).click(toggle_task, inputs=[t_idx], outputs=[t_disp, t_msg]) gr.Button("🗑️ Delete", variant="secondary", scale=1).click(delete_task, inputs=[t_idx], outputs=[t_disp, t_msg]) with gr.Column(scale=1): gr.HTML("
🗓️ Calendar & Events
") with gr.Row(): ev_t = gr.Textbox(label="Event title", scale=3) ev_d = gr.Textbox(label="Date (YYYY-MM-DD)", scale=2) with gr.Row(): ev_time = gr.Textbox(label="Time", placeholder="14:00", scale=1) ev_note = gr.Textbox(label="Note", scale=2) with gr.Row(): ev_add = gr.Button("📅 Add Event", variant="primary") ev_msg = gr.Markdown("") ev_disp = gr.HTML(events_html()) with gr.Row(): ev_idx = gr.Textbox(label="Event # to delete", placeholder="0", scale=1) gr.Button("🗑️ Delete", variant="secondary", scale=2).click(delete_event, inputs=[ev_idx], outputs=[ev_disp, ev_msg]) t_add.click(add_task, inputs=[t_txt, t_due, t_pri, t_note], outputs=[t_disp, t_msg, t_txt, t_due, t_pri, t_note]) ev_add.click(add_event, inputs=[ev_t, ev_d, ev_time, ev_note], outputs=[ev_disp, ev_msg, ev_t, ev_d, ev_time, ev_note]) with gr.Tab("📁 Documents"): with gr.Tabs(): with gr.Tab("⬆️ Upload & Index"): gr.HTML("""
Upload your files. Supported: PDF, DOCX, XLSX, CSV, PPTX, TXT, EML.
⚠️ HF free tier = storage resets on restart. Re-upload files after restart.
""") with gr.Row(): with gr.Column(scale=1): f_up = gr.File(label="Select files", file_count="multiple", file_types=[".pdf",".docx",".doc",".xlsx",".xls",".csv",".txt",".pptx",".ppt",".eml",".rtf"]) f_upbtn = gr.Button("⚡ Index Uploaded Files", variant="primary") f_clr = gr.Button("🗑️ Clear Index", variant="secondary") with gr.Column(scale=1): f_log = gr.Markdown("*Upload files then click Index.*") f_stats = gr.Markdown(lib_stats()) f_upbtn.click(do_upload, inputs=[f_up], outputs=[f_log, f_stats]) f_clr.click(do_clear, outputs=[f_log, f_stats]) with gr.Tab("📄 Preview"): with gr.Row(): p_sel = gr.Dropdown(label="Select document", choices=all_names(), scale=4) p_load = gr.Button("📄 Load", variant="primary", scale=1) gr.Button("🔄", variant="secondary", scale=1).click(lambda: gr.Dropdown(choices=all_names()), outputs=[p_sel]) p_info = gr.Markdown("*Select a file and click Load.*") p_text = gr.Textbox(label="Document content", lines=28, max_lines=60) p_load.click(do_load, inputs=[p_sel], outputs=[p_info, p_text]) with gr.Tab("⚙️ Setup"): gr.Markdown(f""" ## Configuration **AI Backend:** HF Inference API · `{HF_MODEL}` · **100% Free** ### Optional: Add HF Token (removes rate limits) 1. [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens) → New token → Role: **Read** 2. Space → **Settings → Secrets** → add `HF_TOKEN` 3. Restart Space **Current status:** {_badge} ### Supported Files | Type | Extensions | |------|-----------| | Documents | .pdf .docx .doc .rtf | | Spreadsheets | .xlsx .xls .csv | | Presentations | .pptx .ppt | | Text / Email | .txt .eml | ### Storage Note Free tier = ephemeral. Files reset on restart. Re-upload or connect HF Dataset for persistence. """) gr.HTML("""
Manager Intelligence Agent · Free AI · Llama-3-8B · Hugging Face Spaces
""") if __name__ == "__main__": print(f"\n{'='*50}\n Manager Intelligence Agent\n AI: {ai_status()}\n{'='*50}\n") demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False)