diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..9a5e027383a6a094f8af59a141ab498c5f1d23a7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.tflite filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..77e24df871b26b98391caccd828b1e3727b54559 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.10-slim + +WORKDIR /app + +# Install minimal system dependencies +RUN apt-get update && apt-get install -y \ + libgl1-mesa-glx \ + libglib2.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# Copy requirements first for better caching +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy application files +COPY . . + +CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"] diff --git a/Google_Search_tool.py b/Google_Search_tool.py new file mode 100644 index 0000000000000000000000000000000000000000..f357319d3a28fbba5b47484fdac53f575b16237e --- /dev/null +++ b/Google_Search_tool.py @@ -0,0 +1,41 @@ +import os +import logging +from googleapiclient.discovery import build +from dotenv import load_dotenv + +load_dotenv() + +class GoogleSearch: + """Performs Google Custom Search API queries.""" + def __init__(self): + self.api_key = os.getenv("GOOGLE_API_KEY") + self.cse_id = os.getenv("GOOGLE_CSE_ID") + self.service = None + if self.api_key and self.cse_id: + try: + self.service = build("customsearch", "v1", developerKey=self.api_key) + logging.info("✅ Google Custom Search initialized.") + except Exception as e: + logging.error(f"❌ CSE init failed: {e}") + else: + logging.warning("⚠️ GOOGLE_API_KEY or GOOGLE_CSE_ID not set; search disabled.") + + def search(self, queries: list, num_results: int = 1) -> list: + if not self.service: + return [] + out = [] + for q in queries: + try: + resp = self.service.cse().list(q=q, cx=self.cse_id, num=num_results).execute() + items = resp.get("items", []) + formatted = [ + {"title": it.get("title"), "link": it.get("link"), "snippet": it.get("snippet")} + for it in items + ] + out.append({"query": q, "results": formatted}) + except Exception as e: + logging.error(f"❌ Search error for '{q}': {e}") + out.append({"query": q, "results": []}) + return out + +google_search = GoogleSearch() diff --git a/README.md b/README.md index 152c83e3f727caa975abfa7dc16b04e6058073c7..3797697b9342615ceea9b6505e43244930cbf3ca 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,14 @@ --- -title: HexAI Demo -emoji: 🔥 -colorFrom: pink -colorTo: gray -sdk: static -pinned: false -app_build_command: npm run build -app_file: dist/index.html -short_description: Demo with limited version +title: RxGuard Prescription Validator +emoji: ⚕️ +colorFrom: blue +colorTo: indigo +sdk: streamlit +sdk_version: 1.36.0 +app_file: app.py +hf_oauth: true +hardware: + accelerator: T4 + cpu: 2 + memory: 16 --- - -# Svelte + TS + Vite - -This template should help get you started developing with Svelte and TypeScript in Vite. - -## Recommended IDE Setup - -[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). - -## Need an official Svelte framework? - -Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. - -## Technical considerations - -**Why use this over SvelteKit?** - -- It brings its own routing solution which might not be preferable for some users. -- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. - -This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. - -Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. - -**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** - -Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. - -**Why include `.vscode/extensions.json`?** - -Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. - -**Why enable `allowJs` in the TS template?** - -While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. - -**Why is HMR not preserving my local component state?** - -HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). - -If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. - -```ts -// store.ts -// An extremely simple external store -import { writable } from "svelte/store"; -export default writable(0); -``` diff --git a/__pycache__/config.cpython-310.pyc b/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..facf05a71f762db4a1098cae11e663390bb2fc07 Binary files /dev/null and b/__pycache__/config.cpython-310.pyc differ diff --git a/__pycache__/config.cpython-39.pyc b/__pycache__/config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dda04cee96af3fa2c41b5088c8daae2b25e02d51 Binary files /dev/null and b/__pycache__/config.cpython-39.pyc differ diff --git a/__pycache__/google_search_tool.cpython-310.pyc b/__pycache__/google_search_tool.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..41c59ad7968ff63fa0a3452cb0c3a901ac3bf1aa Binary files /dev/null and b/__pycache__/google_search_tool.cpython-310.pyc differ diff --git a/__pycache__/validate_prescription.cpython-310.pyc b/__pycache__/validate_prescription.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..008dc35fb40e9d306183391cf9bcde1a57e2c4dd Binary files /dev/null and b/__pycache__/validate_prescription.cpython-310.pyc differ diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..2ad1a32c687eeda008284ed47147aa5bfe654b43 --- /dev/null +++ b/app.py @@ -0,0 +1,137 @@ +import os +import streamlit as st +from PIL import Image +from config import ( + STATIC_DIR, + UPLOADS_DIR, + HF_TOKEN, + GOOGLE_API_KEY, + GOOGLE_CSE_ID, + GEMINI_API_KEY, + DEVICE +) + +# ─── App Configuration ──────────────────────────────────────────────────── +st.set_page_config( + page_title="RxGuard Prescription Validator", + page_icon="⚕️", + layout="wide", + menu_items={ + 'Get Help': 'https://github.com/your-repo', + 'About': "RxGuard v1.0 - Advanced Prescription Validation" + } +) + +# ─── Session State ──────────────────────────────────────────────────────── +if "analysis_result" not in st.session_state: + st.session_state.analysis_result = None +if "uploaded_filename" not in st.session_state: + st.session_state.uploaded_filename = None + +# ─── UI Components ──────────────────────────────────────────────────────── +def show_service_status(): + """Displays service connectivity status.""" + cols = st.columns(4) + with cols[0]: + st.metric("HuggingFace", "✅" if HF_TOKEN else "❌") + with cols[1]: + st.metric("Google API", "✅" if GOOGLE_API_KEY else "❌") + with cols[2]: + st.metric("Gemini", "✅" if GEMINI_API_KEY else "❌") + with cols[3]: + st.metric("Device", DEVICE.upper()) + +def display_patient_info(info: dict): + """Displays patient information in a formatted card.""" + with st.container(border=True): + st.subheader("👤 Patient Details") + cols = st.columns(2) + with cols[0]: + st.markdown(f"**Name:** {info.get('Name', 'Not detected')}") + st.markdown(f"**Age:** {info.get('Age', 'N/A')}") + with cols[1]: + st.markdown(f"**Date:** {info.get('Date', 'N/A')}") + st.markdown(f"**Physician:** {info.get('PhysicianName', 'N/A')}") + +def display_medications(medications: list): + """Displays medication information with verification.""" + st.subheader("💊 Medications") + if not medications: + st.warning("No medications detected in prescription") + return + + for med in medications: + with st.expander(f"{med.get('drug_raw', 'Unknown Medication')}"): + cols = st.columns([1, 2]) + with cols[0]: + st.markdown(f""" + **Dosage:** `{med.get('dosage', 'N/A')}` + **Frequency:** `{med.get('frequency', 'N/A')}` + """) + + with cols[1]: + if verification := med.get("verification"): + if dosage := verification.get("standard_dosage"): + st.success(f"**Standard Dosage:** {dosage}") + if side_effects := verification.get("side_effects"): + st.warning(f"**Side Effects:** {side_effects}") + if interactions := verification.get("interactions"): + st.error(f"**Interactions:** {interactions}") + +# ─── Main Application ───────────────────────────────────────────────────── +def main(): + st.title("⚕️ RxGuard Prescription Validator") + st.caption("AI-powered prescription verification system") + + show_service_status() + + # Only enable upload if required services are available + if all([HF_TOKEN, GOOGLE_API_KEY, GEMINI_API_KEY]): + uploaded_file = st.file_uploader( + "Upload prescription image (PNG/JPG/JPEG):", + type=["png", "jpg", "jpeg"], + help="Clear image of the prescription" + ) + + if uploaded_file and uploaded_file.name != st.session_state.uploaded_filename: + with st.status("Analyzing prescription...", expanded=True) as status: + try: + # Store the uploaded file + st.session_state.uploaded_filename = uploaded_file.name + file_path = os.path.join(UPLOADS_DIR, uploaded_file.name) + + with open(file_path, "wb") as f: + f.write(uploaded_file.getvalue()) + + # Import processing function only when needed + from validate_prescription import extract_prescription_info + st.session_state.analysis_result = extract_prescription_info(file_path) + + status.update(label="Analysis complete!", state="complete", expanded=False) + except Exception as e: + st.error(f"Processing failed: {str(e)}") + st.session_state.analysis_result = {"error": str(e)} + status.update(label="Analysis failed", state="error") + + # Display results if available + if st.session_state.analysis_result: + result = st.session_state.analysis_result + + if result.get("error"): + st.error(f"❌ Error: {result['error']}") + else: + tab1, tab2 = st.tabs(["Patient Information", "Medication Details"]) + + with tab1: + if uploaded_file: + st.image(uploaded_file, use_column_width=True) + display_patient_info(result["info"]) + + with tab2: + display_medications(result["info"].get("Medications", [])) + + if st.toggle("Show technical details"): + st.json(result.get("debug_info", {})) + +if __name__ == "__main__": + main() diff --git a/apt-packages.txt b/apt-packages.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b05dfc387ff0e73463dfa959682bf07609450a5 --- /dev/null +++ b/apt-packages.txt @@ -0,0 +1,13 @@ +libgl1 +libgl1-mesa-glx +libglib2.0-0 +tesseract-ocr +tesseract-ocr-hin +git +git-lfs +curl +libssl-dev +libffi-dev +python3-dev +build-essential +libsqlite3-dev diff --git a/config.py b/config.py new file mode 100644 index 0000000000000000000000000000000000000000..343c4451a3fc7af328e2367270426c6d8fd8dbbc --- /dev/null +++ b/config.py @@ -0,0 +1,37 @@ +import os +import torch +from dotenv import load_dotenv + +load_dotenv() + +# ─── Directory Configuration ──────────────────────────────────────────────── +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +STATIC_DIR = os.path.join(BASE_DIR, 'static') +os.makedirs(STATIC_DIR, exist_ok=True) + +# ─── API Secrets ──────────────────────────────────────────────────────────── +HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN") # For Hugging Face models +GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY") # For Gemini and Custom Search +GOOGLE_CSE_ID = os.getenv("GOOGLE_CSE_ID") # For medication verification +GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") # Alternative Gemini auth +HALODOC_API_KEY = os.getenv("HALODOC_API_KEY") # Future integration + +# ─── Model Configuration ──────────────────────────────────────────────────── +HF_MODELS = { + "donut": "naver-clova-ix/donut-base-finetuned-cord-v2", + "phi3": "microsoft/phi-3-mini-4k-instruct", +} +GEMINI_MODEL_NAME = "gemini-1.5-flash" # Balanced for speed and accuracy + +# ─── Processing Parameters ───────────────────────────────────────────────── +LEV_THRESH = 0.75 # Levenshtein similarity threshold +SIG_THRESH = 0.65 # Signature verification threshold + +# ─── File Paths ─────────────────────────────────────────────────────────── +DB_PATH = os.path.join(STATIC_DIR, "rxguard.db") +UPLOADS_DIR = os.path.join(STATIC_DIR, "uploads") +os.makedirs(UPLOADS_DIR, exist_ok=True) + +# ─── Hardware Configuration ──────────────────────────────────────────────── +DEVICE = "cpu" # Force CPU for Hugging Face Spaces compatibility +USE_GPU = False diff --git a/data/interactions.csv b/data/interactions.csv new file mode 100644 index 0000000000000000000000000000000000000000..815ad5af3124eaa748c3d8e2dfa602097405abac --- /dev/null +++ b/data/interactions.csv @@ -0,0 +1,3 @@ +cui1,cui2,severity,advice +1191,6801,moderate,"Monitor blood glucose closely; aspirin may enhance the hypoglycemic effect of metformin." +4241,1113,moderate,"Ascorbic acid can increase the absorption of iron. While often beneficial, monitor for iron overload in susceptible patients." diff --git a/data/rxnorm.db b/data/rxnorm.db new file mode 100644 index 0000000000000000000000000000000000000000..8dade48909ab53de6764c55a329191edb5f58cf5 Binary files /dev/null and b/data/rxnorm.db differ diff --git a/data/rxnorm_names.csv b/data/rxnorm_names.csv new file mode 100644 index 0000000000000000000000000000000000000000..ae175da09cf28ff9d578aedd38a0656bed86b60c --- /dev/null +++ b/data/rxnorm_names.csv @@ -0,0 +1,13 @@ +name,cui +Aspirin,1191 +Acetaminophen,161 +Amoxicillin,723 +Metformin,6801 +Lisinopril,29046 +Ferrous Sulfate,4241 +Ascorbic Acid,1113 +Calcium Carbonate / Vitamin D3,12345 +Clonazepam,2623 +Meganeuron,54321 +Creatine,9876 +Salbutamol,9648 diff --git a/drug_interaction_detection/__pycache__/interaction_checker.cpython-310.pyc b/drug_interaction_detection/__pycache__/interaction_checker.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23488f8e8c168e82b9b2a111b51d7cc0e44c4488 Binary files /dev/null and b/drug_interaction_detection/__pycache__/interaction_checker.cpython-310.pyc differ diff --git a/drug_interaction_detection/interaction_checker.py b/drug_interaction_detection/interaction_checker.py new file mode 100644 index 0000000000000000000000000000000000000000..a2811c30b90979b4624356423271a102c44db5ba --- /dev/null +++ b/drug_interaction_detection/interaction_checker.py @@ -0,0 +1,34 @@ +# drug_interaction_detection/interaction_checker.py +import sqlite3 +from config import DB_PATH + +class InteractionChecker: + def __init__(self, db_path: str = DB_PATH): + self.conn = sqlite3.connect(db_path) + self.conn.row_factory = sqlite3.Row + + def find(self, cuis: list[str]) -> list[dict]: + if len(cuis) < 2: return [] + + # Create a list of all unique pairs + pairs = [] + for i in range(len(cuis)): + for j in range(i + 1, len(cuis)): + # Ensure consistent order for querying (e.g., smaller CUI first) + pair = tuple(sorted((cuis[i], cuis[j]))) + pairs.append(pair) + + if not pairs: return [] + + # Query for all pairs at once + placeholders = ", ".join(["(?, ?)"] * len(pairs)) + flat_params = [item for pair in pairs for item in pair] + + query = f""" + SELECT cui1, cui2, severity, advice + FROM interactions + WHERE (cui1, cui2) IN ({placeholders}) + """ + + rows = self.conn.execute(query, flat_params).fetchall() + return [{"pair": (r["cui1"], r["cui2"]), "severity": r["severity"], "advice": r["advice"]} for r in rows] diff --git a/earnest-trilogy-465710-e7-6cc7bbbddb97.json b/earnest-trilogy-465710-e7-6cc7bbbddb97.json new file mode 100644 index 0000000000000000000000000000000000000000..c6c65f131b35215f28287dd21e763e114032755f --- /dev/null +++ b/earnest-trilogy-465710-e7-6cc7bbbddb97.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "earnest-trilogy-465710-e7", + "private_key_id": "6cc7bbbddb970f16876e3f4120ff18be704f5ee5", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCL9vzHnI9qvAMm\n4VvadaDB//B8ibFEi3BNojVaWg5iM12nhIRhhDTCHEryjrQUmxslGiJ/xslQzO6c\nueAXVGiaT+dyZJ6q004aRpjfjkV+T8bmIX8B2hx9bJZ0mTn4rN7Yeg2mOR7F+Psf\njjSm91sX3FTtDO6lRd6olGiRCXn65GPkbXPUZW52xuEVwRuFhsNcJnKgRD3f7rko\nbnBZ0/un7HRg5eNZspHW4eOynOSZcoykCfnQbB4noRsLyGi3VknZDCXpRc9dhlLf\nDZFhjnqzwsoy24Z6uoPSctAX1itL54zQ0x25xUS4pvPO3jy7W9ONctRjzp2oQyIC\n199jv0thAgMBAAECggEAARzStqpT+bDv1E+ACwu6k4mLluKC0YT2Eh3pxJOORUxR\nJc+Kka+1pNHerCXY1ghDcNnvyoTRDUarF71CrrjLFz1ESBnh6NZ4FVgjPLVdMCNQ\nSnxwwvoMgNg77BvFiih4odn63AvcnA2uFFqtaI2IkIyIiHUHpsdth85HNFjx5T3y\nxQwx0P+7QxFXpaQkDXUFqcTysJNzZbhKHVJAtmjVo32H103PKJtYbmVdNci0fxE4\n5SugGB/AvFrmZ2rPzVraIarFueE2m6ENrpU+ESwBFnASwJ0uAqir0ZEz+7VXPGYL\nGwk6rkhhK+GD+z+CRkA6RDuObkUG1ijqT9kf+DCiAQKBgQDDRrDSf6WXhiuh6Cl8\n5JGjD1xfw0T6U63bJdRXN1iPE5+WUwq7Jdtb1tjB9ocNg/6ISIfHBrribLapwrJl\npFQl4UOB731K0NLWbIhiJeVdX/By5boYQK7FB0J4+dQZfIgzl0gsJuT+1wsxvTMJ\nXImmaG+bFLEtEuWOEDrM4OflgQKBgQC3fSM3PIY3o9XC7EIU97G5eWQRAjvSYU6l\nfETIR93ycxahPhU+JvB6ncteJTSEdLLAKq+VnxOvXH/3tlufMmHeQuSEx2IGip2B\nvqnNV8IhY7aQtA0enfT88PmlpEnM+mBPDPKAoJXOoRTanKiMXuwhVFsqfRo8A597\nCxzDPZsV4QKBgC4bWNC61uxp/49g87rLdR+dFuB9iKHadChUTEizhrNxnLKvtM7v\nZ1XN6qwRe13TlpuzFGwHyMSBireWguzA2iV/hKL/WwP5Pm7mfWU/MWLUrj9SwpfL\nXfijeCx8QHosDzSvOZlDLbqGJ9x8obpKIS4rZn6lahgMaCsc5eVODTMBAoGAaQRJ\nFIMielPds1tPEvsVEAeHGykBHg6tWY9/OnXPdMUj7ZM/yzu0JSmMzMxUe37jE5Ma\nvXK3bIVvhFItrDbExtXYPppy4zWQokKCotEYfc25Hqa+X4ieP+qXp5MY3iVq27OY\nU8AVHZcZ/WjuGrD1SroiF3ZUfobAT0bz5larHWECgYAki/VOTjmOfvtR+6aLZW0T\nuPYomIZGCxCY+b7zoxk3YPEd15KG25SI0JsdK2QDwbGyQan4X/eZQlwFacGH+2is\nsOpYrsMuOktTUtjTmOCPq3+6a22k6yxXvxGIjn0XcP1Pgh/aAi2yi2Ejlxgr4JpU\nJUzmpT+C4PQCHMepVFoaLw==\n-----END PRIVATE KEY-----\n", + "client_email": "aihackathon@earnest-trilogy-465710-e7.iam.gserviceaccount.com", + "client_id": "102524806684057807383", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/aihackathon%40earnest-trilogy-465710-e7.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/index.html b/index.html deleted file mode 100644 index b6c5f0afafd6f2e009ed3d2c5de7351bcf7fb12d..0000000000000000000000000000000000000000 --- a/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Vite + Svelte + TS - - -
- - - diff --git a/models/signature_sia.tflite b/models/signature_sia.tflite new file mode 100644 index 0000000000000000000000000000000000000000..d9fa2bc3485c6b9dc476c2e5a80b4497f6880700 --- /dev/null +++ b/models/signature_sia.tflite @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ba80e2f5c688e9fd9fc766a85f266d0a47201def65265ef294168546a2814de +size 804888 diff --git a/package.json b/package.json deleted file mode 100644 index 9013b8ca459416df8386e8607bf202977c5442de..0000000000000000000000000000000000000000 --- a/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "svelte", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json" - }, - "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.3", - "@tsconfig/svelte": "^5.0.4", - "svelte": "^5.28.1", - "svelte-check": "^4.1.6", - "typescript": "~5.8.3", - "vite": "^6.3.5" - } -} diff --git a/prescription_validation/__pycache__/fuzzy_match.cpython-310.pyc b/prescription_validation/__pycache__/fuzzy_match.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35aaef85b25ee925fe3c78c724014efa37d64a3e Binary files /dev/null and b/prescription_validation/__pycache__/fuzzy_match.cpython-310.pyc differ diff --git a/prescription_validation/fuzzy_match.py b/prescription_validation/fuzzy_match.py new file mode 100644 index 0000000000000000000000000000000000000000..6e3ca2fa5d9bf2bea8c56426d867a5debae49bc5 --- /dev/null +++ b/prescription_validation/fuzzy_match.py @@ -0,0 +1,44 @@ +# prescription_validation/fuzzy_match.py +import sqlite3 +import re +from rapidfuzz.distance import Levenshtein +from config import DB_PATH, LEV_THRESH + +class RxLookup: + def __init__(self, db_path: str = DB_PATH): + self.conn = sqlite3.connect(db_path) + self.conn.row_factory = sqlite3.Row + self.drugs = self.conn.execute("SELECT name, cui FROM drugs").fetchall() + + def _clean_token(self, token: str) -> str: + """Removes dosage, form factor, and non-alpha characters.""" + cleaned = token.lower() + cleaned = re.sub(r'(\d+)\s*(mg|ml|mcg|tab|cap|#)', '', cleaned) + cleaned = re.sub(r'[^a-z]', '', cleaned) + return cleaned + + def match(self, token: str) -> tuple[str | None, str | None]: + if not token: + return (None, None) + + cleaned_token = self._clean_token(token) + if not cleaned_token: + return (None, None) + + best_match = None + min_distance = float('inf') + + for row in self.drugs: + name, cui = row["name"], row["cui"] + cleaned_db_name = self._clean_token(name) + + distance = Levenshtein.distance(cleaned_token, cleaned_db_name) + + if distance < min_distance: + min_distance = distance + best_match = (name, cui) + + if best_match and min_distance / len(cleaned_token) < LEV_THRESH: + return best_match + + return (None, None) diff --git a/prescription_validation/zone_detector.py b/prescription_validation/zone_detector.py new file mode 100644 index 0000000000000000000000000000000000000000..9c1b69adb7cd2a3bfa329a782793bbf79db95f24 --- /dev/null +++ b/prescription_validation/zone_detector.py @@ -0,0 +1,27 @@ +# prescription_validation/zone_detector.py +import cv2 +import numpy as np +from ultralytics import YOLO + +class ZoneDetector: + def __init__(self, model_path: str = "models/signature_model.pt"): + try: + self.model = YOLO(model_path) + print(f"✅ Loaded local YOLO model from '{model_path}'") + except Exception as e: + self.model = None + print(f"❌ Failed to load local YOLO model from '{model_path}'. Please ensure the model file exists.") + + def detect(self, img: np.ndarray) -> list[dict]: + if not self.model: return [] + rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) + results = self.model(rgb_img, verbose=False) + detections = [] + for box in results[0].boxes: + x1, y1, x2, y2 = box.xyxy[0].tolist() + class_id = int(box.cls[0]) + detections.append({ + "label": self.model.names[class_id], + "bbox": tuple(map(int, [x1, y1, x2, y2])), + }) + return detections diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb1b2a60bd50538bec9f876511b9cac21e3..0000000000000000000000000000000000000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..65260cecff634926fac4fe3ad07852200fc38098 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,23 @@ +# Core +streamlit==1.36.0 +python-dotenv==1.0.1 + +# AI & Vision +# Using Google's recommended versions for Gemini and Vision +google-generativeai==0.7.1 +google-cloud-vision==3.7.3 +torch==2.3.1 +pillow==10.3.0 +transformers==4.41.0 + +# OCR +paddleocr==2.7.3 +# Using the CPU version of paddlepaddle for broader compatibility on HF Spaces +paddlepaddle==2.6.1 + +# Utils +numpy==1.26.4 +requests==2.32.3 +opencv-python-headless==4.10.0.84 +scikit-image==0.22.0 +pytz==2024.1 diff --git a/scripts/build_interactions_db.py b/scripts/build_interactions_db.py new file mode 100644 index 0000000000000000000000000000000000000000..c998337b601e5d6ad1384ced042eeb093615f8b4 --- /dev/null +++ b/scripts/build_interactions_db.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +import sqlite3, csv, argparse +import sys, os +sys.path.append(os.getcwd()) +from config import DB_PATH, INTERACTIONS_CSV + +def build_db(db_path: str, csv_path: str): + conn = sqlite3.connect(db_path) + c = conn.cursor() + c.execute("DROP TABLE IF EXISTS interactions") + c.execute("CREATE TABLE interactions(cui1 TEXT, cui2 TEXT, severity TEXT, advice TEXT, UNIQUE(cui1, cui2))") + + with open(csv_path, newline='', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + # Ensure consistent order to avoid duplicate entries like (A,B) and (B,A) + cui1, cui2 = sorted((row['cui1'], row['cui2'])) + c.execute( + "INSERT OR IGNORE INTO interactions(cui1, cui2, severity, advice) VALUES(?,?,?,?)", + (cui1, cui2, row['severity'], row['advice']) + ) + conn.commit() + conn.close() + +if __name__ == "__main__": + build_db(DB_PATH, INTERACTIONS_CSV) + print(f"✅ Interactions DB built at {DB_PATH}") diff --git a/scripts/build_rxnorm_db.py b/scripts/build_rxnorm_db.py new file mode 100644 index 0000000000000000000000000000000000000000..fda5823aade24623c0a86d8bae700ee9dab00389 --- /dev/null +++ b/scripts/build_rxnorm_db.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +import sqlite3, csv, argparse +from metaphone import doublemetaphone +import sys, os +sys.path.append(os.getcwd()) +from config import DB_PATH, RXNORM_CSV + +def build_db(db_path: str, csv_path: str): + conn = sqlite3.connect(db_path) + c = conn.cursor() + c.execute("DROP TABLE IF EXISTS drugs") + c.execute("DROP TABLE IF EXISTS metaphone") + c.execute("CREATE TABLE drugs(name TEXT PRIMARY KEY, cui TEXT)") + c.execute("CREATE TABLE metaphone(meta TEXT, name TEXT, cui TEXT)") + + with open(csv_path, newline='', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + nm, cui = row['name'], row['cui'] + c.execute("INSERT OR IGNORE INTO drugs VALUES(?,?)", (nm, cui)) + meta = doublemetaphone(nm)[0] + c.execute("INSERT INTO metaphone VALUES(?,?,?)", (meta, nm, cui)) + conn.commit() + conn.close() + +if __name__ == "__main__": + build_db(DB_PATH, RXNORM_CSV) + print(f"✅ RxNorm DB built at {DB_PATH}") diff --git a/scripts/create_dummy_signature_model.py b/scripts/create_dummy_signature_model.py new file mode 100644 index 0000000000000000000000000000000000000000..06c4305c42693f9e5625dd44401a4461a2b25694 --- /dev/null +++ b/scripts/create_dummy_signature_model.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +import os +import tensorflow as tf +from tensorflow.keras.layers import Input, Flatten, Dense, Subtract +from tensorflow.keras.models import Model +import sys +sys.path.append(os.getcwd()) +from config import SIA_MODEL_PATH + +def build_dummy_siamese(): + inp_a = Input(shape=(224, 224, 1), name="img_a") + inp_b = Input(shape=(224, 224, 1), name="img_b") + encoder_input = Input(shape=(224, 224, 1)) + x = Flatten()(encoder_input) + x = Dense(16, activation="relu")(x) + encoder = Model(encoder_input, x) + encoded_a = encoder(inp_a) + encoded_b = encoder(inp_b) + distance = Subtract()([encoded_a, encoded_b]) + model = Model(inputs=[inp_a, inp_b], outputs=distance) + return model + +if __name__ == "__main__": + print("Building and converting dummy Siamese model...") + model = build_dummy_siamese() + converter = tf.lite.TFLiteConverter.from_keras_model(model) + converter.optimizations = [tf.lite.Optimize.DEFAULT] + tflite_model = converter.convert() + os.makedirs(os.path.dirname(SIA_MODEL_PATH), exist_ok=True) + with open(SIA_MODEL_PATH, "wb") as f: + f.write(tflite_model) + print(f"✅ Dummy TFLite signature model saved to '{SIA_MODEL_PATH}'") diff --git a/signature_verification/__pycache__/signature_detector.cpython-310.pyc b/signature_verification/__pycache__/signature_detector.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..748c4c72e8cc998ca1165e3b5435b2a64365acbe Binary files /dev/null and b/signature_verification/__pycache__/signature_detector.cpython-310.pyc differ diff --git a/signature_verification/__pycache__/signature_generator.cpython-310.pyc b/signature_verification/__pycache__/signature_generator.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fe60963b121626f9e55b0db8a21eb62eb57585a Binary files /dev/null and b/signature_verification/__pycache__/signature_generator.cpython-310.pyc differ diff --git a/signature_verification/__pycache__/signature_siamese.cpython-310.pyc b/signature_verification/__pycache__/signature_siamese.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3930e68ce53f1aebf91c7c6d91a13825230b135e Binary files /dev/null and b/signature_verification/__pycache__/signature_siamese.cpython-310.pyc differ diff --git a/signature_verification/signature_detector.py b/signature_verification/signature_detector.py new file mode 100644 index 0000000000000000000000000000000000000000..7a70ee57de4f18d2e8087344cd359432d920176f --- /dev/null +++ b/signature_verification/signature_detector.py @@ -0,0 +1,40 @@ +# signature_verification/signature_detector.py +import cv2 +import numpy as np + +class SignatureDetector: + """ + Detects and crops a signature from a prescription image using refined OpenCV contour analysis. + This method is fast, offline, and does not require a pre-trained model. + """ + def crop(self, img: np.ndarray) -> np.ndarray | None: + if img is None: return None + + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + blurred = cv2.GaussianBlur(gray, (5, 5), 0) + _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) + + contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + if not contours: return None + + height, width = img.shape[:2] + significant_contours = [] + for cnt in contours: + x, y, w, h = cv2.boundingRect(cnt) + # Filter for contours that are reasonably large and in the bottom 70% of the page + if w > 50 and h > 15 and y > height * 0.3: + if w < width * 0.8 and h < height * 0.4: + significant_contours.append(cnt) + + if not significant_contours: return None + + largest_contour = max(significant_contours, key=cv2.contourArea) + x, y, w, h = cv2.boundingRect(largest_contour) + + padding = 15 + x1 = max(0, x - padding) + y1 = max(0, y - padding) + x2 = min(width, x + w + padding) + y2 = min(height, y + h + padding) + + return img[y1:y2, x1:x2] diff --git a/signature_verification/signature_generator.py b/signature_verification/signature_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..1fa10070cec7fe3df3f9ed3aed2e71034d65ee84 --- /dev/null +++ b/signature_verification/signature_generator.py @@ -0,0 +1,50 @@ +import os +import logging +import numpy as np +import cv2 +from dotenv import load_dotenv +from huggingface_hub import InferenceClient, HfFolder +from PIL import Image + +load_dotenv() + +# Acquire token +hf_token = os.getenv("HUGGING_FACE_HUB_TOKEN") or HfFolder.get_token() +if not hf_token: + print("❌ No Hugging Face token found. Signature generation will fail.") + CLIENT = None +else: + print("✅ Using Hugging Face token for signature generation.") + CLIENT = InferenceClient(token=hf_token) + +MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0" + +def generate_signatures(name: str, num_variations: int = 3) -> list: + """Generates multiple signature variations for a given name.""" + if CLIENT is None: + return [] + + prompts = [ + f"A clean, elegant, handwritten signature of the name '{name}' on a plain white background. Cursive, professional.", + f"Calligraphy signature of '{name}'. Black ink on white paper. Minimalist, artistic.", + f"A doctor's signature for '{name}'. Quick, scribbled, but legible. Official-looking script." + ] + images = [] + for i in range(num_variations): + prompt = prompts[i % len(prompts)] + logging.info(f"Generating signature variation {i+1} for '{name}'…") + try: + pil_img = CLIENT.text_to_image( + prompt, + model=MODEL_ID, + negative_prompt=( + "photograph, text, multiple signatures, watermark, blurry, colorful, background" + ), + guidance_scale=8.0 + ) + np_img = np.array(pil_img) + cv_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR) + images.append(cv_img) + except Exception as e: + logging.error(f"❌ Signature generation failed: {e}") + return images diff --git a/signature_verification/signature_siamese.py b/signature_verification/signature_siamese.py new file mode 100644 index 0000000000000000000000000000000000000000..bcc4ec564b895113d4ac65555f1e9b84e52bbe09 --- /dev/null +++ b/signature_verification/signature_siamese.py @@ -0,0 +1,34 @@ +# signature_verification/signature_siamese.py +import cv2 +import numpy as np +import tensorflow as tf +from config import SIA_MODEL_PATH, SIG_THRESH + +class SignatureSiamese: + def __init__(self, model_path: str = SIA_MODEL_PATH): + try: + self.interp = tf.lite.Interpreter(model_path=model_path) + self.interp.allocate_tensors() + ids = self.interp.get_input_details() + self.in1, self.in2 = ids[0]['index'], ids[1]['index'] + self.out_idx = self.interp.get_output_details()[0]['index'] + print(f"✅ Loaded TFLite Siamese model from {model_path}") + except Exception as e: + self.interp = None + print(f"❌ Failed to load Siamese model from {model_path}: {e}") + + def _prep(self, img: np.ndarray) -> np.ndarray: + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if img.ndim == 3 else img + r = cv2.resize(gray, (224, 224)) + return r.reshape(1, 224, 224, 1).astype(np.float32) / 255.0 + + def verify(self, img1: np.ndarray, img2: np.ndarray) -> tuple[bool, float]: + if not self.interp: + return False, float('inf') + inp1, inp2 = self._prep(img1), self._prep(img2) + self.interp.set_tensor(self.in1, inp1) + self.interp.set_tensor(self.in2, inp2) + self.interp.invoke() + diff = self.interp.get_tensor(self.out_idx) + dist = np.linalg.norm(diff) + return dist < SIG_THRESH, dist diff --git a/src/App.svelte b/src/App.svelte deleted file mode 100644 index f75b68aa25d9c715d2c7fa808b24516bf89e0f11..0000000000000000000000000000000000000000 --- a/src/App.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - -
-
- - - - - - -
-

Vite + Svelte

- -
- -
- -

- Check out SvelteKit, the official Svelte app framework powered by Vite! -

- -

- Click on the Vite and Svelte logos to learn more -

-
- - diff --git a/src/app.css b/src/app.css deleted file mode 100644 index 61ba367832ad77dd81568fe7b66af119713fb56f..0000000000000000000000000000000000000000 --- a/src/app.css +++ /dev/null @@ -1,79 +0,0 @@ -:root { - font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -.card { - padding: 2em; -} - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/src/assets/svelte.svg b/src/assets/svelte.svg deleted file mode 100644 index c5e08481f8aede5a6cc897b0f034e806a8617d7d..0000000000000000000000000000000000000000 --- a/src/assets/svelte.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/lib/Counter.svelte b/src/lib/Counter.svelte deleted file mode 100644 index 37d75ce76f59c812d02ac54c15ce89c94ea7a08a..0000000000000000000000000000000000000000 --- a/src/lib/Counter.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/main.ts b/src/main.ts deleted file mode 100644 index 664a057afa0f4922490083dffada64a6a626bedf..0000000000000000000000000000000000000000 --- a/src/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { mount } from 'svelte' -import './app.css' -import App from './App.svelte' - -const app = mount(App, { - target: document.getElementById('app')!, -}) - -export default app diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a2eaf5705d327b5c9d459c234c01652..0000000000000000000000000000000000000000 --- a/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/static/signatures/fake-autograph-samples-hand-drawn-signatures-examples-of-documents-certificates-and-contracts-with-inked-and-handwritten-lettering-vector.jpg b/static/signatures/fake-autograph-samples-hand-drawn-signatures-examples-of-documents-certificates-and-contracts-with-inked-and-handwritten-lettering-vector.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7db263eda470bfb047d9aac99c8f0b6edb8c29a7 --- /dev/null +++ b/static/signatures/fake-autograph-samples-hand-drawn-signatures-examples-of-documents-certificates-and-contracts-with-inked-and-handwritten-lettering-vector.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d217d350b539ed4e78828029a6f1429de17870099ec2967cb8d6b4de09fb2b06 +size 37920 diff --git a/static/signatures/fake-signature-hand-drawn-sample-own-autograph-fictitious-handwritten-signature-black-ink-scribble-for-sample-contracts-documents-certificates-or-letters-vector-illustration-2WKNPM2.jpg b/static/signatures/fake-signature-hand-drawn-sample-own-autograph-fictitious-handwritten-signature-black-ink-scribble-for-sample-contracts-documents-certificates-or-letters-vector-illustration-2WKNPM2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a7a6a78f56352d11186c6f58c5608a003de08df7 --- /dev/null +++ b/static/signatures/fake-signature-hand-drawn-sample-own-autograph-fictitious-handwritten-signature-black-ink-scribble-for-sample-contracts-documents-certificates-or-letters-vector-illustration-2WKNPM2.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3da3c5c4945b53da41e861075a1edb8e5ac09d81492b5d1dfd47bfdfa602cc5 +size 41028 diff --git a/static/signatures/images.png b/static/signatures/images.png new file mode 100644 index 0000000000000000000000000000000000000000..94299443fcd2176eacd0d699ebe474a00bcae1c6 Binary files /dev/null and b/static/signatures/images.png differ diff --git a/static/signatures/signature-certificate-document-vector-transparent-260nw-2346804443.jpg b/static/signatures/signature-certificate-document-vector-transparent-260nw-2346804443.jpg new file mode 100644 index 0000000000000000000000000000000000000000..17d97a94d874dfbe1ba945d8545f8354f3983298 --- /dev/null +++ b/static/signatures/signature-certificate-document-vector-transparent-260nw-2346804443.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa8ab4ae59c11267822413d07b2a928838c0dea998eabeafdf4facb801dc6c6c +size 8726 diff --git a/static/signatures/signature-vector-hand-drawn-autograph-600nw-2387543207.jpg b/static/signatures/signature-vector-hand-drawn-autograph-600nw-2387543207.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e91e60ee4d01f58f8048bc27fedd7bd8d4c21838 --- /dev/null +++ b/static/signatures/signature-vector-hand-drawn-autograph-600nw-2387543207.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:652082d4a12b0e42583d9fea62032a20eb23dd181d24b7bb60495db85ca31d11 +size 11798 diff --git a/static/uploads/02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg b/static/uploads/02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7f9e8ba16e47cb7e6eb42687b93ec9063a91ec0 --- /dev/null +++ b/static/uploads/02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ce954d7cef59dd695b6b825b8b6268ef12b3898bfd431a422a58979ed6b7e9c +size 2094925 diff --git a/static/uploads/0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg b/static/uploads/0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/1*3xUyINxRtDf2qowd-kkGQA.jpg b/static/uploads/1*3xUyINxRtDf2qowd-kkGQA.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3e9129234398929e8e477f19f413b8357a1e222 --- /dev/null +++ b/static/uploads/1*3xUyINxRtDf2qowd-kkGQA.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:097786a9aded24b704b0997eb19c44bc6a2fc2033bd3a7b05099740cd85be33e +size 175243 diff --git a/static/uploads/255d2936a26d49429c21ce6b06b323b7_vio-4.jpg b/static/uploads/255d2936a26d49429c21ce6b06b323b7_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/255d2936a26d49429c21ce6b06b323b7_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg b/static/uploads/2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/2e2897cdee404769b262c27e8843c39f_vio-4.jpg b/static/uploads/2e2897cdee404769b262c27e8843c39f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/2e2897cdee404769b262c27e8843c39f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg b/static/uploads/2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7f9e8ba16e47cb7e6eb42687b93ec9063a91ec0 --- /dev/null +++ b/static/uploads/2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ce954d7cef59dd695b6b825b8b6268ef12b3898bfd431a422a58979ed6b7e9c +size 2094925 diff --git a/static/uploads/2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg b/static/uploads/2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/3c5fc28d921c489b8386e3941f85201f_vio-4.jpg b/static/uploads/3c5fc28d921c489b8386e3941f85201f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/3c5fc28d921c489b8386e3941f85201f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg b/static/uploads/46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/47a4d74c885c432db75d3ead91e0f239_vio-4.jpg b/static/uploads/47a4d74c885c432db75d3ead91e0f239_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/47a4d74c885c432db75d3ead91e0f239_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg b/static/uploads/55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/5615a569449a43d7854f3c67759247f9_vio-4.jpg b/static/uploads/5615a569449a43d7854f3c67759247f9_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/5615a569449a43d7854f3c67759247f9_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg b/static/uploads/5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg b/static/uploads/62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/6c4cd60326644b07949ead88f2df028f_vio-4.jpg b/static/uploads/6c4cd60326644b07949ead88f2df028f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/6c4cd60326644b07949ead88f2df028f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/70d1a83f05884053b72277464154bb21_vio-4.jpg b/static/uploads/70d1a83f05884053b72277464154bb21_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/70d1a83f05884053b72277464154bb21_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/71288979fef74133b52088142c75c0dd_vio-4.jpg b/static/uploads/71288979fef74133b52088142c75c0dd_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/71288979fef74133b52088142c75c0dd_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg b/static/uploads/8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/85493db5c5e84914b74a8975924db58f_vio-4.jpg b/static/uploads/85493db5c5e84914b74a8975924db58f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/85493db5c5e84914b74a8975924db58f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/89d8ce08fd1a4198ab796f21dca7f886_vio-4.jpg b/static/uploads/89d8ce08fd1a4198ab796f21dca7f886_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/89d8ce08fd1a4198ab796f21dca7f886_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg b/static/uploads/8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg b/static/uploads/93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3e9129234398929e8e477f19f413b8357a1e222 --- /dev/null +++ b/static/uploads/93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:097786a9aded24b704b0997eb19c44bc6a2fc2033bd3a7b05099740cd85be33e +size 175243 diff --git a/static/uploads/IMG_0082.jpg b/static/uploads/IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c7f9e8ba16e47cb7e6eb42687b93ec9063a91ec0 --- /dev/null +++ b/static/uploads/IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ce954d7cef59dd695b6b825b8b6268ef12b3898bfd431a422a58979ed6b7e9c +size 2094925 diff --git a/static/uploads/ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg b/static/uploads/ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg b/static/uploads/ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/ae8668d6ecd944c2bc8d2c709d52d384_vio-4.jpg b/static/uploads/ae8668d6ecd944c2bc8d2c709d52d384_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/ae8668d6ecd944c2bc8d2c709d52d384_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg b/static/uploads/b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg b/static/uploads/b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg b/static/uploads/bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/c210cb3dde814e08959e166093a3d01f_vio-4.jpg b/static/uploads/c210cb3dde814e08959e166093a3d01f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/c210cb3dde814e08959e166093a3d01f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg b/static/uploads/c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/dcd130973735495d8b02e9a825c45247_vio-4.jpg b/static/uploads/dcd130973735495d8b02e9a825c45247_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/dcd130973735495d8b02e9a825c45247_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg b/static/uploads/ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg b/static/uploads/f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/static/uploads/gen_sig_0_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg b/static/uploads/gen_sig_0_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba364f4045f51f7b214ed4087fdae96dae9ccec3 --- /dev/null +++ b/static/uploads/gen_sig_0_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69a1a408dda96151de66418e8a5b7ef41e9b56e6617a2e29f3bf09ffc2442e4f +size 30960 diff --git a/static/uploads/gen_sig_0_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg b/static/uploads/gen_sig_0_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..967539a8f812ccb2c4844f2d97729aa71fce45cc --- /dev/null +++ b/static/uploads/gen_sig_0_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f63e82cccc08bd29b713020aeaafa62ee5d5e9a714b57643bb8e90d77a7f93e7 +size 29921 diff --git a/static/uploads/gen_sig_0_71288979fef74133b52088142c75c0dd_vio-4.jpg b/static/uploads/gen_sig_0_71288979fef74133b52088142c75c0dd_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e922b4beb118899c96b3fffb7694cdcb68c08ca1 --- /dev/null +++ b/static/uploads/gen_sig_0_71288979fef74133b52088142c75c0dd_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec1da58416ea805cf606a5a36a080262df8a2e6b4f313046572008dcc3b5c3d1 +size 34212 diff --git a/static/uploads/gen_sig_0_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg b/static/uploads/gen_sig_0_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..23cf8b02a8daf4e76b2583b4634bf107f57b9c58 --- /dev/null +++ b/static/uploads/gen_sig_0_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cfa83580c34201d9145944bc27e132ad888081c312243bfebc4288d93173cf5 +size 42729 diff --git a/static/uploads/gen_sig_0_IMG_0082.jpg b/static/uploads/gen_sig_0_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff4b726f6c1031b8f6948449f90ba7cbb2268a75 --- /dev/null +++ b/static/uploads/gen_sig_0_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9cdd32b8ad4ed5da1054aa90ca8e41a41cc2c38f1603460785c2fe8bde340ad +size 62704 diff --git a/static/uploads/gen_sig_0_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg b/static/uploads/gen_sig_0_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d6ba02fe20d5c4e64d7902fb6d1985324f8a3bcb --- /dev/null +++ b/static/uploads/gen_sig_0_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2292cb32b0dea1d169da86400dd907304a438de75ecd25f8ad8ab2c86fe08a94 +size 58000 diff --git a/static/uploads/gen_sig_0_c210cb3dde814e08959e166093a3d01f_vio-4.jpg b/static/uploads/gen_sig_0_c210cb3dde814e08959e166093a3d01f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..908f7c0c8b6e566320b2d38153ddf052330b858f --- /dev/null +++ b/static/uploads/gen_sig_0_c210cb3dde814e08959e166093a3d01f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6568cc8ea49f7449206c82590c391232d3aad6474876ebe545d4b266941d174d +size 30159 diff --git a/static/uploads/gen_sig_0_dcd130973735495d8b02e9a825c45247_vio-4.jpg b/static/uploads/gen_sig_0_dcd130973735495d8b02e9a825c45247_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..22ed3cf9b3641433cc3554a27b2de90edb7e2b7f --- /dev/null +++ b/static/uploads/gen_sig_0_dcd130973735495d8b02e9a825c45247_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:110a9446317a347dc5e90da2c984b18e2d73eb9eb0ca4b6da63073247a67eeff +size 25637 diff --git a/static/uploads/gen_sig_0_vio-4.jpg b/static/uploads/gen_sig_0_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bdb9c69a01403b535ec2668f1c1f5fcb4abe15ce --- /dev/null +++ b/static/uploads/gen_sig_0_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:540681e8abfb34b66d167065e0bb949595337f19599197f4e9881710745a28a1 +size 31646 diff --git a/static/uploads/gen_sig_1_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg b/static/uploads/gen_sig_1_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1eeafbc06b462ff6e1f2aa970c12f2c256da7c89 --- /dev/null +++ b/static/uploads/gen_sig_1_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a2c103c958ea9221d2e8179eb7e908553bd6d9e7b65e1dac27585e3acef386ea +size 65195 diff --git a/static/uploads/gen_sig_1_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg b/static/uploads/gen_sig_1_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..938d31dc89cc9bd8a4ae10b1f0c6d4d1b4a3826f --- /dev/null +++ b/static/uploads/gen_sig_1_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a73413d5e14dffb2ec90a7fb7a48a7ca1bf4a442814d4c2d52f8611bb534a08c +size 53739 diff --git a/static/uploads/gen_sig_1_71288979fef74133b52088142c75c0dd_vio-4.jpg b/static/uploads/gen_sig_1_71288979fef74133b52088142c75c0dd_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ba4be149be06181eb47f8f96a169bc610ba660f8 --- /dev/null +++ b/static/uploads/gen_sig_1_71288979fef74133b52088142c75c0dd_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3c254ef2a40114ed5f172385dfae6ca353968d0b40f5fb393207a16dae2d705 +size 52536 diff --git a/static/uploads/gen_sig_1_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg b/static/uploads/gen_sig_1_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d56805b785f23300b0133eb0c61cd5d33657ef71 --- /dev/null +++ b/static/uploads/gen_sig_1_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d24c51fd63a5060fbc2272b5d01265cb8c2679f93c656093b95f977b6ac20b1b +size 63599 diff --git a/static/uploads/gen_sig_1_IMG_0082.jpg b/static/uploads/gen_sig_1_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dc420961cf5d91d90800f4d24cadefeb2c7b37da --- /dev/null +++ b/static/uploads/gen_sig_1_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1b015e37dfdce12269e638043959452b48ec774907d47a4b0dfe6664e022781 +size 74659 diff --git a/static/uploads/gen_sig_1_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg b/static/uploads/gen_sig_1_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..589e66916b21cbd4265d0b6cc490e958f032eeeb --- /dev/null +++ b/static/uploads/gen_sig_1_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:129a916d78f87605c9064c39923deb94fd1470078ce2af04d8f4c9bc07dbd20c +size 63031 diff --git a/static/uploads/gen_sig_1_c210cb3dde814e08959e166093a3d01f_vio-4.jpg b/static/uploads/gen_sig_1_c210cb3dde814e08959e166093a3d01f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e1b3f8fcd94ff188a3a3cc8542f98c4257bf7f6 --- /dev/null +++ b/static/uploads/gen_sig_1_c210cb3dde814e08959e166093a3d01f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:122e784c5cb93090e16022296ea569bc9ee11598710d854c810064cc701647a2 +size 66433 diff --git a/static/uploads/gen_sig_1_dcd130973735495d8b02e9a825c45247_vio-4.jpg b/static/uploads/gen_sig_1_dcd130973735495d8b02e9a825c45247_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..77533b4c7d99d4bfb9e4e6d496d801f038b05757 --- /dev/null +++ b/static/uploads/gen_sig_1_dcd130973735495d8b02e9a825c45247_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e62a7594b951a876dc96d7de012cd9876e2e8c69af5a5a8fbd648f40ff8ce86 +size 64430 diff --git a/static/uploads/gen_sig_1_vio-4.jpg b/static/uploads/gen_sig_1_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ea8ab84f4be5d676a5ccbc231e14e80b274b9dc --- /dev/null +++ b/static/uploads/gen_sig_1_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5c470d4f051e3cff6735da573a0162e97e9c81f6985eb0c4248c60a32e5a2ab +size 62047 diff --git a/static/uploads/gen_sig_2_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg b/static/uploads/gen_sig_2_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e994a0326a56caf2c1062b56e7990c772427c0ed --- /dev/null +++ b/static/uploads/gen_sig_2_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d09ef084ad22f5be59af50d320fba3811eb993f6de2af39030670da5c24eab10 +size 49946 diff --git a/static/uploads/gen_sig_2_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg b/static/uploads/gen_sig_2_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cff1e32930663096a04173759b6dd9c05d91a916 --- /dev/null +++ b/static/uploads/gen_sig_2_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a85971e066db7fe7c22e74b8775b9703aa0ac92c5b1dc07725fa4a2fccf5858 +size 58229 diff --git a/static/uploads/gen_sig_2_71288979fef74133b52088142c75c0dd_vio-4.jpg b/static/uploads/gen_sig_2_71288979fef74133b52088142c75c0dd_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..459d5326e7d7331b84c42e2677deabd0677bfd20 --- /dev/null +++ b/static/uploads/gen_sig_2_71288979fef74133b52088142c75c0dd_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e17fcb5e87115bd664528a43da4ecba7f99a0d7983f51f58ac3638eb7ca3eee6 +size 65129 diff --git a/static/uploads/gen_sig_2_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg b/static/uploads/gen_sig_2_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c576c8d458c005487edd0022e0ff92891b7af7d --- /dev/null +++ b/static/uploads/gen_sig_2_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:217c954053acb66fa71afef37a67601d9b7f5058e01ff80ca8dcc3197f24e630 +size 69264 diff --git a/static/uploads/gen_sig_2_IMG_0082.jpg b/static/uploads/gen_sig_2_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..556a43c5536152e00615d208b8aaf208c3fc56bb --- /dev/null +++ b/static/uploads/gen_sig_2_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4ffe53ecd2b42d6db6e2fdd409b6042730f0a2670dfd748262e75268e744dd12 +size 71202 diff --git a/static/uploads/gen_sig_2_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg b/static/uploads/gen_sig_2_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..08a24553a85ef31b55c7329120c456e26182308e --- /dev/null +++ b/static/uploads/gen_sig_2_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b59c65d56338d812244eb952073d9c4a13f41168dc4118fec864af21bc21075 +size 54590 diff --git a/static/uploads/gen_sig_2_c210cb3dde814e08959e166093a3d01f_vio-4.jpg b/static/uploads/gen_sig_2_c210cb3dde814e08959e166093a3d01f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eae13b69b909a0f772e0dff777b8922f0e8a45c4 --- /dev/null +++ b/static/uploads/gen_sig_2_c210cb3dde814e08959e166093a3d01f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a9777551ed89898928abf0ef15694347241c1aa9729c26d8d7f0616f512f9621 +size 73228 diff --git a/static/uploads/gen_sig_2_dcd130973735495d8b02e9a825c45247_vio-4.jpg b/static/uploads/gen_sig_2_dcd130973735495d8b02e9a825c45247_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..46531b43e760ac0bab7c481b39e67bb83a827d6d --- /dev/null +++ b/static/uploads/gen_sig_2_dcd130973735495d8b02e9a825c45247_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e870a6116e7744055d2f215e03ea22978dd20df043138d446125a7b8fd0299ed +size 54656 diff --git a/static/uploads/gen_sig_2_vio-4.jpg b/static/uploads/gen_sig_2_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7f07ab2cf01dc7c5181b0027af6d28d65fab02d --- /dev/null +++ b/static/uploads/gen_sig_2_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:40bee24ea5e5865ed0b531ed5852bc7f8d08929ff7f37861167be12bced4b406 +size 68377 diff --git a/static/uploads/sig_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg b/static/uploads/sig_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a6f9011b9139bca9327f157060e5fde87aea5b0 --- /dev/null +++ b/static/uploads/sig_02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd896b523005acbef97faa3c989079093142c9a89fae2b312e82c2109063d25d +size 19016 diff --git a/static/uploads/sig_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg b/static/uploads/sig_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_1*3xUyINxRtDf2qowd-kkGQA.jpg b/static/uploads/sig_1*3xUyINxRtDf2qowd-kkGQA.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72bac6c5b168d8cc18c0859b36ea083e8f983a07 --- /dev/null +++ b/static/uploads/sig_1*3xUyINxRtDf2qowd-kkGQA.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:403b26f1fec526f07ed0ac5810f164ba8e1cfd948883fb42e0a0bad3ba784c40 +size 8264 diff --git a/static/uploads/sig_255d2936a26d49429c21ce6b06b323b7_vio-4.jpg b/static/uploads/sig_255d2936a26d49429c21ce6b06b323b7_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_255d2936a26d49429c21ce6b06b323b7_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg b/static/uploads/sig_2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_2e2897cdee404769b262c27e8843c39f_vio-4.jpg b/static/uploads/sig_2e2897cdee404769b262c27e8843c39f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_2e2897cdee404769b262c27e8843c39f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg b/static/uploads/sig_2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a6f9011b9139bca9327f157060e5fde87aea5b0 --- /dev/null +++ b/static/uploads/sig_2e2b1b75c5b84dfba44c64f21e63178b_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd896b523005acbef97faa3c989079093142c9a89fae2b312e82c2109063d25d +size 19016 diff --git a/static/uploads/sig_2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg b/static/uploads/sig_2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_2f8270f4df0d49489bf09f591c52d5bf_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_3c5fc28d921c489b8386e3941f85201f_vio-4.jpg.jpg b/static/uploads/sig_3c5fc28d921c489b8386e3941f85201f_vio-4.jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_3c5fc28d921c489b8386e3941f85201f_vio-4.jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg b/static/uploads/sig_46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_46f73aea013c4f26bbfaae83141c2f1c_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_47a4d74c885c432db75d3ead91e0f239_vio-4.jpg.jpg b/static/uploads/sig_47a4d74c885c432db75d3ead91e0f239_vio-4.jpg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_47a4d74c885c432db75d3ead91e0f239_vio-4.jpg.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg b/static/uploads/sig_55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_55cf887068364f07b4a9caf5d5fbe773_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_5615a569449a43d7854f3c67759247f9_vio-4.jpg b/static/uploads/sig_5615a569449a43d7854f3c67759247f9_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_5615a569449a43d7854f3c67759247f9_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg b/static/uploads/sig_5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_5d6ce884ec9148dab58abe1c867cf389_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg b/static/uploads/sig_62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_62456c3ff3c74d01a6b2485dc303aea6_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_6c4cd60326644b07949ead88f2df028f_vio-4.jpg b/static/uploads/sig_6c4cd60326644b07949ead88f2df028f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_6c4cd60326644b07949ead88f2df028f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_70d1a83f05884053b72277464154bb21_vio-4.jpg b/static/uploads/sig_70d1a83f05884053b72277464154bb21_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_70d1a83f05884053b72277464154bb21_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_71288979fef74133b52088142c75c0dd_vio-4.jpg b/static/uploads/sig_71288979fef74133b52088142c75c0dd_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_71288979fef74133b52088142c75c0dd_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg b/static/uploads/sig_8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_8422c56497134d69a8f4d561c6bedb6d_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_85493db5c5e84914b74a8975924db58f_vio-4.jpg b/static/uploads/sig_85493db5c5e84914b74a8975924db58f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_85493db5c5e84914b74a8975924db58f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg b/static/uploads/sig_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_8e69feeefafb4826a10919c9c0ff51e8_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg b/static/uploads/sig_93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg new file mode 100644 index 0000000000000000000000000000000000000000..72bac6c5b168d8cc18c0859b36ea083e8f983a07 --- /dev/null +++ b/static/uploads/sig_93dbd0501c8542a99ebffa6842a8dac3_1*3xUyINxRtDf2qowd-kkGQA.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:403b26f1fec526f07ed0ac5810f164ba8e1cfd948883fb42e0a0bad3ba784c40 +size 8264 diff --git a/static/uploads/sig_IMG_0082.jpg b/static/uploads/sig_IMG_0082.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a6f9011b9139bca9327f157060e5fde87aea5b0 --- /dev/null +++ b/static/uploads/sig_IMG_0082.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd896b523005acbef97faa3c989079093142c9a89fae2b312e82c2109063d25d +size 19016 diff --git a/static/uploads/sig_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg b/static/uploads/sig_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_ac1c14b69a4a4dc28ad28e9dcf3eb599_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg b/static/uploads/sig_ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_ae3bf6ecf5534779a60521efd4f28336_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg b/static/uploads/sig_b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_b1b2d10448fa4c8bb9bb6cf8ba2e853c_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg b/static/uploads/sig_b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_b8d9eb48bc854dad8fb665216baa329d_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg b/static/uploads/sig_bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_bbfb0dfc9f7d4fcaa892d4a8faad9c42_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_c210cb3dde814e08959e166093a3d01f_vio-4.jpg b/static/uploads/sig_c210cb3dde814e08959e166093a3d01f_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_c210cb3dde814e08959e166093a3d01f_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg b/static/uploads/sig_c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_c26bfc3e700844c6b1a532cb42f072ef_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_dcd130973735495d8b02e9a825c45247_vio-4.jpg b/static/uploads/sig_dcd130973735495d8b02e9a825c45247_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_dcd130973735495d8b02e9a825c45247_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg b/static/uploads/sig_ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_ec04525d639c4b49b07d99884ad1dcde_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg b/static/uploads/sig_f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_f5630e41ddad473287a8a7aed6cd7981_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/sig_vio-4.jpg b/static/uploads/sig_vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25fdb412c06f50a0726a4995692b8f11adc7c542 --- /dev/null +++ b/static/uploads/sig_vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93994163fa2ad4a9c3faaab651c602e3e7c76bb956cc8e10d4531c185f022df +size 18478 diff --git a/static/uploads/vio-4.jpg b/static/uploads/vio-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..706c304a7a7fb7abbd552f6dc451750dd753addc --- /dev/null +++ b/static/uploads/vio-4.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4 +size 50607 diff --git a/svelte.config.js b/svelte.config.js deleted file mode 100644 index b0683fd24d70abb7eeaeef8e39e3a12b4e74775a..0000000000000000000000000000000000000000 --- a/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/tsconfig.app.json b/tsconfig.app.json deleted file mode 100644 index 55a2f9b6548ebf5b6d8fbe87c2cd9fdf8c2492a9..0000000000000000000000000000000000000000 --- a/tsconfig.app.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "isolatedModules": true, - "moduleDetection": "force" - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"] -} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 1ffef600d959ec9e396d5a260bd3f5b927b2cef8..0000000000000000000000000000000000000000 --- a/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 9728af2d81af0efc7985ffc705287be4bad10ba4..0000000000000000000000000000000000000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2022", - "lib": ["ES2023"], - "module": "ESNext", - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/validate_prescription.py b/validate_prescription.py new file mode 100644 index 0000000000000000000000000000000000000000..7de38a2f4ecaf4dc6005a8b46c2d40c562aebfb4 --- /dev/null +++ b/validate_prescription.py @@ -0,0 +1,336 @@ +import os +import re +import json +import logging +import time +import numpy as np +import tempfile +import sqlite3 +import torch +import io +from typing import Dict, Any, List, Optional +from PIL import Image +from dotenv import load_dotenv +from googleapiclient.discovery import build + +# Suppress verbose backend logs +os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" +load_dotenv() + +try: + from transformers import pipeline, DonutProcessor, VisionEncoderDecoderModel, AutoTokenizer + from huggingface_hub import login + import google.generativeai as genai +except ImportError as e: + logging.error(f"Failed to import critical AI libraries: {e}") + raise + +from config import ( + DB_PATH, + HF_TOKEN, + HF_MODELS, + GOOGLE_API_KEY, + GOOGLE_APPLICATION_CREDENTIALS, + GEMINI_MODEL_NAME, + DEVICE, + USE_GPU, + GOOGLE_CSE_ID, +) + +# ─── Configure Logging & Auth ──────────────────────────────────────────────── +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") +if HF_TOKEN: + login(token=HF_TOKEN) + +# ─── Singleton Holders for AI Models ───────────────────────────────────────── +_MODELS = {} +_TEMP_CRED_FILE = None + +class GoogleSearch: + """Performs Google Custom Search API queries.""" + def __init__(self): + self.api_key = GOOGLE_API_KEY + self.cse_id = GOOGLE_CSE_ID + self.service = None + if self.api_key and self.cse_id: + try: + self.service = build("customsearch", "v1", developerKey=self.api_key) + logging.info("Google Custom Search initialized.") + except Exception as e: + logging.error(f"CSE init failed: {e}") + else: + logging.warning("GOOGLE_API_KEY or GOOGLE_CSE_ID not set; search disabled.") + + def search(self, queries: list, num_results: int = 1) -> list: + if not self.service: + return [] + out = [] + for q in queries: + try: + resp = self.service.cse().list(q=q, cx=self.cse_id, num=num_results).execute() + items = resp.get("items", []) + formatted = [ + {"title": it.get("title"), "link": it.get("link"), "snippet": it.get("snippet")} + for it in items + ] + out.append({"query": q, "results": formatted}) + except Exception as e: + logging.error(f"Search error for '{q}': {e}") + out.append({"query": q, "results": []}) + return out + +# Initialize Google Search globally +google_search = GoogleSearch() + +def get_model(name: str): + """Loads and caches AI models to avoid reloading.""" + if name not in _MODELS: + model_id = HF_MODELS.get(name) + if not model_id: + return None + + logging.info(f"Loading model '{name}' ({model_id}) to device '{DEVICE}'...") + try: + quantization_config = {"load_in_8bit": True} if USE_GPU else {} + if name == "donut": + processor = DonutProcessor.from_pretrained(model_id) + model = VisionEncoderDecoderModel.from_pretrained(model_id, **quantization_config) + _MODELS[name] = {"model": model, "processor": processor} + elif name == "phi3": + model = pipeline( + "text-generation", + model=model_id, + torch_dtype=torch.bfloat16, + trust_remote_code=True, + **quantization_config + ) + _MODELS[name] = {"model": model} + logging.info(f"Model '{name}' loaded successfully.") + except Exception as e: + logging.error(f"Failed to load model '{name}': {e}", exc_info=True) + _MODELS[name] = None + + return _MODELS.get(name) + +def get_gemini_client(): + """Initializes and returns the Gemini client.""" + global _TEMP_CRED_FILE + + if "gemini" not in _MODELS: + # Write out credentials file if needed + if creds_json_str := GOOGLE_APPLICATION_CREDENTIALS: + if not _TEMP_CRED_FILE or not os.path.exists(_TEMP_CRED_FILE): + with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as tfp: + tfp.write(creds_json_str) + _TEMP_CRED_FILE = tfp.name + os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = _TEMP_CRED_FILE + + try: + genai.configure(api_key=GOOGLE_API_KEY) + _MODELS["gemini"] = genai.GenerativeModel(GEMINI_MODEL_NAME) + except Exception as e: + logging.error(f"Gemini init failed: {e}") + _MODELS["gemini"] = None + + return _MODELS.get("gemini") + +def verify_medication_with_google(medication_name: str) -> Dict[str, Any]: + """Verifies medication details using Google Search API.""" + if not medication_name: + return {"error": "No medication name provided"} + + queries = [ + f"standard dosage for {medication_name}", + f"side effects of {medication_name}", + f"drug interactions with {medication_name}" + ] + + search_results = google_search.search(queries, num_results=2) + return { + "medication": medication_name, + "verification_results": search_results + } + +def step1_run_donut(image: Image.Image) -> Dict[str, Any]: + donut_components = get_model("donut") + if not donut_components: + return {"error": "Donut model not available."} + + model = donut_components["model"].to(DEVICE) + processor = donut_components["processor"] + + task_prompt = "" + decoder_input_ids = processor.tokenizer( + task_prompt, add_special_tokens=False, return_tensors="pt" + ).input_ids.to(DEVICE) + pixel_values = processor(image, return_tensors="pt").pixel_values.to(DEVICE) + + outputs = model.generate( + pixel_values, + decoder_input_ids=decoder_input_ids, + max_length=model.decoder.config.max_position_embeddings, + early_stopping=True, + use_cache=True, + num_beams=1, + bad_words_ids=[[processor.tokenizer.unk_token_id]], + return_dict_in_generate=True, + ) + sequence = ( + processor.batch_decode(outputs.sequences)[0] + .replace(processor.tokenizer.eos_token, "") + .replace(processor.tokenizer.pad_token, "") + ) + return processor.token2json(sequence) + +def step2_run_phi3(medication_text: str) -> str: + phi3_components = get_model("phi3") + if not phi3_components: + return medication_text + + pipe = phi3_components["model"] + prompt = ( + f"Normalize the following prescription medication line into its components " + f"(drug, dosage, frequency). Raw text: '{medication_text}'" + ) + outputs = pipe(prompt, max_new_tokens=100, do_sample=False) + return outputs[0]["generated_text"].split("Normalized:")[-1].strip() + +def step3_run_gemini_resolver( + image: Image.Image, donut_result: Dict[str, Any], phi3_results: List[str] +) -> Dict[str, Any]: + gemini_client = get_gemini_client() + if not gemini_client: + return {"error": "Gemini resolver not available."} + + prompt = f""" +You are an expert pharmacist's assistant whose sole objective is to reconcile and verify prescription details by cross-referencing multiple AI model outputs against the original prescription image (the ultimate source of truth). + +Attached Inputs: +1. Prescription image file +2. Donut Model Output (layout-aware): + {json.dumps(donut_result, indent=2)} +3. Phi-3 Model Output (medication refinement): + {json.dumps(phi3_results, indent=2)} + +Please follow these steps **in order**: + +1. **Extract & Normalize** + - Read the prescription image and extract: Patient Name, Date, Age, Physician Name, and each listed medication. + - Normalize dates to MM/DD/YYYY and medication names to their exact printed form. + +2. **Compare Model Outputs** + - For each field (Name, Date, Age, PhysicianName), check both model outputs and flag any discrepancies. + - For each medication entry, compare `drug_raw`, `dosage`, and `frequency` from Phi-3 with the layout cues from Donut. + +3. **Verify Against Image** + - Wherever the two models disagree, use the image text as the tiebreaker. + - If both models miss or misread something (e.g. a dosage or frequency), pull it directly from the image. + +4. **Error Correction** + - Correct spelling errors, unit inconsistencies (e.g. "mg" vs "MG"), and frequency shorthand (e.g. "BID" → "twice a day"). + +5. **Assemble Final JSON** + - Populate exactly this schema; do not add extra keys. + - If a field is unreadable or absent on the image, set its value to `null`. + +**Final JSON Schema** +```json +{{ + "Name": "string or null", + "Date": "string (MM/DD/YYYY) or null", + "Age": "string or null", + "PhysicianName": "string or null", + "Medications": [ + {{ + "drug_raw": "string", + "dosage": "string or null", + "frequency": "string or null", + "verification": {{ + "standard_dosage": "string or null", + "side_effects": "string or null", + "interactions": "string or null" + }} + }} + ] +}} +""" + + try: + response = gemini_client.generate_content( + [prompt, image], + generation_config={"response_mime_type": "application/json"}, + ) + result = json.loads(response.text) + + # Enhance with Google Search verification + for med in result.get("Medications", []): + if drug_name := med.get("drug_raw"): + verification = verify_medication_with_google(drug_name) + med["verification"] = { + "standard_dosage": self._extract_dosage_info(verification), + "side_effects": self._extract_side_effects(verification), + "interactions": self._extract_interactions(verification) + } + + return result + except Exception as e: + logging.error(f"Gemini resolver failed: {e}") + return {"error": f"Gemini failed to resolve data: {e}"} + +def _extract_dosage_info(verification_data: Dict) -> Optional[str]: + """Extracts dosage information from verification results.""" + for result in verification_data.get("verification_results", []): + if "standard dosage" in result.get("query", "").lower(): + return result.get("results", [{}])[0].get("snippet") + return None + +def _extract_side_effects(verification_data: Dict) -> Optional[str]: + """Extracts side effects information from verification results.""" + for result in verification_data.get("verification_results", []): + if "side effects" in result.get("query", "").lower(): + return result.get("results", [{}])[0].get("snippet") + return None + +def _extract_interactions(verification_data: Dict) -> Optional[str]: + """Extracts drug interactions information from verification results.""" + for result in verification_data.get("verification_results", []): + if "interactions" in result.get("query", "").lower(): + return result.get("results", [{}])[0].get("snippet") + return None + +def extract_prescription_info(image_path: str) -> Dict[str, Any]: + """Runs the full hybrid AI pipeline.""" + try: + image = Image.open(image_path).convert("RGB") + + logging.info("Step 1: Running Donut model for layout analysis...") + donut_data = step1_run_donut(image) + + medication_lines = [ + item.get("text", "") + for item in donut_data.get("menu", []) + if "medi" in item.get("category", "").lower() + ] + + logging.info("Step 2: Running Phi-3 model for medication refinement...") + phi3_refined_meds = [step2_run_phi3(line) for line in medication_lines] + + logging.info("Step 3: Running Gemini model as the expert resolver...") + final_info = step3_run_gemini_resolver(image, donut_data, phi3_refined_meds) + + if final_info.get("error"): + return final_info + + result = { + "info": final_info, + "error": None, + "debug_info": { + "donut_output": donut_data, + "phi3_refinements": phi3_refined_meds, + }, + } + return result + + except Exception as e: + logging.error(f"Hybrid extraction pipeline failed: {e}", exc_info=True) + return {"error": f"An unexpected error occurred in the pipeline: {e}"} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index d32eba1d63fd99b6a1751597fb072c9aca185dfd..0000000000000000000000000000000000000000 --- a/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [svelte()], -})