Skip to content

Commit 87eac74

Browse files
committed
first commit
0 parents  commit 87eac74

18 files changed

+322
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
3+
.env

__pycache__/constants.cpython-312.pyc

402 Bytes
Binary file not shown.

__pycache__/main.cpython-312.pyc

1.51 KB
Binary file not shown.

__pycache__/schemareq.cpython-312.pyc

471 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

apps/calculator/image.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from fastapi import APIRouter
2+
import base64
3+
from io import BytesIO
4+
from schemareq import ImageData
5+
from apps.calculator.utils2 import understand_image
6+
from apps.calculator.utils3 import generate_image
7+
from PIL import Image
8+
9+
router=APIRouter()
10+
11+
@router.post('')
12+
async def run(imageData:ImageData):
13+
image_data=base64.b64decode(imageData.image.split(",")[1])
14+
image_bytes=BytesIO(image_data)
15+
image=Image.open(image_bytes)
16+
responses=understand_image(img=image,dict_of_vars=imageData.dict_of_vars)
17+
18+
data=[]
19+
for response in responses:
20+
data.append(response)
21+
22+
##image_details=str(response)
23+
24+
print('response in route: ', response.get("Attributes"))
25+
attributes=response.get("Attributes")
26+
primary_object=response.get("Primary Object")
27+
context=response.get("Context")
28+
style_notes=response.get("Style Notes")
29+
30+
generated_image=generate_image(attributes,primary_object,context,style_notes);
31+
32+
buffer = BytesIO()
33+
generated_image.save(buffer, format="PNG")
34+
buffer.seek(0)
35+
base64_image = base64.b64encode(buffer.getvalue()).decode("utf-8")
36+
37+
return {"message": "Image processed", "data": data, "status": "success","image": f"data:image/png;base64,{base64_image}",}

apps/calculator/route.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from fastapi import APIRouter
2+
import base64
3+
from io import BytesIO
4+
from schemareq import ImageData
5+
from apps.calculator.utils import analyze_image
6+
from PIL import Image
7+
8+
router=APIRouter()
9+
10+
@router.post('')
11+
async def run(imageData:ImageData):
12+
image_data=base64.b64decode(imageData.image.split(",")[1])
13+
image_bytes=BytesIO(image_data)
14+
image=Image.open(image_bytes)
15+
responses=analyze_image(img=image,dict_of_vars=imageData.dict_of_vars)
16+
17+
data=[]
18+
for response in responses:
19+
data.append(response)
20+
print('response in route: ', response)
21+
return {"message": "Image processed", "data": data, "status": "success"}
22+
23+

apps/calculator/utils.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import google.generativeai as genai
2+
import os
3+
from dotenv import load_dotenv
4+
import ast
5+
import json
6+
from PIL import Image
7+
8+
load_dotenv()
9+
10+
gemini_api_key=os.getenv("GEMINI_API_KEY")
11+
12+
genai.configure(api_key=gemini_api_key)
13+
14+
def analyze_image(img: Image, dict_of_vars: dict):
15+
model = genai.GenerativeModel(model_name="gemini-1.5-flash")
16+
dict_of_vars_str = json.dumps(dict_of_vars, ensure_ascii=False)
17+
prompt = (
18+
f"You are an advanced mathematical problem solver tasked with analyzing and solving mathematical expressions from images. "
19+
20+
f"Mathematical Expression Rules:\\n"
21+
f"Follow the PEMDAS rule for solving all mathematical expressions:\\n"
22+
f"- P: Parentheses (highest priority)\\n"
23+
f"- E: Exponents\\n"
24+
f"- M/D: Multiplication and Division (left to right)\\n"
25+
f"- A/S: Addition and Subtraction (left to right)\\n\\n"
26+
27+
f"Examples with Detailed Solutions:\\n"
28+
f"1. Expression: 2 + 3 * 4\\n"
29+
f" Step-by-step solution:\\n"
30+
f" - First multiply: 3 * 4 = 12 (multiplication before addition)\\n"
31+
f" - Then add: 2 + 12 = 14\\n"
32+
f" Final answer: 14\\n\\n"
33+
34+
f"2. Expression: 2 + 3 + 5 * 4 - 8 / 2\\n"
35+
f" Step-by-step solution:\\n"
36+
f" - First handle multiplication: 5 * 4 = 20\\n"
37+
f" - Then division: 8 / 2 = 4\\n"
38+
f" - Finally, perform addition and subtraction left to right: 2 + 3 + 20 - 4 = 21\\n"
39+
f" Final answer: 21\\n\\n"
40+
41+
42+
f"Problem Types and Return Formats:\\n\\n"
43+
44+
f"1. Simple Mathematical Expressions\\n"
45+
f" Input example: 2 + 2, 3 * 4, etc.\\n"
46+
f" Return format: [{{'expr': 'given_expression', 'result': calculated_answer}}]\\n"
47+
f" Example: [{{'expr': '2 + 2', 'result': 4}}]\\n\\n"
48+
49+
f"2. Systems of Equations\\n"
50+
f" Input example: x^2 + 2x + 1 = 0, 3y + 4x = 0\\n"
51+
f" Return format: [{{'expr': 'x', 'result': value1, 'assign': True}}, "
52+
f" {{'expr': 'y', 'result': value2, 'assign': True}}]\\n\\n"
53+
54+
f"3. Variable Assignments\\n"
55+
f" Input example: x = 4, y = 5\\n"
56+
f" Return format: [{{'expr': 'x', 'result': 4, 'assign': True}}]\\n\\n"
57+
58+
f"4. Graphical Math Problems\\n"
59+
f" Description: Problems represented through drawings (collisions, triangles, etc.)\\n"
60+
f" Special instruction: Consider color variations in drawings\\n"
61+
f" Return format: [{{'expr': 'problem_description', 'result': calculated_answer}}]\\n\\n"
62+
63+
f"5. Abstract Concept Detection\\n"
64+
f" Description: Identifying abstract concepts from drawings\\n"
65+
f" Return format: [{{'expr': 'drawing_explanation', 'result': 'abstract_concept'}}]\\n\\n"
66+
67+
f"Variable Resolution Rules:\\n"
68+
f"- Use this dictionary for pre-assigned variables: {dict_of_vars_str}\\n"
69+
f"- Replace all variables with their corresponding values before computation\\n"
70+
f"- If a variable is not found in the dictionary, treat it as an unknown to be solved\\n\\n"
71+
72+
f"DO NOT USE BACKTICKS OR MARKDOWN FORMATTING. "
73+
f"PROPERLY QUOTE THE KEYS AND VALUES IN THE DICTIONARY FOR EASIER PARSING WITH Python's ast.literal_eval."
74+
)
75+
76+
response = model.generate_content([prompt, img])
77+
print(response.text)
78+
answers = []
79+
try:
80+
answers = ast.literal_eval(response.text)
81+
except Exception as e:
82+
print(f"Error in parsing response from Gemini API: {e}")
83+
print('returned answer ', answers)
84+
for answer in answers:
85+
if 'assign' in answer:
86+
answer['assign'] = True
87+
else:
88+
answer['assign'] = False
89+
return answers
90+

apps/calculator/utils2.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import google.generativeai as genai
2+
import os
3+
from dotenv import load_dotenv
4+
import ast
5+
from PIL import Image
6+
7+
load_dotenv()
8+
9+
gemini_api_key=os.getenv("GEMINI_API_KEY")
10+
11+
genai.configure(api_key=gemini_api_key)
12+
13+
def understand_image(img: Image, dict_of_vars: dict):
14+
model = genai.GenerativeModel(model_name="gemini-1.5-flash")
15+
prompt = (
16+
f"You are an AI model designed to analyze and interpret drawings provided by users. "
17+
18+
f"Primary Object Identification:\\n"
19+
f"Identify the main object or theme depicted in the drawing. Be creative but stay grounded in the details of the image.\\n\\n"
20+
21+
f"Attributes Description:\\n"
22+
f"Describe key characteristics of the drawing such as shape, size, texture, or patterns. Consider any distinct visual features that stand out.\\n\\n"
23+
24+
f"Contextual Details:\\n"
25+
f"Add possible context based on the drawing. This can include the environment, setting, or mood of the image. If there are interactions or relationships between objects, mention them.\\n\\n"
26+
27+
f"Style Notes:\\n"
28+
f"Describe the style of the drawing, if any. Is it sketchy, detailed, minimalist, or abstract? Also, note the perspective (e.g., top-down view, side view, etc.) and any specific artistic techniques used.\\n\\n"
29+
30+
f"Return Format: [{{'Primary Object': 'description', 'Attributes': 'description', 'Context': 'description', 'Style Notes': 'description'}}]\\n"
31+
f"Example: [{{'Primary Object': 'tree', 'Attributes': 'a simple tree with a trunk and leafy branches', 'Context': 'the tree is drawn against a plain background', 'Style Notes': 'sketched with basic lines and no shading'}}]\\n\\n"
32+
33+
f"DO NOT USE BACKTICKS OR MARKDOWN FORMATTING. "
34+
f"PROPERLY QUOTE THE KEYS AND VALUES IN THE DICTIONARY FOR EASIER PARSING WITH Python's ast.literal_eval."
35+
)
36+
37+
response = model.generate_content([prompt, img])
38+
39+
answers = []
40+
try:
41+
answers = ast.literal_eval(response.text)
42+
except Exception as e:
43+
print(f"Error in parsing response from Gemini API: {e}")
44+
45+
for answer in answers:
46+
if 'assign' in answer:
47+
answer['assign'] = True
48+
else:
49+
answer['assign'] = False
50+
51+
return answers;
52+
53+
54+

apps/calculator/utils3.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import os
2+
from PIL import Image
3+
from io import BytesIO
4+
import requests
5+
from urllib.parse import quote
6+
from dotenv import load_dotenv
7+
import google.generativeai as genai
8+
9+
load_dotenv()
10+
11+
gemini_api_key = os.getenv("GEMINI_API_KEY")
12+
genai.configure(api_key=gemini_api_key)
13+
14+
def generate_image(attributes: str, primary_object: str, context: str, style_notes: str):
15+
final_prompt = f"Create an image of a {attributes} {primary_object} {context}. "
16+
if style_notes:
17+
final_prompt += f"Style: {style_notes}. "
18+
19+
enhanced_prompt = (
20+
f"{final_prompt}, "
21+
"high resolution, highly detailed, sharp focus, "
22+
"professional photography, cinematic lighting, "
23+
"8k uhd, ray tracing, ambient lighting"
24+
)
25+
26+
negative_prompt = (
27+
"blurry, low quality, low resolution, "
28+
"watermark, signature, oversaturated, "
29+
"distorted, deformed, pixelated"
30+
)
31+
32+
base_url = "https://image.pollinations.ai/prompt"
33+
encoded_prompt = quote(enhanced_prompt)
34+
url = f"{base_url}/{encoded_prompt}"
35+
36+
params = {
37+
"width": 1024,
38+
"height": 1024,
39+
"model": "flux-pro",
40+
"sampler": "DPM++ SDE Karras",
41+
"enhance": True,
42+
"nologo": True,
43+
"negative_prompt": negative_prompt,
44+
"upscale": True,
45+
"upscale_amount": "2",
46+
}
47+
48+
try:
49+
response = requests.get(url, params=params, stream=True)
50+
response.raise_for_status()
51+
except requests.exceptions.RequestException as e:
52+
print(f"Request failed: {e}")
53+
return None
54+
if response.status_code == 200:
55+
image = Image.open(BytesIO(response.content))
56+
return image
57+
else:
58+
print(f"Error: {response.status_code} - {response.text}")
59+
return None
60+
61+

constants.py

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import os
2+
from dotenv import load_dotenv
3+
load_dotenv()
4+
5+
SERVER_URL = 'localhost'
6+
PORT = '8900'
7+
ENV = 'dev'
8+
9+
GEMINI_API_KEY =os.getenv("GEMINI_API_KEY")

main.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from contextlib import asynccontextmanager
2+
from fastapi import FastAPI
3+
from fastapi.middleware.cors import CORSMiddleware
4+
import uvicorn
5+
from constants import SERVER_URL,PORT,ENV
6+
from apps.calculator.route import router as calculator_router
7+
from apps.calculator.image import router as image_router
8+
9+
@asynccontextmanager
10+
async def lifespan(app:FastAPI):
11+
yield
12+
13+
14+
app=FastAPI(lifespan=lifespan)
15+
16+
app.add_middleware(
17+
CORSMiddleware,
18+
allow_origins=["*"],
19+
allow_credentials=True,
20+
allow_methods=["*"],
21+
allow_headers=["*"],
22+
)
23+
24+
@app.get("/")
25+
async def root():
26+
return {"server is running good"}
27+
28+
app.include_router(calculator_router,prefix="/calculate",tags=["calculate"])
29+
app.include_router(image_router,prefix="/generate",tags=["generate"])
30+
31+
if __name__ == "__main__":
32+
import uvicorn
33+
uvicorn.run(app, host=SERVER_URL, port=int(PORT),reload=(ENV=="dev"))

requirements.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
google-generativeai
2+
uvicorn
3+
pydantic
4+
fastapi
5+
Pillow
6+
python-dotenv
7+
requests

schemareq.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from pydantic import BaseModel
2+
3+
class ImageData(BaseModel):
4+
image:str
5+
dict_of_vars:dict

0 commit comments

Comments
 (0)