Ankit Thakur commited on
Commit
12f2295
·
1 Parent(s): 89d8caa

Resolve merge conflicts

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -0
  2. Dockerfile +18 -0
  3. Google_Search_tool.py +41 -0
  4. README.md +12 -57
  5. __pycache__/config.cpython-310.pyc +0 -0
  6. __pycache__/config.cpython-39.pyc +0 -0
  7. __pycache__/google_search_tool.cpython-310.pyc +0 -0
  8. __pycache__/validate_prescription.cpython-310.pyc +0 -0
  9. app.py +137 -0
  10. apt-packages.txt +13 -0
  11. config.py +37 -0
  12. data/interactions.csv +3 -0
  13. data/rxnorm.db +0 -0
  14. data/rxnorm_names.csv +13 -0
  15. drug_interaction_detection/__pycache__/interaction_checker.cpython-310.pyc +0 -0
  16. drug_interaction_detection/interaction_checker.py +34 -0
  17. earnest-trilogy-465710-e7-6cc7bbbddb97.json +13 -0
  18. index.html +0 -13
  19. models/signature_sia.tflite +3 -0
  20. package.json +0 -20
  21. prescription_validation/__pycache__/fuzzy_match.cpython-310.pyc +0 -0
  22. prescription_validation/fuzzy_match.py +44 -0
  23. prescription_validation/zone_detector.py +27 -0
  24. public/vite.svg +0 -1
  25. requirements.txt +23 -0
  26. scripts/build_interactions_db.py +27 -0
  27. scripts/build_rxnorm_db.py +28 -0
  28. scripts/create_dummy_signature_model.py +32 -0
  29. signature_verification/__pycache__/signature_detector.cpython-310.pyc +0 -0
  30. signature_verification/__pycache__/signature_generator.cpython-310.pyc +0 -0
  31. signature_verification/__pycache__/signature_siamese.cpython-310.pyc +0 -0
  32. signature_verification/signature_detector.py +40 -0
  33. signature_verification/signature_generator.py +50 -0
  34. signature_verification/signature_siamese.py +34 -0
  35. src/App.svelte +0 -47
  36. src/app.css +0 -79
  37. src/assets/svelte.svg +0 -1
  38. src/lib/Counter.svelte +0 -10
  39. src/main.ts +0 -9
  40. src/vite-env.d.ts +0 -2
  41. static/signatures/fake-autograph-samples-hand-drawn-signatures-examples-of-documents-certificates-and-contracts-with-inked-and-handwritten-lettering-vector.jpg +3 -0
  42. 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 +3 -0
  43. static/signatures/images.png +0 -0
  44. static/signatures/signature-certificate-document-vector-transparent-260nw-2346804443.jpg +3 -0
  45. static/signatures/signature-vector-hand-drawn-autograph-600nw-2387543207.jpg +3 -0
  46. static/uploads/02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg +3 -0
  47. static/uploads/0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg +3 -0
  48. static/uploads/1*3xUyINxRtDf2qowd-kkGQA.jpg +3 -0
  49. static/uploads/255d2936a26d49429c21ce6b06b323b7_vio-4.jpg +3 -0
  50. static/uploads/2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg +3 -0
.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ *.tflite filter=lfs diff=lfs merge=lfs -text
2
+ *.jpg filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install minimal system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ libgl1-mesa-glx \
8
+ libglib2.0-0 \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirements first for better caching
12
+ COPY requirements.txt .
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Copy application files
16
+ COPY . .
17
+
18
+ CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
Google_Search_tool.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from googleapiclient.discovery import build
4
+ from dotenv import load_dotenv
5
+
6
+ load_dotenv()
7
+
8
+ class GoogleSearch:
9
+ """Performs Google Custom Search API queries."""
10
+ def __init__(self):
11
+ self.api_key = os.getenv("GOOGLE_API_KEY")
12
+ self.cse_id = os.getenv("GOOGLE_CSE_ID")
13
+ self.service = None
14
+ if self.api_key and self.cse_id:
15
+ try:
16
+ self.service = build("customsearch", "v1", developerKey=self.api_key)
17
+ logging.info("✅ Google Custom Search initialized.")
18
+ except Exception as e:
19
+ logging.error(f"❌ CSE init failed: {e}")
20
+ else:
21
+ logging.warning("⚠️ GOOGLE_API_KEY or GOOGLE_CSE_ID not set; search disabled.")
22
+
23
+ def search(self, queries: list, num_results: int = 1) -> list:
24
+ if not self.service:
25
+ return []
26
+ out = []
27
+ for q in queries:
28
+ try:
29
+ resp = self.service.cse().list(q=q, cx=self.cse_id, num=num_results).execute()
30
+ items = resp.get("items", [])
31
+ formatted = [
32
+ {"title": it.get("title"), "link": it.get("link"), "snippet": it.get("snippet")}
33
+ for it in items
34
+ ]
35
+ out.append({"query": q, "results": formatted})
36
+ except Exception as e:
37
+ logging.error(f"❌ Search error for '{q}': {e}")
38
+ out.append({"query": q, "results": []})
39
+ return out
40
+
41
+ google_search = GoogleSearch()
README.md CHANGED
@@ -1,59 +1,14 @@
1
  ---
2
- title: HexAI Demo
3
- emoji: 🔥
4
- colorFrom: pink
5
- colorTo: gray
6
- sdk: static
7
- pinned: false
8
- app_build_command: npm run build
9
- app_file: dist/index.html
10
- short_description: Demo with limited version
 
 
 
11
  ---
12
-
13
- # Svelte + TS + Vite
14
-
15
- This template should help get you started developing with Svelte and TypeScript in Vite.
16
-
17
- ## Recommended IDE Setup
18
-
19
- [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
20
-
21
- ## Need an official Svelte framework?
22
-
23
- 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.
24
-
25
- ## Technical considerations
26
-
27
- **Why use this over SvelteKit?**
28
-
29
- - It brings its own routing solution which might not be preferable for some users.
30
- - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
31
-
32
- 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.
33
-
34
- 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.
35
-
36
- **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
37
-
38
- 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.
39
-
40
- **Why include `.vscode/extensions.json`?**
41
-
42
- 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.
43
-
44
- **Why enable `allowJs` in the TS template?**
45
-
46
- 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.
47
-
48
- **Why is HMR not preserving my local component state?**
49
-
50
- 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).
51
-
52
- If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR.
53
-
54
- ```ts
55
- // store.ts
56
- // An extremely simple external store
57
- import { writable } from "svelte/store";
58
- export default writable(0);
59
- ```
 
1
  ---
2
+ title: RxGuard Prescription Validator
3
+ emoji: ⚕️
4
+ colorFrom: blue
5
+ colorTo: indigo
6
+ sdk: streamlit
7
+ sdk_version: 1.36.0
8
+ app_file: app.py
9
+ hf_oauth: true
10
+ hardware:
11
+ accelerator: T4
12
+ cpu: 2
13
+ memory: 16
14
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
__pycache__/config.cpython-310.pyc ADDED
Binary file (522 Bytes). View file
 
__pycache__/config.cpython-39.pyc ADDED
Binary file (598 Bytes). View file
 
__pycache__/google_search_tool.cpython-310.pyc ADDED
Binary file (1.87 kB). View file
 
__pycache__/validate_prescription.cpython-310.pyc ADDED
Binary file (9.28 kB). View file
 
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import streamlit as st
3
+ from PIL import Image
4
+ from config import (
5
+ STATIC_DIR,
6
+ UPLOADS_DIR,
7
+ HF_TOKEN,
8
+ GOOGLE_API_KEY,
9
+ GOOGLE_CSE_ID,
10
+ GEMINI_API_KEY,
11
+ DEVICE
12
+ )
13
+
14
+ # ─── App Configuration ────────────────────────────────────────────────────
15
+ st.set_page_config(
16
+ page_title="RxGuard Prescription Validator",
17
+ page_icon="⚕️",
18
+ layout="wide",
19
+ menu_items={
20
+ 'Get Help': 'https://github.com/your-repo',
21
+ 'About': "RxGuard v1.0 - Advanced Prescription Validation"
22
+ }
23
+ )
24
+
25
+ # ─── Session State ────────────────────────────────────────────────────────
26
+ if "analysis_result" not in st.session_state:
27
+ st.session_state.analysis_result = None
28
+ if "uploaded_filename" not in st.session_state:
29
+ st.session_state.uploaded_filename = None
30
+
31
+ # ─── UI Components ────────────────────────────────────────────────────────
32
+ def show_service_status():
33
+ """Displays service connectivity status."""
34
+ cols = st.columns(4)
35
+ with cols[0]:
36
+ st.metric("HuggingFace", "✅" if HF_TOKEN else "❌")
37
+ with cols[1]:
38
+ st.metric("Google API", "✅" if GOOGLE_API_KEY else "❌")
39
+ with cols[2]:
40
+ st.metric("Gemini", "✅" if GEMINI_API_KEY else "❌")
41
+ with cols[3]:
42
+ st.metric("Device", DEVICE.upper())
43
+
44
+ def display_patient_info(info: dict):
45
+ """Displays patient information in a formatted card."""
46
+ with st.container(border=True):
47
+ st.subheader("👤 Patient Details")
48
+ cols = st.columns(2)
49
+ with cols[0]:
50
+ st.markdown(f"**Name:** {info.get('Name', 'Not detected')}")
51
+ st.markdown(f"**Age:** {info.get('Age', 'N/A')}")
52
+ with cols[1]:
53
+ st.markdown(f"**Date:** {info.get('Date', 'N/A')}")
54
+ st.markdown(f"**Physician:** {info.get('PhysicianName', 'N/A')}")
55
+
56
+ def display_medications(medications: list):
57
+ """Displays medication information with verification."""
58
+ st.subheader("💊 Medications")
59
+ if not medications:
60
+ st.warning("No medications detected in prescription")
61
+ return
62
+
63
+ for med in medications:
64
+ with st.expander(f"{med.get('drug_raw', 'Unknown Medication')}"):
65
+ cols = st.columns([1, 2])
66
+ with cols[0]:
67
+ st.markdown(f"""
68
+ **Dosage:** `{med.get('dosage', 'N/A')}`
69
+ **Frequency:** `{med.get('frequency', 'N/A')}`
70
+ """)
71
+
72
+ with cols[1]:
73
+ if verification := med.get("verification"):
74
+ if dosage := verification.get("standard_dosage"):
75
+ st.success(f"**Standard Dosage:** {dosage}")
76
+ if side_effects := verification.get("side_effects"):
77
+ st.warning(f"**Side Effects:** {side_effects}")
78
+ if interactions := verification.get("interactions"):
79
+ st.error(f"**Interactions:** {interactions}")
80
+
81
+ # ─── Main Application ─────────────────────────────────────────────────────
82
+ def main():
83
+ st.title("⚕️ RxGuard Prescription Validator")
84
+ st.caption("AI-powered prescription verification system")
85
+
86
+ show_service_status()
87
+
88
+ # Only enable upload if required services are available
89
+ if all([HF_TOKEN, GOOGLE_API_KEY, GEMINI_API_KEY]):
90
+ uploaded_file = st.file_uploader(
91
+ "Upload prescription image (PNG/JPG/JPEG):",
92
+ type=["png", "jpg", "jpeg"],
93
+ help="Clear image of the prescription"
94
+ )
95
+
96
+ if uploaded_file and uploaded_file.name != st.session_state.uploaded_filename:
97
+ with st.status("Analyzing prescription...", expanded=True) as status:
98
+ try:
99
+ # Store the uploaded file
100
+ st.session_state.uploaded_filename = uploaded_file.name
101
+ file_path = os.path.join(UPLOADS_DIR, uploaded_file.name)
102
+
103
+ with open(file_path, "wb") as f:
104
+ f.write(uploaded_file.getvalue())
105
+
106
+ # Import processing function only when needed
107
+ from validate_prescription import extract_prescription_info
108
+ st.session_state.analysis_result = extract_prescription_info(file_path)
109
+
110
+ status.update(label="Analysis complete!", state="complete", expanded=False)
111
+ except Exception as e:
112
+ st.error(f"Processing failed: {str(e)}")
113
+ st.session_state.analysis_result = {"error": str(e)}
114
+ status.update(label="Analysis failed", state="error")
115
+
116
+ # Display results if available
117
+ if st.session_state.analysis_result:
118
+ result = st.session_state.analysis_result
119
+
120
+ if result.get("error"):
121
+ st.error(f"❌ Error: {result['error']}")
122
+ else:
123
+ tab1, tab2 = st.tabs(["Patient Information", "Medication Details"])
124
+
125
+ with tab1:
126
+ if uploaded_file:
127
+ st.image(uploaded_file, use_column_width=True)
128
+ display_patient_info(result["info"])
129
+
130
+ with tab2:
131
+ display_medications(result["info"].get("Medications", []))
132
+
133
+ if st.toggle("Show technical details"):
134
+ st.json(result.get("debug_info", {}))
135
+
136
+ if __name__ == "__main__":
137
+ main()
apt-packages.txt ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ libgl1
2
+ libgl1-mesa-glx
3
+ libglib2.0-0
4
+ tesseract-ocr
5
+ tesseract-ocr-hin
6
+ git
7
+ git-lfs
8
+ curl
9
+ libssl-dev
10
+ libffi-dev
11
+ python3-dev
12
+ build-essential
13
+ libsqlite3-dev
config.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import torch
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv()
6
+
7
+ # ─── Directory Configuration ────────────────────────────────────────────────
8
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
9
+ STATIC_DIR = os.path.join(BASE_DIR, 'static')
10
+ os.makedirs(STATIC_DIR, exist_ok=True)
11
+
12
+ # ─── API Secrets ────────────────────────────────────────────────────────────
13
+ HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN") # For Hugging Face models
14
+ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY") # For Gemini and Custom Search
15
+ GOOGLE_CSE_ID = os.getenv("GOOGLE_CSE_ID") # For medication verification
16
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") # Alternative Gemini auth
17
+ HALODOC_API_KEY = os.getenv("HALODOC_API_KEY") # Future integration
18
+
19
+ # ─── Model Configuration ────────────────────────────────────────────────────
20
+ HF_MODELS = {
21
+ "donut": "naver-clova-ix/donut-base-finetuned-cord-v2",
22
+ "phi3": "microsoft/phi-3-mini-4k-instruct",
23
+ }
24
+ GEMINI_MODEL_NAME = "gemini-1.5-flash" # Balanced for speed and accuracy
25
+
26
+ # ─── Processing Parameters ─────────────────────────────────────────────────
27
+ LEV_THRESH = 0.75 # Levenshtein similarity threshold
28
+ SIG_THRESH = 0.65 # Signature verification threshold
29
+
30
+ # ─── File Paths ───────────────────────────────────────────────────────────
31
+ DB_PATH = os.path.join(STATIC_DIR, "rxguard.db")
32
+ UPLOADS_DIR = os.path.join(STATIC_DIR, "uploads")
33
+ os.makedirs(UPLOADS_DIR, exist_ok=True)
34
+
35
+ # ─── Hardware Configuration ────────────────────────────────────────────────
36
+ DEVICE = "cpu" # Force CPU for Hugging Face Spaces compatibility
37
+ USE_GPU = False
data/interactions.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ cui1,cui2,severity,advice
2
+ 1191,6801,moderate,"Monitor blood glucose closely; aspirin may enhance the hypoglycemic effect of metformin."
3
+ 4241,1113,moderate,"Ascorbic acid can increase the absorption of iron. While often beneficial, monitor for iron overload in susceptible patients."
data/rxnorm.db ADDED
Binary file (24.6 kB). View file
 
data/rxnorm_names.csv ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name,cui
2
+ Aspirin,1191
3
+ Acetaminophen,161
4
+ Amoxicillin,723
5
+ Metformin,6801
6
+ Lisinopril,29046
7
+ Ferrous Sulfate,4241
8
+ Ascorbic Acid,1113
9
+ Calcium Carbonate / Vitamin D3,12345
10
+ Clonazepam,2623
11
+ Meganeuron,54321
12
+ Creatine,9876
13
+ Salbutamol,9648
drug_interaction_detection/__pycache__/interaction_checker.cpython-310.pyc ADDED
Binary file (1.6 kB). View file
 
drug_interaction_detection/interaction_checker.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # drug_interaction_detection/interaction_checker.py
2
+ import sqlite3
3
+ from config import DB_PATH
4
+
5
+ class InteractionChecker:
6
+ def __init__(self, db_path: str = DB_PATH):
7
+ self.conn = sqlite3.connect(db_path)
8
+ self.conn.row_factory = sqlite3.Row
9
+
10
+ def find(self, cuis: list[str]) -> list[dict]:
11
+ if len(cuis) < 2: return []
12
+
13
+ # Create a list of all unique pairs
14
+ pairs = []
15
+ for i in range(len(cuis)):
16
+ for j in range(i + 1, len(cuis)):
17
+ # Ensure consistent order for querying (e.g., smaller CUI first)
18
+ pair = tuple(sorted((cuis[i], cuis[j])))
19
+ pairs.append(pair)
20
+
21
+ if not pairs: return []
22
+
23
+ # Query for all pairs at once
24
+ placeholders = ", ".join(["(?, ?)"] * len(pairs))
25
+ flat_params = [item for pair in pairs for item in pair]
26
+
27
+ query = f"""
28
+ SELECT cui1, cui2, severity, advice
29
+ FROM interactions
30
+ WHERE (cui1, cui2) IN ({placeholders})
31
+ """
32
+
33
+ rows = self.conn.execute(query, flat_params).fetchall()
34
+ return [{"pair": (r["cui1"], r["cui2"]), "severity": r["severity"], "advice": r["advice"]} for r in rows]
earnest-trilogy-465710-e7-6cc7bbbddb97.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "earnest-trilogy-465710-e7",
4
+ "private_key_id": "6cc7bbbddb970f16876e3f4120ff18be704f5ee5",
5
+ "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",
6
+ "client_email": "aihackathon@earnest-trilogy-465710-e7.iam.gserviceaccount.com",
7
+ "client_id": "102524806684057807383",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/aihackathon%40earnest-trilogy-465710-e7.iam.gserviceaccount.com",
12
+ "universe_domain": "googleapis.com"
13
+ }
index.html DELETED
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Vite + Svelte + TS</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/src/main.ts"></script>
12
- </body>
13
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
models/signature_sia.tflite ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9ba80e2f5c688e9fd9fc766a85f266d0a47201def65265ef294168546a2814de
3
+ size 804888
package.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "name": "svelte",
3
- "private": true,
4
- "version": "0.0.0",
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite",
8
- "build": "vite build",
9
- "preview": "vite preview",
10
- "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
11
- },
12
- "devDependencies": {
13
- "@sveltejs/vite-plugin-svelte": "^5.0.3",
14
- "@tsconfig/svelte": "^5.0.4",
15
- "svelte": "^5.28.1",
16
- "svelte-check": "^4.1.6",
17
- "typescript": "~5.8.3",
18
- "vite": "^6.3.5"
19
- }
20
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
prescription_validation/__pycache__/fuzzy_match.cpython-310.pyc ADDED
Binary file (1.52 kB). View file
 
prescription_validation/fuzzy_match.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # prescription_validation/fuzzy_match.py
2
+ import sqlite3
3
+ import re
4
+ from rapidfuzz.distance import Levenshtein
5
+ from config import DB_PATH, LEV_THRESH
6
+
7
+ class RxLookup:
8
+ def __init__(self, db_path: str = DB_PATH):
9
+ self.conn = sqlite3.connect(db_path)
10
+ self.conn.row_factory = sqlite3.Row
11
+ self.drugs = self.conn.execute("SELECT name, cui FROM drugs").fetchall()
12
+
13
+ def _clean_token(self, token: str) -> str:
14
+ """Removes dosage, form factor, and non-alpha characters."""
15
+ cleaned = token.lower()
16
+ cleaned = re.sub(r'(\d+)\s*(mg|ml|mcg|tab|cap|#)', '', cleaned)
17
+ cleaned = re.sub(r'[^a-z]', '', cleaned)
18
+ return cleaned
19
+
20
+ def match(self, token: str) -> tuple[str | None, str | None]:
21
+ if not token:
22
+ return (None, None)
23
+
24
+ cleaned_token = self._clean_token(token)
25
+ if not cleaned_token:
26
+ return (None, None)
27
+
28
+ best_match = None
29
+ min_distance = float('inf')
30
+
31
+ for row in self.drugs:
32
+ name, cui = row["name"], row["cui"]
33
+ cleaned_db_name = self._clean_token(name)
34
+
35
+ distance = Levenshtein.distance(cleaned_token, cleaned_db_name)
36
+
37
+ if distance < min_distance:
38
+ min_distance = distance
39
+ best_match = (name, cui)
40
+
41
+ if best_match and min_distance / len(cleaned_token) < LEV_THRESH:
42
+ return best_match
43
+
44
+ return (None, None)
prescription_validation/zone_detector.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # prescription_validation/zone_detector.py
2
+ import cv2
3
+ import numpy as np
4
+ from ultralytics import YOLO
5
+
6
+ class ZoneDetector:
7
+ def __init__(self, model_path: str = "models/signature_model.pt"):
8
+ try:
9
+ self.model = YOLO(model_path)
10
+ print(f"✅ Loaded local YOLO model from '{model_path}'")
11
+ except Exception as e:
12
+ self.model = None
13
+ print(f"❌ Failed to load local YOLO model from '{model_path}'. Please ensure the model file exists.")
14
+
15
+ def detect(self, img: np.ndarray) -> list[dict]:
16
+ if not self.model: return []
17
+ rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
18
+ results = self.model(rgb_img, verbose=False)
19
+ detections = []
20
+ for box in results[0].boxes:
21
+ x1, y1, x2, y2 = box.xyxy[0].tolist()
22
+ class_id = int(box.cls[0])
23
+ detections.append({
24
+ "label": self.model.names[class_id],
25
+ "bbox": tuple(map(int, [x1, y1, x2, y2])),
26
+ })
27
+ return detections
public/vite.svg DELETED
requirements.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core
2
+ streamlit==1.36.0
3
+ python-dotenv==1.0.1
4
+
5
+ # AI & Vision
6
+ # Using Google's recommended versions for Gemini and Vision
7
+ google-generativeai==0.7.1
8
+ google-cloud-vision==3.7.3
9
+ torch==2.3.1
10
+ pillow==10.3.0
11
+ transformers==4.41.0
12
+
13
+ # OCR
14
+ paddleocr==2.7.3
15
+ # Using the CPU version of paddlepaddle for broader compatibility on HF Spaces
16
+ paddlepaddle==2.6.1
17
+
18
+ # Utils
19
+ numpy==1.26.4
20
+ requests==2.32.3
21
+ opencv-python-headless==4.10.0.84
22
+ scikit-image==0.22.0
23
+ pytz==2024.1
scripts/build_interactions_db.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import sqlite3, csv, argparse
3
+ import sys, os
4
+ sys.path.append(os.getcwd())
5
+ from config import DB_PATH, INTERACTIONS_CSV
6
+
7
+ def build_db(db_path: str, csv_path: str):
8
+ conn = sqlite3.connect(db_path)
9
+ c = conn.cursor()
10
+ c.execute("DROP TABLE IF EXISTS interactions")
11
+ c.execute("CREATE TABLE interactions(cui1 TEXT, cui2 TEXT, severity TEXT, advice TEXT, UNIQUE(cui1, cui2))")
12
+
13
+ with open(csv_path, newline='', encoding='utf-8') as f:
14
+ reader = csv.DictReader(f)
15
+ for row in reader:
16
+ # Ensure consistent order to avoid duplicate entries like (A,B) and (B,A)
17
+ cui1, cui2 = sorted((row['cui1'], row['cui2']))
18
+ c.execute(
19
+ "INSERT OR IGNORE INTO interactions(cui1, cui2, severity, advice) VALUES(?,?,?,?)",
20
+ (cui1, cui2, row['severity'], row['advice'])
21
+ )
22
+ conn.commit()
23
+ conn.close()
24
+
25
+ if __name__ == "__main__":
26
+ build_db(DB_PATH, INTERACTIONS_CSV)
27
+ print(f"✅ Interactions DB built at {DB_PATH}")
scripts/build_rxnorm_db.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import sqlite3, csv, argparse
3
+ from metaphone import doublemetaphone
4
+ import sys, os
5
+ sys.path.append(os.getcwd())
6
+ from config import DB_PATH, RXNORM_CSV
7
+
8
+ def build_db(db_path: str, csv_path: str):
9
+ conn = sqlite3.connect(db_path)
10
+ c = conn.cursor()
11
+ c.execute("DROP TABLE IF EXISTS drugs")
12
+ c.execute("DROP TABLE IF EXISTS metaphone")
13
+ c.execute("CREATE TABLE drugs(name TEXT PRIMARY KEY, cui TEXT)")
14
+ c.execute("CREATE TABLE metaphone(meta TEXT, name TEXT, cui TEXT)")
15
+
16
+ with open(csv_path, newline='', encoding='utf-8') as f:
17
+ reader = csv.DictReader(f)
18
+ for row in reader:
19
+ nm, cui = row['name'], row['cui']
20
+ c.execute("INSERT OR IGNORE INTO drugs VALUES(?,?)", (nm, cui))
21
+ meta = doublemetaphone(nm)[0]
22
+ c.execute("INSERT INTO metaphone VALUES(?,?,?)", (meta, nm, cui))
23
+ conn.commit()
24
+ conn.close()
25
+
26
+ if __name__ == "__main__":
27
+ build_db(DB_PATH, RXNORM_CSV)
28
+ print(f"✅ RxNorm DB built at {DB_PATH}")
scripts/create_dummy_signature_model.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ import os
3
+ import tensorflow as tf
4
+ from tensorflow.keras.layers import Input, Flatten, Dense, Subtract
5
+ from tensorflow.keras.models import Model
6
+ import sys
7
+ sys.path.append(os.getcwd())
8
+ from config import SIA_MODEL_PATH
9
+
10
+ def build_dummy_siamese():
11
+ inp_a = Input(shape=(224, 224, 1), name="img_a")
12
+ inp_b = Input(shape=(224, 224, 1), name="img_b")
13
+ encoder_input = Input(shape=(224, 224, 1))
14
+ x = Flatten()(encoder_input)
15
+ x = Dense(16, activation="relu")(x)
16
+ encoder = Model(encoder_input, x)
17
+ encoded_a = encoder(inp_a)
18
+ encoded_b = encoder(inp_b)
19
+ distance = Subtract()([encoded_a, encoded_b])
20
+ model = Model(inputs=[inp_a, inp_b], outputs=distance)
21
+ return model
22
+
23
+ if __name__ == "__main__":
24
+ print("Building and converting dummy Siamese model...")
25
+ model = build_dummy_siamese()
26
+ converter = tf.lite.TFLiteConverter.from_keras_model(model)
27
+ converter.optimizations = [tf.lite.Optimize.DEFAULT]
28
+ tflite_model = converter.convert()
29
+ os.makedirs(os.path.dirname(SIA_MODEL_PATH), exist_ok=True)
30
+ with open(SIA_MODEL_PATH, "wb") as f:
31
+ f.write(tflite_model)
32
+ print(f"✅ Dummy TFLite signature model saved to '{SIA_MODEL_PATH}'")
signature_verification/__pycache__/signature_detector.cpython-310.pyc ADDED
Binary file (1.5 kB). View file
 
signature_verification/__pycache__/signature_generator.cpython-310.pyc ADDED
Binary file (1.91 kB). View file
 
signature_verification/__pycache__/signature_siamese.cpython-310.pyc ADDED
Binary file (1.84 kB). View file
 
signature_verification/signature_detector.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # signature_verification/signature_detector.py
2
+ import cv2
3
+ import numpy as np
4
+
5
+ class SignatureDetector:
6
+ """
7
+ Detects and crops a signature from a prescription image using refined OpenCV contour analysis.
8
+ This method is fast, offline, and does not require a pre-trained model.
9
+ """
10
+ def crop(self, img: np.ndarray) -> np.ndarray | None:
11
+ if img is None: return None
12
+
13
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
14
+ blurred = cv2.GaussianBlur(gray, (5, 5), 0)
15
+ _, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
16
+
17
+ contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
18
+ if not contours: return None
19
+
20
+ height, width = img.shape[:2]
21
+ significant_contours = []
22
+ for cnt in contours:
23
+ x, y, w, h = cv2.boundingRect(cnt)
24
+ # Filter for contours that are reasonably large and in the bottom 70% of the page
25
+ if w > 50 and h > 15 and y > height * 0.3:
26
+ if w < width * 0.8 and h < height * 0.4:
27
+ significant_contours.append(cnt)
28
+
29
+ if not significant_contours: return None
30
+
31
+ largest_contour = max(significant_contours, key=cv2.contourArea)
32
+ x, y, w, h = cv2.boundingRect(largest_contour)
33
+
34
+ padding = 15
35
+ x1 = max(0, x - padding)
36
+ y1 = max(0, y - padding)
37
+ x2 = min(width, x + w + padding)
38
+ y2 = min(height, y + h + padding)
39
+
40
+ return img[y1:y2, x1:x2]
signature_verification/signature_generator.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ import numpy as np
4
+ import cv2
5
+ from dotenv import load_dotenv
6
+ from huggingface_hub import InferenceClient, HfFolder
7
+ from PIL import Image
8
+
9
+ load_dotenv()
10
+
11
+ # Acquire token
12
+ hf_token = os.getenv("HUGGING_FACE_HUB_TOKEN") or HfFolder.get_token()
13
+ if not hf_token:
14
+ print("❌ No Hugging Face token found. Signature generation will fail.")
15
+ CLIENT = None
16
+ else:
17
+ print("✅ Using Hugging Face token for signature generation.")
18
+ CLIENT = InferenceClient(token=hf_token)
19
+
20
+ MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
21
+
22
+ def generate_signatures(name: str, num_variations: int = 3) -> list:
23
+ """Generates multiple signature variations for a given name."""
24
+ if CLIENT is None:
25
+ return []
26
+
27
+ prompts = [
28
+ f"A clean, elegant, handwritten signature of the name '{name}' on a plain white background. Cursive, professional.",
29
+ f"Calligraphy signature of '{name}'. Black ink on white paper. Minimalist, artistic.",
30
+ f"A doctor's signature for '{name}'. Quick, scribbled, but legible. Official-looking script."
31
+ ]
32
+ images = []
33
+ for i in range(num_variations):
34
+ prompt = prompts[i % len(prompts)]
35
+ logging.info(f"Generating signature variation {i+1} for '{name}'…")
36
+ try:
37
+ pil_img = CLIENT.text_to_image(
38
+ prompt,
39
+ model=MODEL_ID,
40
+ negative_prompt=(
41
+ "photograph, text, multiple signatures, watermark, blurry, colorful, background"
42
+ ),
43
+ guidance_scale=8.0
44
+ )
45
+ np_img = np.array(pil_img)
46
+ cv_img = cv2.cvtColor(np_img, cv2.COLOR_RGB2BGR)
47
+ images.append(cv_img)
48
+ except Exception as e:
49
+ logging.error(f"❌ Signature generation failed: {e}")
50
+ return images
signature_verification/signature_siamese.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # signature_verification/signature_siamese.py
2
+ import cv2
3
+ import numpy as np
4
+ import tensorflow as tf
5
+ from config import SIA_MODEL_PATH, SIG_THRESH
6
+
7
+ class SignatureSiamese:
8
+ def __init__(self, model_path: str = SIA_MODEL_PATH):
9
+ try:
10
+ self.interp = tf.lite.Interpreter(model_path=model_path)
11
+ self.interp.allocate_tensors()
12
+ ids = self.interp.get_input_details()
13
+ self.in1, self.in2 = ids[0]['index'], ids[1]['index']
14
+ self.out_idx = self.interp.get_output_details()[0]['index']
15
+ print(f"✅ Loaded TFLite Siamese model from {model_path}")
16
+ except Exception as e:
17
+ self.interp = None
18
+ print(f"❌ Failed to load Siamese model from {model_path}: {e}")
19
+
20
+ def _prep(self, img: np.ndarray) -> np.ndarray:
21
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) if img.ndim == 3 else img
22
+ r = cv2.resize(gray, (224, 224))
23
+ return r.reshape(1, 224, 224, 1).astype(np.float32) / 255.0
24
+
25
+ def verify(self, img1: np.ndarray, img2: np.ndarray) -> tuple[bool, float]:
26
+ if not self.interp:
27
+ return False, float('inf')
28
+ inp1, inp2 = self._prep(img1), self._prep(img2)
29
+ self.interp.set_tensor(self.in1, inp1)
30
+ self.interp.set_tensor(self.in2, inp2)
31
+ self.interp.invoke()
32
+ diff = self.interp.get_tensor(self.out_idx)
33
+ dist = np.linalg.norm(diff)
34
+ return dist < SIG_THRESH, dist
src/App.svelte DELETED
@@ -1,47 +0,0 @@
1
- <script lang="ts">
2
- import svelteLogo from './assets/svelte.svg'
3
- import viteLogo from '/vite.svg'
4
- import Counter from './lib/Counter.svelte'
5
- </script>
6
-
7
- <main>
8
- <div>
9
- <a href="https://vite.dev" target="_blank" rel="noreferrer">
10
- <img src={viteLogo} class="logo" alt="Vite Logo" />
11
- </a>
12
- <a href="https://svelte.dev" target="_blank" rel="noreferrer">
13
- <img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
14
- </a>
15
- </div>
16
- <h1>Vite + Svelte</h1>
17
-
18
- <div class="card">
19
- <Counter />
20
- </div>
21
-
22
- <p>
23
- Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
24
- </p>
25
-
26
- <p class="read-the-docs">
27
- Click on the Vite and Svelte logos to learn more
28
- </p>
29
- </main>
30
-
31
- <style>
32
- .logo {
33
- height: 6em;
34
- padding: 1.5em;
35
- will-change: filter;
36
- transition: filter 300ms;
37
- }
38
- .logo:hover {
39
- filter: drop-shadow(0 0 2em #646cffaa);
40
- }
41
- .logo.svelte:hover {
42
- filter: drop-shadow(0 0 2em #ff3e00aa);
43
- }
44
- .read-the-docs {
45
- color: #888;
46
- }
47
- </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app.css DELETED
@@ -1,79 +0,0 @@
1
- :root {
2
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
- line-height: 1.5;
4
- font-weight: 400;
5
-
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
9
-
10
- font-synthesis: none;
11
- text-rendering: optimizeLegibility;
12
- -webkit-font-smoothing: antialiased;
13
- -moz-osx-font-smoothing: grayscale;
14
- }
15
-
16
- a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
20
- }
21
- a:hover {
22
- color: #535bf2;
23
- }
24
-
25
- body {
26
- margin: 0;
27
- display: flex;
28
- place-items: center;
29
- min-width: 320px;
30
- min-height: 100vh;
31
- }
32
-
33
- h1 {
34
- font-size: 3.2em;
35
- line-height: 1.1;
36
- }
37
-
38
- .card {
39
- padding: 2em;
40
- }
41
-
42
- #app {
43
- max-width: 1280px;
44
- margin: 0 auto;
45
- padding: 2rem;
46
- text-align: center;
47
- }
48
-
49
- button {
50
- border-radius: 8px;
51
- border: 1px solid transparent;
52
- padding: 0.6em 1.2em;
53
- font-size: 1em;
54
- font-weight: 500;
55
- font-family: inherit;
56
- background-color: #1a1a1a;
57
- cursor: pointer;
58
- transition: border-color 0.25s;
59
- }
60
- button:hover {
61
- border-color: #646cff;
62
- }
63
- button:focus,
64
- button:focus-visible {
65
- outline: 4px auto -webkit-focus-ring-color;
66
- }
67
-
68
- @media (prefers-color-scheme: light) {
69
- :root {
70
- color: #213547;
71
- background-color: #ffffff;
72
- }
73
- a:hover {
74
- color: #747bff;
75
- }
76
- button {
77
- background-color: #f9f9f9;
78
- }
79
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/assets/svelte.svg DELETED
src/lib/Counter.svelte DELETED
@@ -1,10 +0,0 @@
1
- <script lang="ts">
2
- let count: number = $state(0)
3
- const increment = () => {
4
- count += 1
5
- }
6
- </script>
7
-
8
- <button onclick={increment}>
9
- count is {count}
10
- </button>
 
 
 
 
 
 
 
 
 
 
 
src/main.ts DELETED
@@ -1,9 +0,0 @@
1
- import { mount } from 'svelte'
2
- import './app.css'
3
- import App from './App.svelte'
4
-
5
- const app = mount(App, {
6
- target: document.getElementById('app')!,
7
- })
8
-
9
- export default app
 
 
 
 
 
 
 
 
 
 
src/vite-env.d.ts DELETED
@@ -1,2 +0,0 @@
1
- /// <reference types="svelte" />
2
- /// <reference types="vite/client" />
 
 
 
static/signatures/fake-autograph-samples-hand-drawn-signatures-examples-of-documents-certificates-and-contracts-with-inked-and-handwritten-lettering-vector.jpg ADDED

Git LFS Details

  • SHA256: d217d350b539ed4e78828029a6f1429de17870099ec2967cb8d6b4de09fb2b06
  • Pointer size: 130 Bytes
  • Size of remote file: 37.9 kB
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 ADDED

Git LFS Details

  • SHA256: f3da3c5c4945b53da41e861075a1edb8e5ac09d81492b5d1dfd47bfdfa602cc5
  • Pointer size: 130 Bytes
  • Size of remote file: 41 kB
static/signatures/images.png ADDED
static/signatures/signature-certificate-document-vector-transparent-260nw-2346804443.jpg ADDED

Git LFS Details

  • SHA256: fa8ab4ae59c11267822413d07b2a928838c0dea998eabeafdf4facb801dc6c6c
  • Pointer size: 129 Bytes
  • Size of remote file: 8.73 kB
static/signatures/signature-vector-hand-drawn-autograph-600nw-2387543207.jpg ADDED

Git LFS Details

  • SHA256: 652082d4a12b0e42583d9fea62032a20eb23dd181d24b7bb60495db85ca31d11
  • Pointer size: 130 Bytes
  • Size of remote file: 11.8 kB
static/uploads/02af69ed359f4d27b46ca3cfc814288b_IMG_0082.jpg ADDED

Git LFS Details

  • SHA256: 7ce954d7cef59dd695b6b825b8b6268ef12b3898bfd431a422a58979ed6b7e9c
  • Pointer size: 132 Bytes
  • Size of remote file: 2.09 MB
static/uploads/0bc297f68f84453f8e5630a45d3baf83_vio-4.jpg ADDED

Git LFS Details

  • SHA256: 95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4
  • Pointer size: 130 Bytes
  • Size of remote file: 50.6 kB
static/uploads/1*3xUyINxRtDf2qowd-kkGQA.jpg ADDED

Git LFS Details

  • SHA256: 097786a9aded24b704b0997eb19c44bc6a2fc2033bd3a7b05099740cd85be33e
  • Pointer size: 131 Bytes
  • Size of remote file: 175 kB
static/uploads/255d2936a26d49429c21ce6b06b323b7_vio-4.jpg ADDED

Git LFS Details

  • SHA256: 95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4
  • Pointer size: 130 Bytes
  • Size of remote file: 50.6 kB
static/uploads/2b090d65e18f4e1ba1a048c6a2722d03_vio-4.jpg ADDED

Git LFS Details

  • SHA256: 95cfc9d07bfe93f0f8cab14ef8829f5c3881eb06df7c23f81650a500225185c4
  • Pointer size: 130 Bytes
  • Size of remote file: 50.6 kB