Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Dockerfile
README.md
*.pyc
*.pyo
*.pyd
__pycache__
.pytest_cache
.env
22 changes: 22 additions & 0 deletions .gcloudignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This file specifies files that are *not* uploaded to Google Cloud
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore

# Python pycache:
__pycache__/
# Ignored by the build system
/setup.cfg
env/
.env
service_account_key.json
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
node_modules/
node_modules/
*.pyc
__pycache__/
instance/
.db
service_account_key.json
semantic_retrieval.py
node_modules
knowledgebase.py
env/
venv
.env
Lib
Scripts
data/
AQA.py
22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Dockerfile
FROM python:3.9.17-bookworm
# Allow statements and log messages to immediately appear in the logs
ENV PYTHONUNBUFFERED True
# Copy local code to the container image.
ENV APP_HOME /back-end
WORKDIR $APP_HOME
COPY . ./

RUN apt-get update && apt-get install -y \
libzbar0 \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir --upgrade pip
RUN pip install --no-cache-dir -r requirements.txt

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
11 changes: 11 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from flask import Flask
import os
from .routes import main
# this file is to run the app, it calls the blueprint of main from init, which calls from route. All this is done so it is modular.

app = Flask(__name__)
app.secret_key = os.getenv('FLASK_SECRET_KEY', 'your_default_secret_key')
app.register_blueprint(main)

if __name__ == "__main__":
app.run(debug=True) # run the app after it's created
9 changes: 9 additions & 0 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
runtime: python39

entrypoint: gunicorn -b :$PORT app:app

handlers:
- url: /static
static_dir: appp/static
- url: /.*
script: auto
Binary file added requirements.txt
Binary file not shown.
109 changes: 109 additions & 0 deletions routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os
import json
from datetime import datetime
from flask import Flask, request, jsonify, Blueprint
import google.generativeai as genai
from google.ai.generativelanguage_v1beta.types import content

main = Blueprint('main', __name__)

#gemini
GENAI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GENAI_API_KEY:
raise ValueError("GEMINI_API_KEY is not set in the environment variables.")

genai.configure(api_key=GENAI_API_KEY)

def send_prompt_to_gemini(prompt):
"""
Sends a prompt to the Gemini API and returns the structured JSON response.
"""
try:
generation_config = {
"temperature": 1,
"top_p": 0.95,
"top_k": 40,
"max_output_tokens": 8192,
"response_schema": content.Schema(
type=content.Type.OBJECT,
properties={
"title": content.Schema(type=content.Type.STRING),
"timestamp_start": content.Schema(type=content.Type.STRING),
"timestamp_end": content.Schema(type=content.Type.STRING),
"location": content.Schema(type=content.Type.STRING),
"description": content.Schema(type=content.Type.STRING),
},
),
"response_mime_type": "application/json",
}

model = genai.GenerativeModel(
model_name="gemini-1.5-flash-8b",
generation_config=generation_config,
)

chat_session = model.start_chat(history=[])
response = chat_session.send_message(prompt)

return response.to_dict()
except Exception as e:
return {"error": str(e)}

@main.route("/process_text", methods=["POST"])
def process_text():
"""
Endpoint to process the selected text from the Chrome extension.
"""
try:
data = request.json
selected_text = data.get("selected_text", "")
if not selected_text:
return jsonify({"error": "selected_text is required"}), 400

today = datetime.now().strftime("%B %d, %Y")
prompt = f"""
I will give you some text that I want you to parse. The text should describe an event.
Please provide a raw JSON response with the following fields:

title: the title of the event.
timestamp_start: a UTC timestamp of when the event starts in the format YYYYMMDDTHHMMSS. If no year is given, default to the upcoming instance of that date.
timestamp_end: a UTC timestamp of when the event ends in the format YYYYMMDDTHHMMSS. (If not given, default to one hour after start.)
location: the location of the event.
description: a short 2-3 sentence description of the event containing any pertinent information or links.

Please parse the following text:
Today's date is {today}. {selected_text}
"""

gemini_response = send_prompt_to_gemini(prompt)

if "error" in gemini_response:
return jsonify(gemini_response), 500

# parse that jawn
title = gemini_response.get("title", "Untitled Event")
timestamp_start = gemini_response.get("timestamp_start")
timestamp_end = gemini_response.get("timestamp_end")
location = gemini_response.get("location", "")
description = gemini_response.get("description", "No description provided.")

if not timestamp_start:
return jsonify({"error": "timestamp_start is missing from the response."}), 400

gcal_link = (
f"https://www.google.com/calendar/render?action=TEMPLATE&text={title}" \
f"&dates={timestamp_start}/{timestamp_end or ''}" \
f"&details={description}" \
f"&location={location}"
)

return jsonify({
"title": title,
"timestamp_start": timestamp_start,
"timestamp_end": timestamp_end,
"location": location,
"description": description,
"gcal_link": gcal_link
})
except Exception as e:
return jsonify({"error": str(e)}), 500