Sunil Surendra Singh
commited on
Commit
β’
7ef4827
1
Parent(s):
c803eb6
cleint and server code integrated
Browse files- .gitattributes +2 -0
- .github/workflows/main.yml +1 -1
- Dockerfile +12 -0
- README.md +17 -4
- assets/title.jpeg +3 -0
- assets/wip.jpg +3 -0
- requirements.txt +0 -2
- server_requirements.txt +4 -0
- src/app_config.py +0 -15
- src/client.py +12 -7
- src/server.py +12 -5
- src/server_config.py +29 -0
.gitattributes
CHANGED
@@ -1 +1,3 @@
|
|
1 |
*.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
1 |
*.png filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
.github/workflows/main.yml
CHANGED
@@ -16,4 +16,4 @@ jobs:
|
|
16 |
- name: Push to hub
|
17 |
env:
|
18 |
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
19 |
-
run: git push --force https://sssingh:$HF_TOKEN@huggingface.co/spaces/sssingh/
|
|
|
16 |
- name: Push to hub
|
17 |
env:
|
18 |
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
19 |
+
run: git push --force https://sssingh:$HF_TOKEN@huggingface.co/spaces/sssingh/guruzee main
|
Dockerfile
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.10
|
2 |
+
|
3 |
+
WORKDIR app
|
4 |
+
|
5 |
+
COPY server_requirements.txt .
|
6 |
+
RUN pip install -r server_requirements.txt
|
7 |
+
|
8 |
+
COPY src/server_config.py .
|
9 |
+
COPY src/server.py .
|
10 |
+
COPY .env .
|
11 |
+
|
12 |
+
CMD ["uvicorn", "server:guruzee", "--host=0.0.0.0", "--port=8000"]
|
README.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1 |
-
|
2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
## Introduction
|
5 |
GuruZee, your go-to guru for primary school math (for now).
|
@@ -20,7 +33,7 @@ Solve a problem
|
|
20 |
just select one of the pre-configured `Example` image from Example section at the
|
21 |
bottom. The answer and explanation will appear on the right.
|
22 |
|
23 |
-
<img src="https://github.com/sssingh/guruzee/blob/main/assets/
|
24 |
|
25 |
Prepare questions and answers
|
26 |
-----------------------------
|
@@ -30,5 +43,5 @@ just select one the pre-configured `Example` image from Example section in the b
|
|
30 |
The answer and explanation will appear on the right.
|
31 |
|
32 |
## App Architecture
|
33 |
-
|
34 |
|
|
|
1 |
+
|
2 |
+
title: Guruzee
|
3 |
+
emoji: π
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: red
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 4.4.1
|
8 |
+
app_file: src/client.py
|
9 |
+
pinned: false
|
10 |
+
license: mit
|
11 |
+
|
12 |
+
# GuruZee
|
13 |
+
***Where Math Meets Marvel with AI Wizardry for Primary School Prowess! π§βπβ¨***
|
14 |
+
|
15 |
+
<img src="https://github.com/sssingh/guruzee/blob/main/assets/title.png?raw=true" width="1000" height="400"/><br><br>
|
16 |
|
17 |
## Introduction
|
18 |
GuruZee, your go-to guru for primary school math (for now).
|
|
|
33 |
just select one of the pre-configured `Example` image from Example section at the
|
34 |
bottom. The answer and explanation will appear on the right.
|
35 |
|
36 |
+
<img src="https://github.com/sssingh/guruzee/blob/main/assets/app-example.png?raw=true" width="1000" height="450"/><br><br>
|
37 |
|
38 |
Prepare questions and answers
|
39 |
-----------------------------
|
|
|
43 |
The answer and explanation will appear on the right.
|
44 |
|
45 |
## App Architecture
|
46 |
+
<img src="https://github.com/sssingh/guruzee/blob/main/assets/wip.jpg?raw=true" width="1000" height="400"/><br><br>
|
47 |
|
assets/title.jpeg
ADDED
Git LFS Details
|
assets/wip.jpg
ADDED
Git LFS Details
|
requirements.txt
CHANGED
@@ -1,5 +1,3 @@
|
|
1 |
-
fastapi
|
2 |
-
uvicorn
|
3 |
requests
|
4 |
pymongo[tls, srv]==4.4.*
|
5 |
gradio==3.45.*
|
|
|
|
|
|
|
1 |
requests
|
2 |
pymongo[tls, srv]==4.4.*
|
3 |
gradio==3.45.*
|
server_requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fastapi
|
2 |
+
uvicorn
|
3 |
+
requests
|
4 |
+
python-dotenv
|
src/app_config.py
CHANGED
@@ -8,28 +8,13 @@ load_dotenv()
|
|
8 |
|
9 |
@dataclass
|
10 |
class __AppConfig:
|
11 |
-
solver_persona = """You an expert primary school maths teacher. Given an
|
12 |
-
image of a primary school maths problem you can analyze the problem and
|
13 |
-
produce a detailed solution with explanation."""
|
14 |
-
teacher_persona = (
|
15 |
-
solver_persona
|
16 |
-
+ """ \nIn addition to this, given a
|
17 |
-
collection images from primary school maths text book you can generate
|
18 |
-
questions and there answers based on the topic shown in text book images,
|
19 |
-
you will provide the detailed answers with explanation"""
|
20 |
-
)
|
21 |
-
solver_instruction = """Analyze the primary school math problem in the the image.
|
22 |
-
Strictly first provide the answer to the problem and then only the solution
|
23 |
-
explanation. Put a newline after each 80 chars"""
|
24 |
openai_max_access_count = 200
|
25 |
openai_curr_access_count = None
|
26 |
mongo_client = None
|
27 |
db = "mydb"
|
28 |
collection = "guruzee-openai-access-counter"
|
29 |
key = "current_count"
|
30 |
-
OPENAI_API_ENDPOINT = os.getenv("OPENAI_API_ENDPOINT")
|
31 |
GURUZEE_API_ENDPOINT = os.getenv("GURUZEE_API_ENDPOINT")
|
32 |
-
OPENAI_KEY = os.getenv("OPENAI_KEY")
|
33 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
34 |
MONGO_CONN_STR = os.getenv("MONGO_CONN_STR")
|
35 |
title = "GuruZee, your go-to guru for primary school math"
|
|
|
8 |
|
9 |
@dataclass
|
10 |
class __AppConfig:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
openai_max_access_count = 200
|
12 |
openai_curr_access_count = None
|
13 |
mongo_client = None
|
14 |
db = "mydb"
|
15 |
collection = "guruzee-openai-access-counter"
|
16 |
key = "current_count"
|
|
|
17 |
GURUZEE_API_ENDPOINT = os.getenv("GURUZEE_API_ENDPOINT")
|
|
|
18 |
HF_TOKEN = os.getenv("HF_TOKEN")
|
19 |
MONGO_CONN_STR = os.getenv("MONGO_CONN_STR")
|
20 |
title = "GuruZee, your go-to guru for primary school math"
|
src/client.py
CHANGED
@@ -25,12 +25,17 @@ def solve(image_path: str):
|
|
25 |
Invokes the GuruZee API passing the raw image bytes and returns the response
|
26 |
to client
|
27 |
"""
|
28 |
-
print(image_path)
|
29 |
image_data = __encode_image(image_path=image_path)
|
30 |
headers = {"Content-Type": "application/json"}
|
31 |
payload = {"data": image_data}
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
|
36 |
def create_interface():
|
@@ -72,8 +77,8 @@ def create_interface():
|
|
72 |
<br>
|
73 |
Select/upload an `Image` containing the problem Then hit
|
74 |
`GO!` button.
|
75 |
-
Alternatively, just select one the pre-configured `Example` image
|
76 |
-
from Example section
|
77 |
<br>
|
78 |
Visit the [project's repo](https://github.com/sssingh/GuruZee)
|
79 |
<br>
|
@@ -147,13 +152,13 @@ def create_interface():
|
|
147 |
],
|
148 |
fn=solve,
|
149 |
inputs=[image],
|
150 |
-
outputs=[answer],
|
151 |
run_on_click=True,
|
152 |
)
|
153 |
submit_button.click(
|
154 |
fn=solve,
|
155 |
inputs=[image],
|
156 |
-
outputs=[answer],
|
157 |
)
|
158 |
clear_button.click(fn=clear, inputs=[], outputs=[image, answer])
|
159 |
image.clear(fn=clear, inputs=[], outputs=[image, answer])
|
|
|
25 |
Invokes the GuruZee API passing the raw image bytes and returns the response
|
26 |
to client
|
27 |
"""
|
|
|
28 |
image_data = __encode_image(image_path=image_path)
|
29 |
headers = {"Content-Type": "application/json"}
|
30 |
payload = {"data": image_data}
|
31 |
+
end_point = config.GURUZEE_API_ENDPOINT + "/solve"
|
32 |
+
response = requests.post(end_point, headers=headers, json=payload)
|
33 |
+
# increment the openai access counter and compute count stats
|
34 |
+
mongo.increment_curr_access_count()
|
35 |
+
max_count = config.openai_max_access_count
|
36 |
+
curr_count = config.openai_curr_access_count
|
37 |
+
available_count = max_count - curr_count
|
38 |
+
return response.json(), max_count, curr_count, available_count
|
39 |
|
40 |
|
41 |
def create_interface():
|
|
|
77 |
<br>
|
78 |
Select/upload an `Image` containing the problem Then hit
|
79 |
`GO!` button.
|
80 |
+
Alternatively, just select one of the pre-configured `Example` image
|
81 |
+
from the Example section at the bottom**
|
82 |
<br>
|
83 |
Visit the [project's repo](https://github.com/sssingh/GuruZee)
|
84 |
<br>
|
|
|
152 |
],
|
153 |
fn=solve,
|
154 |
inputs=[image],
|
155 |
+
outputs=[answer, max_count, curr_count, available_count],
|
156 |
run_on_click=True,
|
157 |
)
|
158 |
submit_button.click(
|
159 |
fn=solve,
|
160 |
inputs=[image],
|
161 |
+
outputs=[answer, max_count, curr_count, available_count],
|
162 |
)
|
163 |
clear_button.click(fn=clear, inputs=[], outputs=[image, answer])
|
164 |
image.clear(fn=clear, inputs=[], outputs=[image, answer])
|
src/server.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import requests
|
2 |
-
from
|
3 |
from fastapi import FastAPI
|
4 |
from pydantic import BaseModel
|
5 |
|
@@ -18,17 +18,17 @@ def __analyze_single_image(image_data: str):
|
|
18 |
image_data = {"url": f"data:image/jpeg;base64,{image_data}"}
|
19 |
headers = {
|
20 |
"Content-Type": "application/json",
|
21 |
-
"Authorization": f"Bearer {
|
22 |
}
|
23 |
payload = {
|
24 |
"model": "gpt-4-vision-preview",
|
25 |
"temperature": 0.2, # low temperature because we want deterministic responses
|
26 |
"messages": [
|
27 |
-
{"role": "system", "content":
|
28 |
{
|
29 |
"role": "user",
|
30 |
"content": [
|
31 |
-
{"type": "text", "text":
|
32 |
{
|
33 |
"type": "image_url",
|
34 |
"image_url": image_data,
|
@@ -39,7 +39,9 @@ def __analyze_single_image(image_data: str):
|
|
39 |
"max_tokens": 600,
|
40 |
}
|
41 |
|
42 |
-
response = requests.post(
|
|
|
|
|
43 |
return response.json()
|
44 |
|
45 |
|
@@ -51,3 +53,8 @@ async def solve(image: SingleImageData):
|
|
51 |
"""
|
52 |
output = __analyze_single_image(image.data)
|
53 |
return output["choices"][0]["message"]["content"]
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import requests
|
2 |
+
from server_config import server_config
|
3 |
from fastapi import FastAPI
|
4 |
from pydantic import BaseModel
|
5 |
|
|
|
18 |
image_data = {"url": f"data:image/jpeg;base64,{image_data}"}
|
19 |
headers = {
|
20 |
"Content-Type": "application/json",
|
21 |
+
"Authorization": f"Bearer {server_config.OPENAI_KEY}",
|
22 |
}
|
23 |
payload = {
|
24 |
"model": "gpt-4-vision-preview",
|
25 |
"temperature": 0.2, # low temperature because we want deterministic responses
|
26 |
"messages": [
|
27 |
+
{"role": "system", "content": server_config.solver_persona},
|
28 |
{
|
29 |
"role": "user",
|
30 |
"content": [
|
31 |
+
{"type": "text", "text": server_config.solver_instruction},
|
32 |
{
|
33 |
"type": "image_url",
|
34 |
"image_url": image_data,
|
|
|
39 |
"max_tokens": 600,
|
40 |
}
|
41 |
|
42 |
+
response = requests.post(
|
43 |
+
server_config.OPENAI_API_ENDPOINT, headers=headers, json=payload
|
44 |
+
)
|
45 |
return response.json()
|
46 |
|
47 |
|
|
|
53 |
"""
|
54 |
output = __analyze_single_image(image.data)
|
55 |
return output["choices"][0]["message"]["content"]
|
56 |
+
|
57 |
+
|
58 |
+
@guruzee.get("/health")
|
59 |
+
async def health():
|
60 |
+
return {"Message": "Healthy and kicking!"}
|
src/server_config.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
from dataclasses import dataclass
|
4 |
+
|
5 |
+
# load environment variables from .env (only available in dev environment)
|
6 |
+
load_dotenv()
|
7 |
+
|
8 |
+
|
9 |
+
@dataclass
|
10 |
+
class __ServerConfig:
|
11 |
+
solver_persona = """You an expert primary school maths teacher. Given an
|
12 |
+
image of a primary school maths problem you can analyze the problem and
|
13 |
+
produce a detailed solution with explanation."""
|
14 |
+
teacher_persona = (
|
15 |
+
solver_persona
|
16 |
+
+ """ \nIn addition to this, given a
|
17 |
+
collection images from primary school maths text book you can generate
|
18 |
+
questions and there answers based on the topic shown in text book images,
|
19 |
+
you will provide the detailed answers with explanation"""
|
20 |
+
)
|
21 |
+
solver_instruction = """Analyze the primary school math problem in the the image.
|
22 |
+
Strictly first provide the answer to the problem and then only the solution
|
23 |
+
explanation. Put a newline after each 80 chars"""
|
24 |
+
teacher_instruction = """"""
|
25 |
+
OPENAI_API_ENDPOINT = os.getenv("OPENAI_API_ENDPOINT")
|
26 |
+
OPENAI_KEY = os.getenv("OPENAI_KEY")
|
27 |
+
|
28 |
+
|
29 |
+
server_config = __ServerConfig()
|