Venkat V commited on
Commit
ff2cc46
Β·
1 Parent(s): 6baf36d

plumbing code for streamlit, fast api

Browse files
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
app.py CHANGED
@@ -1 +1,72 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ from fastapi import FastAPI, UploadFile, File,Form
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.responses import JSONResponse
5
+ import uvicorn
6
+ from PIL import Image
7
+ import io
8
+ import json
9
+
10
+ # Import your pipeline modules
11
+ from yolo_module import run_yolo
12
+ from ocr_module import extract_text
13
+ from graph_module import map_arrows, build_flowchart_json
14
+ from summarizer_module import summarize_flowchart
15
+
16
+ app = FastAPI()
17
+
18
+ # CORS for Streamlit access
19
+ app.add_middleware(
20
+ CORSMiddleware,
21
+ allow_origins=["*"],
22
+ allow_credentials=True,
23
+ allow_methods=["*"],
24
+ allow_headers=["*"],
25
+ )
26
+
27
+ @app.post("/process-image")
28
+ async def process_image(file: UploadFile = File(...), debug: str = Form("false")):
29
+ debug_mode = debug.lower() == "true"
30
+
31
+ debug_log = []
32
+ if debug_mode: debug_log.append("πŸ“₯ Received file: file")
33
+ print("πŸ“₯ Received file:", file.filename)
34
+
35
+
36
+ contents = await file.read()
37
+ image = Image.open(io.BytesIO(contents)).convert("RGB")
38
+ if debug_mode: debug_log.append("βœ… Image loaded and converted to RGB")
39
+ print("βœ… Image loaded and converted to RGB")
40
+
41
+ # Step 1: Run YOLO detection
42
+ boxes, arrows = run_yolo(image)
43
+ if debug_mode: debug_log.append(f"πŸ“¦ YOLO detected {len(boxes)} boxes and {len(arrows)} arrows")
44
+
45
+ # Step 2: OCR on boxes
46
+ for box in boxes:
47
+ box["text"] = extract_text(image, box["bbox"])
48
+ if debug_mode: debug_log.append(f"πŸ” OCR text for box {box['id']}: {box['text']}")
49
+ print(f"πŸ” OCR text for box {box['id']}: {box['text']}")
50
+
51
+ # Step 3: Map arrows to boxes and build graph
52
+ edges = map_arrows(boxes, arrows)
53
+ if debug_mode: debug_log.append(f"🧭 Mapped {len(edges)} edges from arrows to boxes")
54
+ flowchart_json = build_flowchart_json(boxes, edges)
55
+ print("🧠 Flowchart JSON structure:")
56
+ print(json.dumps(flowchart_json, indent=2))
57
+
58
+
59
+
60
+ # Step 4: Summarize flowchart in English
61
+ summary = summarize_flowchart(flowchart_json)
62
+ print("πŸ“ Generated English summary:")
63
+ print(summary)
64
+
65
+ return JSONResponse({
66
+ "flowchart": flowchart_json,
67
+ "summary": summary,
68
+ "debug": "\n".join(debug_log) if debug_mode else ""
69
+ })
70
+
71
+ if __name__ == "__main__":
72
+ uvicorn.run(app, host="0.0.0.0", port=7860)
graph_module/.DS_Store ADDED
Binary file (6.15 kB). View file
 
graph_module/__init__.py CHANGED
@@ -1 +1,79 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # flowchart_builder.py
2
+
3
+ from shapely.geometry import box, Point
4
+
5
+
6
+ def map_arrows(nodes, arrows):
7
+ """
8
+ Matches arrows to source and target nodes based on geometric positions.
9
+ Returns a list of edges as (source_id, target_id).
10
+ """
11
+ for node in nodes:
12
+ node["shape"] = box(*node["bbox"])
13
+
14
+ edges = []
15
+ for arrow in arrows:
16
+ tail_point = Point(arrow["tail"])
17
+ head_point = Point(arrow["head"])
18
+
19
+ source = next((n["id"] for n in nodes if n["shape"].contains(tail_point)), None)
20
+ target = next((n["id"] for n in nodes if n["shape"].contains(head_point)), None)
21
+
22
+ if source and target:
23
+ edges.append((source, target))
24
+ return edges
25
+
26
+
27
+ def build_flowchart_json(nodes, edges):
28
+ """
29
+ Builds a structured JSON from node and edge data.
30
+ """
31
+ # Step 1: Build graph
32
+ graph = {n["id"]: {"text": n.get("text", ""), "type": n["type"], "next": []} for n in nodes}
33
+ for source, target in edges:
34
+ graph[source]["next"].append(target)
35
+
36
+ # Step 2: Build flowchart JSON format
37
+ flowchart_json = {
38
+ "start": next((n["id"] for n in nodes if n["type"] == "start"), None),
39
+ "steps": []
40
+ }
41
+
42
+ for node_id, info in graph.items():
43
+ step = {
44
+ "id": node_id,
45
+ "text": info["text"],
46
+ "type": info["type"]
47
+ }
48
+ if info["type"] == "decision" and len(info["next"]) >= 2:
49
+ step["branches"] = {
50
+ "yes": info["next"][0],
51
+ "no": info["next"][1]
52
+ }
53
+ elif len(info["next"]) == 1:
54
+ step["next"] = info["next"][0]
55
+ flowchart_json["steps"].append(step)
56
+
57
+ return flowchart_json
58
+
59
+
60
+ # Example usage
61
+ if __name__ == "__main__":
62
+ nodes = [
63
+ {"id": "node1", "bbox": [100, 100, 200, 150], "text": "Start", "type": "start"},
64
+ {"id": "node2", "bbox": [300, 100, 400, 150], "text": "Is valid?", "type": "decision"},
65
+ {"id": "node3", "bbox": [500, 50, 600, 100], "text": "Approve", "type": "process"},
66
+ {"id": "node4", "bbox": [500, 150, 600, 200], "text": "Reject", "type": "process"}
67
+ ]
68
+
69
+ arrows = [
70
+ {"id": "arrow1", "tail": (200, 125), "head": (300, 125)},
71
+ {"id": "arrow2", "tail": (400, 125), "head": (500, 75)},
72
+ {"id": "arrow3", "tail": (400, 125), "head": (500, 175)}
73
+ ]
74
+
75
+ edges = map_arrows(nodes, arrows)
76
+ flowchart_json = build_flowchart_json(nodes, edges)
77
+
78
+ import json
79
+ print(json.dumps(flowchart_json, indent=2))
ocr_module/__init__.py CHANGED
@@ -1 +1,18 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytesseract
2
+ from PIL import Image
3
+
4
+ def extract_text(image, bbox):
5
+ """
6
+ Run OCR on a cropped region of the image.
7
+
8
+ Parameters:
9
+ image (PIL.Image): The full image.
10
+ bbox (list): [x1, y1, x2, y2] coordinates of the region to crop.
11
+
12
+ Returns:
13
+ str: Extracted text.
14
+ """
15
+ x1, y1, x2, y2 = bbox
16
+ cropped = image.crop((x1, y1, x2, y2))
17
+ text = pytesseract.image_to_string(cropped).strip()
18
+ return text
requirements.txt CHANGED
@@ -4,3 +4,5 @@ pillow
4
  shapely
5
  pytesseract
6
  transformers
 
 
 
4
  shapely
5
  pytesseract
6
  transformers
7
+ torch
8
+ python-multipart
streamlit_app.py CHANGED
@@ -1 +1,65 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # streamlit_app.py
2
+ import streamlit as st
3
+ import requests
4
+ import json
5
+ from PIL import Image
6
+ import io
7
+
8
+ API_URL = "http://localhost:7860/process-image" # Change if hosted elsewhere
9
+
10
+ st.set_page_config(page_title="Flowchart to English", layout="wide")
11
+ st.title("πŸ“„ Flowchart to Plain English")
12
+
13
+ # Debug mode switch
14
+ debug_mode = st.toggle("πŸ”§ Show Debug Info", value=False)
15
+
16
+ uploaded_file = st.file_uploader("Upload a flowchart image", type=["png", "jpg", "jpeg"])
17
+
18
+ if uploaded_file:
19
+ # Resize image for smaller canvas
20
+ image = Image.open(uploaded_file)
21
+ max_width = 600
22
+ ratio = max_width / float(image.size[0])
23
+ new_height = int((float(image.size[1]) * float(ratio)))
24
+ resized_image = image.resize((max_width, new_height))
25
+ st.image(resized_image, caption="Uploaded Image", use_container_width=False)
26
+
27
+ if st.button("πŸ” Analyze Flowchart"):
28
+ progress = st.progress(0, text="Sending image to backend...")
29
+
30
+ try:
31
+ response = requests.post(
32
+ API_URL,
33
+ files={"file": uploaded_file.getvalue()},
34
+ data={"debug": str(debug_mode).lower()}
35
+ )
36
+ progress.progress(50, text="Processing detection, OCR, and reasoning...")
37
+
38
+ if response.status_code == 200:
39
+ data = response.json()
40
+ progress.progress(80, text="Generating explanation using LLM...")
41
+
42
+ # Display debug summary from backend (conditionally)
43
+ if debug_mode:
44
+ debug_info = data.get("debug", "No debug info available.")
45
+ st.markdown("### πŸ§ͺ Debug Pipeline Info")
46
+ st.code(debug_info, language="markdown")
47
+
48
+ # Display side-by-side columns
49
+ col1, col2 = st.columns(2)
50
+
51
+ with col1:
52
+ st.subheader("🧠 Flowchart JSON")
53
+ st.json(data["flowchart"])
54
+
55
+ with col2:
56
+ st.subheader("πŸ“ English Summary")
57
+ st.markdown(data["summary"])
58
+
59
+ progress.progress(100, text="Done!")
60
+ else:
61
+ st.error(f"Something went wrong: {response.status_code}")
62
+ except Exception as e:
63
+ st.error(f"An error occurred: {e}")
64
+ else:
65
+ st.info("Upload a flowchart image to begin.")
summarizer_module/__init__.py CHANGED
@@ -1 +1,34 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # summarizer_module/__init__.py
2
+
3
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
4
+
5
+ # Use a small local model (e.g., Phi-2)
6
+ MODEL_ID = "microsoft/phi-2" # Ensure it's downloaded and cached locally
7
+
8
+ # Load model and tokenizer
9
+ model = AutoModelForCausalLM.from_pretrained(MODEL_ID)
10
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
11
+ summarizer = pipeline("text-generation", model=model, tokenizer=tokenizer)
12
+
13
+ def summarize_flowchart(flowchart_json):
14
+ """
15
+ Given a flowchart JSON with 'start' and 'steps', returns a plain English explanation
16
+ formatted as bullets and sub-bullets.
17
+
18
+ Args:
19
+ flowchart_json (dict): Structured representation of flowchart
20
+
21
+ Returns:
22
+ str: Bullet-style natural language summary of the logic
23
+ """
24
+ prompt = (
25
+ "Turn the following flowchart into a bullet-point explanation in plain English.\n"
26
+ "Use bullets for steps and sub-bullets for branches.\n"
27
+ "\n"
28
+ f"Flowchart JSON:\n{flowchart_json}\n"
29
+ "\nExplanation:"
30
+ )
31
+
32
+ result = summarizer(prompt, max_new_tokens=300, do_sample=False)[0]["generated_text"]
33
+ explanation = result.split("Explanation:")[-1].strip()
34
+ return explanation
yolo_module/__init__.py CHANGED
@@ -1 +1,16 @@
1
- # Placeholder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # yolo_module/__init__.py
2
+
3
+ def run_yolo(image):
4
+ """
5
+ Placeholder YOLO inference function.
6
+ In actual implementation, load your model and return detected boxes/arrows.
7
+ """
8
+ # For now, return dummy values
9
+ boxes = [
10
+ {"id": "node1", "bbox": [100, 100, 200, 150], "text": "", "type": "start"},
11
+ {"id": "node2", "bbox": [300, 100, 400, 150], "text": "", "type": "decision"},
12
+ ]
13
+ arrows = [
14
+ {"id": "arrow1", "tail": (200, 125), "head": (300, 125)}
15
+ ]
16
+ return boxes, arrows