├── migrations ├── alembic │ ├── README │ ├── script.py.mako │ └── env.py └── alembic.ini ├── -r ├── instance ├── plan.jpg └── database.db ├── requirements.txt ├── hospital cash price.xlsx ├── .env.example ├── .vscode └── settings.json ├── .gitignore ├── README.md ├── config.py ├── chunker.py ├── scraper.py ├── database.py ├── post (1).py ├── utils.py ├── models.py ├── beaches.txt ├── post.py ├── vectorizor.py ├── app.py └── json_file.json /migrations/alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /-r: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevGhost511/James-chatbot-backend/HEAD/-r -------------------------------------------------------------------------------- /instance/plan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevGhost511/James-chatbot-backend/HEAD/instance/plan.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevGhost511/James-chatbot-backend/HEAD/requirements.txt -------------------------------------------------------------------------------- /instance/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevGhost511/James-chatbot-backend/HEAD/instance/database.db -------------------------------------------------------------------------------- /hospital cash price.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevGhost511/James-chatbot-backend/HEAD/hospital cash price.xlsx -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DATABASE_URL = "your_elephantsql_url" 2 | DB_USERNAME = "your_username" 3 | DB_PASSWORD = "your_password" 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.inlineSuggest.showToolbar": "onHover", 3 | "python.pythonPath": "venv\\Scripts\\python.exe" 4 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | *.log 3 | *.pyc 4 | __pycache__ 5 | 6 | # Environments 7 | .env 8 | .venv 9 | env/ 10 | venv/ 11 | ENV/ 12 | env.bak/ 13 | venv.bak/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Install necessary python packages 2 | ``` 3 | pip install -r requirements.txt 4 | ``` 5 | 6 | ## Running Locally 7 | 8 | After cloning the repo, put your environmental variables in `.env`. 9 | ``` 10 | OPENAI_API_KEY = 11 | UPLOAD_FOLDER = 12 | SERPER_API_KEY = 13 | STROM_GLASS_API_KEY = 14 | ``` 15 | 16 | Then, run the following in the command line and your application will be available at `http://localhost:5000` 17 | 18 | ```bash 19 | python app.py 20 | ``` 21 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | basedir = os.path.abspath(os.path.dirname(__file__)) 3 | 4 | 5 | class Config(object): 6 | DEBUG = False 7 | TESTING = False 8 | CSRF_ENABLED = True 9 | SECRET_KEY = 'this-really-needs-to-be-changed' 10 | SQLALCHEMY_DATABASE_URI = os.environ['DATABASE_URL'] 11 | 12 | 13 | class ProductionConfig(Config): 14 | DEBUG = False 15 | 16 | 17 | class StagingConfig(Config): 18 | DEVELOPMENT = True 19 | DEBUG = True 20 | 21 | 22 | class DevelopmentConfig(Config): 23 | DEVELOPMENT = True 24 | DEBUG = True 25 | 26 | 27 | class TestingConfig(Config): 28 | TESTING = True -------------------------------------------------------------------------------- /migrations/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from typing import Sequence, Union 9 | 10 | from alembic import op 11 | import sqlalchemy as sa 12 | ${imports if imports else ""} 13 | 14 | # revision identifiers, used by Alembic. 15 | revision: str = ${repr(up_revision)} 16 | down_revision: Union[str, None] = ${repr(down_revision)} 17 | branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} 18 | depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} 19 | 20 | 21 | def upgrade() -> None: 22 | ${upgrades if upgrades else "pass"} 23 | 24 | 25 | def downgrade() -> None: 26 | ${downgrades if downgrades else "pass"} 27 | -------------------------------------------------------------------------------- /chunker.py: -------------------------------------------------------------------------------- 1 | import tiktoken 2 | from langchain.text_splitter import RecursiveCharacterTextSplitter 3 | from langchain.vectorstores import Pinecone 4 | 5 | from langchain.embeddings.openai import OpenAIEmbeddings 6 | import os 7 | from dotenv import load_dotenv 8 | 9 | load_dotenv() 10 | tokenizer = tiktoken.get_encoding('cl100k_base') 11 | OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") 12 | print("Openai---->",OPENAI_API_KEY) 13 | def tiktoken_len(text): 14 | tokens = tokenizer.encode( 15 | text, 16 | disallowed_special=() 17 | ) 18 | return len(tokens) 19 | 20 | def tiktoken_split(text): 21 | splitter = RecursiveCharacterTextSplitter( 22 | chunk_size=1000, 23 | chunk_overlap=20, 24 | length_function=tiktoken_len, 25 | separators=['\n\n', '\n', ' ', ''] 26 | ) 27 | chunks = splitter.split_text(text) 28 | 29 | return chunks 30 | 31 | def getPineconeFromIndex(index_name): 32 | embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) 33 | 34 | docsearch = Pinecone.from_existing_index( 35 | index_name=index_name, embedding= embeddings 36 | ) 37 | return docsearch 38 | 39 | def saveToPinecone(chunks, embeddings, index_name, metalist, ids): 40 | print("Ids---->", ids) 41 | 42 | Pinecone.from_texts(chunks, index_name= index_name, embedding=embeddings, metadatas = metalist, ids = ids) 43 | 44 | print("Success embedding...") 45 | 46 | 47 | -------------------------------------------------------------------------------- /scraper.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | from chunker import tiktoken_split 4 | 5 | # Define a function to scrape the text content from a URL 6 | def scrape_url(url): 7 | try: 8 | # Send a GET request to the URL 9 | response = requests.get(url) 10 | 11 | # Parse the HTML content using BeautifulSoup 12 | soup = BeautifulSoup(response.content, 'html.parser') 13 | 14 | 15 | # Extract the relevant text content from the HTML 16 | text = soup.get_text() 17 | # Preprocess the text content as needed 18 | processed_text = preprocess_text(text) 19 | # print(processed_text) 20 | return processed_text 21 | except : 22 | return False 23 | 24 | # Define a function to preprocess the extracted text content 25 | def preprocess_text(text): 26 | # Clean the text by removing unwanted characters and symbols 27 | cleaned_text = text.replace('\n', ' ').replace('\r', '').strip() 28 | return cleaned_text 29 | 30 | 31 | # Scrape the text content from each URL and store it in a list 32 | def scrape_urls(urls): 33 | # Scrape the text content from each URL 34 | scraped_data = [] 35 | try: 36 | for url in urls: 37 | scraped_text = scrape_url(url) 38 | if scraped_text is False: 39 | return False 40 | scraped_data.append(scraped_text) 41 | return scraped_data 42 | except: 43 | return False 44 | 45 | def get_chunks(url): 46 | chunks = [] 47 | try: 48 | chunks.extend(tiktoken_split(scrape_url(url))) 49 | return chunks 50 | except: 51 | return False 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /database.py: -------------------------------------------------------------------------------- 1 | import os 2 | import psycopg2 3 | import urllib.parse as up 4 | from dotenv import load_dotenv 5 | from flask_sqlalchemy import SQLAlchemy 6 | from app import db 7 | 8 | load_dotenv() 9 | 10 | up.uses_netloc.append("postgres") 11 | url = up.urlparse(os.getenv("DATABASE_URL")) 12 | 13 | # Connect to database 14 | try : 15 | conn = psycopg2.connect(database=url.path[1:], 16 | user = url.username, 17 | password= url.password, 18 | host=url.hostname, 19 | port=url.port) 20 | print(f"Connected to database: {url.path[1:]}") 21 | except : 22 | print(f"Error connecting to database: {os.getenv('DATABASE_URL')}") 23 | 24 | 25 | # Open a cursor to perform database operations 26 | cur = conn.cursor() 27 | def init_db(): 28 | db.create_all() 29 | return True 30 | 31 | 32 | # Execute a command: this creates a new table 33 | # cur.execute('DROP TABLE IF EXISTS books;') 34 | 35 | # cur.execute('DROP TABLE IF EXISTS users;') 36 | 37 | # cur.execute('CREATE TABLE users (id serial PRIMARY KEY,' 38 | # 'title varchar (150) NOT NULL,' 39 | # 'author varchar (50) NOT NULL,' 40 | # 'pages_num integer NOT NULL,' 41 | # 'review text,' 42 | # 'date_added date DEFAULT CURRENT_TIMESTAMP);' 43 | # ) 44 | 45 | # # Insert data into the table 46 | 47 | # cur.execute('INSERT INTO books (title, author, pages_num, review)' 48 | # 'VALUES (%s, %s, %s, %s)', 49 | # ('A Tale of Two Cities', 50 | # 'Charles Dickens', 51 | # 489, 52 | # 'A great classic!') 53 | # ) 54 | 55 | 56 | # cur.execute('INSERT INTO books (title, author, pages_num, review)' 57 | # 'VALUES (%s, %s, %s, %s)', 58 | # ('Anna Karenina', 59 | # 'Leo Tolstoy', 60 | # 864, 61 | # 'Another great classic!') 62 | # ) 63 | 64 | # conn.commit() 65 | 66 | cur.close() 67 | conn.close() -------------------------------------------------------------------------------- /migrations/alembic/env.py: -------------------------------------------------------------------------------- 1 | from logging.config import fileConfig 2 | 3 | from sqlalchemy import engine_from_config 4 | from sqlalchemy import pool 5 | 6 | from alembic import context 7 | 8 | # this is the Alembic Config object, which provides 9 | # access to the values within the .ini file in use. 10 | config = context.config 11 | 12 | # Interpret the config file for Python logging. 13 | # This line sets up loggers basically. 14 | if config.config_file_name is not None: 15 | fileConfig(config.config_file_name) 16 | 17 | # add your model's MetaData object here 18 | # for 'autogenerate' support 19 | # from myapp import mymodel 20 | # target_metadata = mymodel.Base.metadata 21 | target_metadata = None 22 | 23 | # other values from the config, defined by the needs of env.py, 24 | # can be acquired: 25 | # my_important_option = config.get_main_option("my_important_option") 26 | # ... etc. 27 | 28 | 29 | def run_migrations_offline() -> None: 30 | """Run migrations in 'offline' mode. 31 | 32 | This configures the context with just a URL 33 | and not an Engine, though an Engine is acceptable 34 | here as well. By skipping the Engine creation 35 | we don't even need a DBAPI to be available. 36 | 37 | Calls to context.execute() here emit the given string to the 38 | script output. 39 | 40 | """ 41 | url = config.get_main_option("sqlalchemy.url") 42 | context.configure( 43 | url=url, 44 | target_metadata=target_metadata, 45 | literal_binds=True, 46 | dialect_opts={"paramstyle": "named"}, 47 | ) 48 | 49 | with context.begin_transaction(): 50 | context.run_migrations() 51 | 52 | 53 | def run_migrations_online() -> None: 54 | """Run migrations in 'online' mode. 55 | 56 | In this scenario we need to create an Engine 57 | and associate a connection with the context. 58 | 59 | """ 60 | connectable = engine_from_config( 61 | config.get_section(config.config_ini_section, {}), 62 | prefix="sqlalchemy.", 63 | poolclass=pool.NullPool, 64 | ) 65 | 66 | with connectable.connect() as connection: 67 | context.configure( 68 | connection=connection, target_metadata=target_metadata 69 | ) 70 | 71 | with context.begin_transaction(): 72 | context.run_migrations() 73 | 74 | 75 | if context.is_offline_mode(): 76 | run_migrations_offline() 77 | else: 78 | run_migrations_online() 79 | -------------------------------------------------------------------------------- /migrations/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s 8 | # Uncomment the line below if you want the files to be prepended with date and time 9 | # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file 10 | # for all available tokens 11 | # file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s 12 | 13 | # sys.path path, will be prepended to sys.path if present. 14 | # defaults to the current working directory. 15 | prepend_sys_path = . 16 | 17 | # timezone to use when rendering the date within the migration file 18 | # as well as the filename. 19 | # If specified, requires the python>=3.9 or backports.zoneinfo library. 20 | # Any required deps can installed by adding `alembic[tz]` to the pip requirements 21 | # string value is passed to ZoneInfo() 22 | # leave blank for localtime 23 | # timezone = 24 | 25 | # max length of characters to apply to the 26 | # "slug" field 27 | # truncate_slug_length = 40 28 | 29 | # set to 'true' to run the environment during 30 | # the 'revision' command, regardless of autogenerate 31 | # revision_environment = false 32 | 33 | # set to 'true' to allow .pyc and .pyo files without 34 | # a source .py file to be detected as revisions in the 35 | # versions/ directory 36 | # sourceless = false 37 | 38 | # version location specification; This defaults 39 | # to alembic/versions. When using multiple version 40 | # directories, initial revisions must be specified with --version-path. 41 | # The path separator used here should be the separator specified by "version_path_separator" below. 42 | # version_locations = %(here)s/bar:%(here)s/bat:alembic/versions 43 | 44 | # version path separator; As mentioned above, this is the character used to split 45 | # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep. 46 | # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas. 47 | # Valid values for version_path_separator are: 48 | # 49 | # version_path_separator = : 50 | # version_path_separator = ; 51 | # version_path_separator = space 52 | version_path_separator = os # Use os.pathsep. Default configuration used for new projects. 53 | 54 | # set to 'true' to search source files recursively 55 | # in each "version_locations" directory 56 | # new in Alembic version 1.10 57 | # recursive_version_locations = false 58 | 59 | # the output encoding used when revision files 60 | # are written from script.py.mako 61 | # output_encoding = utf-8 62 | 63 | sqlalchemy.url = postgres://wupfyunp:ToNHB7RT2h3L1EUpB0ZFJJKATluoEouZ@berry.db.elephantsql.com/wupfyunp 64 | 65 | 66 | [post_write_hooks] 67 | # post_write_hooks defines scripts or Python functions that are run 68 | # on newly generated revision scripts. See the documentation for further 69 | # detail and examples 70 | 71 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 72 | # hooks = black 73 | # black.type = console_scripts 74 | # black.entrypoint = black 75 | # black.options = -l 79 REVISION_SCRIPT_FILENAME 76 | 77 | # lint with attempts to fix using "ruff" - use the exec runner, execute a binary 78 | # hooks = ruff 79 | # ruff.type = exec 80 | # ruff.executable = %(here)s/.venv/bin/ruff 81 | # ruff.options = --fix REVISION_SCRIPT_FILENAME 82 | 83 | # Logging configuration 84 | [loggers] 85 | keys = root,sqlalchemy,alembic 86 | 87 | [handlers] 88 | keys = console 89 | 90 | [formatters] 91 | keys = generic 92 | 93 | [logger_root] 94 | level = WARN 95 | handlers = console 96 | qualname = 97 | 98 | [logger_sqlalchemy] 99 | level = WARN 100 | handlers = 101 | qualname = sqlalchemy.engine 102 | 103 | [logger_alembic] 104 | level = INFO 105 | handlers = 106 | qualname = alembic 107 | 108 | [handler_console] 109 | class = StreamHandler 110 | args = (sys.stderr,) 111 | level = NOTSET 112 | formatter = generic 113 | 114 | [formatter_generic] 115 | format = %(levelname)-5.5s [%(name)s] %(message)s 116 | datefmt = %H:%M:%S 117 | -------------------------------------------------------------------------------- /post (1).py: -------------------------------------------------------------------------------- 1 | import requests 2 | import schedule 3 | import time 4 | import logging 5 | from openai import OpenAI 6 | import random 7 | 8 | # Setup basic configuration for logging 9 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 10 | 11 | # Hardcoded API key for OpenAI 12 | api_key = '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' 13 | 14 | # Initialize OpenAI client with the API key 15 | client = OpenAI(api_key=api_key) 16 | 17 | # Facebook Page details 18 | page_id = '288361271766168' 19 | access_token = 'EAAYlFUewjJIBO2r6IAWinh0tFEXLSKNaA5w3mE7BUmAK5LgaTMgkvt2JIZCeWYDb0McWxtivdQQhDgcHgE9ZCo1UN8SZCv1VDs1MCXxZC8eMzvDWZCgqxbieGALzhQBG5ZBVqKVR2jlCdGMXX6YNSalNRMtHUdeD4O07ZBZAiICNNebchuitQXK0laCXKWwHLc9PvImKZAIXXdtIP5wZDZD' 20 | 21 | def generate_recipe_and_post(): 22 | logging.info("Starting recipe and post generation process") 23 | 24 | # Read ingredients from file and select 3 random ones 25 | with open('ingredients.txt', 'r') as file: 26 | ingredients = file.readlines() 27 | selected_ingredients = random.sample(ingredients, 3) 28 | ingredients_text = ', '.join([ingredient.strip() for ingredient in selected_ingredients]) 29 | 30 | recipe_prompt = "Create a random meal recipe that includes the following 3 ingredients: " + ingredients_text + ". Ignore the amount of the ingredient you decide. Only respond with the Recipe name and the recipe no text before or after except hashtags that may be popularly clicked." 31 | 32 | try: 33 | logging.info("Generating recipe with prompt") 34 | completion = client.chat.completions.create( 35 | model="gpt-4", 36 | messages=[ 37 | {"role": "system", "content": "You are a helpful assistant."}, 38 | {"role": "user", "content": recipe_prompt} 39 | ] 40 | ) 41 | recipe_text = completion.choices[0].message.content 42 | logging.info("Generated Recipe:\n%s", recipe_text) 43 | except Exception as e: 44 | logging.error("Failed to generate recipe: %s", e) 45 | return 46 | 47 | descriptive_prompt = "Imagine you are making an image of this finished cooked meal next to a uniquely attractive chef (pick female or male random but consistent in the prompt you write and random hair color and random traits every time which equate. skin color etc, unique photo lighting, unique setting etc), respond with a prompt that would generate the image in a text to image generator that uses very descriptive terms." 48 | 49 | try: 50 | logging.info("Generating descriptive prompt for the image") 51 | completion = client.chat.completions.create( 52 | model="gpt-4", 53 | messages=[ 54 | {"role": "system", "content": "You are a chef who returns recipe posts."}, 55 | {"role": "user", "content": descriptive_prompt + " Recipe: " + recipe_text + " including camera and lighting and quality angles of variations and unique image locations. be descriptive like a photographer describing, no rustic"} 56 | ] 57 | ) 58 | image_prompt = completion.choices[0].message.content 59 | logging.info("Generated Descriptive Prompt for Image:\n%s", image_prompt) 60 | except Exception as e: 61 | logging.error("Failed to generate descriptive prompt: %s", e) 62 | return 63 | 64 | try: 65 | logging.info("Generating image for the recipe") 66 | response = client.images.generate( 67 | model="dall-e-3", 68 | prompt=image_prompt, 69 | size="1024x1024", 70 | n=1, 71 | ) 72 | image_url = response.data[0].url 73 | logging.info("Generated Image URL: %s", image_url) 74 | except Exception as e: 75 | logging.error("Failed to generate image: %s", e) 76 | return 77 | 78 | try: 79 | logging.info("Uploading photo to Facebook without publishing") 80 | photo_id = upload_photo_without_publishing(page_id, image_url, recipe_text) # Pass recipe_text here 81 | if photo_id: 82 | logging.info("Publishing photo story with uploaded photo") 83 | publish_photo_story(page_id, photo_id) 84 | logging.info("Posting to Facebook") 85 | publish_photo_with_message(page_id, recipe_text, image_url) 86 | except Exception as e: 87 | logging.error("Failed to post to Facebook: %s", e) 88 | 89 | def upload_photo_without_publishing(page_id, photo_url, caption): 90 | url = f"https://graph.facebook.com/{page_id}/photos" 91 | payload = { 92 | 'url': photo_url, 93 | 'published': 'false', 94 | 'access_token': access_token, 95 | 'caption': caption # Use the passed caption here 96 | } 97 | response = requests.post(url, data=payload) 98 | if response.status_code == 200: 99 | photo_id = response.json().get('id') 100 | logging.info("Successfully uploaded photo without publishing. Photo ID: %s", photo_id) 101 | return photo_id 102 | else: 103 | logging.error("Failed to upload photo without publishing. Response: %s", response.text) 104 | return None 105 | 106 | def publish_photo_story(page_id, photo_id): 107 | url = f"https://graph.facebook.com/{page_id}/photo_stories" 108 | payload = { 109 | 'photo_id': photo_id, 110 | 'access_token': access_token 111 | } 112 | response = requests.post(url, data=payload) 113 | if response.status_code == 200 and response.json().get('success'): 114 | logging.info("Successfully published photo story. Response: %s", response.json()) 115 | else: 116 | logging.error("Failed to publish photo story. Response: %s", response.text) 117 | 118 | def publish_photo_with_message(page_id, message, photo_url): 119 | url = f"https://graph.facebook.com/{page_id}/photos" 120 | payload = { 121 | 'url': photo_url, 122 | 'caption': message, 123 | 'access_token': access_token 124 | } 125 | response = requests.post(url, data=payload) 126 | if response.status_code == 200: 127 | logging.info("Successfully published to Facebook: %s", response.json()) 128 | else: 129 | logging.error("Failed to publish to Facebook. Response: %s", response.text) 130 | 131 | # Call the function immediately for initial execution 132 | generate_recipe_and_post() 133 | 134 | # Schedule the task to run every hour 135 | schedule.every(1).hour.do(generate_recipe_and_post) 136 | 137 | # Run the scheduler indefinitely 138 | if __name__ == "__main__": 139 | while True: 140 | schedule.run_pending() 141 | time.sleep(1) # Sleep for a minute to avoid excessive CPU usage -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | from vectorizor import query_refiner 2 | from scraper import get_chunks 3 | from vectorizor import store_embeddings_in_pinecone, simple_generate, generate_surfing_image 4 | from vectorizor import generate_answer 5 | import pandas 6 | import requests 7 | import os 8 | import openai 9 | import simplejson as json 10 | import openpyxl as xl 11 | from chunker import tiktoken_split 12 | from dotenv import load_dotenv 13 | load_dotenv() 14 | 15 | # Set up STROM_GLASS_API_KEY 16 | STROM_GLASS_API_KEY = '57387656-d281-11ee-8a07-0242ac130002-573876b0-d281-11ee-8a07-0242ac130002' 17 | 18 | 19 | def generate_query(user_id, knowledge_name, chat_history, user_query): 20 | template = """ 21 | The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know current information but provides the latest information. If there is no conversation history, plz provide proper answer automatically based on the query. 22 | The response must be less than 300 words.\n 23 | Knowledge Base:{context}\n 24 | Chat history: {chat_history}\n 25 | Human: {human_input}\n 26 | Your response as Chatbot:""" 27 | 28 | print("Get query....") 29 | answer = generate_answer(query=user_query, user_id = user_id, knowledge_name=knowledge_name, latest_records=chat_history, template=template) 30 | 31 | return answer 32 | 33 | def get_lat_long_for_beach(query): 34 | try: 35 | 36 | prompt = f"Provide the latitude and longitude and the name of the beach the user wants to go surfing in the query. This is the user's query:{query} Only respond in a format like this nothing else. Format: latitude, longitude, name of the place:34.0195, -118.4912, Arugam Bay" 37 | response = simple_generate(prompt) 38 | lat_long = response.split(',') 39 | latitude = lat_long[0].strip() 40 | longitude = lat_long[1].strip() 41 | beach = lat_long[2].strip() 42 | 43 | return latitude, longitude, beach 44 | except Exception as e: 45 | print(str(e)) 46 | return None, None, None 47 | 48 | def get_surf_conditions(lat, long): 49 | print("Strom glass api key ---->", STROM_GLASS_API_KEY) 50 | 51 | response = requests.get( 52 | 'https://api.stormglass.io/v2/weather/point', 53 | params={ 54 | 'lat': lat, 55 | 'lng': long, 56 | 'params': ','.join(['waveHeight', 'waterTemperature', 'windSpeed', 'windDirection']), 57 | }, 58 | headers={ 59 | 'Authorization': STROM_GLASS_API_KEY 60 | } 61 | ) 62 | # Do something with response data. 63 | if response.status_code == 200: 64 | print(f"Received response from StormGlass: {response.json()}") 65 | return response.json() 66 | else: 67 | print(f"Failed to fetch data from StormGlass, Status Code={response.status_code}, Response={response.text}") 68 | return {'error': 'Failed to fetch data', 'status_code': response.status_code} 69 | 70 | def generate_surf_response(query): 71 | try: 72 | surf_instructions, beach = get_weather_data_and_surf_instruction(query) 73 | print("OHeree-----") 74 | if surf_instructions and beach: 75 | hash_tag = generate_hashtags(surf_instructions) 76 | image_url = generate_surfing_image(surf_instructions, beach) 77 | print("Image URL =======>", image_url) 78 | return surf_instructions, image_url, hash_tag 79 | except Exception as e: 80 | print("Failed to generate the response:", e) 81 | return None, None, None 82 | 83 | def get_weather_data_and_surf_instruction(query): 84 | latitude, longitude, beach = get_lat_long_for_beach(query) 85 | if latitude and longitude: 86 | surf_conditions = get_surf_conditions(latitude, longitude) 87 | print("Surfing =====>", surf_conditions) 88 | if 'error' not in surf_conditions: 89 | conditions_str = f"Wave Height: {surf_conditions['hours'][0]['waveHeight']['noaa']}m, Water Temperature: {surf_conditions['hours'][0]['waterTemperature']['noaa']}C, Wind Speed: {surf_conditions['hours'][0]['windSpeed']['noaa']}m/s, Wind Direction: {surf_conditions['hours'][0]['windDirection']['noaa']} degrees" 90 | else: 91 | conditions_str = "No conditions available" 92 | else: 93 | conditions_str = "No conditions available" 94 | 95 | surf_prompt = f"Write a facebook post update for the local surfers. You are a local surf expert at {beach}, considering the current wave conditions, select what size/type of board would be best for these conditions, and provide local tips for surfers based on the following conditions: {conditions_str}. Come up with other tips to say. Only say nice things about the local only if you mention them. The response must be less than 1500 characters" 96 | try: 97 | response = openai.chat.completions.create( 98 | model="gpt-4-turbo-preview", 99 | messages=[ 100 | {"role": "system", "content": "You are a helpful assistant."}, 101 | {"role": "user", "content": surf_prompt} 102 | ] 103 | ) 104 | surf_instructions = response.choices[0].message.content 105 | return surf_instructions, beach 106 | 107 | except Exception as e: 108 | print("Failed to generate surfing content: %s", e) 109 | return None, None 110 | 111 | def generate_hashtags(surf_instructions): 112 | hashtag_prompt = f"Based on the following content, generate relevant hashtags: {surf_instructions}" 113 | 114 | try: 115 | print("Generating hashtags") 116 | response = openai.chat.completions.create( 117 | model="gpt-4-turbo-preview", 118 | messages=[ 119 | {"role": "system", "content": "You are a social media expert. Generate relevant hashtags based on the content."}, 120 | {"role": "user", "content": hashtag_prompt} 121 | ] 122 | ) 123 | hashtags = response.choices[0].message.content 124 | print("Generated Hashtags:\n%s", hashtags) 125 | return hashtags 126 | except Exception as e: 127 | print("Failed to generate hashtags: %s", e) 128 | return None 129 | 130 | def generate_kb_from_xlsx(assistant_id, knowledge_id, path, api_key, index_name): 131 | excel = xl.load_workbook(path) 132 | sheetnames = excel.sheetnames 133 | res = {} 134 | for sheetname in sheetnames: 135 | data = pandas.read_excel("hospital cash price.xlsx", sheet_name=sheetname) 136 | json_data = data.to_json() 137 | res.update({sheetname: json_data}) 138 | str_data = json.dumps(res) 139 | chunks = tiktoken_split(str_data) 140 | metadic ={'knowledge':knowledge_id, 'assistant':assistant_id} 141 | metalist = [] 142 | ids = [] 143 | 144 | for c in enumerate(chunks): 145 | metalist.append(metadic) 146 | ids.append(str(knowledge_id)) 147 | 148 | store_embeddings_in_pinecone(chunks, metalist, api_key, ids, index_name) 149 | return len(chunks) 150 | 151 | def generate_kb_from_file(assistant_id, knowledge_id, path, api_key, index_name): 152 | try: 153 | extension = path.split('.')[-1] 154 | extension = extension.lower() 155 | if extension == 'txt': 156 | count = generate_kb_from_txt(assistant_id=assistant_id, knowledge_id=knowledge_id, path=path, api_key=api_key, index_name=index_name) 157 | os.remove(path) 158 | return count 159 | if extension == 'xlsx' or extension == 'xls': 160 | count = generate_kb_from_xlsx(assistant_id, knowledge_id, path, api_key=api_key, index_name=index_name) 161 | os.remove(path) 162 | return count 163 | return -1 164 | except Exception as e: 165 | print(str(e)) 166 | return -1 167 | 168 | def generate_kb_from_txt(assistant_id, knowledge_id, path, api_key, index_name): 169 | try: 170 | with open(path, encoding='utf8') as f: 171 | content = f.read() 172 | chunks = tiktoken_split(content) 173 | metadic ={'knowledge':knowledge_id, 'assistant':assistant_id} 174 | metalist = [] 175 | ids = [] 176 | for index, chunk in enumerate(chunks): 177 | metalist.append(metadic) 178 | ids.append(str(knowledge_id)+"_"+str(index)) 179 | 180 | store_embeddings_in_pinecone(chunks, metalist, api_key, ids, index_name) 181 | return len(chunks) 182 | except Exception as e: 183 | print(str(e)) 184 | return -1 185 | 186 | def generate_kb_from_url(assistant_id, knowledge_id, url, api_key, index_name): 187 | try: 188 | chunks = get_chunks(url) 189 | if chunks is None: 190 | return False 191 | metadic ={'knowledge':knowledge_id, 'assistant':assistant_id} 192 | print(chunks) 193 | metalist = [] 194 | ids = [] 195 | for index, chunk in enumerate(chunks): 196 | metalist.append(metadic) 197 | ids.append(str(knowledge_id)+"_"+str(index)) 198 | store_embeddings_in_pinecone(chunks, metalist, api_key, ids, index_name) 199 | return len(chunks) 200 | except Exception as e: 201 | print(str(e)) 202 | return -1 203 | 204 | def get_response(query, prompt, latest_records, assistant_id): 205 | 206 | end = """ 207 | Context:{context} 208 | Chat history:{chat_history} 209 | Human: {human_input} 210 | Assistant:""" 211 | template = prompt + end 212 | answer = generate_answer(query=query, assistant_id=assistant_id, latest_records=latest_records, template=template) 213 | 214 | return answer 215 | 216 | def query_without_knowledge(chat_history, user_query): 217 | template = """The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. 218 | Context:{context} 219 | Chat history:{chat_history} 220 | Human: {human_input} 221 | AI:""" 222 | 223 | return "" 224 | -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from flask_sqlalchemy import SQLAlchemy 2 | from sqlalchemy.sql import func 3 | from datetime import datetime 4 | from uuid import uuid4 5 | 6 | db = SQLAlchemy() 7 | 8 | class User(db.Model): 9 | __tablename__ = 'users' 10 | 11 | id = db.Column(db.Integer, primary_key=True, nullable = False, autoincrement = True) 12 | chat_id = db.Column(db.String(), nullable = True) 13 | name = db.Column(db.String(), nullable = False) 14 | email = db.Column(db.String(), unique = True, nullable = False) 15 | password = db.Column(db.String(), nullable = True) 16 | role = db.Column(db.String(), nullable = False, default = 'user') 17 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 18 | 19 | def __init__(self, name, email, password): 20 | self.name = name 21 | self.email = email 22 | self.password = password 23 | 24 | def register_user_if_not_exist(self): 25 | db_user = User.query.filter(User.user_id == self.user_id).all() 26 | if not db_user: 27 | db.session.add(self) 28 | db.session.commit() 29 | return True 30 | 31 | def get_by_username(name): 32 | db_user = User.query.filter(User.name == name).first() 33 | return db_user 34 | 35 | def json(self): 36 | return {'id': self.id, 'name':self.name} 37 | 38 | def __repr__(self): 39 | return f"" 40 | 41 | class ChatId(db.Model): 42 | __tablename__ = 'chat_ids' 43 | 44 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 45 | chat_id = db.Column(db.String(), unique = True, nullable = True) 46 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 47 | 48 | def __init__(self, chat_id): 49 | self.chat_id = chat_id 50 | 51 | def json(self): 52 | return {'id':self.id, 'chat_id': self.chat_id, 'created_at':self.created_at} 53 | 54 | def __repr__(self): 55 | return f"" 56 | 57 | class PrePrompt(db.Model): 58 | __tablename__ = 'preprompts' 59 | 60 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 61 | title = db.Column(db.String(), unique = True, nullable = False) 62 | prompt = db.Column(db.String(), nullable = False) 63 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 64 | assistant_id = db.Column(db.Integer) 65 | 66 | def __init__(self, assistant_id, title, prompt): 67 | self.assistant_id = assistant_id 68 | self.title = title 69 | self.prompt = prompt 70 | 71 | def json(self): 72 | return {'id':self.id,'assistant_id':self.assistant_id, 'title':self.title, 'prompt':self.prompt, 'created_at':self.created_at} 73 | 74 | def __repr__(self): 75 | return f"" 76 | 77 | class CloserPrompt(db.Model): 78 | __tablename__ = 'closer_prompts' 79 | 80 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 81 | prompt = db.Column(db.String(), nullable = False) 82 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 83 | assistant_id = db.Column(db.Integer) 84 | 85 | def __init__(self, assistant_id, prompt): 86 | self.assistant_id = assistant_id 87 | self.prompt = prompt 88 | 89 | def json(self): 90 | return {'id':self.id, 'assistant_id':self.assistant_id, 'prompt':self.prompt, 'created_at':self.created_at} 91 | 92 | def __repr__(self): 93 | return f"" 94 | 95 | class PushPrompt(db.Model): 96 | __tablename__ = 'push_prompts' 97 | 98 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 99 | prompt = db.Column(db.String(), nullable = False) 100 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 101 | assistant_id = db.Column(db.Integer) 102 | 103 | def __init__(self, assistant_id, prompt): 104 | self.assistant_id = assistant_id 105 | self.prompt = prompt 106 | 107 | def json(self): 108 | return {'id':self.id, 'assistant_id':self.assistant_id, 'prompt':self.prompt, 'created_at':self.created_at} 109 | 110 | def __repr__(self): 111 | return f"" 112 | 113 | class KnowledgeBase(db.Model): 114 | __tablename__ = 'knowledge_bases' 115 | 116 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 117 | assistant_id = db.Column(db.String(), nullable = False) 118 | name = db.Column(db.String(), unique = True, nullable = False) 119 | count = db.Column(db.Integer, nullable = False, default = 0) 120 | type_of_knowledge = db.Column(db.String(), nullable = False) 121 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 122 | 123 | def __init__(self, assistant_id, name, type_of_knowledge, count): 124 | self.assistant_id = assistant_id 125 | self.name = name 126 | self.type_of_knowledge = type_of_knowledge 127 | self.count = count 128 | 129 | def json(self): 130 | return {'id':self.id, 'assistant_id':self.assistant_id, 'name':self.name, 'type_of_knowledge':self.type_of_knowledge, 'created_at':self.created_at} 131 | 132 | def __repr__(self): 133 | return f"" 134 | 135 | class Assistant(db.Model): 136 | __tablename__ = 'assistants' 137 | 138 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 139 | name = db.Column(db.String(), unique = True, nullable = False) 140 | prompt = db.Column(db.String(), nullable = False) 141 | use_sql = db.Column(db.Boolean, nullable = False) 142 | use_pinecone = db.Column(db.Boolean, nullable = False) 143 | use_serp = db.Column(db.Boolean, nullable = False) 144 | facebook_enable = db.Column(db.Boolean, nullable = False) 145 | facebook_token = db.Column(db.String(), nullable = True) 146 | sql_host = db.Column(db.String(), nullable = True) 147 | sql_username = db.Column(db.String(), nullable = True) 148 | sql_password = db.Column(db.String(), nullable = True) 149 | sql_db_name = db.Column(db.String(), nullable = True) 150 | sql_port = db.Column(db.String(), nullable = True) 151 | pinecone_api_key =db.Column(db.String(), nullable = True) 152 | pinecone_environment = db.Column(db.String(), nullable = True) 153 | pinecone_index_name = db.Column(db.String(), nullable = True) 154 | assistant_avatar = db.Column(db.String(), nullable = True) 155 | user_avatar = db.Column(db.String(), nullable=True) 156 | weather_api = db.Column(db.Boolean, nullable=False) 157 | image = db.Column(db.Boolean, nullable = True) 158 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 159 | 160 | def __init__(self, name, prompt, use_serp, use_sql, use_pinecone, sql_host, sql_username, sql_password, sql_port, sql_db_name, pinecone_api_key, pinecone_environment, pinecone_index_name, facebook_enable, facebook_token, assistant_avatar, user_avatar, weather_api, image): 161 | self.name = name 162 | self.prompt = prompt 163 | self.use_sql = use_sql 164 | self.use_pinecone = use_pinecone 165 | self.use_serp = use_serp 166 | self.sql_host = sql_host 167 | self.sql_username = sql_username 168 | self.sql_password = sql_password 169 | self.sql_db_name = sql_db_name 170 | self.sql_port = sql_port 171 | self.pinecone_api_key = pinecone_api_key 172 | self.pinecone_environment = pinecone_environment 173 | self.pinecone_index_name = pinecone_index_name 174 | self.facebook_enable = facebook_enable 175 | self.facebook_token = facebook_token 176 | self.assistant_avatar = assistant_avatar 177 | self.user_avatar = user_avatar 178 | self.weather_api = weather_api 179 | self.image = image 180 | 181 | def json(self): 182 | return {'id':self.id, 'assistant_name':self.name, 'prompt':self.prompt, 183 | 'use_sql':self.use_sql,'sql_host':self.sql_host, 'sql_username':self.sql_username, 'sql_password':self.sql_password, 'sql_port':self.sql_port, 'sql_db_name':self.sql_db_name, 184 | 'use_pinecone':self.use_pinecone, 'pinecone_api_key':self.pinecone_api_key, 'pinecone_environment':self.pinecone_environment, 'pinecone_index_name':self.pinecone_index_name, 185 | 'use_serp':self.use_serp, 186 | 'facebook_enable':self.facebook_enable, 187 | 'facebook_token':self.facebook_token, 188 | 'created_at':self.created_at, 189 | 'assistant_avatar':self.assistant_avatar, 190 | 'user_avatar': self.user_avatar, 191 | 'weather_api': self.weather_api, 192 | 'image': self.image 193 | } 194 | 195 | def __repr__(self): 196 | return f"" 197 | 198 | class ChatHistory(db.Model): 199 | __tablename__ = 'chat_history' 200 | 201 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 202 | chat_id = db.Column(db.String(), nullable = False) 203 | user_query = db.Column(db.String(), nullable = False) 204 | response = db.Column(db.String(), nullable = False) 205 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 206 | 207 | def __init__(self, chat_id, user_query, response): 208 | self.chat_id = chat_id 209 | self.user_query = user_query 210 | self.response = response 211 | 212 | def json(self): 213 | return {'id':self.id, 'chat_id':self.chat_id, 'user_query':self.user_query, 'response':self.response} 214 | 215 | def __repr__(self): 216 | return f"" 217 | 218 | class InheritChat(db.Model): 219 | __tablename__ = 'inherit_chat' 220 | 221 | id = db.Column(db.Integer, primary_key=True, autoincrement = True) 222 | history_id = db.Column(db.String(), nullable=False) 223 | user_query = db.Column(db.String(), nullable = False) 224 | response = db.Column(db.String(), nullable = False) 225 | created_at = db.Column(db.DateTime, nullable = False, default=datetime.utcnow) 226 | 227 | def __init__(self, history_id, user_query, response): 228 | self.history_id = history_id 229 | self.user_query = user_query 230 | self.response = response 231 | 232 | def json(self): 233 | return {'id':self.id, 'history_id':self.history_id, 'user_id':self.user_query, 'response':self.response, 'count':self.count} 234 | 235 | def __repr__(self): 236 | return f"" 237 | 238 | 239 | -------------------------------------------------------------------------------- /beaches.txt: -------------------------------------------------------------------------------- 1 | Aberavon, Wales 2 | Aileen's, Ireland 3 | Amado Beach, Algarve, Portugal 4 | Anchor Point, Taghazout, Morocco 5 | Angourie Point, New South Wales, Australia 6 | Arrifana Beach, Algarve, Portugal 7 | Arugam Bay, Sri Lanka 8 | Assinie Mafia, Ivory Coast 9 | Backdoor, Oahu, Hawaii 10 | Balangan Beach, Bali, Indonesia 11 | Ballena Marine National Park Beaches, Costa Rica 12 | Bamburgh, Northumberland, England 13 | Banzai Pipeline, Oahu, Hawaii 14 | Barra de la Cruz, Oaxaca, Mexico 15 | Basset's Cove, Cornwall, England 16 | Belhaven Bay (Dunbar), Scotland 17 | Beliche Beach, Algarve, Portugal 18 | Bells Beach, Victoria, Australia 19 | Berawa Beach, Bali, Indonesia 20 | Biarritz, France 21 | Bingin Beach, Bali, Indonesia 22 | Bluff Beach, Bocas del Toro, Panama 23 | Bocas del Toro, Panama 24 | Bondi Beach, Sydney, Australia 25 | Booby's Bay, Cornwall, England 26 | Brandon Bay, County Kerry, Ireland 27 | Broad Haven South, Wales 28 | Bundoran Beach, Ireland 29 | Burger World, Mentawai Islands, Indonesia 30 | Burleigh Heads, Gold Coast, Australia 31 | Busua Beach, Ghana 32 | Cabarita Beach, New South Wales, Australia 33 | Cahuita National Park Beaches, Costa Rica 34 | Cambutal, Los Santos, Panama 35 | Canggu, Bali, Indonesia 36 | Capbreton, France 37 | Cape Cornwall, St Just, Cornwall, England 38 | Cape Fear (Ours), New South Wales, Australia 39 | Cape St. Francis, South Africa 40 | Carbis Bay, St Ives, Cornwall, England 41 | Carenero Point, Bocas del Toro, Panama 42 | Castelejo Beach, Algarve, Portugal 43 | Caswell Bay, Wales 44 | Chapel Porth Beach, Cornwall, England 45 | Chenggong, Taitung County, Taiwan 46 | Chicama, Peru 47 | Chopes (Teahupo'o), Tahiti, French Polynesia 48 | Cloud 9, Siargao Island, Philippines 49 | Cloudbreak, Tavarua Island, Fiji 50 | Constantine Bay, Cornwall, England 51 | Corcovado National Park Beaches, Costa Rica 52 | Cordoama Beach, Algarve, Portugal 53 | Côte des Basques, Biarritz, France 54 | Coverack, Cornwall, England 55 | Coxos, Ericeira, Portugal 56 | Crantock Beach, Cornwall, England 57 | Crantock Beach, Newquay, England 58 | Crescent Head, New South Wales, Australia 59 | Croyde Bay, England 60 | Croyde, Devon, England 61 | Daku Island, Siargao Island, Philippines 62 | Daymer Bay, Cornwall, England 63 | Deadman's Cove, Cornwall, England 64 | Desert Point, Lombok, Indonesia 65 | Dominical, Costa Rica 66 | Dominicalito Beach, Costa Rica 67 | Drake Bay Beaches, Costa Rica 68 | Dreamland Beach, Bali, Indonesia 69 | Dum Dums, Bocas del Toro, Panama 70 | Duranbah Beach (D-Bah), Gold Coast, Australia 71 | E-Bay, Mentawai Islands, Indonesia 72 | Easkey, Ireland 73 | Echo Beach, Bali, Indonesia 74 | El Gringo (The Chilean Pipeline), Arica, Chile 75 | El Palmar, Andalusia, Spain 76 | El Tunco, El Salvador 77 | El Yanke, Nicaragua 78 | El Zonte, El Salvador 79 | Ensenada, Baja California, Mexico 80 | Fistral Beach (North), Newquay, Cornwall, England 81 | Fistral Beach (South), Newquay, Cornwall, England 82 | Fistral Beach, Newquay, England 83 | Freshwater West, Wales 84 | Fulong Beach, New Taipei City, Taiwan 85 | G-Land (Plengkung Beach), Java, Indonesia 86 | Gandoca-Manzanillo Wildlife Refuge Beaches, Costa Rica 87 | Garrettstown, Ireland 88 | Godrevy Point, Cornwall, England 89 | Godrevy, Cornwall, England 90 | Gokarna Main Beach, Karnataka, India 91 | Grand-Bereby, Ivory Coast 92 | Great Western Beach, Newquay, England 93 | Green Bowl, Bali, Indonesia 94 | Greenmount Beach, Gold Coast, Australia 95 | Guiones Beach, Nosara, Costa Rica 96 | Gunwalloe (Church Cove), Cornwall, England 97 | Gwenver Beach, Cornwall, England 98 | Gwithian Towans, Cornwall, England 99 | Gwithian, Cornwall, England 100 | Haeundae Beach, Busan, South Korea 101 | Harlyn Bay, Cornwall, England 102 | Hayle Towans, Cornwall, England 103 | Hell's Mouth, Cornwall, England 104 | Hendaye Plage, France 105 | Hikkaduwa Beach, Sri Lanka 106 | Hollow Trees (HT's), Mentawai Islands, Indonesia 107 | Holywell Bay, Cornwall, England 108 | Hossegor (La Gravière), France 109 | Hossegor, France 110 | Ichinomiya Beach, Chiba Prefecture, Japan 111 | Impossibles, Bali, Indonesia 112 | Imsouane, Morocco 113 | Inch Beach, County Kerry, Ireland 114 | Inch Reef, Ireland 115 | Inchydoney, Ireland 116 | Isla Holbox, Quintana Roo, Mexico 117 | Itacoatiara, Niterói, Brazil 118 | Jaco Beach, Costa Rica 119 | Jails, North Male Atoll, Maldives 120 | Jaws (Peahi), Maui, Hawaii 121 | Jeffreys Bay, South Africa 122 | Jinzun Harbor, Taitung County, Taiwan 123 | Joaquina Beach, Florianópolis, Brazil 124 | Jukdo Beach, Yangyang County, South Korea 125 | K-38, Rosarito, Mexico 126 | Kennack Sands, Cornwall, England 127 | Keramas, Bali, Indonesia 128 | Kingfisher Bay, Mentawai Islands, Indonesia 129 | Kirra, Gold Coast, Australia 130 | Kokrobite Beach, Ghana 131 | Kovalam Beach, Kerala, India 132 | Krui Left, Sumatra, Indonesia 133 | Kuta Beach, Bali, Indonesia 134 | Kynance Cove, Cornwall, England 135 | La Libertad, El Salvador 136 | La Saladita, Guerrero, Mexico 137 | La Ticla, Michoacán, Mexico 138 | Lacanau Ocean, France 139 | Lacanau, France 140 | Lahinch Beach, Ireland 141 | Lamorna Cove, Cornwall, England 142 | Lance's Right, Mentawai Islands, Indonesia 143 | Lances Left, Mentawai Islands, Indonesia 144 | Land's End, Cornwall, England 145 | Langland Bay, Wales 146 | Laniakea, Oahu, Hawaii 147 | Las Flores, El Salvador 148 | Le Penon, Seignosse, France 149 | Lennox Head, New South Wales, Australia 150 | Little Fistral, Newquay, England 151 | Llangennith, Wales 152 | Long Rock Beach, Cornwall, England 153 | Los Locos, Cantabria, Spain 154 | Lower Trestles, California, USA 155 | Lusty Glaze, Newquay, England 156 | Macaronis, Mentawai Islands, Indonesia 157 | Machrihanish, Scotland 158 | Mahahual, Quintana Roo, Mexico 159 | Mal Pais, Costa Rica 160 | Malibu, California, USA 161 | Manly Beach, Sydney, Australia 162 | Manorbier, Wales 163 | Manu Bay, Raglan, New Zealand 164 | Manuel Antonio National Park Beaches, Costa Rica 165 | Manzanillo Beach, Puerto Viejo, Costa Rica 166 | Māori Bay (Muriwai), North Island, New Zealand 167 | Marazion (St Michael's Mount), Cornwall, England 168 | Marbella, Costa Rica 169 | Maresias, São Paulo, Brazil 170 | Margaret River, Western Australia 171 | Marloes Sands, Wales 172 | Matapalo Beach, Costa Rica 173 | Mavericks, California, USA 174 | Mawgan Porth, Cornwall, England 175 | Medewi, Bali, Indonesia 176 | Merewether Beach, New South Wales, Australia 177 | Mexico Towans Beach, Cornwall, England 178 | Mirissa Beach, Sri Lanka 179 | Mompiche, Ecuador 180 | Montañita, Ecuador 181 | Morro Negrito, Panama 182 | Mother Ivey's Bay, Cornwall, England 183 | Mount's Bay, Cornwall, England 184 | Mousehole, Cornwall, England 185 | Mullaghmore Head, Ireland 186 | Mundaka, Basque Country, Spain 187 | N'Gor Right, Dakar, Senegal 188 | Namotu Left, Fiji 189 | Nanjizal Bay, Cornwall, England 190 | Nazare, Portugal 191 | Newgale, Wales 192 | Nias, North Sumatra, Indonesia 193 | No Kandui, Mentawai Islands, Indonesia 194 | Noosa Heads, Queensland, Australia 195 | Nosara, Costa Rica 196 | Nyang Nyang, Bali, Indonesia 197 | Odeceixe Beach, Algarve, Portugal 198 | Ollie's Point, Costa Rica 199 | Ostional Beach, Nosara, Costa Rica 200 | Ouakam, Dakar, Senegal 201 | Padang Padang, Bali, Indonesia 202 | Padma Beach, Bali, Indonesia 203 | Pascuales, Colima, Mexico 204 | Pavones, Costa Rica 205 | Pease Bay, Scotland 206 | Pererenan Beach, Bali, Indonesia 207 | Perranporth Beach (Penhale Sands), Cornwall, England 208 | Perranporth Beach, Cornwall, England 209 | Perranuthnoe, Cornwall, England 210 | Piha Beach, North Island, New Zealand 211 | Pipeline, Oahu, Hawaii 212 | Pitstops, Mentawai Islands, Indonesia 213 | Playa Avellanas, Costa Rica 214 | Playa Blanca (Cahuita), Costa Rica 215 | Playa Chiquita, Puerto Viejo, Costa Rica 216 | Playa Cocles, Puerto Viejo, Costa Rica 217 | Playa Colorado, Nicaragua 218 | Playa de Mundaka, Basque Country, Spain 219 | Playa de Sopelana, Basque Country, Spain 220 | Playa El Coco, Nicaragua 221 | Playa El Palmar, Ixtapa, Mexico 222 | Playa Gigante, Nicaragua 223 | Playa Grande, Costa Rica 224 | Playa Hermosa, Costa Rica 225 | Playa Hermosa, Nicaragua 226 | Playa Maderas, Nicaragua 227 | Playa Marsella, Nicaragua 228 | Playa Negra (Puerto Viejo), Costa Rica 229 | Playa Negra, Costa Rica 230 | Playa Remanso, Nicaragua 231 | Playa Santana, Nicaragua 232 | Playa Venao, Panama 233 | Playa Zicatela, Puerto Escondido, Mexico 234 | Poldhu Cove, Cornwall, England 235 | Polzeath Beach, Cornwall, England 236 | Popoyo, Nicaragua 237 | Porth Neigwl (Hell's Mouth), Wales 238 | Porthcawl, Wales 239 | Porthcothan Bay, Cornwall, England 240 | Porthcurno Beach, Cornwall, England 241 | Porthleven Beach, Cornwall, England 242 | Porthleven, Cornwall, England 243 | Porthmeor Beach, St Ives, Cornwall, England 244 | Porthtowan Beach, Cornwall, England 245 | Portreath Beach, Cornwall, England 246 | Portreath Harbour Wall, Cornwall, England 247 | Praa Sands, Cornwall, England 248 | Praia da Pipa, Rio Grande do Norte, Brazil 249 | Praia do Futuro, Fortaleza, Brazil 250 | Praia do Norte, Nazaré, Portugal 251 | Puerto Escondido, Oaxaca, Mexico 252 | Punta Banco, Costa Rica 253 | Punta Burica, Panama 254 | Punta de Lobos, Pichilemu, Chile 255 | Punta de Mita, Nayarit, Mexico 256 | Punta Hermosa, Lima, Peru 257 | Punta Mango, El Salvador 258 | Punta Roca, El Salvador 259 | Punta Uva, Puerto Viejo, Costa Rica 260 | Putsborough, Devon, England 261 | Quicksilver, Siargao Island, Philippines 262 | Raglan, North Island, New Zealand 263 | Red Frog Beach, Bocas del Toro, Panama 264 | Rest Bay, Porthcawl, Wales 265 | Restaurants, Tavarua Island, Fiji 266 | Rhossili Bay, Wales 267 | Rincon, California, USA 268 | Rock Beach, Cornwall, England 269 | Rodiles Beach, Asturias, Spain 270 | Rossnowlagh Beach, County Donegal, Ireland 271 | Safi Beach, Morocco 272 | Salsa Brava, Puerto Viejo, Costa Rica 273 | Saltburn-by-the-Sea, North Yorkshire, England 274 | San Miguel, Ensenada, Mexico 275 | Sandy Beach, Oahu, Hawaii 276 | Santa Catalina, Panama 277 | Santa Teresa, Costa Rica 278 | Saunton Sands, Devon, England 279 | Sayulita, Nayarit, Mexico 280 | Scarborough Beach, Perth, Australia 281 | Scarborough, North Yorkshire, England 282 | Scorpion Bay, Baja California Sur, Mexico 283 | Seminyak Beach, Bali, Indonesia 284 | Sennen Cove, Cornwall, England 285 | Seseh Beach, Bali, Indonesia 286 | Shipstern Bluff, Tasmania, Australia 287 | Shipwreck Bay, Northland, New Zealand 288 | Shirahama Beach, Wakayama Prefecture, Japan 289 | Shonan Beach, Kanagawa Prefecture, Japan 290 | Silverbacks, Bocas del Toro, Panama 291 | Skeleton Bay, Namibia 292 | Snapper Rocks, Gold Coast, Australia 293 | Somo Beach, Cantabria, Spain 294 | Songjeong Beach, Busan, South Korea 295 | Southerndown, Wales 296 | St Ives Bay, Cornwall, England 297 | St Ives Harbour Beach, St Ives, Cornwall, England 298 | Strandhill, Ireland 299 | Sultans, North Male Atoll, Maldives 300 | Suluban Beach (Uluwatu), Bali, Indonesia 301 | Sunset Beach, Oahu, Hawaii 302 | Sunzal, El Salvador 303 | Supertubes, Jeffreys Bay, South Africa 304 | Supertubos, Peniche, Portugal 305 | Taghazout Beach, Morocco 306 | Tallows Beach, Byron Bay, Australia 307 | Tamarindo, Costa Rica 308 | Tanjung Setia Beach, Sumatra, Indonesia 309 | Teahupo'o, Tahiti, French Polynesia 310 | The Box, Margaret River, Western Australia 311 | The Pass, Byron Bay, Australia 312 | The Right, Western Australia 313 | The Wedge, Newport Beach, California, USA 314 | Thurso East, Scotland 315 | Todos Santos, Baja California Sur, Mexico 316 | Tolcarne Beach, Newquay, England 317 | Tonel Beach, Algarve, Portugal 318 | Towan Beach, Newquay, England 319 | Towan Headland, Newquay, England 320 | Tramore, Ireland 321 | Treasure Island, Fiji 322 | Trebarwith Strand, Cornwall, England 323 | Trestles, California, USA 324 | Trevaunance Cove, St Agnes, Cornwall, England 325 | Treyarnon Bay, Cornwall, England 326 | Troncones Point, Guerrero, Mexico 327 | Tullan Strand, County Donegal, Ireland 328 | Tynemouth, Northumberland, England 329 | Ujung Bocur, Sumatra, Indonesia 330 | Uluwatu, Bali, Indonesia 331 | Upton Towans Beach, Cornwall, England 332 | Uvita, Costa Rica 333 | Varkala Beach, Kerala, India 334 | Venao Beach, Los Santos, Panama 335 | Waimea Bay, Oahu, Hawaii 336 | Wategos Beach, Byron Bay, Australia 337 | Watergate Bay, Newquay, England 338 | Way Jambu (Sumatran Pipeline), Sumatra, Indonesia 339 | Weligama Beach, Sri Lanka 340 | Whangamata Beach, North Island, New Zealand 341 | Whitesands Bay, Wales 342 | Witch's Rock, Costa Rica 343 | Wizard Beach, Bocas del Toro, Panama 344 | Woolacombe Beach, Devon, England 345 | Yoff Beach, Dakar, Senegal 346 | Zarautz Beach, Basque Country, Spain 347 | Zicatela Beach, Puerto Escondido, Mexico 348 | Zippers, San Jose del Cabo, Mexico -------------------------------------------------------------------------------- /post.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import logging 3 | from openai import OpenAI 4 | import os 5 | import schedule 6 | import time 7 | from dotenv import load_dotenv 8 | import random 9 | 10 | load_dotenv() 11 | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') 12 | 13 | api_key = os.getenv('OPENAI_API_KEY') 14 | LT_LONG_TOKEN = os.getenv('LT_LONG_TOKEN') 15 | STORMGLASS_API_KEY = "76916c28-f3b2-11ed-8d52-0242ac130002-76916d04-f3b2-11ed-8d52-0242ac130002" # Replace with your StormGlass API key 16 | 17 | if not api_key or not LT_LONG_TOKEN: 18 | raise ValueError("Environment variables for OpenAI API key or Facebook/Instagram long-lived access token are missing.") 19 | 20 | client = OpenAI(api_key=api_key) 21 | 22 | page_id = '192229940650983' 23 | ig_user_id = '17841460703039794' 24 | 25 | def fetch_surf_conditions(api_key, latitude, longitude): 26 | url = "https://api.stormglass.io/v2/weather/point" 27 | params = { 28 | 'lat': latitude, 29 | 'lng': longitude, 30 | 'params': ','.join(['waveHeight', 'waterTemperature', 'windSpeed', 'windDirection']), 31 | } 32 | headers = { 33 | 'Authorization': api_key 34 | } 35 | 36 | logging.info(f"Sending request to StormGlass: URL={url}, Params={params}") 37 | response = requests.get(url, params=params, headers=headers) 38 | 39 | if response.status_code == 200: 40 | logging.info(f"Received response from StormGlass: {response.json()}") 41 | return response.json() 42 | else: 43 | logging.error(f"Failed to fetch data from StormGlass, Status Code={response.status_code}, Response={response.text}") 44 | return {'error': 'Failed to fetch data', 'status_code': response.status_code} 45 | 46 | def get_lat_long_for_beach(beach_name): 47 | prompt = f"Provide the latitude and longitude for {beach_name} beach. Only respond in a format like this nothing else:34.0195, -118.4912" 48 | try: 49 | response = client.chat.completions.create( 50 | model="gpt-4", 51 | messages=[ 52 | {"role": "system", "content": "You are a geographical information system. Provide accurate data."}, 53 | {"role": "user", "content": prompt} 54 | ] 55 | ) 56 | lat_long_response = response.choices[0].message.content 57 | logging.info("Latitude and Longitude Response:\n%s", lat_long_response) 58 | # Example parsing, you might need to adjust based on the response format 59 | lat_long = lat_long_response.split(',') 60 | latitude = lat_long[0].strip() 61 | longitude = lat_long[1].strip() 62 | return latitude, longitude 63 | except Exception as e: 64 | logging.error("Failed to get latitude and longitude: %s", e) 65 | return None, None 66 | 67 | def generate_surfing_content(): 68 | try: 69 | with open('beaches.txt', 'r') as file: 70 | beaches = file.readlines() 71 | beach = random.choice(beaches).strip() 72 | except FileNotFoundError: 73 | logging.error("beach.txt file not found.") 74 | return None, None 75 | except Exception as e: 76 | logging.error("Failed to read from beach.txt: %s", e) 77 | return None, None 78 | 79 | latitude, longitude = get_lat_long_for_beach(beach) 80 | if latitude and longitude: 81 | surf_conditions = fetch_surf_conditions(STORMGLASS_API_KEY, latitude, longitude) 82 | if 'error' not in surf_conditions: 83 | conditions_str = f"Wave Height: {surf_conditions['hours'][0]['waveHeight']['noaa']}m, Water Temperature: {surf_conditions['hours'][0]['waterTemperature']['noaa']}C, Wind Speed: {surf_conditions['hours'][0]['windSpeed']['noaa']}m/s, Wind Direction: {surf_conditions['hours'][0]['windDirection']['noaa']} degrees" 84 | else: 85 | conditions_str = "No conditions available" 86 | else: 87 | conditions_str = "No conditions available" 88 | 89 | surf_prompt = f"Write a facebook post update for the local surfers. You are a local surf expert at {beach}, considering the current wave conditions, select what size/type of board would be best for these conditions, and provide local tips for surfers based on the following conditions: {conditions_str}. Come up with other tips to say. Only say nice things about the local only if you mention them." 90 | 91 | try: 92 | logging.info("Generating surfing content") 93 | response = client.chat.completions.create( 94 | model="gpt-4", 95 | messages=[ 96 | {"role": "system", "content": "You are an old school surfer lingo talking knowledgeable surfing guide. Don't give newbie lessons"}, 97 | {"role": "user", "content": surf_prompt} 98 | ] 99 | ) 100 | surf_instructions = response.choices[0].message.content 101 | logging.info("Generated Surfing Content:\n%s", surf_instructions) 102 | return surf_instructions, beach 103 | except Exception as e: 104 | logging.error("Failed to generate surfing content: %s", e) 105 | return None, None 106 | 107 | def generate_hashtags(surf_instructions): 108 | hashtag_prompt = f"Based on the following content, generate relevant hashtags: {surf_instructions}" 109 | 110 | try: 111 | logging.info("Generating hashtags") 112 | response = client.chat.completions.create( 113 | model="gpt-4", 114 | messages=[ 115 | {"role": "system", "content": "You are a social media expert. Generate relevant hashtags based on the content."}, 116 | {"role": "user", "content": hashtag_prompt} 117 | ] 118 | ) 119 | hashtags = response.choices[0].message.content 120 | logging.info("Generated Hashtags:\n%s", hashtags) 121 | return hashtags 122 | except Exception as e: 123 | logging.error("Failed to generate hashtags: %s", e) 124 | return None 125 | 126 | def generate_surfing_image(surf_instructions, beach): 127 | image_prompt = f"Real Photo of someone surfing the best wave at {beach}. Put someone at this location, on a wave, and on this board doing this surf style. make sure the physics of the surfer angle based on the wave is correct positioning, human photo realistic. No words or text" 128 | 129 | try: 130 | logging.info("Generating surfing image with prompt: %s", image_prompt) 131 | response = client.images.generate( 132 | model="dall-e-3", 133 | prompt=image_prompt, 134 | size="1024x1024", 135 | n=1, 136 | ) 137 | image_url = response.data[0].url 138 | logging.info("Generated Surfing Image URL: %s", image_url) 139 | 140 | return image_url 141 | except Exception as e: 142 | logging.error("Failed to generate surfing image: %s", e) 143 | return None 144 | 145 | def generate_content_and_post(): 146 | logging.info("Starting surfing content generation and posting process") 147 | 148 | try: 149 | surf_instructions, beach = generate_surfing_content() # This returns both surf_instructions and beach 150 | if surf_instructions and beach: 151 | hashtags = generate_hashtags(surf_instructions) 152 | image_url = generate_surfing_image(surf_instructions, beach) # Make sure to pass both arguments here 153 | if image_url: 154 | try: 155 | logging.info("Posting to Facebook and Instagram") 156 | publish_photo_with_message(page_id, ig_user_id, surf_instructions, image_url, hashtags) 157 | except Exception as e: 158 | logging.error("Failed to post to Facebook or Instagram: %s", e) 159 | except Exception as e: 160 | logging.error("An error occurred during content generation or posting: %s", e) 161 | 162 | def publish_photo_with_message(page_id, ig_user_id, message, photo_url, hashtags): 163 | # Combine message and hashtags for posting 164 | full_message = f"{message}\n\n{hashtags}" 165 | 166 | # Upload photo to Facebook with published set to false for story 167 | try: 168 | fb_photo_upload_url = f"https://graph.facebook.com/{page_id}/photos" 169 | fb_photo_upload_payload = { 170 | 'url': photo_url, 171 | 'caption': full_message, 172 | 'published': 'false', 173 | 'access_token': LT_LONG_TOKEN 174 | } 175 | fb_photo_upload_response = requests.post(fb_photo_upload_url, data=fb_photo_upload_payload) 176 | if fb_photo_upload_response.status_code == 200: 177 | photo_id = fb_photo_upload_response.json().get('id') 178 | logging.info("Successfully uploaded photo to Facebook for story: %s", fb_photo_upload_response.json()) 179 | 180 | # Publish a photo story on Facebook 181 | fb_photo_story_url = f"https://graph.facebook.com/{page_id}/photo_stories" 182 | fb_photo_story_payload = { 183 | 'photo_id': photo_id, 184 | 'access_token': LT_LONG_TOKEN 185 | } 186 | fb_photo_story_response = requests.post(fb_photo_story_url, data=fb_photo_story_payload) 187 | if fb_photo_story_response.status_code == 200: 188 | logging.info("Successfully published photo story to Facebook: %s", fb_photo_story_response.json()) 189 | else: 190 | logging.error("Failed to publish photo story to Facebook. Response: %s", fb_photo_story_response.text) 191 | else: 192 | logging.error("Failed to upload photo to Facebook for story. Response: %s", fb_photo_upload_response.text) 193 | except Exception as e: 194 | logging.error("Exception occurred while uploading photo or publishing photo story to Facebook: %s", e) 195 | 196 | # Post to Facebook profile 197 | try: 198 | fb_profile_url = f"https://graph.facebook.com/{page_id}/photos" 199 | fb_profile_payload = { 200 | 'url': photo_url, 201 | 'caption': full_message, 202 | 'access_token': LT_LONG_TOKEN 203 | } 204 | fb_profile_response = requests.post(fb_profile_url, data=fb_profile_payload) 205 | if fb_profile_response.status_code == 200: 206 | logging.info("Successfully published to Facebook profile: %s", fb_profile_response.json()) 207 | else: 208 | logging.error("Failed to publish to Facebook profile. Response: %s", fb_profile_response.text) 209 | except Exception as e: 210 | logging.error("Exception occurred while posting to Facebook profile: %s", e) 211 | 212 | # Create a media container on Instagram for feed 213 | try: 214 | ig_media_url = f"https://graph.facebook.com/v10.0/{ig_user_id}/media" 215 | ig_media_payload = { 216 | 'image_url': photo_url, 217 | 'caption': full_message, 218 | 'access_token': LT_LONG_TOKEN 219 | } 220 | ig_media_response = requests.post(ig_media_url, data=ig_media_payload) 221 | logging.info(f"Instagram media container creation response: {ig_media_response.json()}") 222 | if ig_media_response.status_code == 200: 223 | ig_media_id = ig_media_response.json().get('id') 224 | logging.info("Successfully created Instagram media container for feed.") 225 | 226 | # Publish the media container to Instagram feed 227 | ig_publish_url = f"https://graph.facebook.com/v10.0/{ig_user_id}/media_publish" 228 | ig_publish_payload = { 229 | 'creation_id': ig_media_id, 230 | 'access_token': LT_LONG_TOKEN 231 | } 232 | ig_publish_response = requests.post(ig_publish_url, data=ig_publish_payload) 233 | logging.info(f"Instagram feed publish response: {ig_publish_response.json()}") 234 | if ig_publish_response.status_code == 200: 235 | logging.info("Successfully published to Instagram feed.") 236 | else: 237 | logging.error("Failed to publish to Instagram feed.") 238 | else: 239 | logging.error("Failed to create Instagram media container for feed.") 240 | except Exception as e: 241 | logging.error(f"Exception occurred while posting to Instagram feed: {e}") 242 | 243 | # Create a media container on Instagram for story 244 | try: 245 | ig_story_media_url = f"https://graph.facebook.com/v10.0/{ig_user_id}/media" 246 | ig_story_media_payload = { 247 | 'image_url': photo_url, 248 | 'caption': full_message, 249 | 'access_token': LT_LONG_TOKEN, 250 | 'media_type': 'STORIES' # Corrected parameter for story media type 251 | } 252 | ig_story_media_response = requests.post(ig_story_media_url, data=ig_story_media_payload) 253 | logging.info(f"Instagram story media container creation response: {ig_story_media_response.json()}") 254 | if ig_story_media_response.status_code == 200: 255 | ig_story_media_id = ig_story_media_response.json().get('id') 256 | logging.info("Successfully created Instagram media container for story.") 257 | 258 | # Publish the media container to Instagram story 259 | ig_story_publish_url = f"https://graph.facebook.com/v10.0/{ig_user_id}/media_publish" 260 | ig_story_publish_payload = { 261 | 'creation_id': ig_story_media_id, 262 | 'access_token': LT_LONG_TOKEN 263 | } 264 | ig_story_publish_response = requests.post(ig_story_publish_url, data=ig_story_publish_payload) 265 | logging.info(f"Instagram story publish response: {ig_story_publish_response.json()}") 266 | if ig_story_publish_response.status_code == 200: 267 | logging.info("Successfully published to Instagram story.") 268 | else: 269 | logging.error("Failed to publish to Instagram story.") 270 | else: 271 | logging.error("Failed to create Instagram media container for story.") 272 | except Exception as e: 273 | logging.error(f"Exception occurred while posting to Instagram story: {e}") 274 | 275 | 276 | 277 | generate_content_and_post() 278 | 279 | # Adjust the schedule as needed 280 | schedule.every(1).hour.do(generate_content_and_post) # For demonstration, adjust as needed 281 | 282 | while True: 283 | schedule.run_pending() 284 | time.sleep(1) -------------------------------------------------------------------------------- /vectorizor.py: -------------------------------------------------------------------------------- 1 | 2 | import openai 3 | from pinecone import Pinecone, ServerlessSpec 4 | from openai import OpenAI 5 | import time 6 | from uuid import uuid4 7 | import pymysql 8 | # from langchain.vectorstores import Pinecone 9 | from langchain.utilities import SQLDatabase, GoogleSerperAPIWrapper 10 | from langchain.prompts.chat import ChatPromptTemplate 11 | from langchain.prompts import PromptTemplate 12 | from langchain.chat_models import ChatOpenAI 13 | from langchain.memory import ConversationBufferMemory 14 | from langchain.agents.agent_types import AgentType 15 | from langchain_experimental.sql import SQLDatabaseChain 16 | from langchain.embeddings.openai import OpenAIEmbeddings 17 | from langchain.chains.question_answering import load_qa_chain 18 | import mysql.connector 19 | from langchain.agents import create_sql_agent, initialize_agent, Tool 20 | from langchain.agents.agent_toolkits import SQLDatabaseToolkit 21 | from langchain_openai import OpenAI 22 | from langchain.schema import SystemMessage, HumanMessage 23 | from langchain_core.runnables import RunnablePassthrough 24 | from sqlalchemy import create_engine 25 | from urllib.parse import quote 26 | 27 | from models import KnowledgeBase 28 | from sqlalchemy.engine.url import URL 29 | # from langchain.sql_database import SQLDatabase 30 | from models import Assistant, KnowledgeBase 31 | # from langchain import LargeLanguageModel 32 | import os 33 | import base64 34 | import requests 35 | from dotenv import load_dotenv 36 | from chunker import getPineconeFromIndex, saveToPinecone 37 | load_dotenv() 38 | 39 | # Set up OpenAI and Pinecone API keys 40 | OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") 41 | SERPER_API_KEY = os.getenv("SERPER_API_KEY") 42 | PINECONE_API_KEY = os.getenv("PINECONE_API_KEY") 43 | INDEX_NAME = os.getenv("INDEX_NAME") 44 | PINECONE_ENVIRONMENT = os.getenv("PINECONE_ENVIRONMENT") 45 | PINECONE_INDEX_DIMENSION = os.getenv("PINECONE_INDEX_DIMENSION") 46 | PINECONE_INDEX_NAME = os.getenv("PINECONE_INDEX_NAME") 47 | DOLT_HOST = os.getenv("DOLT_HOST") 48 | DOLT_PORT = os.getenv("DOLT_PORT") 49 | DOLT_USERNAME = os.getenv("DOLT_USERNAME") 50 | DOLT_PASSWORD = os.getenv("DOLT_PASSWORD") 51 | DOLT_DATABASE = os.getenv("DOLT_DATABASE") 52 | 53 | # db = mysql.connector.connect( 54 | # host = DOLT_HOST, 55 | # user = DOLT_USERNAME, 56 | # password = DOLT_PASSWORD, 57 | # database = DOLT_DATABASE 58 | # ) 59 | 60 | print(SERPER_API_KEY) 61 | openai.api_key = OPENAI_API_KEY 62 | 63 | def encode_image(image_path): 64 | with open(image_path, "rb") as image_file: 65 | return base64.b64encode(image_file.read()).decode('utf-8') 66 | 67 | # Messaging image 68 | def image_qeury(query, image_path): 69 | base64_image = encode_image(image_path) 70 | # print("Base64 code >>>>", base64_image) 71 | headers = { 72 | "Content-Type": "application/json", 73 | "Authorization": f"Bearer {OPENAI_API_KEY}" 74 | } 75 | 76 | payload = { 77 | "model":"gpt-4-vision-preview", 78 | "messages":[ 79 | { 80 | "role":"user", 81 | "content":[ 82 | { 83 | "type":"text", 84 | "text":query 85 | }, 86 | { 87 | "type":"image_url", 88 | "image_url": { 89 | "url":f"data:image/jpeg;base64, {base64_image}" 90 | } 91 | } 92 | ] 93 | } 94 | ], 95 | "max_tokens": 4096 96 | } 97 | response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload) 98 | print(response.json()) 99 | return response.json() 100 | 101 | # Connect to SQL 102 | def sql_connect(host, port, username, password, db_name): 103 | try: 104 | db = mysql.connector.connect( 105 | host = host, 106 | port = port, 107 | user = username, 108 | password = password, 109 | database = db_name 110 | ) 111 | return db 112 | except: 113 | return None 114 | 115 | # Connect to Pinecone 116 | def pinecone_connect(api_key, environment, index_name): 117 | try: 118 | pinecone = Pinecone(api_key=api_key) 119 | if index_name not in pinecone.list_indexes().names(): 120 | return {"success": False, "message": "There is no such an index"} 121 | 122 | 123 | index = pinecone.Index(index_name) 124 | print("Index is ----->", index) 125 | return {"success": True, "message": "Index created successfully.", "index": index} 126 | except Exception as e: 127 | error_message = str(e) 128 | print(error_message) 129 | return {"success": False, "message": f"Error: {error_message}"} 130 | 131 | # The response will be a string that is a question 132 | def query_refiner(conversation, query): 133 | response = openai.Completion.create( 134 | model="gpt-4-turbo-preview", 135 | messages=[ 136 | {"role": "system", "content": "You are a helpful assistant."}, 137 | {"role": "user", "content": "Who won the world series in 2020?"} 138 | ] 139 | ) 140 | return response.choices[0].message.content 141 | 142 | def preprompt_generate(query, assistant_id): 143 | limit = '' 144 | if assistant_id == 5: 145 | limit = ' Each query must be less than 20 characters' 146 | prompt = f'Q: Give me 3 different related queries with {query}.{limit} A:' 147 | response = openai.chat.completions.create( 148 | model="gpt-4-turbo-preview", 149 | messages=[ 150 | {"role": "system", "content": "You are a helpful related topic generator. Only provide 3 topics at once."}, 151 | {"role": "user", "content": prompt} 152 | ] 153 | ) 154 | return response.choices[0].message.content 155 | 156 | 157 | def simple_generate(query): 158 | response = openai.chat.completions.create( 159 | model="gpt-4-turbo-preview", 160 | messages=[ 161 | {"role": "system", "content": "You are a helpful assistant."}, 162 | {"role": "user", "content": query} 163 | ] 164 | ) 165 | return response.choices[0].message.content 166 | 167 | # Generate the answer 168 | def generate_answer(query, assistant_id, template, latest_records): 169 | prompt = PromptTemplate( 170 | input_variables=["chat_history", "human_input", "context"], 171 | template=template 172 | ) 173 | assistant = Assistant.query.filter_by(id=assistant_id).first() 174 | api_key = assistant.pinecone_api_key 175 | environment = assistant.pinecone_environment 176 | index_name = assistant.pinecone_index_name 177 | memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input") 178 | embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) 179 | 180 | docsearch = getPineconeFromIndex(index_name) 181 | 182 | docs = docsearch.similarity_search(query, k=8, filter={'assistant': (assistant_id)}) 183 | # print(docs) 184 | chat_openai = OpenAI(temperature = 0.7, model = "gpt-4-turbo-preview", openai_api_key = OPENAI_API_KEY) 185 | 186 | chain = load_qa_chain(chat_openai, chain_type="stuff", prompt=prompt, memory=memory) 187 | if len(latest_records) == 0: 188 | print("No history>..") 189 | for index, record in enumerate(latest_records): 190 | # print(record['user_query']) 191 | chain.memory.save_context({'human_input':record['user_query']}, {'output':record['response']}) 192 | 193 | 194 | output = chain ({'input_documents':docs, 'human_input': query}, return_only_outputs=False) 195 | chain.memory.clear() 196 | 197 | return output['output_text'] 198 | 199 | # Generating Text Embeddings with OpenAI's API 200 | def generate_text_embeddings(text_chunks): 201 | embeddings = [] 202 | for chunk in text_chunks: 203 | response = openai.embeddings.create(input=chunk, model="text-embedding-ada-002") 204 | embeddings.append(response['data'][0]['embedding']) 205 | return embeddings 206 | 207 | # Initialize Pinecone index 208 | def init_pinecone(index_name, dimension): 209 | pinecone = Pinecone(api_key=PINECONE_API_KEY) 210 | if index_name not in pinecone.list_indexes().names(): 211 | pinecone.create_index( 212 | name=index_name, 213 | dimension=dimension, 214 | spec=ServerlessSpec( 215 | cloud="aws", 216 | region="us-west-2" 217 | ) 218 | ) 219 | return pinecone.Index(index_name) 220 | 221 | # Storing and Retrieving Embeddings with Pinecone credentials 222 | def store_embeddings_in_pinecone(chunks, metalist, pinecone_api_key, ids, pinecone_index_name): 223 | try: 224 | if pinecone_api_key is not None: 225 | PINECONE_API_KEY = pinecone_api_key 226 | 227 | if pinecone_index_name is not None: 228 | PINECONE_INDEX_NAME = pinecone_index_name 229 | # pinecone.init(api_key=PINECONE_API_KEY, environment=PINECONE_ENVIRONMENT) 230 | embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) 231 | saveToPinecone(chunks, embeddings, PINECONE_INDEX_NAME, metalist, ids) 232 | 233 | print("Success embedding...") 234 | return True 235 | except Exception as e: 236 | print("Error embedding...", str(e)) 237 | return False 238 | 239 | def retrieve_embeddings_from_pinecone(index_name, query_embedding): 240 | pinecone = Pinecone(api_key=PINECONE_API_KEY, environment=PINECONE_ENVIRONMENT) 241 | vector_store = pinecone.Index(index_name) 242 | results = vector_store.query(queries=query_embedding) 243 | return results 244 | 245 | # Delete all records of the index 246 | def del_all_records(assistant_id): 247 | try: 248 | assistant = Assistant.query.filter_by(id=assistant_id).first() 249 | pinecone_api_key = assistant.pinecone_api_key 250 | pinecone_environment = assistant.pinecone_environment 251 | pinecone_index_name = assistant.pinecone_index_name 252 | index = pinecone_connect(pinecone_api_key, pinecone_environment, pinecone_index_name) 253 | index.delete(delete_all=True) 254 | return True 255 | except Exception as e: 256 | print(str(e)) 257 | return False 258 | 259 | def del_knowledgebase_by_assistant_id(assistant_id): 260 | try : 261 | assistant = Assistant.query.filter_by(assistant_id=assistant_id).first() 262 | api_key = assistant.pinecone_api_key 263 | environment = assistant.pinecone_environment 264 | index_name = assistant.pinecone_index_name 265 | pinecone=Pinecone(api_key=api_key) 266 | index = pinecone.Index(index_name) 267 | index.delete( 268 | filter={ 269 | 'assistant':assistant_id 270 | } 271 | ) 272 | print('Deleted assistant ', assistant_id) 273 | return True 274 | except Exception as e: 275 | print(str(e)) 276 | return False 277 | 278 | def del_knowledge_by_knowledge_id(knowledge_id, assistant_id): 279 | try: 280 | # print("knowledge_id >>", assistant_id) 281 | assistant = Assistant.query.filter_by(id=assistant_id).first() 282 | api_key = assistant.pinecone_api_key 283 | environment = assistant.pinecone_environment 284 | index_name = assistant.pinecone_index_name 285 | pinecone=Pinecone(api_key=api_key) 286 | index = pinecone.Index(index_name) 287 | knowledge_base = KnowledgeBase.query.filter_by(id=knowledge_id).first() 288 | 289 | count = knowledge_base.count 290 | ids = [f"{knowledge_id}_{i}" for i in range(count)] 291 | print(knowledge_id, count) 292 | 293 | print(ids) 294 | index.delete(ids=ids) 295 | print("Deletion success!") 296 | return True 297 | except Exception as e: 298 | print(str(e)) 299 | return False 300 | 301 | # Create embeddings and populate the index with the train data 302 | def create_and_index_embeddings(text_chunks, metalist): 303 | 304 | # Initialize Pinecone index 305 | try: 306 | chatgpt_index = init_pinecone(INDEX_NAME) 307 | embeddings = generate_text_embeddings(text_chunks) 308 | for embedding in embeddings: 309 | chatgpt_index.upsert(items=[embedding], metadata = [metalist]) 310 | except Exception as e: 311 | print(e) 312 | return chatgpt_index 313 | 314 | # Query with database 315 | def query_with_dolt(query, prompt, assistant_id): 316 | # sql_db = SQLDatabase.from_dbapi(db) 317 | assistant = Assistant.query.filter_by(id=assistant_id).first() 318 | sql_host = assistant.sql_host 319 | sql_username = assistant.sql_username 320 | sql_password = assistant.sql_password 321 | sql_db_name = assistant.sql_db_name 322 | final_prompt = ChatPromptTemplate.from_messages( 323 | [ 324 | ("system", 325 | prompt 326 | ), 327 | ("user", "{question}\n ai: "), 328 | ] 329 | ) 330 | db = SQLDatabase.from_uri(f"mysql+mysqldb://{sql_username}:{sql_password}@{sql_host}/{sql_db_name}?ssl=1") 331 | llm = ChatOpenAI (temperature=0, model='gpt-4-turbo-preview') 332 | tookkit = SQLDatabaseToolkit(db=db, llm=llm) 333 | agent_executor = create_sql_agent( 334 | llm=llm, 335 | toolkit=tookkit, 336 | verbose=True, 337 | agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, 338 | ) 339 | 340 | res = agent_executor.run(final_prompt.format(question=query)) 341 | # print(res) 342 | return res 343 | 344 | def query_with_both(query, prompt, assistant_id): 345 | assistant = Assistant.query.filter_by(id=assistant_id).first() 346 | sql_host = assistant.sql_host 347 | sql_username = assistant.sql_username 348 | sql_password = assistant.sql_password 349 | sql_port = assistant.sql_port 350 | sql_db_name = assistant.sql_db_name 351 | pinecone_index_name = assistant.pinecone_index_name 352 | pinecone_environment = assistant.pinecone_environment 353 | pinecone_api_key = assistant.pinecone_api_key 354 | 355 | 356 | 357 | memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input") 358 | embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) 359 | 360 | docsearch = getPineconeFromIndex(pinecone_index_name) 361 | 362 | docs = docsearch.similarity_search(query, k=8, filter={'assistant': (assistant_id)}) 363 | starter = f"Use this one of knowledge base: {docs}" 364 | # sql_db = SQLDatabase.from_dbapi(db) 365 | final_prompt = ChatPromptTemplate.from_messages( 366 | [ 367 | ("system", 368 | starter+prompt 369 | ), 370 | ("user", "{question}\n ai: "), 371 | ] 372 | ) 373 | db = SQLDatabase.from_uri(f"mysql+mysqldb://{sql_username}:{sql_password}@{sql_host}/{sql_db_name}?ssl=1") 374 | llm = ChatOpenAI (temperature=0, model='gpt-4-turbo-preview') 375 | 376 | toolkit = SQLDatabaseToolkit(db=db, llm=llm) 377 | agent_executor = create_sql_agent( 378 | llm=llm, 379 | toolkit=toolkit, 380 | verbose=True, 381 | agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, 382 | ) 383 | 384 | res = agent_executor.run(final_prompt.format(question=query)) 385 | # print(res) 386 | return res 387 | 388 | # Get result from pinecone 389 | def pinecone_result(assistant_id, query): 390 | try: 391 | start_time = time.time() 392 | assistant = Assistant.query.filter_by(id=assistant_id).first() 393 | pinecone_api_key = assistant.pinecone_api_key 394 | pinecone_environment = assistant.pinecone_environment 395 | pinecone_index_name = assistant.pinecone_index_name 396 | 397 | embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY) 398 | 399 | docsearch = getPineconeFromIndex(pinecone_index_name) 400 | print("Assistant id >>>", assistant_id) 401 | docs = docsearch.similarity_search(query, k=8, filter={'assistant': str(assistant_id)}) 402 | print("Pinecone Result >>>", docs) 403 | end_time = time.time() 404 | print(f'>>> Pinecone search takes {end_time-start_time} seconds') 405 | 406 | return docs[0].page_content 407 | except Exception as e: 408 | print(str(e)) 409 | return 'There is no relevant information.' 410 | 411 | # Get result from SERP 412 | def serp_result(query): 413 | try: 414 | start_time = time.time() 415 | llm = OpenAI(temperature=0, model="gpt-4-turbo-preview") 416 | search = GoogleSerperAPIWrapper() 417 | 418 | tools = [ 419 | Tool( 420 | name="Intermediate Answer", 421 | func=search.run, 422 | description="userful for when you need to ask with google search" 423 | ) 424 | ] 425 | result = search.results(query) 426 | end_time = time.time() 427 | print('SERP Result >>>', result) 428 | print(f'>>> Google search takes {end_time-start_time} seconds') 429 | return result 430 | 431 | except Exception as e: 432 | print(str(e)) 433 | return 'There is no relevant information.' 434 | 435 | # Generate an image for surf bot 436 | def generate_surfing_image(surf_instructions, beach): 437 | try: 438 | image_prompt = f"Real Photo of someone surfing the best wave at {beach}. Put someone at this location, on a wave, and on this board doing this surf style. make sure the physics of the surfer angle based on the wave is correct positioning, human photo realistic. No words or text" 439 | print("Generating surfing image with prompt:", image_prompt) 440 | headers = { 441 | "Content-Type": "application/json", 442 | "Authorization": f"Bearer {OPENAI_API_KEY}" 443 | } 444 | payload = { 445 | "model": "dall-e-3", 446 | "prompt": image_prompt, 447 | "n": 1, 448 | "size": "1024x1024", 449 | "response_format":"url" 450 | } 451 | response = requests.post("https://api.openai.com/v1/images/generations", headers=headers, json=payload) 452 | # print(response.json()) 453 | json_res = response.json() 454 | print("Json data of image url >>>>>", json_res) 455 | image_url = json_res["data"][0]["url"] 456 | print("Generated Surfing Image URL: %s", image_url) 457 | return image_url 458 | except Exception as e: 459 | print("Failed to generate surfing image: %s", e) 460 | return None 461 | 462 | # Generate an image using dall-e-3 model 463 | def generate_image(query): 464 | try: 465 | descriptive_prompt = "Imagine you are making an image of this finished cooked meal. Include descriptive terms related to the dish itself, such as its appearance, colors, textures, arrangement, and any unique presentation details. Also, consider aspects like lighting, angles, and settings to enhance the visual appeal of the dish." 466 | 467 | print("Generating images...") 468 | headers = { 469 | "Content-Type": "application/json", 470 | "Authorization": f"Bearer {OPENAI_API_KEY}" 471 | } 472 | 473 | prompt = "Content: " +descriptive_prompt+" + Recipe: "+ query + "including camera and lighting and quality angles of variations and unique image locations. be descriptive like a photographer describing, no rustic" 474 | print("Prompt >>>", prompt) 475 | payload = { 476 | "model": "dall-e-3", 477 | "prompt": prompt, 478 | "n": 1, 479 | "size": "1024x1024", 480 | "response_format":"url" 481 | } 482 | response = requests.post("https://api.openai.com/v1/images/generations", headers=headers, json=payload) 483 | # print(response.json()) 484 | json_res = response.json() 485 | print("Json data of image url >>>>>", json_res) 486 | image_url = json_res["data"][0]["url"] 487 | return image_url 488 | except Exception as e: 489 | print(str(e)) 490 | return str(e) 491 | 492 | # Get result from sql 493 | def sql_result(assistant_id, query): 494 | try: 495 | start_time = time.time() 496 | assistant = Assistant.query.filter_by(id=assistant_id).first() 497 | sql_host = assistant.sql_host 498 | sql_username = assistant.sql_username 499 | sql_password = quote(assistant_sql_password, safe='') 500 | sql_port = assistant.sql_port 501 | sql_db_name = assistant.sql_db_name 502 | 503 | connection_string = f'mysql+mysqldb://{sql_username}:{sql_password}@{sql_host}:{sql_port}/{sql_db_name}?ssl=1' 504 | 505 | db = SQLDatabase.from_uri(connection_string) 506 | print("DB connected to>>>", db) 507 | llm = ChatOpenAI (temperature=0, model='gpt-4-turbo-preview') 508 | toolkit = SQLDatabaseToolkit(db=db, llm=llm) 509 | agent_executor = create_sql_agent( 510 | llm=llm, 511 | toolkit=toolkit, 512 | verbose=True, 513 | agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, 514 | ) 515 | prompt = assistant.prompt 516 | template = prompt + query 517 | # question = template.format(question=query) 518 | 519 | result = agent_executor.run(template) 520 | end_time = time.time() 521 | 522 | print("SQL Result >>>", result) 523 | print(f'>>> SQL query takes {end_time-start_time} seconds') 524 | 525 | return result 526 | except Exception as e: 527 | print(str(e)) 528 | return 'There is no relevant information.' 529 | 530 | # Generate answers with all results 531 | def generate_final_answer(assistant_id, query): 532 | try: 533 | start_time = time.time() 534 | assistant = Assistant.query.filter_by(id=assistant_id).first() 535 | if assistant.use_pinecone: 536 | pinecone_res = pinecone_result(assistant_id, query) 537 | else: 538 | pinecone_res = 'There is no relevant information' 539 | if assistant.use_serp: 540 | serp_res = serp_result(query) 541 | else: 542 | serp_res = 'There is no relevant information' 543 | if assistant.use_sql: 544 | sql_res = sql_result(assistant_id, query) 545 | else: 546 | sql_res = 'There is no relevant information' 547 | preprompt = assistant.prompt 548 | template = """{preprompt}\nThere are 3 kind of knowledge base for given information: SQL Results, Pinecone Restuls and SERp Results. Summarize the information to give a helpful assistant to users. If there is no relevant information, Give me general ideal to user. Don't indicate that where the info is from. 549 | SQL Results:{sql_result} 550 | Pinecone Results:{pinecone_result} 551 | SERP Results:{serp_result} 552 | Human: {human_input} 553 | Assistant:""" 554 | prompt = PromptTemplate.from_template(template) 555 | # print(template) 556 | question = prompt.format( 557 | preprompt = preprompt, 558 | sql_result= sql_res, 559 | pinecone_result = pinecone_res, 560 | serp_result = serp_res, 561 | human_input = query 562 | ) 563 | 564 | print("Template >>>", question) 565 | 566 | 567 | llm = ChatOpenAI (temperature=0, model='gpt-4-turbo-preview') 568 | messages = [ 569 | SystemMessage( 570 | content= "You are a helpful assistant that privdes relevant answers" 571 | ), 572 | HumanMessage( 573 | content=question 574 | ) 575 | ] 576 | result = llm(messages) 577 | 578 | end_time = time.time() 579 | print(f'Final query takes {end_time-start_time} seconds') 580 | 581 | return result.content 582 | except Exception as e: 583 | print(str(e)) 584 | return "Error" 585 | 586 | 587 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import os 2 | import uuid 3 | import time 4 | from dotenv import load_dotenv 5 | from flask import Flask, request, jsonify, make_response 6 | from sqlalchemy import func, desc 7 | from flask_cors import CORS 8 | from flask_migrate import Migrate 9 | from werkzeug.utils import secure_filename 10 | from utils import generate_surf_response, generate_kb_from_file, generate_kb_from_url, get_response 11 | from models import db, ChatId, User, PushPrompt, PrePrompt, CloserPrompt, KnowledgeBase, Assistant, ChatHistory, InheritChat 12 | from vectorizor import generate_image, image_qeury, generate_final_answer,pinecone_result, sql_result, serp_result, simple_generate, del_knowledge_by_knowledge_id, del_knowledgebase_by_assistant_id, del_all_records, preprompt_generate, query_with_dolt, sql_connect, pinecone_connect, query_with_both 13 | 14 | app = Flask(__name__) 15 | # app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL") 16 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db?check_same_thread=False&mode=WAL' 17 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 18 | app.config['SQLALCHEMY_POOL_SIZE'] = 20 19 | app.config['UPLOAD_FOLDER'] = os.getenv('UPLOAD_FOLDER') 20 | 21 | db.init_app(app) 22 | migrate = Migrate(app, db) 23 | CORS(app) 24 | 25 | @app.route("/") 26 | def index(): 27 | db.create_all() 28 | # del_all_records() 29 | # print('Deleted') 30 | return "This is APIs for CustomGPT!" 31 | 32 | # User register 33 | @app.route('/register', methods =['POST']) 34 | def register(): 35 | try: 36 | data = request.get_json() 37 | print(data) 38 | name = data['name'] 39 | email = data['email'] 40 | password = data['password'] 41 | new_user = User(name=name, email=email, password=password) 42 | db.session.add(new_user) 43 | db.session.commit() 44 | return make_response(jsonify({'result':new_user.id}), 201) 45 | except Exception as e: 46 | print(str(e)) 47 | return make_response(jsonify({'result':'User already exists'}), 409) 48 | 49 | # User log in 50 | @app.route('/login', methods=['POST']) 51 | def login(): 52 | try: 53 | data = request.get_json() 54 | email = data['email'] 55 | password = data['password'] 56 | user = User.query.filter_by(email=email).first() 57 | if user: 58 | if user.password == password: 59 | return make_response(jsonify({'result':user.id}), 200) 60 | else: 61 | return make_response(jsonify({'result':'Incorrect password'}), 400) 62 | else: 63 | return make_response(jsonify({'result':'User does not exist'}), 400) 64 | except Exception as e: 65 | print(str(e)) 66 | return make_response(jsonify({'result':'Error'}), 400) 67 | 68 | # Google auth 69 | @app.route('/google_auth', methods=['POST']) 70 | def google_auth(): 71 | try: 72 | data = request.get_json() 73 | email = data['email'] 74 | name = data['name'] 75 | if 'password' in data: 76 | password = data['password'] 77 | else: 78 | password = '' 79 | user = User.query.filter_by(email=email).first() 80 | if user: 81 | return make_response(jsonify({'result':user.id}), 201) 82 | new_user = User(email=email, name=name, password=password) 83 | db.session.add(new_user) 84 | db.session.commit() 85 | return make_response(jsonify({'result':new_user.id}), 201) 86 | except Exception as e: 87 | print(str(e)) 88 | return make_response(jsonify({'result':'Error'}), 400) 89 | 90 | @app.route('/test_serp', methods=['POST']) 91 | def test_serp(): 92 | data = request.get_json() 93 | query = data['query'] 94 | result = serp_result(query) 95 | print('Result >>', result) 96 | return make_response(jsonify({'result':result})) 97 | 98 | @app.route('/test_sql', methods =['POST']) 99 | def test_sql(): 100 | data = request.get_json() 101 | assistant_id = data['assistant_id'] 102 | query = data['query'] 103 | result = sql_result(assistant_id=assistant_id, query=query) 104 | print('Result >>>', result) 105 | return make_response(jsonify({'result':result})) 106 | 107 | # Pinecone connectivity test api 108 | @app.route('/test_pinecone', methods =['POST']) 109 | def test_pinecone(): 110 | data = request.get_json() 111 | assistant_id = data['assistant_id'] 112 | query = data['query'] 113 | result = pinecone_result(assistant_id=assistant_id, query=query) 114 | print('Result >>>', result) 115 | return make_response(jsonify({'result':result})) 116 | 117 | 118 | @app.route('/test_weather_api', methods = ['POST']) 119 | def test_weather_api(): 120 | data = request.get_json() 121 | query = data['query'] 122 | result = generate_surf_response(query) 123 | return make_response(jsonify({'response':result}), 201) 124 | 125 | # API to get user's query 126 | @app.route('/user_query', methods=['POST']) 127 | def test_final(): 128 | try: 129 | start_time = time.time() 130 | data = request.form 131 | query = data['query'] 132 | print("Received from frontend=====>", data) 133 | chat_id = data['chat_id'] 134 | chat = '' 135 | hashtags = '' 136 | image_url = '' 137 | response = '' 138 | if 'assistant_id' in data: 139 | assistant_id = data['assistant_id'] 140 | else : 141 | assistant_id = 1 142 | if chat_id: 143 | chat = ChatId.query.filter_by(chat_id = chat_id).first() 144 | if chat == '': # New user 145 | chat_id = str(uuid.uuid4()) 146 | # print(chat_id) 147 | chat = ChatId(chat_id=chat_id) 148 | db.session.add(chat) 149 | db.session.commit() 150 | file = request.files.get('image') 151 | if file: 152 | try: 153 | print('Get files...') 154 | if file.filename=='': 155 | print('No selected file...') 156 | extension = file.filename.rsplit('.', 1)[1].lower() 157 | filename = secure_filename(file.filename) 158 | save_path = app.config['UPLOAD_FOLDER']+ filename 159 | file.save(save_path) 160 | response = image_qeury(query=query, image_path=save_path)['choices'][0]['message']['content'] 161 | except Exception as e: 162 | print(str(e)) 163 | response = "There is an error in Backend!" 164 | else: 165 | print("There is no image file") 166 | if assistant_id == "8": 167 | response, image_url, hashtags = generate_surf_response(query) 168 | 169 | else: 170 | # Get 3 recent chat history 171 | chat_history = ChatHistory.query.filter_by(chat_id=chat_id).order_by(desc(ChatHistory.created_at)).limit(3).all() 172 | latest_records = [chat.json() for chat in chat_history] 173 | response = generate_final_answer(assistant_id=assistant_id, query=query) 174 | 175 | print("assistant id is >>>>>", assistant_id) 176 | if assistant_id == "5": 177 | print("Recipes >>>>>", response) 178 | image_url = generate_image(response) 179 | print("Image Url >>>>>>>",image_url) 180 | closer_prompt = CloserPrompt.query.order_by(func.random()).first() 181 | # print(response) 182 | pre_prompts= preprompt_generate(query, assistant_id) 183 | pre_prompts = pre_prompts.replace('1. ', '').replace('2. ', '').replace('3. ', '').replace('. ', '.').replace('"','') 184 | pre_prompts = pre_prompts.split('\n') 185 | new_chat = ChatHistory(chat_id=chat_id, user_query=query, response=response) 186 | # Save messages to database 187 | db.session.add(new_chat) 188 | db.session.commit() 189 | image_enable = Assistant.query.filter_by(id=assistant_id).first().image 190 | if image_enable == 0: 191 | image_url = '' 192 | end_time = time.time() 193 | # print(response) 194 | print(f"The query took {end_time-start_time} seconds") 195 | print(image_url) 196 | return make_response(jsonify({'response':response, 'closer':closer_prompt.prompt, 'pre_prompts':pre_prompts, 'chat_id':new_chat.chat_id, 'hashtags':hashtags, 'image':image_url}), 201) 197 | 198 | except Exception as e: 199 | print(str(e)) 200 | response = 'Busy network. Try again later' 201 | return make_response(jsonify({'response':response}), 201) 202 | 203 | # Generate image test api 204 | @app.route('/generate_image', methods=['POST']) 205 | def generate_iamge_from(): 206 | data = request.get_json() 207 | query = data['query'] 208 | result = generate_image(query) 209 | return make_response(jsonify({'response':result}), 201) 210 | 211 | def query_from_sql(data): 212 | try: 213 | start_time = time.time() 214 | # print(data) 215 | query = data['query'] 216 | if 'user_id' in data: 217 | user_id = data['user_id'] 218 | else: 219 | user_id = 1 220 | if 'assistant_id' in data: 221 | assistant_id = data['assistant_id'] 222 | else : 223 | assistant_id = 1 224 | if user_id == '': # New user 225 | user_id = str(uuid.uuid4()) 226 | user = User(user_id=user_id) 227 | db.session.add(user) 228 | db.session.commit() 229 | 230 | prompt = Assistant.query.filter_by(assistant_id=assistant_id).first().prompt 231 | # print(f"Prompt of Assistant >>> {prompt}") 232 | # Get 3 recent chat history 233 | chat_history = ChatHistory.query.order_by(desc(ChatHistory.created_at)).limit(3).all() 234 | latest_records = [chat.json() for chat in chat_history] 235 | # print(latest_records) 236 | # return latest_records 237 | response = get_response(query, prompt, latest_records, user_id, assistant_id) 238 | closer_prompt = CloserPrompt.query.order_by(func.random()).first() 239 | 240 | pre_prompts= preprompt_generate(query) 241 | pre_prompts = pre_prompts.replace('1. ', '').replace('2. ', '').replace('3. ', '').replace('. ', '.').replace('"','') 242 | pre_prompts = pre_prompts.split('\n') 243 | new_chat = ChatHistory(user_id=user_id, user_query=query, response=response) 244 | # Save messages to database 245 | db.session.add(new_chat) 246 | db.session.commit() 247 | end_time = time.time() 248 | print(f"The query took {end_time-start_time} seconds") 249 | return make_response(jsonify({'response':response, 'closer':closer_prompt.prompt, 'pre_prompts':pre_prompts, 'chat_id':new_chat.id}), 201) 250 | 251 | except Exception as e: 252 | print(str(e)) 253 | response = 'Busy network. Try again later' 254 | return make_response(jsonify({'response':response}), 201) 255 | 256 | # Response to the query 257 | @app.route('/user_query1', methods=['POST']) 258 | def query(): 259 | try: 260 | data = request.get_json() 261 | print(data) 262 | query = data['query'] 263 | if 'user_id' in data: 264 | user_id = data['user_id'] 265 | else: 266 | user_id = 1 267 | if 'assistant_id' in data: 268 | assistant_id = data['assistant_id'] 269 | else : 270 | assistant_id = 1 271 | prompt = Assistant.query.filter_by(user_id=user_id).first().prompt 272 | 273 | chat_history = ChatHistory.query.order_by(desc(ChatHistory.created_at)).limit(6).all() 274 | latest_records = [chat.json() for chat in chat_history] 275 | # print(latest_records) 276 | # return latest_records 277 | response = get_response(query, prompt, latest_records, user_id, assistant_id) 278 | closer_prompt = CloserPrompt.query.order_by(func.random()).first() 279 | 280 | pre_prompts= preprompt_generate(query) 281 | pre_prompts = pre_prompts.replace('1. ', '').replace('2. ', '').replace('3. ', '').replace('. ', '.').replace('"','') 282 | pre_prompts = pre_prompts.split('\n') 283 | new_chat = ChatHistory(user_id=user_id, user_query=query, response=response) 284 | # Save messages to database 285 | db.session.add(new_chat) 286 | db.session.commit() 287 | # print(response) 288 | return make_response(jsonify({'response':response, 'closer':closer_prompt.prompt, 'pre_prompts':pre_prompts, 'chat_id':new_chat.id}), 201) 289 | 290 | except Exception as e: 291 | print(str(e)) 292 | response = 'Busy network. Try again later' 293 | return make_response(jsonify({'response':response}), 201) 294 | 295 | # Response from dolt 296 | @app.route('/user_query2', methods=['POST']) 297 | def query_from_dolt(): 298 | try: 299 | start_time = time.time() 300 | data = request.get_json() 301 | query = data['query'] 302 | print(data) 303 | if 'user_id' in data: 304 | user_id = data['user_id'] 305 | else: 306 | user_id = 1 307 | if 'assistant_id' in data: 308 | assistant_id = data['assistant_id'] 309 | else : 310 | assistant_id = 1 311 | if user_id == '': # New user 312 | user_id = str(uuid.uuid4()) 313 | user = User(user_id=user_id) 314 | db.session.add(user) 315 | db.session.commit() 316 | print(user_id) 317 | assistant = Assistant.query.filter_by(id = assistant_id).first() 318 | use_sql = assistant.use_sql 319 | use_pinecone = assistant.use_pinecone 320 | prompt = assistant.prompt 321 | 322 | chat_history = ChatHistory.query.filter_by(user_id=user_id).order_by(desc(ChatHistory.created_at)).limit(6).all() 323 | latest_records = [chat.json() for chat in chat_history] 324 | if use_sql == 1 and use_pinecone == 0: 325 | print('Only SQL>>>') 326 | response = query_with_dolt(query, prompt, assistant_id) 327 | if use_sql ==0 and use_pinecone == 1: 328 | print('Only Pinecone>>>') 329 | response = get_response(query=query, prompt=prompt, latest_records=latest_records, assistant_id=assistant_id) 330 | if use_sql ==0 and use_pinecone == 0: 331 | print('Only None>>>') 332 | response = simple_generate(query) 333 | if use_sql == 1 and use_pinecone == 1: 334 | response = query_with_both(query, prompt, assistant_id) 335 | closer_prompt = CloserPrompt.query.order_by(func.random()).first() 336 | 337 | pre_prompts= preprompt_generate(query) 338 | pre_prompts = pre_prompts.replace('1. ', '').replace('2. ', '').replace('3. ', '').replace('. ', '.').replace('"','') 339 | pre_prompts = pre_prompts.split('\n') 340 | 341 | new_chat = ChatHistory(user_id=user_id, user_query=query, response=response) 342 | db.session.add(new_chat) 343 | db.session.commit() 344 | end_time = time.time() 345 | print(f"The query took {end_time-start_time} seconds") 346 | print(new_chat.user_id) 347 | return make_response(jsonify({'response':response, 'closer':closer_prompt.prompt, 'pre_prompts':pre_prompts, 'chat_id':new_chat.user_id}), 201) 348 | 349 | except TypeError as e: 350 | print(str(e)) 351 | response = 'Bad structure of database!' 352 | return make_response(jsonify({'response':response}), 201) 353 | except ValueError as e: 354 | print(str(e)) 355 | response = 'Invalid value' 356 | return make_response(jsonify({'response':response}), 201) 357 | except Exception as e: 358 | print(str(e)) 359 | response = 'Token limit' 360 | return make_response(jsonify({'response':response}), 201) 361 | 362 | 363 | # Delete message 364 | @app.route('/del_message', methods = ['POST']) 365 | def del_message(): 366 | try: 367 | data = request.get_json() 368 | chat_id = data['chat_id'] 369 | chat_history = ChatHistory.query.filter_by(id=chat_id).first() 370 | db.session.delete(chat_history) 371 | db.session.commit() 372 | return make_response(jsonify({'chat_id':chat_id}), 201) 373 | except: 374 | return make_response(jsonify({'result':'Failed!'}), 201) 375 | 376 | # Get chat history 377 | @app.route('/get_chat_history', methods =['POST']) 378 | def get_chats(): 379 | try: 380 | data = request.get_json() 381 | print(data) 382 | chat_id = data['user_id'] 383 | if 'hsitory_id' in data: 384 | history_id = data['history_id'] 385 | print('From shared history...', history_id) 386 | pre_chats = ChatHistory.query.filter_by(chat_id=chat_id).all() 387 | db.session.delete(pre_chats) 388 | db.session.commit() 389 | shared_chats = InheritChat.query.filter_by(history_id=history_id).all() 390 | for chat in shared_chats: 391 | new_chat = ChatHistory(chat_id=chat_id, user_query=chat.user_query, response=chat.response) 392 | db.session.add(new_chat) 393 | db.session.commit() 394 | chats = ChatHistory.query.filter_by(chat_id=chat_id).all() 395 | print('No shared') 396 | if chats: 397 | return make_response(jsonify([chat.json() for chat in chats]), 201) 398 | return make_response(jsonify({'result':'Not found!'})) 399 | except Exception as e: 400 | 401 | print(str(e)) 402 | return make_response(jsonify({'result':'Server Error!'}), 201) 403 | 404 | # Get and Add push prompt 405 | @app.route('/push_prompt', methods = ['POST', 'GET']) 406 | def push_prompt(): 407 | if request.method == 'GET': 408 | try: 409 | assistant_id = request.args.get('assistant_id') 410 | with app.app_context(): 411 | push_prompts = PushPrompt.query.filter_by(assistant_id=assistant_id).all() 412 | return make_response(jsonify([push_prompt.json() for push_prompt in push_prompts]), 200) 413 | except Exception as e: 414 | print(str(e)) 415 | return make_response(jsonify({'prompts':'Error'}), 500) 416 | if request.method == 'POST': 417 | try: 418 | with app.app_context(): 419 | data = request.get_json() 420 | prompt = data['prompt'] 421 | assistant_id = data['assistant_id'] 422 | push_prompt = PushPrompt(prompt=prompt, assistant_id= assistant_id) 423 | db.session.add(push_prompt) 424 | db.session.commit() 425 | # push_prompt = PushPrompt.query.filter_by(prompt=prompt).first() 426 | return make_response(jsonify(push_prompt.json()), 201) 427 | except Exception as e: 428 | print(str(e)) 429 | return make_response(jsonify({'result':'Failed'}), 500) 430 | 431 | # Get and add pre-prompt 432 | @app.route('/pre_prompt', methods = ['POST', 'GET']) 433 | def pre_prompt(): 434 | if request.method == 'GET': 435 | assistant_id = request.args.get('assistant_id') 436 | with app.app_context(): 437 | pre_prompts = PrePrompt.query.filter_by(assistant_id=assistant_id).all() 438 | return make_response(jsonify([pre_prompt.json() for pre_prompt in pre_prompts])) 439 | 440 | if request.method == 'POST': 441 | try: 442 | with app.app_context(): 443 | data = request.get_json() 444 | prompt = data['prompt'] 445 | title = data['title'] 446 | assistant_id = data['assistant_id'] 447 | pre_prompt = PrePrompt(assistant_id=assistant_id, title=title ,prompt=prompt) 448 | db.session.add(pre_prompt) 449 | db.session.commit() 450 | return make_response(jsonify(pre_prompt.json()), 201) 451 | except Exception as e: 452 | print(str(e)) 453 | return make_response(jsonify({'result':'Failed'}), 500) 454 | 455 | # Get and add closer prompt 456 | @app.route('/closer_prompt', methods = ['POST', 'GET']) 457 | def closer_prompt(): 458 | 459 | if request.method == 'GET': 460 | assistant_id = request.args.get('assistant_id') 461 | 462 | with app.app_context(): 463 | 464 | closer_prompts = CloserPrompt.query.filter_by(assistant_id=assistant_id).all() 465 | return make_response(jsonify([closer_prompt.json() for closer_prompt in closer_prompts])) 466 | 467 | if request.method == 'POST': 468 | try: 469 | with app.app_context(): 470 | data = request.get_json() 471 | prompt = data['prompt'] 472 | assistant_id = data['assistant_id'] 473 | closer_prompt = CloserPrompt(assistant_id=assistant_id, prompt=prompt) 474 | db.session.add(closer_prompt) 475 | db.session.commit() 476 | # closer_prompt = CloserPrompt.query.filter_by(prompt=prompt).first() 477 | return make_response(jsonify(closer_prompt.json()), 201) 478 | except Exception as e: 479 | print(str(e)) 480 | return make_response(jsonify({'result':'Failed'}), 500) 481 | 482 | @app.route('/prompt', methods = ['POST', 'GET']) 483 | def prompt(): 484 | if request.method == 'GET': 485 | assistant_id = request.args.get('assistant_id') 486 | 487 | with app.app_context(): 488 | 489 | prompts = Prompt.query.filter_by(assistant_id=assistant_id).all() 490 | return make_response(jsonify([prompt.json() for prompt in prompts])) 491 | 492 | if request.method == 'POST': 493 | try: 494 | with app.app_context(): 495 | data = request.get_json() 496 | prompt = data['prompt'] 497 | assistant_id = data['assistant_id'] 498 | prompt = Prompt(assistant_id=assistant_id, prompt=prompt) 499 | db.session.add(prompt) 500 | db.session.commit() 501 | # closer_prompt = CloserPrompt.query.filter_by(prompt=prompt).first() 502 | return make_response(jsonify(prompt.json()), 201) 503 | except Exception as e: 504 | print(str(e)) 505 | return make_response(jsonify({'result':'Failed'}), 500) 506 | 507 | # Delete push prompt 508 | @app.route('/del_push_prompt', methods=['POST']) 509 | def delete_push_prompt(): 510 | try: 511 | with app.app_context(): 512 | data = request.get_json() 513 | id = data['id'] 514 | push_prompt = PushPrompt.query.filter_by(id=id).first() 515 | if push_prompt: 516 | db.session.delete(push_prompt) 517 | db.session.commit() 518 | return make_response(jsonify({'id':id}), 200) 519 | return make_response(jsonify({'message':'Not found!'}), 404) 520 | except Exception as e: 521 | print(str(e)) 522 | return make_response(jsonify({'message':'Error deleting'}), 500) 523 | 524 | # Delete pre prompt 525 | @app.route('/del_pre_prompt', methods=['POST']) 526 | def delete_pre_prompt(): 527 | try: 528 | with app.app_context(): 529 | data = request.get_json() 530 | id = data['id'] 531 | pre_prompt = PrePrompt.query.filter_by(id=id).first() 532 | if pre_prompt: 533 | db.session.delete(pre_prompt) 534 | db.session.commit() 535 | return make_response(jsonify({'id':id}), 200) 536 | return make_response(jsonify({'message':'Not found!'}), 404) 537 | except Exception as e: 538 | print(str(e)) 539 | return make_response(jsonify({'message':'Error deleting'}), 500) 540 | 541 | # Delete closer prompt 542 | @app.route('/del_closer_prompt', methods=['POST']) 543 | def delete_closer_prompt(): 544 | try: 545 | with app.app_context(): 546 | data = request.get_json() 547 | id = data['id'] 548 | closer_prompt = CloserPrompt.query.filter_by(id=id).first() 549 | if closer_prompt: 550 | db.session.delete(closer_prompt) 551 | db.session.commit() 552 | return make_response(jsonify({'id':id}), 200) 553 | return make_response(jsonify({'message':'Not found!'}), 404) 554 | except Exception as e: 555 | print(str(e)) 556 | return make_response(jsonify({'message':'Error deleting'}), 500) 557 | 558 | # Update pre-prompt 559 | @app.route('/update_pre_prompt', methods=['POST']) 560 | def update_pre_prompt(): 561 | try: 562 | with app.app_context(): 563 | data = request.get_json() 564 | id = data['id'] 565 | prompt = data['prompt'] 566 | title = data['title'] 567 | pre_prompt = PrePrompt.query.filter_by(id=id).first() 568 | if pre_prompt: 569 | pre_prompt.title = title 570 | pre_prompt.prompt = prompt 571 | db.session.commit() 572 | return make_response(jsonify(pre_prompt.json()), 200) 573 | return make_response(jsonify({'message':'Not found!'}), 404) 574 | except Exception as e: 575 | print(str(e)) 576 | return make_response(jsonify({'message':'Already exits!'}), 500) 577 | 578 | # Update prompt 579 | @app.route('/update_prompt', methods=['POST']) 580 | def update_prompt(): 581 | try: 582 | with app.app_context(): 583 | data = request.get_json() 584 | id = data['assistant_id'] 585 | prompt = data['prompt'] 586 | pre_prompt = Assistant.query.filter_by(id=id).first() 587 | if pre_prompt: 588 | pre_prompt.prompt = prompt 589 | db.session.commit() 590 | return make_response(jsonify(pre_prompt.json()), 200) 591 | return make_response(jsonify({'message':'Not found!'}), 404) 592 | except Exception as e: 593 | print(str(e)) 594 | return make_response(jsonify({'message':'Busy network! Try later!'}), 500) 595 | 596 | # Update push-prompt 597 | @app.route('/update_push_prompt', methods=['POST']) 598 | def update_push_prompt(): 599 | try: 600 | with app.app_context(): 601 | data = request.get_json() 602 | id = data['id'] 603 | prompt = data['prompt'] 604 | push_prompt = PushPrompt.query.filter_by(id=id).first() 605 | if push_prompt: 606 | push_prompt.prompt = prompt 607 | db.session.commit() 608 | return make_response(jsonify(push_prompt.json()), 200) 609 | return make_response(jsonify({'message':'Not found!'}), 404) 610 | except Exception as e: 611 | print(str(e)) 612 | return make_response(jsonify({'message':'Already exits!'}), 500) 613 | 614 | # Update pre-prompt 615 | @app.route('/update_closer_prompt', methods=['POST']) 616 | def update_closer_prompt(): 617 | try: 618 | with app.app_context(): 619 | data = request.get_json() 620 | id = data['id'] 621 | prompt = data['prompt'] 622 | closer_prompt = CloserPrompt.query.filter_by(id=id).first() 623 | if closer_prompt: 624 | closer_prompt.prompt = prompt 625 | db.session.commit() 626 | return make_response(jsonify(closer_prompt.json()), 200) 627 | return make_response(jsonify({'message':'Not found!'}), 404) 628 | except Exception as e: 629 | print(str(e)) 630 | return make_response(jsonify({'message':'Already exits!'}), 500) 631 | 632 | # Add a new knowledge to a certain assistant 633 | @app.route('/add_knowledge', methods=['POST']) 634 | def add_knowledge(): 635 | if 'assistant_id' in request.form: 636 | assistant_id = request.form['assistant_id'] 637 | assistant = Assistant.query.filter_by(id=assistant_id).first() 638 | pinecone_api_key = assistant.pinecone_api_key 639 | pinecone_environment = assistant.pinecone_environment 640 | pinecone_index_name = assistant.pinecone_index_name 641 | file = request.files.get('file') 642 | if file: 643 | try: 644 | print('Get files...') 645 | if file.filename=='': 646 | print('No selected file...') 647 | extension = file.filename.rsplit('.', 1)[1].lower() 648 | filename = secure_filename(file.filename) 649 | save_path = app.config['UPLOAD_FOLDER']+ filename 650 | file.save(save_path) 651 | new_knowledge = KnowledgeBase(assistant_id=assistant_id, name=filename, type_of_knowledge=extension, count=0) 652 | db.session.add(new_knowledge) 653 | db.session.commit() 654 | count = generate_kb_from_file(assistant_id, new_knowledge.id, save_path, pinecone_api_key, pinecone_index_name) 655 | 656 | knowledge = KnowledgeBase.query.filter_by(id=new_knowledge.id).first() 657 | knowledge.count = count 658 | db.session.commit() 659 | print('Succesfully saved a file', count) 660 | # Save to pinecone 661 | 662 | 663 | return make_response(jsonify(new_knowledge.json()), 201) 664 | except Exception as e: 665 | print(str(e)) 666 | return make_response(jsonify({'result':'Failed!'}), 500) 667 | if 'knowledge_name' in request.form : 668 | knowledge_name = request.form['knowledge_name'] 669 | if knowledge_name: 670 | with app.app_context(): 671 | try: 672 | new_knowledge = KnowledgeBase(assistant_id=assistant_id, name=knowledge_name, type_of_knowledge='URL', count=0) 673 | db.session.add(new_knowledge) 674 | db.session.commit() 675 | count = generate_kb_from_url(assistant_id=assistant_id, knowledge_id=new_knowledge.id, url=knowledge_name, api_key=pinecone_api_key, index_name=pinecone_index_name) 676 | if count == -1: 677 | return make_response(jsonify({'result':'Invalid URL'}), 200) 678 | knowledge = KnowledgeBase.query.filter_by(id=new_knowledge.id).first() 679 | knowledge.count = count 680 | db.session.commit() 681 | print('Successfully saved a URL', count) 682 | return make_response(jsonify(new_knowledge.json()), 200) 683 | except Exception as e: 684 | print(str(e)) 685 | return make_response(jsonify({'result':'Failed!'}), 201) 686 | return make_response(jsonify({'result':'Invalid data format'}), 500) 687 | 688 | # Get knowledge bases for a specific assistant_id 689 | @app.route('/get_knowledge', methods = ['POST']) 690 | def get_knowledge(): 691 | data = request.get_json() 692 | assistant_id = data['assistant_id'] 693 | print(data) 694 | with app.app_context(): 695 | try: 696 | knowledge_bases = KnowledgeBase.query.filter_by(assistant_id=assistant_id).all() 697 | if knowledge_bases: 698 | print(knowledge_bases[0].json()) 699 | return make_response(jsonify([knowledge_base.json() for knowledge_base in knowledge_bases]), 200) 700 | return make_response(jsonify({'result':'Not found'}), 200) 701 | except Exception as e: 702 | print(str(e)) 703 | return make_response(jsonify({'result':'Failed!'}), 500) 704 | 705 | # Delete knowledge base for a specific knowledge_id 706 | @app.route('/del_knowledge', methods=['POST']) 707 | def delete_knowledge(): 708 | try: 709 | with app.app_context(): 710 | data = request.get_json() 711 | # print(data) 712 | id = data['id'] 713 | knowledge_base = KnowledgeBase.query.filter_by(id=id).first() 714 | 715 | if knowledge_base: 716 | print(knowledge_base.assistant_id) 717 | # Delete knowledge in pinecone 718 | del_knowledge_by_knowledge_id(id, knowledge_base.assistant_id) 719 | db.session.delete(knowledge_base) 720 | db.session.commit() 721 | return make_response(jsonify({'id':id}), 200) 722 | return make_response(jsonify({'message':'Not found!'}), 404) 723 | except Exception as e: 724 | print(str(e)) 725 | return make_response(jsonify({'message':'Error deleting'}), 500) 726 | 727 | # Add a new assistant 728 | @app.route('/add_assistant', methods=['POST']) 729 | def add_assistant(): 730 | data = request.get_json() 731 | assistant_name = data['assistant_name'] 732 | prompt = data['prompt'] 733 | use_sql = data['use_sql'] 734 | use_pinecone = data['use_pinecone'] 735 | use_serp = data['use_serp'] 736 | facebook_enable = data['facebook_enable'] 737 | assistant_avatar = data['assistant_avatar'] 738 | user_avatar = data['user_avatar'] 739 | weather_api = data['weather_api'] 740 | image_enable = data['image_enable'] 741 | print(data) 742 | if use_sql: 743 | sql_host = data['sql_host'] 744 | sql_username = data['sql_username'] 745 | sql_password = data['sql_password'] 746 | sql_db_name = data['sql_db_name'] 747 | sql_port = data['sql_port'] 748 | else: 749 | sql_host = '' 750 | sql_username = '' 751 | sql_password = '' 752 | sql_db_name = '' 753 | sql_port = '' 754 | if use_pinecone: 755 | pinecone_api_key = data['pinecone_api_key'] 756 | pinecone_environment = data['pinecone_environment'] 757 | pinecone_index_name = data['pinecone_index_name'] 758 | else: 759 | pinecone_api_key = '' 760 | pinecone_environment = '' 761 | pinecone_index_name = '' 762 | if facebook_enable: 763 | facebook_token = data['facebook_token'] 764 | else: 765 | facebook_token = '' 766 | 767 | with app.app_context(): 768 | try: 769 | new_assistant = Assistant(name=assistant_name, prompt=prompt, use_sql=use_sql,use_pinecone=use_pinecone,use_serp=use_serp, facebook_enable=facebook_enable, facebook_token=facebook_token, sql_host=sql_host, sql_username=sql_username, sql_password=sql_password, sql_port=sql_port, sql_db_name=sql_db_name, pinecone_api_key=pinecone_api_key, pinecone_environment=pinecone_environment, pinecone_index_name=pinecone_index_name, assistant_avatar = assistant_avatar, user_avatar= user_avatar, weather_api=weather_api, image = image_enable) 770 | db.session.add(new_assistant) 771 | db.session.commit() 772 | print('Successfully saved assistant') 773 | return make_response(jsonify(new_assistant.json()),201) 774 | except Exception as e: 775 | print(str(e)) 776 | return make_response(jsonify({'result':'Error saving'})) 777 | 778 | # Get assistants 779 | @app.route('/get_assistant', methods=['GET', 'POST']) 780 | def get_assistant(): 781 | if request.method == 'GET': 782 | with app.app_context(): 783 | try: 784 | assistants = Assistant.query.all() 785 | print(assistants) 786 | return make_response(jsonify([assistant.json() for assistant in assistants])) 787 | except Exception as e: 788 | print(str(e)) 789 | return make_response(jsonify({'result':'Database Error'})) 790 | if request.method == 'POST': 791 | data = request.get_json() 792 | id = data['assistant_id'] 793 | with app.app_context(): 794 | try: 795 | assistant = Assistant.query.filter_by(id=id).first() 796 | return make_response(jsonify(assistant.json()),200) 797 | except Exception as e: 798 | print(str(e)) 799 | return make_response(jsonify({'result':'Failed!'})) 800 | 801 | # Delete an assistant 802 | @app.route('/del_assistant', methods=['POST']) 803 | def del_assistant(): 804 | data = request.get_json() 805 | id = data['id'] 806 | with app.app_context(): 807 | try: 808 | assistant = Assistant.query.filter_by(id=id).first() 809 | if assistant: 810 | db.session.delete(assistant) 811 | db.session.commit() 812 | del_knowledgebase_by_assistant_id(id) 813 | return make_response(jsonify({'id':id})) 814 | except: 815 | return make_response(jsonify({'result':'Failed!'})) 816 | 817 | # Update the name of assistant 818 | @app.route('/update_assistant', methods=['POST']) 819 | def update_assistant(): 820 | try: 821 | data = request.get_json() 822 | id = data['id'] 823 | prompt = data['prompt'] 824 | assistant_name = data['assistant_name'] 825 | use_sql = data['use_sql'] 826 | use_serp = data['use_serp'] 827 | use_pinecone = data['use_pinecone'] 828 | facebook_enable = data['facebook_enable'] 829 | assistant_avatar = data['assistant_avatar'] 830 | user_avatar = data['user_avatar'] 831 | weather_api = data['weather_api'] 832 | image_enable = data['image_enable'] 833 | if use_sql: 834 | sql_host = data['sql_host'] 835 | sql_username = data['sql_username'] 836 | sql_password = data['sql_password'] 837 | sql_db_name = data['sql_db_name'] 838 | sql_port = data['sql_port'] 839 | else: 840 | sql_host = '' 841 | sql_username = '' 842 | sql_password = '' 843 | sql_db_name = '' 844 | sql_port = '' 845 | if use_pinecone: 846 | pinecone_api_key = data['pinecone_api_key'] 847 | pinecone_environment = data['pinecone_environment'] 848 | pinecone_index_name = data['pinecone_index_name'] 849 | else: 850 | pinecone_api_key = '' 851 | pinecone_environment = '' 852 | pinecone_index_name = '' 853 | 854 | if facebook_enable: 855 | facebook_token = data['facebook_token'] 856 | else: 857 | facebook_token = '' 858 | assistant = Assistant.query.filter_by(id=id).first() 859 | if assistant: 860 | assistant.name = assistant_name 861 | assistant.prompt = prompt 862 | assistant.use_sql = use_sql 863 | assistant.use_pinecone = use_pinecone 864 | assistant.use_serp = use_serp 865 | assistant.sql_host = sql_host 866 | assistant.sql_username = sql_username 867 | assistant.sql_password = sql_password 868 | assistant.sql_db_name = sql_db_name 869 | assistant.sql_port = sql_port 870 | assistant.pinecone_api_key = pinecone_api_key 871 | assistant.pinecone_environment = pinecone_environment 872 | assistant.pinecone_index_name = pinecone_index_name 873 | assistant.facebook_enable = facebook_enable 874 | assistant.facebook_token = facebook_token 875 | assistant.assistant_avatar = assistant_avatar 876 | assistant.user_avatar = user_avatar 877 | assistant.weather_api = weather_api 878 | assistant.image = image_enable 879 | 880 | db.session.commit() 881 | return make_response(jsonify(assistant.json()), 201) 882 | return make_response(jsonify({'result':'Not found'}), 201) 883 | except Exception as e: 884 | print(str(e)) 885 | return make_response(jsonify({'result':'Failed'}), 500) 886 | 887 | # Get the first 3 random pre-prompts 888 | @app.route('/get_initial_prompts', methods=['GET']) 889 | def get_initial_prompts(): 890 | assistant_id = request.args.get('assistant_id') 891 | row_count = PrePrompt.query.count() 892 | if row_count > 2: 893 | preprompts = PrePrompt.query.filter_by(assistant_id=assistant_id).order_by(func.random()).limit(3) 894 | print(preprompts) 895 | return make_response(jsonify([preprompt.json() for preprompt in preprompts]), 200) 896 | if row_count > 0: 897 | preprompts = PrePrompt.query.all() 898 | return make_response(jsonify([preprompt.json() for preprompt in preprompts])) 899 | 900 | return make_response(jsonify({'result':'None'})) 901 | 902 | # Share the link[] 903 | @app.route('/share_chat', methods = ['POST']) 904 | def share_chat(): 905 | try: 906 | data = request.get_json() 907 | user_id = data['user_id'] 908 | 909 | user = User.query.filter_by(id=user_id).first() 910 | if user.shared == 0: 911 | user.shared = 1 912 | history_id = str(uuid.uuid4()) 913 | user.history_id = history_id 914 | with app.app_context(): 915 | chats = ChatHistory.query.filter_by(user_id=user_id).all() 916 | for chat in chats: 917 | new_history = InheritChat(history_id=history_id, user_query=chat.user_query, response=chat.response) 918 | db.session.add(new_history) 919 | db.session.commit() 920 | return make_response(jsonify({'history_id':history_id}), 201) 921 | history_id = user.history_id 922 | return make_response(jsonify({'history_id':history_id}), 201) 923 | 924 | except Exception as e: 925 | print(str(e)) 926 | return make_response(jsonify({'result':'Failed!'}), 500) 927 | 928 | # Test SQL connection 929 | @app.route('/test_sql_connection', methods =['POST']) 930 | def test_sql_connection(): 931 | try: 932 | data = request.get_json() 933 | host = data['host'] 934 | username = data['username'] 935 | password = data['password'] 936 | db_name = data['db_name'] 937 | port = data['port'] 938 | db = sql_connect(host=host, username=username, port=port, password=password, db_name=db_name) 939 | 940 | if db: 941 | db.close() 942 | return make_response(jsonify({'result':True}), 200) 943 | else: 944 | return make_response(jsonify({'result':True}), 200) 945 | 946 | except Exception as e: 947 | print(str(e)) 948 | return make_response(jsonify({'result':'Busy server. Try again later!'}), 500) 949 | 950 | # Test Pinecone connections 951 | @app.route('/test_pinecone_connection', methods = ['POST']) 952 | def test_pinecone_connection(): 953 | try: 954 | data = request.get_json() 955 | api_key = data['api_key'] 956 | environment = data['environment'] 957 | index_name = data['index_name'] 958 | res = pinecone_connect(api_key=api_key, environment=environment, index_name=index_name) 959 | 960 | if res["success"]: 961 | return make_response(jsonify({'result':True}), 200) 962 | else: 963 | return make_response(jsonify({'result':False}), 200) 964 | 965 | except Exception as e: 966 | print(str(e)) 967 | return make_response(jsonify({'result':False}), 200) 968 | 969 | 970 | if __name__ == '__main__': 971 | app.run(debug=True) 972 | 973 | -------------------------------------------------------------------------------- /json_file.json: -------------------------------------------------------------------------------- 1 | { 2 | "orlandohealth.com": "{\"Hospital name\":{\"0\":\"Bayfront Health St. Petersburg\",\"1\":\"Bayfront Health St. Petersburg\",\"2\":\"Bayfront Health St. Petersburg\",\"3\":\"Bayfront Health St. Petersburg\",\"4\":\"Bayfront Health St. Petersburg\",\"5\":\"Bayfront Health St. Petersburg\",\"6\":\"Bayfront Health St. Petersburg\",\"7\":\"Bayfront Health St. Petersburg\",\"8\":\"Bayfront Health St. Petersburg\",\"9\":\"Bayfront Health St. Petersburg\",\"10\":\"Orlando Health - Health Central Hospital\",\"11\":\"Orlando Health - Health Central Hospital\",\"12\":\"Orlando Health - Health Central Hospital\",\"13\":\"Orlando Health - Health Central Hospital\",\"14\":\"Orlando Health - Health Central Hospital\",\"15\":\"Orlando Health - Health Central Hospital\",\"16\":\"Orlando Health - Health Central Hospital\",\"17\":\"Orlando Health - Health Central Hospital\",\"18\":\"Orlando Health - Health Central Hospital\",\"19\":\"Orlando Health - Health Central Hospital\",\"20\":\"Orlando Health Arnold Palmer Hospital for Children\",\"21\":\"Orlando Health Arnold Palmer Hospital for Children\",\"22\":\"Orlando Health Arnold Palmer Hospital for Children\",\"23\":\"Orlando Health Arnold Palmer Hospital for Children\",\"24\":\"Orlando Health Arnold Palmer Hospital for Children\",\"25\":\"Orlando Health Arnold Palmer Hospital for Children\",\"26\":\"Orlando Health Arnold Palmer Hospital for Children\",\"27\":\"Orlando Health Arnold Palmer Hospital for Children\",\"28\":\"Orlando Health Arnold Palmer Hospital for Children\",\"29\":\"Orlando Health Arnold Palmer Hospital for Children\",\"30\":\"Orlando Health Dr P. Phillips Hospital\",\"31\":\"Orlando Health Dr P. Phillips Hospital\",\"32\":\"Orlando Health Dr P. Phillips Hospital\",\"33\":\"Orlando Health Dr P. Phillips Hospital\",\"34\":\"Orlando Health Dr P. Phillips Hospital\",\"35\":\"Orlando Health Dr P. Phillips Hospital\",\"36\":\"Orlando Health Dr P. Phillips Hospital\",\"37\":\"Orlando Health Dr P. Phillips Hospital\",\"38\":\"Orlando Health Dr P. Phillips Hospital\",\"39\":\"Orlando Health Dr P. Phillips Hospital\",\"40\":\"Orlando Health Horizon West Hospital\",\"41\":\"Orlando Health Horizon West Hospital\",\"42\":\"Orlando Health Horizon West Hospital\",\"43\":\"Orlando Health Horizon West Hospital\",\"44\":\"Orlando Health Horizon West Hospital\",\"45\":\"Orlando Health Horizon West Hospital\",\"46\":\"Orlando Health Horizon West Hospital\",\"47\":\"Orlando Health Horizon West Hospital\",\"48\":\"Orlando Health Horizon West Hospital\",\"49\":\"Orlando Health Horizon West Hospital\",\"50\":\"Orlando Health Imaging Centers Alafaya\",\"51\":\"Orlando Health Imaging Centers Alafaya\",\"52\":\"Orlando Health Imaging Centers Alafaya\",\"53\":\"Orlando Health Imaging Centers Alafaya\",\"54\":\"Orlando Health Imaging Centers Alafaya\",\"55\":\"Orlando Health Imaging Centers Alafaya\",\"56\":\"Orlando Health Imaging Centers Alafaya\",\"57\":\"Orlando Health Imaging Centers Alafaya\",\"58\":\"Orlando Health Imaging Centers Alafaya\",\"59\":\"Orlando Health Imaging Centers Alafaya\",\"60\":\"Orlando Health Imaging Centers Altamonte Springs\",\"61\":\"Orlando Health Imaging Centers Altamonte Springs\",\"62\":\"Orlando Health Imaging Centers Altamonte Springs\",\"63\":\"Orlando Health Imaging Centers Altamonte Springs\",\"64\":\"Orlando Health Imaging Centers Altamonte Springs\",\"65\":\"Orlando Health Imaging Centers Altamonte Springs\",\"66\":\"Orlando Health Imaging Centers Altamonte Springs\",\"67\":\"Orlando Health Imaging Centers Altamonte Springs\",\"68\":\"Orlando Health Imaging Centers Altamonte Springs\",\"69\":\"Orlando Health Imaging Centers Altamonte Springs\",\"70\":\"Orlando Health Imaging Centers Columbia\",\"71\":\"Orlando Health Imaging Centers Columbia\",\"72\":\"Orlando Health Imaging Centers Columbia\",\"73\":\"Orlando Health Imaging Centers Columbia\",\"74\":\"Orlando Health Imaging Centers Columbia\",\"75\":\"Orlando Health Imaging Centers Columbia\",\"76\":\"Orlando Health Imaging Centers Columbia\",\"77\":\"Orlando Health Imaging Centers Columbia\",\"78\":\"Orlando Health Imaging Centers Columbia\",\"79\":\"Orlando Health Imaging Centers Columbia\",\"80\":\"Orlando Health Imaging Centers Lake Mary\",\"81\":\"Orlando Health Imaging Centers Lake Mary\",\"82\":\"Orlando Health Imaging Centers Lake Mary\",\"83\":\"Orlando Health Imaging Centers Lake Mary\",\"84\":\"Orlando Health Imaging Centers Lake Mary\",\"85\":\"Orlando Health Imaging Centers Lake Mary\",\"86\":\"Orlando Health Imaging Centers Lake Mary\",\"87\":\"Orlando Health Imaging Centers Lake Mary\",\"88\":\"Orlando Health Imaging Centers Lake Mary\",\"89\":\"Orlando Health Imaging Centers Lake Mary\",\"90\":\"Orlando Health Imaging Centers Ocoee\",\"91\":\"Orlando Health Imaging Centers Ocoee\",\"92\":\"Orlando Health Imaging Centers Ocoee\",\"93\":\"Orlando Health Imaging Centers Ocoee\",\"94\":\"Orlando Health Imaging Centers Ocoee\",\"95\":\"Orlando Health Imaging Centers Ocoee\",\"96\":\"Orlando Health Imaging Centers Ocoee\",\"97\":\"Orlando Health Imaging Centers Ocoee\",\"98\":\"Orlando Health Imaging Centers Ocoee\",\"99\":\"Orlando Health Imaging Centers Ocoee\",\"100\":\"Orlando Health Imaging Centers Osceola\",\"101\":\"Orlando Health Imaging Centers Osceola\",\"102\":\"Orlando Health Imaging Centers Osceola\",\"103\":\"Orlando Health Imaging Centers Osceola\",\"104\":\"Orlando Health Imaging Centers Osceola\",\"105\":\"Orlando Health Imaging Centers Osceola\",\"106\":\"Orlando Health Imaging Centers Osceola\",\"107\":\"Orlando Health Imaging Centers Osceola\",\"108\":\"Orlando Health Imaging Centers Osceola\",\"109\":\"Orlando Health Imaging Centers Osceola\",\"110\":\"Orlando Health Imaging Centers Spring Lake\",\"111\":\"Orlando Health Imaging Centers Spring Lake\",\"112\":\"Orlando Health Imaging Centers Spring Lake\",\"113\":\"Orlando Health Imaging Centers Spring Lake\",\"114\":\"Orlando Health Imaging Centers Spring Lake\",\"115\":\"Orlando Health Imaging Centers Spring Lake\",\"116\":\"Orlando Health Imaging Centers Spring Lake\",\"117\":\"Orlando Health Imaging Centers Spring Lake\",\"118\":\"Orlando Health Imaging Centers Spring Lake\",\"119\":\"Orlando Health Imaging Centers Spring Lake\",\"120\":\"Orlando Health Imaging Centers Summerport\",\"121\":\"Orlando Health Imaging Centers Summerport\",\"122\":\"Orlando Health Imaging Centers Summerport\",\"123\":\"Orlando Health Imaging Centers Summerport\",\"124\":\"Orlando Health Imaging Centers Summerport\",\"125\":\"Orlando Health Imaging Centers Summerport\",\"126\":\"Orlando Health Imaging Centers Summerport\",\"127\":\"Orlando Health Imaging Centers Summerport\",\"128\":\"Orlando Health Imaging Centers Summerport\",\"129\":\"Orlando Health Imaging Centers Summerport\",\"130\":\"Orlando Health Imaging Centers Winter Park\",\"131\":\"Orlando Health Imaging Centers Winter Park\",\"132\":\"Orlando Health Imaging Centers Winter Park\",\"133\":\"Orlando Health Imaging Centers Winter Park\",\"134\":\"Orlando Health Imaging Centers Winter Park\",\"135\":\"Orlando Health Imaging Centers Winter Park\",\"136\":\"Orlando Health Imaging Centers Winter Park\",\"137\":\"Orlando Health Imaging Centers Winter Park\",\"138\":\"Orlando Health Imaging Centers Winter Park\",\"139\":\"Orlando Health Imaging Centers Winter Park\",\"140\":\"Orlando Health Jewett Orthopedic Institute\",\"141\":\"Orlando Health Jewett Orthopedic Institute\",\"142\":\"Orlando Health Jewett Orthopedic Institute\",\"143\":\"Orlando Health Jewett Orthopedic Institute\",\"144\":\"Orlando Health Jewett Orthopedic Institute\",\"145\":\"Orlando Health Jewett Orthopedic Institute\",\"146\":\"Orlando Health Jewett Orthopedic Institute\",\"147\":\"Orlando Health Jewett Orthopedic Institute\",\"148\":\"Orlando Health Jewett Orthopedic Institute\",\"149\":\"Orlando Health Jewett Orthopedic Institute\",\"150\":\"Orlando Health Labworks\",\"151\":\"Orlando Health Labworks\",\"152\":\"Orlando Health Labworks\",\"153\":\"Orlando Health Labworks\",\"154\":\"Orlando Health Labworks\",\"155\":\"Orlando Health Labworks\",\"156\":\"Orlando Health Labworks\",\"157\":\"Orlando Health Labworks\",\"158\":\"Orlando Health Labworks\",\"159\":\"Orlando Health Labworks\",\"160\":\"Orlando Health Orlando Regional Medical Center\",\"161\":\"Orlando Health Orlando Regional Medical Center\",\"162\":\"Orlando Health Orlando Regional Medical Center\",\"163\":\"Orlando Health Orlando Regional Medical Center\",\"164\":\"Orlando Health Orlando Regional Medical Center\",\"165\":\"Orlando Health Orlando Regional Medical Center\",\"166\":\"Orlando Health Orlando Regional Medical Center\",\"167\":\"Orlando Health Orlando Regional Medical Center\",\"168\":\"Orlando Health Orlando Regional Medical Center\",\"169\":\"Orlando Health Orlando Regional Medical Center\",\"170\":\"Orlando Health South Lake Hospital\",\"171\":\"Orlando Health South Lake Hospital\",\"172\":\"Orlando Health South Lake Hospital\",\"173\":\"Orlando Health South Lake Hospital\",\"174\":\"Orlando Health South Lake Hospital\",\"175\":\"Orlando Health South Lake Hospital\",\"176\":\"Orlando Health South Lake Hospital\",\"177\":\"Orlando Health South Lake Hospital\",\"178\":\"Orlando Health South Lake Hospital\",\"179\":\"Orlando Health South Lake Hospital\",\"180\":\"Orlando Health South Seminole Hospital\",\"181\":\"Orlando Health South Seminole Hospital\",\"182\":\"Orlando Health South Seminole Hospital\",\"183\":\"Orlando Health South Seminole Hospital\",\"184\":\"Orlando Health South Seminole Hospital\",\"185\":\"Orlando Health South Seminole Hospital\",\"186\":\"Orlando Health South Seminole Hospital\",\"187\":\"Orlando Health South Seminole Hospital\",\"188\":\"Orlando Health South Seminole Hospital\",\"189\":\"Orlando Health South Seminole Hospital\",\"190\":\"Orlando Health St. Cloud Hospital\",\"191\":\"Orlando Health St. Cloud Hospital\",\"192\":\"Orlando Health St. Cloud Hospital\",\"193\":\"Orlando Health St. Cloud Hospital\",\"194\":\"Orlando Health St. Cloud Hospital\",\"195\":\"Orlando Health St. Cloud Hospital\",\"196\":\"Orlando Health St. Cloud Hospital\",\"197\":\"Orlando Health St. Cloud Hospital\",\"198\":\"Orlando Health St. Cloud Hospital\",\"199\":\"Orlando Health St. Cloud Hospital\",\"200\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"201\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"202\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"203\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"204\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"205\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"206\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"207\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"208\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\",\"209\":\"Orlando Health Winnie Palmer Hospital for Women and Babies\"},\"CPT Code\":{\"0\":99214,\"1\":99281,\"2\":93010,\"3\":71550,\"4\":70551,\"5\":72141,\"6\":77066,\"7\":99204,\"8\":93015,\"9\":96130,\"10\":99214,\"11\":99281,\"12\":93010,\"13\":71550,\"14\":70551,\"15\":72141,\"16\":77066,\"17\":99204,\"18\":93015,\"19\":96130,\"20\":99214,\"21\":99281,\"22\":93010,\"23\":71550,\"24\":70551,\"25\":72141,\"26\":77066,\"27\":99204,\"28\":93015,\"29\":96130,\"30\":99214,\"31\":99281,\"32\":93010,\"33\":71550,\"34\":70551,\"35\":72141,\"36\":77066,\"37\":99204,\"38\":93015,\"39\":96130,\"40\":99214,\"41\":99281,\"42\":93010,\"43\":71550,\"44\":70551,\"45\":72141,\"46\":77066,\"47\":99204,\"48\":93015,\"49\":96130,\"50\":99214,\"51\":99281,\"52\":93010,\"53\":71550,\"54\":70551,\"55\":72141,\"56\":77066,\"57\":99204,\"58\":93015,\"59\":96130,\"60\":99214,\"61\":99281,\"62\":93010,\"63\":71550,\"64\":70551,\"65\":72141,\"66\":77066,\"67\":99204,\"68\":93015,\"69\":96130,\"70\":99214,\"71\":99281,\"72\":93010,\"73\":71550,\"74\":70551,\"75\":72141,\"76\":77066,\"77\":99204,\"78\":93015,\"79\":96130,\"80\":99214,\"81\":99281,\"82\":93010,\"83\":71550,\"84\":70551,\"85\":72141,\"86\":77066,\"87\":99204,\"88\":93015,\"89\":96130,\"90\":99214,\"91\":99281,\"92\":93010,\"93\":71550,\"94\":70551,\"95\":72141,\"96\":77066,\"97\":99204,\"98\":93015,\"99\":96130,\"100\":99214,\"101\":99281,\"102\":93010,\"103\":71550,\"104\":70551,\"105\":72141,\"106\":77066,\"107\":99204,\"108\":93015,\"109\":96130,\"110\":99214,\"111\":99281,\"112\":93010,\"113\":71550,\"114\":70551,\"115\":72141,\"116\":77066,\"117\":99204,\"118\":93015,\"119\":96130,\"120\":99214,\"121\":99281,\"122\":93010,\"123\":71550,\"124\":70551,\"125\":72141,\"126\":77066,\"127\":99204,\"128\":93015,\"129\":96130,\"130\":99214,\"131\":99281,\"132\":93010,\"133\":71550,\"134\":70551,\"135\":72141,\"136\":77066,\"137\":99204,\"138\":93015,\"139\":96130,\"140\":99214,\"141\":99281,\"142\":93010,\"143\":71550,\"144\":70551,\"145\":72141,\"146\":77066,\"147\":99204,\"148\":93015,\"149\":96130,\"150\":99214,\"151\":99281,\"152\":93010,\"153\":71550,\"154\":70551,\"155\":72141,\"156\":77066,\"157\":99204,\"158\":93015,\"159\":96130,\"160\":99214,\"161\":99281,\"162\":93010,\"163\":71550,\"164\":70551,\"165\":72141,\"166\":77066,\"167\":99204,\"168\":93015,\"169\":96130,\"170\":99214,\"171\":99281,\"172\":93010,\"173\":71550,\"174\":70551,\"175\":72141,\"176\":77066,\"177\":99204,\"178\":93015,\"179\":96130,\"180\":99214,\"181\":99281,\"182\":93010,\"183\":71550,\"184\":70551,\"185\":72141,\"186\":77066,\"187\":99204,\"188\":93015,\"189\":96130,\"190\":99214,\"191\":99281,\"192\":93010,\"193\":71550,\"194\":70551,\"195\":72141,\"196\":77066,\"197\":99204,\"198\":93015,\"199\":96130,\"200\":99214,\"201\":99281,\"202\":93010,\"203\":71550,\"204\":70551,\"205\":72141,\"206\":77066,\"207\":99204,\"208\":93015,\"209\":96130},\"Cash Price\":{\"0\":null,\"1\":null,\"2\":283.0,\"3\":null,\"4\":null,\"5\":null,\"6\":688.0,\"7\":200.0,\"8\":null,\"9\":null,\"10\":null,\"11\":null,\"12\":283.0,\"13\":null,\"14\":null,\"15\":null,\"16\":688.0,\"17\":200.0,\"18\":null,\"19\":null,\"20\":null,\"21\":null,\"22\":283.0,\"23\":null,\"24\":null,\"25\":null,\"26\":688.0,\"27\":200.0,\"28\":null,\"29\":null,\"30\":null,\"31\":null,\"32\":283.0,\"33\":null,\"34\":null,\"35\":null,\"36\":688.0,\"37\":200.0,\"38\":null,\"39\":null,\"40\":null,\"41\":null,\"42\":283.0,\"43\":null,\"44\":null,\"45\":null,\"46\":688.0,\"47\":200.0,\"48\":null,\"49\":null,\"50\":null,\"51\":null,\"52\":null,\"53\":null,\"54\":null,\"55\":233.0,\"56\":null,\"57\":200.0,\"58\":null,\"59\":null,\"60\":null,\"61\":null,\"62\":null,\"63\":null,\"64\":null,\"65\":248.0,\"66\":null,\"67\":200.0,\"68\":null,\"69\":null,\"70\":null,\"71\":null,\"72\":null,\"73\":null,\"74\":null,\"75\":233.0,\"76\":null,\"77\":200.0,\"78\":null,\"79\":null,\"80\":null,\"81\":null,\"82\":null,\"83\":null,\"84\":null,\"85\":248.0,\"86\":null,\"87\":200.0,\"88\":null,\"89\":null,\"90\":null,\"91\":null,\"92\":null,\"93\":null,\"94\":null,\"95\":248.0,\"96\":null,\"97\":200.0,\"98\":null,\"99\":null,\"100\":null,\"101\":null,\"102\":null,\"103\":null,\"104\":null,\"105\":233.0,\"106\":null,\"107\":200.0,\"108\":null,\"109\":null,\"110\":null,\"111\":null,\"112\":null,\"113\":null,\"114\":null,\"115\":248.0,\"116\":null,\"117\":200.0,\"118\":null,\"119\":null,\"120\":null,\"121\":null,\"122\":null,\"123\":null,\"124\":null,\"125\":248.0,\"126\":null,\"127\":200.0,\"128\":null,\"129\":null,\"130\":null,\"131\":null,\"132\":null,\"133\":null,\"134\":null,\"135\":248.0,\"136\":null,\"137\":200.0,\"138\":null,\"139\":null,\"140\":null,\"141\":null,\"142\":283.0,\"143\":null,\"144\":null,\"145\":null,\"146\":688.0,\"147\":200.0,\"148\":null,\"149\":null,\"150\":null,\"151\":null,\"152\":null,\"153\":null,\"154\":null,\"155\":null,\"156\":null,\"157\":200.0,\"158\":null,\"159\":null,\"160\":null,\"161\":null,\"162\":283.0,\"163\":null,\"164\":null,\"165\":null,\"166\":688.0,\"167\":200.0,\"168\":null,\"169\":null,\"170\":null,\"171\":null,\"172\":283.0,\"173\":null,\"174\":null,\"175\":null,\"176\":688.0,\"177\":200.0,\"178\":null,\"179\":null,\"180\":null,\"181\":null,\"182\":283.0,\"183\":null,\"184\":null,\"185\":null,\"186\":688.0,\"187\":200.0,\"188\":null,\"189\":null,\"190\":null,\"191\":null,\"192\":283.0,\"193\":null,\"194\":null,\"195\":null,\"196\":639.0,\"197\":338.0,\"198\":null,\"199\":null,\"200\":null,\"201\":null,\"202\":283.0,\"203\":null,\"204\":null,\"205\":null,\"206\":688.0,\"207\":200.0,\"208\":null,\"209\":null}}", 3 | "adventhealth.com": "{\"Hospital name\":{\"0\":\"AdventHealth Florida\",\"1\":\"AdventHealth Florida\",\"2\":\"AdventHealth Altamonte Springs\",\"3\":\"AdventHealth Apopka\",\"4\":\"AdventHealth Carrollwood\",\"5\":\"AdventHealth Celebration\",\"6\":\"AdventHealth Central Texas\",\"7\":\"AdventHealth Connerton\",\"8\":\"AdventHealth Dade City\",\"9\":\"AdventHealth Daytona Beach\",\"10\":\"AdventHealth Deland\",\"11\":\"AdventHealth Durand\",\"12\":\"AdventHealth East Orlando\",\"13\":\"AdventHealth Fish Memorial\",\"14\":\"AdventHealth Gordon\",\"15\":\"AdventHealth Heart of Florida\",\"16\":\"AdventHealth Hendersonville\",\"17\":\"AdventHealth Kansas City Bariatric\",\"18\":\"AdventHealth Kissimmee\",\"19\":\"AdventHealth Lake Placid\",\"20\":\"AdventHealth Lake Wales\",\"21\":\"AdventHealth Manchester\",\"22\":\"AdventHealth Murray\",\"23\":\"AdventHealth New Smyrna Beach\",\"24\":\"AdventHealth North Pinellas\",\"25\":\"AdventHealth Ocala\",\"26\":\"AdventHealth Orlando\",\"27\":\"AdventHealth Ottawa\",\"28\":\"AdventHealth Palm Coast\",\"29\":\"AdventHealth Palm Coast Parkway\",\"30\":\"AdventHealth Redmond\",\"31\":\"AdventHealth Rollins Brook\",\"32\":\"AdventHealth Sebring\",\"33\":\"AdventHealth Shawnee Mission\",\"34\":\"AdventHealth Shawnee Mission\",\"35\":\"AdventHealth Tampa\",\"36\":\"AdventHealth Waterman\",\"37\":\"AdventHealth Wauchula\",\"38\":\"AdventHealth Wesley Chapel\",\"39\":\"AdventHealth Winter Garden\",\"40\":\"AdventHealth Winter Park\",\"41\":\"AdventHealth Zephyrhills\",\"42\":\"Texas Health Huguley Parent Location\",\"43\":\"Texas Health Mansfield Parent Location\",\"44\":\"AdventHealth Florida\",\"45\":\"AdventHealth Altamonte Springs\",\"46\":\"AdventHealth Apopka\",\"47\":\"AdventHealth Carrollwood\",\"48\":\"AdventHealth Celebration\",\"49\":\"AdventHealth Central Texas\",\"50\":\"AdventHealth Dade City\",\"51\":\"AdventHealth Daytona Beach\",\"52\":\"AdventHealth Deland\",\"53\":\"AdventHealth Durand\",\"54\":\"AdventHealth East Orlando\",\"55\":\"AdventHealth Fish Memorial\",\"56\":\"AdventHealth Gordon\",\"57\":\"AdventHealth Heart of Florida\",\"58\":\"AdventHealth Hendersonville\",\"59\":\"AdventHealth Kissimmee\",\"60\":\"AdventHealth Lake Placid\",\"61\":\"AdventHealth Lake Wales\",\"62\":\"AdventHealth Manchester\",\"63\":\"AdventHealth Murray\",\"64\":\"AdventHealth New Smyrna Beach\",\"65\":\"AdventHealth North Pinellas\",\"66\":\"AdventHealth Ocala\",\"67\":\"AdventHealth Orlando\",\"68\":\"AdventHealth Ottawa\",\"69\":\"AdventHealth Palm Coast\",\"70\":\"AdventHealth Palm Coast Parkway\",\"71\":\"AdventHealth Redmond\",\"72\":\"AdventHealth Rollins Brook\",\"73\":\"AdventHealth Sebring\",\"74\":\"AdventHealth Shawnee Mission\",\"75\":\"AdventHealth Shawnee Mission\",\"76\":\"AdventHealth Tampa\",\"77\":\"AdventHealth Waterman\",\"78\":\"AdventHealth Wauchula\",\"79\":\"AdventHealth Wesley Chapel\",\"80\":\"AdventHealth Winter Garden\",\"81\":\"AdventHealth Winter Park\",\"82\":\"AdventHealth Zephyrhills\",\"83\":\"Texas Health Huguley Parent Location\",\"84\":\"Texas Health Mansfield Parent Location\",\"85\":\"AdventHealth Florida\",\"86\":\"AdventHealth Apopka\",\"87\":\"AdventHealth Carrollwood\",\"88\":\"AdventHealth Celebration\",\"89\":\"AdventHealth Central Texas\",\"90\":\"AdventHealth Daytona Beach\",\"91\":\"AdventHealth Deland\",\"92\":\"AdventHealth Durand\",\"93\":\"AdventHealth East Orlando\",\"94\":\"AdventHealth Fish Memorial\",\"95\":\"AdventHealth Gordon\",\"96\":\"AdventHealth Heart of Florida\",\"97\":\"AdventHealth Hendersonville\",\"98\":\"AdventHealth Kissimmee\",\"99\":\"AdventHealth Lake Wales\",\"100\":\"AdventHealth Manchester\",\"101\":\"AdventHealth Murray\",\"102\":\"AdventHealth New Smyrna Beach\",\"103\":\"AdventHealth North Pinellas\",\"104\":\"AdventHealth Orlando\",\"105\":\"AdventHealth Ottawa\",\"106\":\"AdventHealth Palm Coast\",\"107\":\"AdventHealth Redmond\",\"108\":\"AdventHealth Sebring\",\"109\":\"AdventHealth Shawnee Mission\",\"110\":\"AdventHealth Tampa\",\"111\":\"AdventHealth Waterman\",\"112\":\"AdventHealth Wesley Chapel\",\"113\":\"AdventHealth Winter Park\",\"114\":\"AdventHealth Zephyrhills\",\"115\":\"Texas Health Huguley Parent Location\",\"116\":\"Texas Health Mansfield Parent Location\",\"117\":\"AdventHealth Florida\",\"118\":\"AdventHealth Florida\",\"119\":\"AdventHealth Florida\"},\"CPT Code\":{\"0\":99214,\"1\":99281,\"2\":93010,\"3\":93010,\"4\":93010,\"5\":93010,\"6\":93010,\"7\":93010,\"8\":93010,\"9\":93010,\"10\":93010,\"11\":93010,\"12\":93010,\"13\":93010,\"14\":93010,\"15\":93010,\"16\":93010,\"17\":93010,\"18\":93010,\"19\":93010,\"20\":93010,\"21\":93010,\"22\":93010,\"23\":93010,\"24\":93010,\"25\":93010,\"26\":93010,\"27\":93010,\"28\":93010,\"29\":93010,\"30\":93010,\"31\":93010,\"32\":93010,\"33\":93010,\"34\":93010,\"35\":93010,\"36\":93010,\"37\":93010,\"38\":93010,\"39\":93010,\"40\":93010,\"41\":93010,\"42\":93010,\"43\":93010,\"44\":71550,\"45\":70551,\"46\":70551,\"47\":70551,\"48\":70551,\"49\":70551,\"50\":70551,\"51\":70551,\"52\":70551,\"53\":70551,\"54\":70551,\"55\":70551,\"56\":70551,\"57\":70551,\"58\":70551,\"59\":70551,\"60\":70551,\"61\":70551,\"62\":70551,\"63\":70551,\"64\":70551,\"65\":70551,\"66\":70551,\"67\":70551,\"68\":70551,\"69\":70551,\"70\":70551,\"71\":70551,\"72\":70551,\"73\":70551,\"74\":70551,\"75\":70551,\"76\":70551,\"77\":70551,\"78\":70551,\"79\":70551,\"80\":70551,\"81\":70551,\"82\":70551,\"83\":70551,\"84\":70551,\"85\":72141,\"86\":77066,\"87\":77066,\"88\":77066,\"89\":77066,\"90\":77066,\"91\":77066,\"92\":77066,\"93\":77066,\"94\":77066,\"95\":77066,\"96\":77066,\"97\":77066,\"98\":77066,\"99\":77066,\"100\":77066,\"101\":77066,\"102\":77066,\"103\":77066,\"104\":77066,\"105\":77066,\"106\":77066,\"107\":77066,\"108\":77066,\"109\":77066,\"110\":77066,\"111\":77066,\"112\":77066,\"113\":77066,\"114\":77066,\"115\":77066,\"116\":77066,\"117\":99204,\"118\":93015,\"119\":96130},\"Cash Price\":{\"0\":null,\"1\":null,\"2\":74.0,\"3\":74.0,\"4\":115.0,\"5\":74.0,\"6\":109.0,\"7\":125.0,\"8\":115.0,\"9\":74.0,\"10\":74.0,\"11\":191.0,\"12\":74.0,\"13\":74.0,\"14\":121.0,\"15\":74.0,\"16\":113.0,\"17\":140.0,\"18\":74.0,\"19\":115.0,\"20\":74.0,\"21\":84.0,\"22\":121.0,\"23\":74.0,\"24\":115.0,\"25\":115.0,\"26\":115.0,\"27\":140.0,\"28\":74.0,\"29\":74.0,\"30\":140.0,\"31\":109.0,\"32\":115.0,\"33\":140.0,\"34\":140.0,\"35\":115.0,\"36\":74.0,\"37\":115.0,\"38\":115.0,\"39\":74.0,\"40\":74.0,\"41\":115.0,\"42\":151.0,\"43\":151.0,\"44\":null,\"45\":613.0,\"46\":613.0,\"47\":499.0,\"48\":499.0,\"49\":1090.0,\"50\":499.0,\"51\":499.0,\"52\":613.0,\"53\":3380.0,\"54\":3380.0,\"55\":613.0,\"56\":793.0,\"57\":613.0,\"58\":1451.0,\"59\":1451.0,\"60\":499.0,\"61\":613.0,\"62\":1183.0,\"63\":793.0,\"64\":793.0,\"65\":499.0,\"66\":499.0,\"67\":499.0,\"68\":805.0,\"69\":805.0,\"70\":613.0,\"71\":1565.0,\"72\":1090.0,\"73\":499.0,\"74\":805.0,\"75\":805.0,\"76\":499.0,\"77\":499.0,\"78\":499.0,\"79\":499.0,\"80\":613.0,\"81\":613.0,\"82\":499.0,\"83\":912.0,\"84\":912.0,\"85\":null,\"86\":385.0,\"87\":377.0,\"88\":385.0,\"89\":338.0,\"90\":385.0,\"91\":385.0,\"92\":528.0,\"93\":385.0,\"94\":385.0,\"95\":213.0,\"96\":385.0,\"97\":421.0,\"98\":385.0,\"99\":385.0,\"100\":418.0,\"101\":213.0,\"102\":385.0,\"103\":377.0,\"104\":385.0,\"105\":264.0,\"106\":385.0,\"107\":189.0,\"108\":377.0,\"109\":264.0,\"110\":377.0,\"111\":385.0,\"112\":377.0,\"113\":385.0,\"114\":377.0,\"115\":360.0,\"116\":360.0,\"117\":null,\"118\":null,\"119\":null}}", 4 | "tgh.org": "{\"Hospital Name\":{\"0\":\"Tampa General Hospital\",\"1\":\"Tampa General Hospital\",\"2\":\"Tampa General Hospital\",\"3\":\"Tampa General Hospital\",\"4\":\"Tampa General Hospital\",\"5\":\"Tampa General Hospital\",\"6\":\"Tampa General Hospital\",\"7\":\"Tampa General Hospital\",\"8\":\"Tampa General Hospital\",\"9\":\"Tampa General Hospital\",\"10\":\"Tampa General Hospital\",\"11\":\"Tampa General Hospital\",\"12\":\"Tampa General Hospital\"},\"CPT Code\":{\"0\":99214,\"1\":99214,\"2\":99281,\"3\":93010,\"4\":71550,\"5\":70551,\"6\":72141,\"7\":77066,\"8\":77066,\"9\":99204,\"10\":99204,\"11\":93015,\"12\":96130},\"Cash Price\":{\"0\":366.0,\"1\":914.0,\"2\":null,\"3\":null,\"4\":2958.0,\"5\":4349.0,\"6\":3365.0,\"7\":179.0,\"8\":null,\"9\":165.0,\"10\":413.0,\"11\":508.0,\"12\":null},\"Description\":{\"0\":\"Office Visit- Existing patient\",\"1\":\"Outpatient Visit Level 4\",\"2\":null,\"3\":null,\"4\":\"HB MRI Chest WO Cont CPT 71550 CDM 61000003\",\"5\":\"HB MRI Brain WO Cont CPT 70551 CDM 61100010\",\"6\":\"HB MRI Cervical Spine WO Cont CPT 72141 CDM 61200001\",\"7\":\"HB MAMMOGRAPHY OF BOTH BREAST\",\"8\":\"MAMMO DIAGNOSTIC BILAT\",\"9\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT,TYPICALLY 45MIN\\/ INSURANCE\",\"10\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT,TYPICALLY 45MIN\\/ SELF PAY\",\"11\":\"HB Cardiovascular Stress Test CPT 93015 CDM 48000095\",\"12\":null}}", 5 | "hcafloridahealthcare.com": "{\"Hospital name\":{\"0\":\"Aventura Hospital\",\"1\":\"Aventura Hospital\",\"2\":\"Aventura Hospital\",\"3\":\"Aventura Hospital\",\"4\":\"Aventura Hospital\",\"5\":\"Aventura Hospital\",\"6\":\"Aventura Hospital\",\"7\":\"Aventura Hospital\",\"8\":\"Aventura Hospital\",\"9\":\"Aventura Hospital\",\"10\":\"Bayonet Point Hospital\",\"11\":\"Bayonet Point Hospital\",\"12\":\"Bayonet Point Hospital\",\"13\":\"Bayonet Point Hospital\",\"14\":\"Bayonet Point Hospital\",\"15\":\"Bayonet Point Hospital\",\"16\":\"Bayonet Point Hospital\",\"17\":\"Bayonet Point Hospital\",\"18\":\"Bayonet Point Hospital\",\"19\":\"Bayonet Point Hospital\",\"20\":\"Blake Hospital\",\"21\":\"Blake Hospital\",\"22\":\"Blake Hospital\",\"23\":\"Blake Hospital\",\"24\":\"Blake Hospital\",\"25\":\"Blake Hospital\",\"26\":\"Blake Hospital\",\"27\":\"Blake Hospital\",\"28\":\"Blake Hospital\",\"29\":\"Blake Hospital\",\"30\":\"Brandon Hospital\",\"31\":\"Brandon Hospital\",\"32\":\"Brandon Hospital\",\"33\":\"Brandon Hospital\",\"34\":\"Brandon Hospital\",\"35\":\"Brandon Hospital\",\"36\":\"Brandon Hospital\",\"37\":\"Brandon Hospital\",\"38\":\"Brandon Hospital\",\"39\":\"Brandon Hospital\",\"40\":\"Capital Hospital\",\"41\":\"Capital Hospital\",\"42\":\"Capital Hospital\",\"43\":\"Capital Hospital\",\"44\":\"Capital Hospital\",\"45\":\"Capital Hospital\",\"46\":\"Capital Hospital\",\"47\":\"Capital Hospital\",\"48\":\"Capital Hospital\",\"49\":\"Capital Hospital\",\"50\":\"Citrus Hospital\",\"51\":\"Citrus Hospital\",\"52\":\"Citrus Hospital\",\"53\":\"Citrus Hospital\",\"54\":\"Citrus Hospital\",\"55\":\"Citrus Hospital\",\"56\":\"Citrus Hospital\",\"57\":\"Citrus Hospital\",\"58\":\"Citrus Hospital\",\"59\":\"Citrus Hospital\",\"60\":\"Englewood Hospital\",\"61\":\"Englewood Hospital\",\"62\":\"Englewood Hospital\",\"63\":\"Englewood Hospital\",\"64\":\"Englewood Hospital\",\"65\":\"Englewood Hospital\",\"66\":\"Englewood Hospital\",\"67\":\"Englewood Hospital\",\"68\":\"Englewood Hospital\",\"69\":\"Englewood Hospital\",\"70\":\"Fawcett Hospital\",\"71\":\"Fawcett Hospital\",\"72\":\"Fawcett Hospital\",\"73\":\"Fawcett Hospital\",\"74\":\"Fawcett Hospital\",\"75\":\"Fawcett Hospital\",\"76\":\"Fawcett Hospital\",\"77\":\"Fawcett Hospital\",\"78\":\"Fawcett Hospital\",\"79\":\"Fawcett Hospital\",\"80\":\"Fort Walton-Destin Hospital\",\"81\":\"Fort Walton-Destin Hospital\",\"82\":\"Fort Walton-Destin Hospital\",\"83\":\"Fort Walton-Destin Hospital\",\"84\":\"Fort Walton-Destin Hospital\",\"85\":\"Fort Walton-Destin Hospital\",\"86\":\"Fort Walton-Destin Hospital\",\"87\":\"Fort Walton-Destin Hospital\",\"88\":\"Fort Walton-Destin Hospital\",\"89\":\"Fort Walton-Destin Hospital\",\"90\":\"Gulf Coast Hospital\",\"91\":\"Gulf Coast Hospital\",\"92\":\"Gulf Coast Hospital\",\"93\":\"Gulf Coast Hospital\",\"94\":\"Gulf Coast Hospital\",\"95\":\"Gulf Coast Hospital\",\"96\":\"Gulf Coast Hospital\",\"97\":\"Gulf Coast Hospital\",\"98\":\"Gulf Coast Hospital\",\"99\":\"Gulf Coast Hospital\",\"100\":\"Highlands Hospital\",\"101\":\"Highlands Hospital\",\"102\":\"Highlands Hospital\",\"103\":\"Highlands Hospital\",\"104\":\"Highlands Hospital\",\"105\":\"Highlands Hospital\",\"106\":\"Highlands Hospital\",\"107\":\"Highlands Hospital\",\"108\":\"Highlands Hospital\",\"109\":\"Highlands Hospital\",\"110\":\"JFK Hospital\",\"111\":\"JFK Hospital\",\"112\":\"JFK Hospital\",\"113\":\"JFK Hospital\",\"114\":\"JFK Hospital\",\"115\":\"JFK Hospital\",\"116\":\"JFK Hospital\",\"117\":\"JFK Hospital\",\"118\":\"JFK Hospital\",\"119\":\"JFK Hospital\",\"120\":\"JFK North Hospital\",\"121\":\"JFK North Hospital\",\"122\":\"JFK North Hospital\",\"123\":\"JFK North Hospital\",\"124\":\"JFK North Hospital\",\"125\":\"JFK North Hospital\",\"126\":\"JFK North Hospital\",\"127\":\"JFK North Hospital\",\"128\":\"JFK North Hospital\",\"129\":\"JFK North Hospital\",\"130\":\"Kendall Hospital\",\"131\":\"Kendall Hospital\",\"132\":\"Kendall Hospital\",\"133\":\"Kendall Hospital\",\"134\":\"Kendall Hospital\",\"135\":\"Kendall Hospital\",\"136\":\"Kendall Hospital\",\"137\":\"Kendall Hospital\",\"138\":\"Kendall Hospital\",\"139\":\"Kendall Hospital\",\"140\":\"Lake City Hospital\",\"141\":\"Lake City Hospital\",\"142\":\"Lake City Hospital\",\"143\":\"Lake City Hospital\",\"144\":\"Lake City Hospital\",\"145\":\"Lake City Hospital\",\"146\":\"Lake City Hospital\",\"147\":\"Lake City Hospital\",\"148\":\"Lake City Hospital\",\"149\":\"Lake City Hospital\",\"150\":\"Lake Monroe Hospital\",\"151\":\"Lake Monroe Hospital\",\"152\":\"Lake Monroe Hospital\",\"153\":\"Lake Monroe Hospital\",\"154\":\"Lake Monroe Hospital\",\"155\":\"Lake Monroe Hospital\",\"156\":\"Lake Monroe Hospital\",\"157\":\"Lake Monroe Hospital\",\"158\":\"Lake Monroe Hospital\",\"159\":\"Lake Monroe Hospital\",\"160\":\"Largo Hospital\",\"161\":\"Largo Hospital\",\"162\":\"Largo Hospital\",\"163\":\"Largo Hospital\",\"164\":\"Largo Hospital\",\"165\":\"Largo Hospital\",\"166\":\"Largo Hospital\",\"167\":\"Largo Hospital\",\"168\":\"Largo Hospital\",\"169\":\"Largo Hospital\",\"170\":\"Largo West Hospital\",\"171\":\"Largo West Hospital\",\"172\":\"Largo West Hospital\",\"173\":\"Largo West Hospital\",\"174\":\"Largo West Hospital\",\"175\":\"Largo West Hospital\",\"176\":\"Largo West Hospital\",\"177\":\"Largo West Hospital\",\"178\":\"Largo West Hospital\",\"179\":\"Largo West Hospital\",\"180\":\"Lawnwood Hospital\",\"181\":\"Lawnwood Hospital\",\"182\":\"Lawnwood Hospital\",\"183\":\"Lawnwood Hospital\",\"184\":\"Lawnwood Hospital\",\"185\":\"Lawnwood Hospital\",\"186\":\"Lawnwood Hospital\",\"187\":\"Lawnwood Hospital\",\"188\":\"Lawnwood Hospital\",\"189\":\"Lawnwood Hospital\",\"190\":\"Memorial Hospital\",\"191\":\"Memorial Hospital\",\"192\":\"Memorial Hospital\",\"193\":\"Memorial Hospital\",\"194\":\"Memorial Hospital\",\"195\":\"Memorial Hospital\",\"196\":\"Memorial Hospital\",\"197\":\"Memorial Hospital\",\"198\":\"Memorial Hospital\",\"199\":\"Memorial Hospital\",\"200\":\"Mercy Hospital\",\"201\":\"Mercy Hospital\",\"202\":\"Mercy Hospital\",\"203\":\"Mercy Hospital\",\"204\":\"Mercy Hospital\",\"205\":\"Mercy Hospital\",\"206\":\"Mercy Hospital\",\"207\":\"Mercy Hospital\",\"208\":\"Mercy Hospital\",\"209\":\"Mercy Hospital\",\"210\":\"North Florida Hospital\",\"211\":\"North Florida Hospital\",\"212\":\"North Florida Hospital\",\"213\":\"North Florida Hospital\",\"214\":\"North Florida Hospital\",\"215\":\"North Florida Hospital\",\"216\":\"North Florida Hospital\",\"217\":\"North Florida Hospital\",\"218\":\"North Florida Hospital\",\"219\":\"North Florida Hospital\",\"220\":\"Northside Hospital\",\"221\":\"Northside Hospital\",\"222\":\"Northside Hospital\",\"223\":\"Northside Hospital\",\"224\":\"Northside Hospital\",\"225\":\"Northside Hospital\",\"226\":\"Northside Hospital\",\"227\":\"Northside Hospital\",\"228\":\"Northside Hospital\",\"229\":\"Northside Hospital\",\"230\":\"Northwest Hospital\",\"231\":\"Northwest Hospital\",\"232\":\"Northwest Hospital\",\"233\":\"Northwest Hospital\",\"234\":\"Northwest Hospital\",\"235\":\"Northwest Hospital\",\"236\":\"Northwest Hospital\",\"237\":\"Northwest Hospital\",\"238\":\"Northwest Hospital\",\"239\":\"Northwest Hospital\",\"240\":\"Oak Hill Hospital\",\"241\":\"Oak Hill Hospital\",\"242\":\"Oak Hill Hospital\",\"243\":\"Oak Hill Hospital\",\"244\":\"Oak Hill Hospital\",\"245\":\"Oak Hill Hospital\",\"246\":\"Oak Hill Hospital\",\"247\":\"Oak Hill Hospital\",\"248\":\"Oak Hill Hospital\",\"249\":\"Oak Hill Hospital\",\"250\":\"Ocala Hospital\",\"251\":\"Ocala Hospital\",\"252\":\"Ocala Hospital\",\"253\":\"Ocala Hospital\",\"254\":\"Ocala Hospital\",\"255\":\"Ocala Hospital\",\"256\":\"Ocala Hospital\",\"257\":\"Ocala Hospital\",\"258\":\"Ocala Hospital\",\"259\":\"Ocala Hospital\",\"260\":\"Orange Park Hospital\",\"261\":\"Orange Park Hospital\",\"262\":\"Orange Park Hospital\",\"263\":\"Orange Park Hospital\",\"264\":\"Orange Park Hospital\",\"265\":\"Orange Park Hospital\",\"266\":\"Orange Park Hospital\",\"267\":\"Orange Park Hospital\",\"268\":\"Orange Park Hospital\",\"269\":\"Orange Park Hospital\",\"270\":\"Osceola Hospital\",\"271\":\"Osceola Hospital\",\"272\":\"Osceola Hospital\",\"273\":\"Osceola Hospital\",\"274\":\"Osceola Hospital\",\"275\":\"Osceola Hospital\",\"276\":\"Osceola Hospital\",\"277\":\"Osceola Hospital\",\"278\":\"Osceola Hospital\",\"279\":\"Osceola Hospital\",\"280\":\"Oviedo Medical Center\",\"281\":\"Oviedo Medical Center\",\"282\":\"Oviedo Medical Center\",\"283\":\"Oviedo Medical Center\",\"284\":\"Oviedo Medical Center\",\"285\":\"Oviedo Medical Center\",\"286\":\"Oviedo Medical Center\",\"287\":\"Oviedo Medical Center\",\"288\":\"Oviedo Medical Center\",\"289\":\"Oviedo Medical Center\",\"290\":\"Palms West Hospital\",\"291\":\"Palms West Hospital\",\"292\":\"Palms West Hospital\",\"293\":\"Palms West Hospital\",\"294\":\"Palms West Hospital\",\"295\":\"Palms West Hospital\",\"296\":\"Palms West Hospital\",\"297\":\"Palms West Hospital\",\"298\":\"Palms West Hospital\",\"299\":\"Palms West Hospital\",\"300\":\"Pasadena Hospital\",\"301\":\"Pasadena Hospital\",\"302\":\"Pasadena Hospital\",\"303\":\"Pasadena Hospital\",\"304\":\"Pasadena Hospital\",\"305\":\"Pasadena Hospital\",\"306\":\"Pasadena Hospital\",\"307\":\"Pasadena Hospital\",\"308\":\"Pasadena Hospital\",\"309\":\"Pasadena Hospital\",\"310\":\"Poinciana Hospital\",\"311\":\"Poinciana Hospital\",\"312\":\"Poinciana Hospital\",\"313\":\"Poinciana Hospital\",\"314\":\"Poinciana Hospital\",\"315\":\"Poinciana Hospital\",\"316\":\"Poinciana Hospital\",\"317\":\"Poinciana Hospital\",\"318\":\"Poinciana Hospital\",\"319\":\"Poinciana Hospital\",\"320\":\"Putnam Hospital\",\"321\":\"Putnam Hospital\",\"322\":\"Putnam Hospital\",\"323\":\"Putnam Hospital\",\"324\":\"Putnam Hospital\",\"325\":\"Putnam Hospital\",\"326\":\"Putnam Hospital\",\"327\":\"Putnam Hospital\",\"328\":\"Putnam Hospital\",\"329\":\"Putnam Hospital\",\"330\":\"Raulerson Hospital\",\"331\":\"Raulerson Hospital\",\"332\":\"Raulerson Hospital\",\"333\":\"Raulerson Hospital\",\"334\":\"Raulerson Hospital\",\"335\":\"Raulerson Hospital\",\"336\":\"Raulerson Hospital\",\"337\":\"Raulerson Hospital\",\"338\":\"Raulerson Hospital\",\"339\":\"Raulerson Hospital\",\"340\":\"Sarasota Doctors Hospital\",\"341\":\"Sarasota Doctors Hospital\",\"342\":\"Sarasota Doctors Hospital\",\"343\":\"Sarasota Doctors Hospital\",\"344\":\"Sarasota Doctors Hospital\",\"345\":\"Sarasota Doctors Hospital\",\"346\":\"Sarasota Doctors Hospital\",\"347\":\"Sarasota Doctors Hospital\",\"348\":\"Sarasota Doctors Hospital\",\"349\":\"Sarasota Doctors Hospital\",\"350\":\"South Shore Hospital\",\"351\":\"South Shore Hospital\",\"352\":\"South Shore Hospital\",\"353\":\"South Shore Hospital\",\"354\":\"South Shore Hospital\",\"355\":\"South Shore Hospital\",\"356\":\"South Shore Hospital\",\"357\":\"South Shore Hospital\",\"358\":\"South Shore Hospital\",\"359\":\"South Shore Hospital\",\"360\":\"South Tampa Hospital\",\"361\":\"South Tampa Hospital\",\"362\":\"South Tampa Hospital\",\"363\":\"South Tampa Hospital\",\"364\":\"South Tampa Hospital\",\"365\":\"South Tampa Hospital\",\"366\":\"South Tampa Hospital\",\"367\":\"South Tampa Hospital\",\"368\":\"South Tampa Hospital\",\"369\":\"South Tampa Hospital\",\"370\":\"St. Lucie Hospital\",\"371\":\"St. Lucie Hospital\",\"372\":\"St. Lucie Hospital\",\"373\":\"St. Lucie Hospital\",\"374\":\"St. Lucie Hospital\",\"375\":\"St. Lucie Hospital\",\"376\":\"St. Lucie Hospital\",\"377\":\"St. Lucie Hospital\",\"378\":\"St. Lucie Hospital\",\"379\":\"St. Lucie Hospital\",\"380\":\"St. Petersburg Hospital\",\"381\":\"St. Petersburg Hospital\",\"382\":\"St. Petersburg Hospital\",\"383\":\"St. Petersburg Hospital\",\"384\":\"St. Petersburg Hospital\",\"385\":\"St. Petersburg Hospital\",\"386\":\"St. Petersburg Hospital\",\"387\":\"St. Petersburg Hospital\",\"388\":\"St. Petersburg Hospital\",\"389\":\"St. Petersburg Hospital\",\"390\":\"Trinity Hospital\",\"391\":\"Trinity Hospital\",\"392\":\"Trinity Hospital\",\"393\":\"Trinity Hospital\",\"394\":\"Trinity Hospital\",\"395\":\"Trinity Hospital\",\"396\":\"Trinity Hospital\",\"397\":\"Trinity Hospital\",\"398\":\"Trinity Hospital\",\"399\":\"Trinity Hospital\",\"400\":\"Twin Cities Hospital\",\"401\":\"Twin Cities Hospital\",\"402\":\"Twin Cities Hospital\",\"403\":\"Twin Cities Hospital\",\"404\":\"Twin Cities Hospital\",\"405\":\"Twin Cities Hospital\",\"406\":\"Twin Cities Hospital\",\"407\":\"Twin Cities Hospital\",\"408\":\"Twin Cities Hospital\",\"409\":\"Twin Cities Hospital\",\"410\":\"UCF Lake Nona Hospital\",\"411\":\"UCF Lake Nona Hospital\",\"412\":\"UCF Lake Nona Hospital\",\"413\":\"UCF Lake Nona Hospital\",\"414\":\"UCF Lake Nona Hospital\",\"415\":\"UCF Lake Nona Hospital\",\"416\":\"UCF Lake Nona Hospital\",\"417\":\"UCF Lake Nona Hospital\",\"418\":\"UCF Lake Nona Hospital\",\"419\":\"UCF Lake Nona Hospital\",\"420\":\"University Hospital\",\"421\":\"University Hospital\",\"422\":\"University Hospital\",\"423\":\"University Hospital\",\"424\":\"University Hospital\",\"425\":\"University Hospital\",\"426\":\"University Hospital\",\"427\":\"University Hospital\",\"428\":\"University Hospital\",\"429\":\"University Hospital\",\"430\":\"West Hospital\",\"431\":\"West Hospital\",\"432\":\"West Hospital\",\"433\":\"West Hospital\",\"434\":\"West Hospital\",\"435\":\"West Hospital\",\"436\":\"West Hospital\",\"437\":\"West Hospital\",\"438\":\"West Hospital\",\"439\":\"West Hospital\",\"440\":\"West Marion Hospital\",\"441\":\"West Marion Hospital\",\"442\":\"West Marion Hospital\",\"443\":\"West Marion Hospital\",\"444\":\"West Marion Hospital\",\"445\":\"West Marion Hospital\",\"446\":\"West Marion Hospital\",\"447\":\"West Marion Hospital\",\"448\":\"West Marion Hospital\",\"449\":\"West Marion Hospital\",\"450\":\"West Tampa Hospital\",\"451\":\"West Tampa Hospital\",\"452\":\"West Tampa Hospital\",\"453\":\"West Tampa Hospital\",\"454\":\"West Tampa Hospital\",\"455\":\"West Tampa Hospital\",\"456\":\"West Tampa Hospital\",\"457\":\"West Tampa Hospital\",\"458\":\"West Tampa Hospital\",\"459\":\"West Tampa Hospital\",\"460\":\"Westside Hospital\",\"461\":\"Westside Hospital\",\"462\":\"Westside Hospital\",\"463\":\"Westside Hospital\",\"464\":\"Westside Hospital\",\"465\":\"Westside Hospital\",\"466\":\"Westside Hospital\",\"467\":\"Westside Hospital\",\"468\":\"Westside Hospital\",\"469\":\"Westside Hospital\",\"470\":\"Woodmont Hospital\",\"471\":\"Woodmont Hospital\",\"472\":\"Woodmont Hospital\",\"473\":\"Woodmont Hospital\",\"474\":\"Woodmont Hospital\",\"475\":\"Woodmont Hospital\",\"476\":\"Woodmont Hospital\",\"477\":\"Woodmont Hospital\",\"478\":\"Woodmont Hospital\",\"479\":\"Woodmont Hospital\"},\"CPT Code\":{\"0\":99214,\"1\":99281,\"2\":93010,\"3\":71550,\"4\":70551,\"5\":72141,\"6\":77066,\"7\":99204,\"8\":93015,\"9\":96130,\"10\":99214,\"11\":99281,\"12\":93010,\"13\":71550,\"14\":70551,\"15\":72141,\"16\":77066,\"17\":99204,\"18\":93015,\"19\":96130,\"20\":99214,\"21\":99281,\"22\":93010,\"23\":71550,\"24\":70551,\"25\":72141,\"26\":77066,\"27\":99204,\"28\":93015,\"29\":96130,\"30\":99214,\"31\":99281,\"32\":93010,\"33\":71550,\"34\":70551,\"35\":72141,\"36\":77066,\"37\":99204,\"38\":93015,\"39\":96130,\"40\":99214,\"41\":99281,\"42\":93010,\"43\":71550,\"44\":70551,\"45\":72141,\"46\":77066,\"47\":99204,\"48\":93015,\"49\":96130,\"50\":99214,\"51\":99281,\"52\":93010,\"53\":71550,\"54\":70551,\"55\":72141,\"56\":77066,\"57\":99204,\"58\":93015,\"59\":96130,\"60\":99214,\"61\":99281,\"62\":93010,\"63\":71550,\"64\":70551,\"65\":72141,\"66\":77066,\"67\":99204,\"68\":93015,\"69\":96130,\"70\":99214,\"71\":99281,\"72\":93010,\"73\":71550,\"74\":70551,\"75\":72141,\"76\":77066,\"77\":99204,\"78\":93015,\"79\":96130,\"80\":99214,\"81\":99281,\"82\":93010,\"83\":71550,\"84\":70551,\"85\":72141,\"86\":77066,\"87\":99204,\"88\":93015,\"89\":96130,\"90\":99214,\"91\":99281,\"92\":93010,\"93\":71550,\"94\":70551,\"95\":72141,\"96\":77066,\"97\":99204,\"98\":93015,\"99\":96130,\"100\":99214,\"101\":99281,\"102\":93010,\"103\":71550,\"104\":70551,\"105\":72141,\"106\":77066,\"107\":99204,\"108\":93015,\"109\":96130,\"110\":99214,\"111\":99281,\"112\":93010,\"113\":71550,\"114\":70551,\"115\":72141,\"116\":77066,\"117\":99204,\"118\":93015,\"119\":96130,\"120\":99214,\"121\":99281,\"122\":93010,\"123\":71550,\"124\":70551,\"125\":72141,\"126\":77066,\"127\":99204,\"128\":93015,\"129\":96130,\"130\":99214,\"131\":99281,\"132\":93010,\"133\":71550,\"134\":70551,\"135\":72141,\"136\":77066,\"137\":99204,\"138\":93015,\"139\":96130,\"140\":99214,\"141\":99281,\"142\":93010,\"143\":71550,\"144\":70551,\"145\":72141,\"146\":77066,\"147\":99204,\"148\":93015,\"149\":96130,\"150\":99214,\"151\":99281,\"152\":93010,\"153\":71550,\"154\":70551,\"155\":72141,\"156\":77066,\"157\":99204,\"158\":93015,\"159\":96130,\"160\":99214,\"161\":99281,\"162\":93010,\"163\":71550,\"164\":70551,\"165\":72141,\"166\":77066,\"167\":99204,\"168\":93015,\"169\":96130,\"170\":99214,\"171\":99281,\"172\":93010,\"173\":71550,\"174\":70551,\"175\":72141,\"176\":77066,\"177\":99204,\"178\":93015,\"179\":96130,\"180\":99214,\"181\":99281,\"182\":93010,\"183\":71550,\"184\":70551,\"185\":72141,\"186\":77066,\"187\":99204,\"188\":93015,\"189\":96130,\"190\":99214,\"191\":99281,\"192\":93010,\"193\":71550,\"194\":70551,\"195\":72141,\"196\":77066,\"197\":99204,\"198\":93015,\"199\":96130,\"200\":99214,\"201\":99281,\"202\":93010,\"203\":71550,\"204\":70551,\"205\":72141,\"206\":77066,\"207\":99204,\"208\":93015,\"209\":96130,\"210\":99214,\"211\":99281,\"212\":93010,\"213\":71550,\"214\":70551,\"215\":72141,\"216\":77066,\"217\":99204,\"218\":93015,\"219\":96130,\"220\":99214,\"221\":99281,\"222\":93010,\"223\":71550,\"224\":70551,\"225\":72141,\"226\":77066,\"227\":99204,\"228\":93015,\"229\":96130,\"230\":99214,\"231\":99281,\"232\":93010,\"233\":71550,\"234\":70551,\"235\":72141,\"236\":77066,\"237\":99204,\"238\":93015,\"239\":96130,\"240\":99214,\"241\":99281,\"242\":93010,\"243\":71550,\"244\":70551,\"245\":72141,\"246\":77066,\"247\":99204,\"248\":93015,\"249\":96130,\"250\":99214,\"251\":99281,\"252\":93010,\"253\":71550,\"254\":70551,\"255\":72141,\"256\":77066,\"257\":99204,\"258\":93015,\"259\":96130,\"260\":99214,\"261\":99281,\"262\":93010,\"263\":71550,\"264\":70551,\"265\":72141,\"266\":77066,\"267\":99204,\"268\":93015,\"269\":96130,\"270\":99214,\"271\":99281,\"272\":93010,\"273\":71550,\"274\":70551,\"275\":72141,\"276\":77066,\"277\":99204,\"278\":93015,\"279\":96130,\"280\":99214,\"281\":99281,\"282\":93010,\"283\":71550,\"284\":70551,\"285\":72141,\"286\":77066,\"287\":99204,\"288\":93015,\"289\":96130,\"290\":99214,\"291\":99281,\"292\":93010,\"293\":71550,\"294\":70551,\"295\":72141,\"296\":77066,\"297\":99204,\"298\":93015,\"299\":96130,\"300\":99214,\"301\":99281,\"302\":93010,\"303\":71550,\"304\":70551,\"305\":72141,\"306\":77066,\"307\":99204,\"308\":93015,\"309\":96130,\"310\":99214,\"311\":99281,\"312\":93010,\"313\":71550,\"314\":70551,\"315\":72141,\"316\":77066,\"317\":99204,\"318\":93015,\"319\":96130,\"320\":99214,\"321\":99281,\"322\":93010,\"323\":71550,\"324\":70551,\"325\":72141,\"326\":77066,\"327\":99204,\"328\":93015,\"329\":96130,\"330\":99214,\"331\":99281,\"332\":93010,\"333\":71550,\"334\":70551,\"335\":72141,\"336\":77066,\"337\":99204,\"338\":93015,\"339\":96130,\"340\":99214,\"341\":99281,\"342\":93010,\"343\":71550,\"344\":70551,\"345\":72141,\"346\":77066,\"347\":99204,\"348\":93015,\"349\":96130,\"350\":99214,\"351\":99281,\"352\":93010,\"353\":71550,\"354\":70551,\"355\":72141,\"356\":77066,\"357\":99204,\"358\":93015,\"359\":96130,\"360\":99214,\"361\":99281,\"362\":93010,\"363\":71550,\"364\":70551,\"365\":72141,\"366\":77066,\"367\":99204,\"368\":93015,\"369\":96130,\"370\":99214,\"371\":99281,\"372\":93010,\"373\":71550,\"374\":70551,\"375\":72141,\"376\":77066,\"377\":99204,\"378\":93015,\"379\":96130,\"380\":99214,\"381\":99281,\"382\":93010,\"383\":71550,\"384\":70551,\"385\":72141,\"386\":77066,\"387\":99204,\"388\":93015,\"389\":96130,\"390\":99214,\"391\":99281,\"392\":93010,\"393\":71550,\"394\":70551,\"395\":72141,\"396\":77066,\"397\":99204,\"398\":93015,\"399\":96130,\"400\":99214,\"401\":99281,\"402\":93010,\"403\":71550,\"404\":70551,\"405\":72141,\"406\":77066,\"407\":99204,\"408\":93015,\"409\":96130,\"410\":99214,\"411\":99281,\"412\":93010,\"413\":71550,\"414\":70551,\"415\":72141,\"416\":77066,\"417\":99204,\"418\":93015,\"419\":96130,\"420\":99214,\"421\":99281,\"422\":93010,\"423\":71550,\"424\":70551,\"425\":72141,\"426\":77066,\"427\":99204,\"428\":93015,\"429\":96130,\"430\":99214,\"431\":99281,\"432\":93010,\"433\":71550,\"434\":70551,\"435\":72141,\"436\":77066,\"437\":99204,\"438\":93015,\"439\":96130,\"440\":99214,\"441\":99281,\"442\":93010,\"443\":71550,\"444\":70551,\"445\":72141,\"446\":77066,\"447\":99204,\"448\":93015,\"449\":96130,\"450\":99214,\"451\":99281,\"452\":93010,\"453\":71550,\"454\":70551,\"455\":72141,\"456\":77066,\"457\":99204,\"458\":93015,\"459\":96130,\"460\":99214,\"461\":99281,\"462\":93010,\"463\":71550,\"464\":70551,\"465\":72141,\"466\":77066,\"467\":99204,\"468\":93015,\"469\":96130,\"470\":99214,\"471\":99281,\"472\":93010,\"473\":71550,\"474\":70551,\"475\":72141,\"476\":77066,\"477\":99204,\"478\":93015,\"479\":96130},\"Cash Price\":{\"0\":null,\"1\":null,\"2\":null,\"3\":null,\"4\":3745.0,\"5\":3745.0,\"6\":957.0,\"7\":878.0,\"8\":null,\"9\":null,\"10\":null,\"11\":null,\"12\":null,\"13\":null,\"14\":4064.0,\"15\":4064.0,\"16\":null,\"17\":251.0,\"18\":null,\"19\":null,\"20\":null,\"21\":null,\"22\":null,\"23\":null,\"24\":3981.0,\"25\":4145.0,\"26\":234.0,\"27\":null,\"28\":null,\"29\":null,\"30\":null,\"31\":null,\"32\":null,\"33\":null,\"34\":4223.0,\"35\":4223.0,\"36\":194.0,\"37\":950.0,\"38\":null,\"39\":null,\"40\":null,\"41\":null,\"42\":null,\"43\":null,\"44\":1871.0,\"45\":1871.0,\"46\":465.0,\"47\":null,\"48\":null,\"49\":null,\"50\":null,\"51\":null,\"52\":null,\"53\":null,\"54\":null,\"55\":null,\"56\":null,\"57\":null,\"58\":null,\"59\":null,\"60\":null,\"61\":null,\"62\":null,\"63\":null,\"64\":3745.0,\"65\":3745.0,\"66\":957.0,\"67\":878.0,\"68\":null,\"69\":878.0,\"70\":null,\"71\":null,\"72\":null,\"73\":null,\"74\":6572.0,\"75\":6520.0,\"76\":756.0,\"77\":1665.0,\"78\":null,\"79\":null,\"80\":null,\"81\":null,\"82\":null,\"83\":null,\"84\":7135.0,\"85\":7135.0,\"86\":784.0,\"87\":null,\"88\":null,\"89\":null,\"90\":null,\"91\":null,\"92\":null,\"93\":null,\"94\":5252.0,\"95\":6655.0,\"96\":484.0,\"97\":null,\"98\":null,\"99\":null,\"100\":null,\"101\":null,\"102\":null,\"103\":null,\"104\":2514.0,\"105\":2836.0,\"106\":1362.0,\"107\":815.0,\"108\":null,\"109\":null,\"110\":null,\"111\":null,\"112\":null,\"113\":null,\"114\":3545.0,\"115\":3672.0,\"116\":337.0,\"117\":339.0,\"118\":null,\"119\":null,\"120\":null,\"121\":null,\"122\":null,\"123\":null,\"124\":3545.0,\"125\":3672.0,\"126\":null,\"127\":null,\"128\":null,\"129\":null,\"130\":null,\"131\":null,\"132\":null,\"133\":null,\"134\":8653.0,\"135\":8277.0,\"136\":607.0,\"137\":334.0,\"138\":334.0,\"139\":null,\"140\":null,\"141\":null,\"142\":null,\"143\":null,\"144\":3724.0,\"145\":3724.0,\"146\":470.0,\"147\":null,\"148\":null,\"149\":null,\"150\":null,\"151\":null,\"152\":null,\"153\":null,\"154\":10689.0,\"155\":3201.0,\"156\":648.0,\"157\":null,\"158\":null,\"159\":null,\"160\":null,\"161\":null,\"162\":null,\"163\":null,\"164\":7812.0,\"165\":8249.0,\"166\":896.0,\"167\":238.0,\"168\":null,\"169\":null,\"170\":null,\"171\":null,\"172\":null,\"173\":null,\"174\":7812.0,\"175\":8249.0,\"176\":896.0,\"177\":238.0,\"178\":null,\"179\":null,\"180\":null,\"181\":null,\"182\":null,\"183\":null,\"184\":5008.0,\"185\":7068.0,\"186\":null,\"187\":null,\"188\":null,\"189\":null,\"190\":null,\"191\":null,\"192\":null,\"193\":null,\"194\":7322.0,\"195\":7490.0,\"196\":702.0,\"197\":2077.0,\"198\":null,\"199\":null,\"200\":null,\"201\":null,\"202\":null,\"203\":null,\"204\":3830.0,\"205\":3983.0,\"206\":296.0,\"207\":917.0,\"208\":null,\"209\":null,\"210\":null,\"211\":null,\"212\":null,\"213\":null,\"214\":3360.0,\"215\":3360.0,\"216\":574.0,\"217\":337.0,\"218\":null,\"219\":null,\"220\":null,\"221\":null,\"222\":null,\"223\":null,\"224\":3973.0,\"225\":3973.0,\"226\":null,\"227\":null,\"228\":null,\"229\":null,\"230\":null,\"231\":null,\"232\":null,\"233\":null,\"234\":5585.0,\"235\":5585.0,\"236\":400.0,\"237\":null,\"238\":null,\"239\":null,\"240\":null,\"241\":null,\"242\":null,\"243\":null,\"244\":7252.0,\"245\":7252.0,\"246\":480.0,\"247\":617.0,\"248\":617.0,\"249\":null,\"250\":null,\"251\":null,\"252\":null,\"253\":null,\"254\":11643.0,\"255\":5859.0,\"256\":null,\"257\":730.0,\"258\":null,\"259\":null,\"260\":null,\"261\":null,\"262\":null,\"263\":null,\"264\":8003.0,\"265\":6478.0,\"266\":800.0,\"267\":null,\"268\":null,\"269\":null,\"270\":null,\"271\":null,\"272\":null,\"273\":null,\"274\":8414.0,\"275\":8062.0,\"276\":1724.0,\"277\":1229.0,\"278\":null,\"279\":null,\"280\":null,\"281\":null,\"282\":null,\"283\":null,\"284\":10017.0,\"285\":3000.0,\"286\":578.0,\"287\":null,\"288\":null,\"289\":null,\"290\":null,\"291\":null,\"292\":null,\"293\":null,\"294\":7805.0,\"295\":null,\"296\":898.0,\"297\":null,\"298\":null,\"299\":null,\"300\":null,\"301\":null,\"302\":null,\"303\":null,\"304\":8634.0,\"305\":null,\"306\":591.0,\"307\":null,\"308\":null,\"309\":null,\"310\":null,\"311\":null,\"312\":null,\"313\":null,\"314\":4951.0,\"315\":5996.0,\"316\":761.0,\"317\":null,\"318\":null,\"319\":null,\"320\":null,\"321\":null,\"322\":null,\"323\":null,\"324\":5277.0,\"325\":5277.0,\"326\":2167.0,\"327\":1335.0,\"328\":null,\"329\":null,\"330\":null,\"331\":null,\"332\":null,\"333\":null,\"334\":5277.0,\"335\":5277.0,\"336\":2167.0,\"337\":1335.0,\"338\":null,\"339\":null,\"340\":null,\"341\":null,\"342\":null,\"343\":null,\"344\":9979.0,\"345\":7545.0,\"346\":566.0,\"347\":null,\"348\":null,\"349\":null,\"350\":null,\"351\":null,\"352\":null,\"353\":null,\"354\":9979.0,\"355\":7545.0,\"356\":566.0,\"357\":null,\"358\":null,\"359\":null,\"360\":null,\"361\":null,\"362\":null,\"363\":null,\"364\":9979.0,\"365\":7545.0,\"366\":566.0,\"367\":null,\"368\":null,\"369\":null,\"370\":null,\"371\":null,\"372\":null,\"373\":null,\"374\":9979.0,\"375\":7545.0,\"376\":566.0,\"377\":null,\"378\":null,\"379\":null,\"380\":null,\"381\":null,\"382\":null,\"383\":null,\"384\":9979.0,\"385\":7545.0,\"386\":566.0,\"387\":null,\"388\":null,\"389\":null,\"390\":null,\"391\":null,\"392\":null,\"393\":null,\"394\":4321.0,\"395\":4321.0,\"396\":509.0,\"397\":996.0,\"398\":null,\"399\":null,\"400\":null,\"401\":null,\"402\":null,\"403\":null,\"404\":1726.0,\"405\":1726.0,\"406\":847.0,\"407\":null,\"408\":null,\"409\":null,\"410\":null,\"411\":null,\"412\":null,\"413\":null,\"414\":8485.0,\"415\":8129.0,\"416\":534.0,\"417\":321.0,\"418\":null,\"419\":null,\"420\":null,\"421\":null,\"422\":null,\"423\":null,\"424\":3920.0,\"425\":4078.0,\"426\":301.0,\"427\":null,\"428\":null,\"429\":null,\"430\":null,\"431\":null,\"432\":null,\"433\":null,\"434\":1640.0,\"435\":3261.0,\"436\":431.0,\"437\":null,\"438\":null,\"439\":null,\"440\":null,\"441\":null,\"442\":null,\"443\":null,\"444\":11643.0,\"445\":5859.0,\"446\":null,\"447\":730.0,\"448\":null,\"449\":null,\"450\":null,\"451\":null,\"452\":null,\"453\":null,\"454\":null,\"455\":null,\"456\":null,\"457\":null,\"458\":null,\"459\":null,\"460\":null,\"461\":null,\"462\":null,\"463\":null,\"464\":6007.0,\"465\":4352.0,\"466\":null,\"467\":null,\"468\":null,\"469\":null,\"470\":null,\"471\":null,\"472\":null,\"473\":null,\"474\":9269.0,\"475\":9269.0,\"476\":null,\"477\":1235.0,\"478\":null,\"479\":null}}", 6 | "mylrh.org": "{\"Hospital name\":{\"0\":\"Lakeland Regional Hospital\",\"1\":\"Lakeland Regional Hospital\",\"2\":\"Lakeland Regional Hospital\",\"3\":\"Lakeland Regional Hospital\",\"4\":\"Lakeland Regional Hospital\",\"5\":\"Lakeland Regional Hospital\",\"6\":\"Lakeland Regional Hospital\",\"7\":\"Lakeland Regional Hospital\",\"8\":\"Lakeland Regional Hospital\",\"9\":\"Lakeland Regional Hospital\",\"10\":\"Lakeland Regional Hospital\",\"11\":\"Lakeland Regional Hospital\",\"12\":\"Lakeland Regional Hospital\"},\"CPT Code\":{\"0\":99214,\"1\":99214,\"2\":99214,\"3\":99281,\"4\":93010,\"5\":71550,\"6\":70551,\"7\":72141,\"8\":77066,\"9\":99204,\"10\":99204,\"11\":93015,\"12\":96130},\"Cash Price\":{\"0\":186.0,\"1\":186.0,\"2\":289.0,\"3\":null,\"4\":null,\"5\":null,\"6\":292.0,\"7\":284.0,\"8\":226.0,\"9\":244.0,\"10\":403.0,\"11\":null,\"12\":176.0},\"Description\":{\"0\":\"Video Visit\",\"1\":\"Established patient office or other outpatient, visit typically 25 minutes\",\"2\":\"HOSPITAL FACILITY FEE - OFFICE\\/OUTPATIENT ESTABLISHED MOD MDM 30-39 MIN\",\"3\":null,\"4\":null,\"5\":null,\"6\":\"MRI scan brain\",\"7\":\"MRI scan of upper spinal canal\",\"8\":\"Diagnostic mammography of both breasts\",\"9\":\"New patient office or other outpatient visit, typically 45 minutes\",\"10\":\"HOSPITAL FACILITY FEE - PR OFFICE\\/OUTPATIENT NEW MODERATE MDM 45-59 MINUTES\",\"11\":null,\"12\":\"Testing Evaluation 1st hour\"}}", 7 | "shands.org": "{\"Hospital name\":{\"0\":\"UF Health Shands Hospital\",\"1\":\"UF Health Shands Hospital\",\"2\":\"UF Health Jacksonville\",\"3\":\"UF Health Jacksonville\",\"4\":\"UF Health Jacksonville\",\"5\":\"UF Health Shands Hospital\",\"6\":\"UF Health Shands Hospital\",\"7\":\"UF Health Shands Hospital\",\"8\":\"UF Health Shands Hospital\",\"9\":\"UF Health Jacksonville\",\"10\":\"UF Health Jacksonville\",\"11\":\"UF Health Shands Hospital\",\"12\":\"Shands at the University of Florida\",\"13\":\"UF Health Shands Hospital\",\"14\":\"Shands at the University of Florida\",\"15\":\"UF Health Shands Hospital\",\"16\":\"UF Health Shands Hospital\",\"17\":\"UF Health Shands Hospital\",\"18\":\"UF Health Shands Hospital\",\"19\":\"UF Health Shands Hospital\",\"20\":\"UF Health Shands Hospital\",\"21\":\"Shands at the University of Florida\",\"22\":\"Shands at the University of Florida\",\"23\":\"UF Health Shands Hospital\",\"24\":\"Uf Health Leesburg Hospital\",\"25\":\"Uf Health Leesburg Hospital\",\"26\":\"Uf Health Leesburg Hospital\",\"27\":\"UF Health Shands Hospital\",\"28\":\"Uf Health Leesburg Hospital\",\"29\":\"UF Health Shands Hospital\",\"30\":\"UF Health Shands Hospital\",\"31\":\"Uf Health Leesburg Hospital\",\"32\":\"Uf Health Leesburg Hospital\",\"33\":\"Uf Health the Villages Hospital\",\"34\":\"Uf Health the Villages Hospital\",\"35\":\"Uf Health the Villages Hospital\",\"36\":\"Uf Health the Villages Hospital\",\"37\":\"UF Health Shands Hospital\",\"38\":\"Uf Health the Villages Hospital\",\"39\":\"UF Health Shands Hospital\",\"40\":\"UF Health Shands Hospital\",\"41\":\"Uf Health the Villages Hospital\",\"42\":\"Uf Health the Villages Hospital\"},\"CPT Code\":{\"0\":99214,\"1\":99214,\"2\":99281,\"3\":93010,\"4\":71550,\"5\":70551,\"6\":72141,\"7\":77066,\"8\":99204,\"9\":93015,\"10\":96130,\"11\":99214,\"12\":99281,\"13\":93010,\"14\":71550,\"15\":70551,\"16\":72141,\"17\":77066,\"18\":77066,\"19\":99204,\"20\":99204,\"21\":93015,\"22\":96130,\"23\":99214,\"24\":99281,\"25\":93010,\"26\":71550,\"27\":70551,\"28\":72141,\"29\":77066,\"30\":99204,\"31\":93015,\"32\":96130,\"33\":99214,\"34\":99281,\"35\":93010,\"36\":71550,\"37\":70551,\"38\":72141,\"39\":77066,\"40\":99204,\"41\":93015,\"42\":96130},\"Cash Price\":{\"0\":308.0,\"1\":315.0,\"2\":null,\"3\":null,\"4\":null,\"5\":2485.0,\"6\":2612.0,\"7\":458.0,\"8\":399.0,\"9\":null,\"10\":null,\"11\":511.0,\"12\":null,\"13\":162.0,\"14\":null,\"15\":1348.0,\"16\":1348.0,\"17\":406.0,\"18\":718.0,\"19\":349.0,\"20\":641.0,\"21\":null,\"22\":null,\"23\":null,\"24\":546.0,\"25\":null,\"26\":null,\"27\":1155.0,\"28\":null,\"29\":278.0,\"30\":349.0,\"31\":null,\"32\":null,\"33\":null,\"34\":null,\"35\":null,\"36\":null,\"37\":1155.0,\"38\":null,\"39\":278.0,\"40\":349.0,\"41\":null,\"42\":null},\"Description\":{\"0\":\"OFFICE\\/OUTPT VISIT,EST,LEVL IV---\",\"1\":\"OFFICE CONUSLTATION,LEVEL IV---\",\"2\":null,\"3\":null,\"4\":null,\"5\":\"MRI BRAIN---\",\"6\":\"MRI, CERV SPINE---\",\"7\":\"DIAGNOSTIC MAMMOGRAPHY COMPUTER-AIDED DETCJ BI---\",\"8\":\"OFFICE\\/OUTPT VISIT,NEW,LEVL IV---\",\"9\":null,\"10\":null,\"11\":\"ESTABLISHED PATIENT OFFICE OR OTHER OUTPATIENT VISIT LEVEL 4\",\"12\":null,\"13\":\"ELECTROCARDIOGRAM, TRACING\",\"14\":null,\"15\":\"MRI BRAIN INCLUDING BRAIN STEM WITHOUT CONTRAST\",\"16\":\"MRI CERVICAL SPINE WITHOUT CONTRAST\",\"17\":\"MAMMOGRAPHY DIAGNOSTIC BILATERAL\",\"18\":\"MAMMOGRAPHY DIAGNOSTIC BILATERAL WITH TOMO\",\"19\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT LEVEL 4\",\"20\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT LEVEL 4\",\"21\":null,\"22\":null,\"23\":null,\"24\":\"HB ER LEVEL 1\",\"25\":null,\"26\":null,\"27\":\"HB MRI BRAIN & BRAINSTEM W\\/O CONTRAS\",\"28\":null,\"29\":\"HB COMPUT MAMM DIAG BILAT\",\"30\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT LEVEL 4\",\"31\":null,\"32\":null,\"33\":null,\"34\":null,\"35\":null,\"36\":null,\"37\":\"HB MRI BRAIN & BRAINSTEM W\\/O CONTRAS\",\"38\":null,\"39\":\"HB COMPUT MAMM DIAG BILAT\",\"40\":\"NEW PATIENT OFFICE OR OTHER OUTPATIENT VISIT LEVEL 4\",\"41\":null,\"42\":null}}", 8 | "Definitions": "{\"Common CPT Codes Used\":{\"0\":99214,\"1\":99281,\"2\":93010,\"3\":71550,\"4\":70551,\"5\":72141,\"6\":77066,\"7\":99204,\"8\":93015,\"9\":96130},\"CPT Universal Description if Undefined\":{\"0\":\"OFFICE O\\/P EST MOD 30 MIN\",\"1\":\"Emergency Dept Visit\",\"2\":\"EKG with Interpretation\",\"3\":\"MRI Chest without contrast\",\"4\":\"BRAIN MRI without contract\",\"5\":\"MRI Cervical Spine\",\"6\":\"Diagnostic Mammography\",\"7\":\"Office visit New Patient\",\"8\":\"Treadmill Cardiac Stress Testing\",\"9\":\"Psychological Evaluation (initial)\"}}" 9 | } --------------------------------------------------------------------------------