Spaces:
Sleeping
Sleeping
Download backend/python-service/storage.py from bardd/mike-backend: direct link, hf CLI and curl.
- Browser
- Download file 15.5 kB
-
https://huggingface.co/spaces/bardd/mike-backend/resolve/main/backend/python-service/storage.py
- Command line
-
hf download hf://spaces/bardd/mike-backend/backend/python-service/storage.py
-
curl -L -o storage.py https://huggingface.co/spaces/bardd/mike-backend/resolve/main/backend/python-service/storage.py
15.5 kB
| from __future__ import annotations | |
| import json | |
| import os | |
| import sqlite3 | |
| import uuid | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| from typing import Any, Optional | |
| from fastapi import HTTPException | |
| from models import ( | |
| ApplyResult, | |
| ChatConversation, | |
| ChatConversationDetail, | |
| ChatConversationSummary, | |
| ChatMessage, | |
| ReviewResponse, | |
| RunDetail, | |
| RunSummary, | |
| ) | |
| PUBLIC_AGENT_NAME = "TabularAgent" | |
| ROOT_DIR = Path(__file__).resolve().parent | |
| DATA_DIR = Path(os.environ.get("MIKE_PLAYBOOK_DATA_DIR", ROOT_DIR / "data")) | |
| DB_PATH = DATA_DIR / "tabular_review.sqlite3" | |
| def utc_now() -> str: | |
| return datetime.now(timezone.utc).isoformat() | |
| def new_id(prefix: str) -> str: | |
| return f"{prefix}_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:10]}" | |
| def reviewed_docx_name(document_name: str) -> str: | |
| stem = Path(document_name or "document.docx").stem or "document" | |
| safe_stem = "".join( | |
| ch if ch.isalnum() or ch in "._- " else "_" for ch in stem | |
| ).strip("._ ") | |
| safe_stem = safe_stem.replace(" ", "_") | |
| while "__" in safe_stem: | |
| safe_stem = safe_stem.replace("__", "_") | |
| return f"{safe_stem or 'document'}_tabular_reviewed.docx" | |
| def short_timestamp(value: str) -> str: | |
| try: | |
| dt = datetime.fromisoformat(value) | |
| except ValueError: | |
| return value[:16] | |
| return dt.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M") | |
| def connection() -> sqlite3.Connection: | |
| DATA_DIR.mkdir(parents=True, exist_ok=True) | |
| conn = sqlite3.connect(DB_PATH) | |
| conn.row_factory = sqlite3.Row | |
| return conn | |
| def init_db() -> None: | |
| with connection() as conn: | |
| conn.executescript( | |
| """ | |
| create table if not exists workflow_runs ( | |
| run_id text primary key, | |
| owner_username text not null default 'admin', | |
| created_at text not null, | |
| document_name text not null, | |
| original_docx_path text not null, | |
| commented_docx_path text, | |
| document_text text not null, | |
| playbook_id text not null, | |
| playbook_name text not null, | |
| playbook_text text not null, | |
| max_findings integer not null, | |
| status text not null, | |
| result_json text not null, | |
| apply_report_json text not null, | |
| model text, | |
| usage_json text | |
| ); | |
| create table if not exists chat_conversations ( | |
| conversation_id text primary key, | |
| owner_username text not null default 'admin', | |
| title text not null, | |
| created_at text not null, | |
| updated_at text not null | |
| ); | |
| create table if not exists chat_messages ( | |
| message_id text primary key, | |
| conversation_id text not null, | |
| owner_username text not null default 'admin', | |
| created_at text not null, | |
| role text not null, | |
| content text not null, | |
| document_name text, | |
| foreign key(conversation_id) references chat_conversations(conversation_id) | |
| ); | |
| """ | |
| ) | |
| _ensure_column( | |
| conn, "workflow_runs", "owner_username", "text not null default 'admin'" | |
| ) | |
| _ensure_column( | |
| conn, | |
| "chat_conversations", | |
| "owner_username", | |
| "text not null default 'admin'", | |
| ) | |
| _ensure_column( | |
| conn, "chat_messages", "owner_username", "text not null default 'admin'" | |
| ) | |
| def _ensure_column( | |
| conn: sqlite3.Connection, table: str, column: str, definition: str | |
| ) -> None: | |
| existing = { | |
| row["name"] for row in conn.execute(f"pragma table_info({table})").fetchall() | |
| } | |
| if column not in existing: | |
| conn.execute(f"alter table {table} add column {column} {definition}") | |
| def save_workflow_run( | |
| *, | |
| owner_username: str, | |
| run_id: str, | |
| document_name: str, | |
| original_docx_path: Path, | |
| commented_docx_path: Optional[Path], | |
| document_text: str, | |
| playbook_id: str, | |
| playbook_name: str, | |
| playbook_text: str, | |
| max_findings: int, | |
| status: str, | |
| result: ReviewResponse, | |
| apply_report: list[ApplyResult], | |
| model: Optional[str], | |
| usage: Optional[dict[str, Any]], | |
| ) -> None: | |
| with connection() as conn: | |
| conn.execute( | |
| """ | |
| insert or replace into workflow_runs ( | |
| run_id, owner_username, created_at, document_name, original_docx_path, commented_docx_path, | |
| document_text, playbook_id, playbook_name, playbook_text, max_findings, | |
| status, result_json, apply_report_json, model, usage_json | |
| ) | |
| values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) | |
| """, | |
| ( | |
| run_id, | |
| owner_username, | |
| utc_now(), | |
| document_name, | |
| str(original_docx_path), | |
| str(commented_docx_path) if commented_docx_path else None, | |
| document_text, | |
| playbook_id, | |
| playbook_name, | |
| playbook_text, | |
| max_findings, | |
| status, | |
| result.model_dump_json(), | |
| json.dumps( | |
| [item.model_dump() for item in apply_report], ensure_ascii=False | |
| ), | |
| model, | |
| json.dumps(usage, ensure_ascii=False) if usage else None, | |
| ), | |
| ) | |
| def _summary_from_row(row: sqlite3.Row) -> RunSummary: | |
| result = json.loads(row["result_json"]) | |
| apply_report = json.loads(row["apply_report_json"]) | |
| findings = result.get("findings") if isinstance(result, dict) else [] | |
| applied_count = sum(1 for item in apply_report if item.get("status") == "applied") | |
| return RunSummary( | |
| run_id=row["run_id"], | |
| created_at=row["created_at"], | |
| created_short=short_timestamp(row["created_at"]), | |
| document_name=row["document_name"], | |
| commented_docx_name=reviewed_docx_name(row["document_name"]), | |
| playbook_id=row["playbook_id"], | |
| playbook_name=row["playbook_name"], | |
| status=row["status"], | |
| finding_count=len(findings) if isinstance(findings, list) else 0, | |
| applied_count=applied_count, | |
| model=PUBLIC_AGENT_NAME, | |
| ) | |
| def list_runs( | |
| owner_username: str, limit: int = 50, playbook_id: str | None = None | |
| ) -> list[RunSummary]: | |
| with connection() as conn: | |
| if playbook_id: | |
| rows = conn.execute( | |
| "select * from workflow_runs where owner_username = ? and playbook_id = ? order by created_at desc limit ?", | |
| (owner_username, playbook_id, limit), | |
| ).fetchall() | |
| else: | |
| rows = conn.execute( | |
| "select * from workflow_runs where owner_username = ? order by created_at desc limit ?", | |
| (owner_username, limit), | |
| ).fetchall() | |
| return [_summary_from_row(row) for row in rows] | |
| def get_run(run_id: str, owner_username: str) -> RunDetail: | |
| with connection() as conn: | |
| row = conn.execute( | |
| "select * from workflow_runs where run_id = ? and owner_username = ?", | |
| (run_id, owner_username), | |
| ).fetchone() | |
| if not row: | |
| raise HTTPException(status_code=404, detail=f"Workflow run not found: {run_id}") | |
| summary = _summary_from_row(row) | |
| usage = json.loads(row["usage_json"]) if row["usage_json"] else None | |
| commented_path = ( | |
| Path(row["commented_docx_path"]) if row["commented_docx_path"] else None | |
| ) | |
| return RunDetail( | |
| **summary.model_dump(), | |
| document_text=row["document_text"], | |
| playbook_text=row["playbook_text"], | |
| result=ReviewResponse.model_validate_json(row["result_json"]), | |
| apply_report=[ | |
| ApplyResult.model_validate(item) | |
| for item in json.loads(row["apply_report_json"]) | |
| ], | |
| usage=usage, | |
| commented_docx_available=bool(commented_path and commented_path.exists()), | |
| ) | |
| def get_commented_docx_path(run_id: str, owner_username: str) -> Path: | |
| with connection() as conn: | |
| row = conn.execute( | |
| "select commented_docx_path from workflow_runs where run_id = ? and owner_username = ?", | |
| (run_id, owner_username), | |
| ).fetchone() | |
| if not row or not row["commented_docx_path"]: | |
| raise HTTPException( | |
| status_code=404, detail="Commented DOCX is not available for this run." | |
| ) | |
| path = Path(row["commented_docx_path"]) | |
| if not path.exists(): | |
| raise HTTPException(status_code=404, detail="Commented DOCX file is missing.") | |
| return path | |
| def save_chat_message( | |
| *, | |
| owner_username: str, | |
| conversation_id: Optional[str], | |
| role: str, | |
| content: str, | |
| document_name: Optional[str] = None, | |
| ) -> str: | |
| now = utc_now() | |
| conv_id = conversation_id or new_id("conv") | |
| title = content.strip().splitlines()[0][:80] or "New conversation" | |
| message_id = new_id("msg") | |
| with connection() as conn: | |
| existing = conn.execute( | |
| "select conversation_id from chat_conversations where conversation_id = ? and owner_username = ?", | |
| (conv_id, owner_username), | |
| ).fetchone() | |
| if not existing: | |
| conn.execute( | |
| "insert into chat_conversations (conversation_id, owner_username, title, created_at, updated_at) values (?, ?, ?, ?, ?)", | |
| (conv_id, owner_username, title, now, now), | |
| ) | |
| else: | |
| conn.execute( | |
| "update chat_conversations set updated_at = ? where conversation_id = ? and owner_username = ?", | |
| (now, conv_id, owner_username), | |
| ) | |
| conn.execute( | |
| """ | |
| insert into chat_messages ( | |
| message_id, conversation_id, owner_username, created_at, role, content, document_name | |
| ) | |
| values (?, ?, ?, ?, ?, ?, ?) | |
| """, | |
| ( | |
| message_id, | |
| conv_id, | |
| owner_username, | |
| now, | |
| role, | |
| content, | |
| document_name, | |
| ), | |
| ) | |
| return conv_id | |
| def list_conversations( | |
| owner_username: str, limit: int = 20 | |
| ) -> list[ChatConversationSummary]: | |
| with connection() as conn: | |
| rows = conn.execute( | |
| """ | |
| select conversation_id, title, created_at, updated_at | |
| from chat_conversations | |
| where owner_username = ? | |
| order by updated_at desc | |
| limit ? | |
| """, | |
| (owner_username, limit), | |
| ).fetchall() | |
| return [ | |
| ChatConversationSummary( | |
| conversation_id=row["conversation_id"], | |
| title=row["title"], | |
| created_at=row["created_at"], | |
| updated_at=row["updated_at"], | |
| ) | |
| for row in rows | |
| ] | |
| def get_conversation( | |
| conversation_id: str, owner_username: str | |
| ) -> ChatConversationDetail: | |
| with connection() as conn: | |
| row = conn.execute( | |
| """ | |
| select conversation_id, owner_username, title, created_at, updated_at | |
| from chat_conversations | |
| where conversation_id = ? and owner_username = ? | |
| """, | |
| (conversation_id, owner_username), | |
| ).fetchone() | |
| if not row: | |
| raise HTTPException( | |
| status_code=404, detail=f"Conversation not found: {conversation_id}" | |
| ) | |
| messages = conn.execute( | |
| """ | |
| select message_id, created_at, role, content, document_name | |
| from chat_messages | |
| where conversation_id = ? and owner_username = ? | |
| order by created_at asc | |
| """, | |
| (conversation_id, owner_username), | |
| ).fetchall() | |
| return ChatConversationDetail( | |
| conversation_id=row["conversation_id"], | |
| owner_username=row["owner_username"], | |
| title=row["title"], | |
| created_at=row["created_at"], | |
| updated_at=row["updated_at"], | |
| messages=[ | |
| ChatMessage( | |
| id=message["message_id"], | |
| role=message["role"], | |
| content=message["content"], | |
| created_at=message["created_at"], | |
| document_name=message["document_name"], | |
| ) | |
| for message in messages | |
| ], | |
| ) | |
| def run_to_markdown(run_id: str, owner_username: str) -> str: | |
| run = get_run(run_id, owner_username) | |
| lines = [ | |
| f"# Review Run: {run.document_name}", | |
| "", | |
| "## Metadata", | |
| "", | |
| f"- Run ID: `{run.run_id}`", | |
| f"- Created: `{run.created_short}`", | |
| f"- Playbook: `{run.playbook_name}` (`{run.playbook_id}`)", | |
| f"- Status: `{run.status}`", | |
| f"- Agent: `{PUBLIC_AGENT_NAME}`", | |
| f"- Findings: `{run.finding_count}`", | |
| f"- Comments applied: `{run.applied_count}`", | |
| "", | |
| "## Findings", | |
| "", | |
| ] | |
| for index, finding in enumerate(run.result.findings, start=1): | |
| apply_result = next( | |
| (item for item in run.apply_report if item.id == finding.id), None | |
| ) | |
| lines.extend( | |
| [ | |
| f"### {index}. {finding.clause_type} - {finding.risk_level}", | |
| "", | |
| f"**Issue:** {finding.issue}", | |
| "", | |
| f"**Comment inserted:** {finding.comment}", | |
| "", | |
| f"**Internal reasoning:**\n- **Clause/Section:** {finding.review_reasoning.get('clause_section', 'N/A') if isinstance(finding.review_reasoning, dict) else finding.review_reasoning}\n- **Violated Standard:** {finding.review_reasoning.get('violated_standard', 'N/A') if isinstance(finding.review_reasoning, dict) else 'N/A'}\n- **Zamil Exposure:** {finding.review_reasoning.get('zamil_exposure', 'N/A') if isinstance(finding.review_reasoning, dict) else 'N/A'}", | |
| "", | |
| f"**Confidence:** {finding.confidence}", | |
| "", | |
| f"**Apply status:** {apply_result.status if apply_result else 'not_applied'}", | |
| "", | |
| "**Target text:**", | |
| "", | |
| "```text", | |
| finding.target_text, | |
| "```", | |
| "", | |
| ] | |
| ) | |
| if not run.result.findings: | |
| lines.append("No findings were returned.") | |
| lines.append("") | |
| lines.extend( | |
| [ | |
| "## Apply Report", | |
| "", | |
| "```json", | |
| json.dumps( | |
| [item.model_dump() for item in run.apply_report], | |
| indent=2, | |
| ensure_ascii=False, | |
| ), | |
| "```", | |
| "", | |
| "## Document Text", | |
| "", | |
| "```text", | |
| run.document_text, | |
| "```", | |
| "", | |
| "## Playbook Text", | |
| "", | |
| "```yaml", | |
| run.playbook_text, | |
| "```", | |
| "", | |
| "## Raw Result JSON", | |
| "", | |
| "```json", | |
| run.result.model_dump_json(indent=2), | |
| "```", | |
| "", | |
| ] | |
| ) | |
| return "\n".join(lines) | |