├── .gitignore ├── README.md ├── schemas ├── tcg.schema ├── tmdb.schema └── yelp.schema ├── create_schema_index.py └── demo.py /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .chromadb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | ![Query building](https://user-images.githubusercontent.com/10900474/232677841-30794237-7295-4a10-b627-e9d9c682d27d.png) 4 | ![Final answer](https://user-images.githubusercontent.com/10900474/232677862-0000da7e-b124-48a2-835d-edb4f414eedc.png) 5 | 6 | Access services with a public GraphQL API, GPT plugin style, but without writing any plugin code. 7 | Currently supported schema: Github, Yelp, TMDB (movie database), and Pokemon Trading cards. 8 | 9 | You can ask the service any questions, and it will be turned into a GraphQL query, get exdcuted, and return desired answer. 10 | 11 | It can be extended to any public and private GraphQL service with a schema file of any size. You need to create a index for each tool by using provided scirpt, and at run time the index will be used to provide the most relevant part of the schema for Language models to build a query. 12 | 13 | ## Requirement 14 | ``` 15 | pip install openai langchain termcolor colorama chromadb tiktoken 16 | ``` 17 | 18 | ``` 19 | export OPENAI_ORG="" 20 | export OPENAI_API_KEY="" 21 | export GITHUB_PERSONAL_TOKEN="" //if you want to use the github query, you will need to provide your own token 22 | ``` 23 | 24 | If you want to try it on another schema, you need to provide a schema file and modify the code to include it. 25 | - You can use [gql-sdl tool](https://www.npmjs.com/package/gql-sdl) to download a graphql schema from an endpoint. 26 | - Then, you can then modify the code to add that schema. Add payload and headers of the new graphql endpoint in `main()`, and add the name of the service in the prompt template inside `create_tool_choice_prompt()` 27 | 28 | ## Usage 29 | First, create index for the schema to use. We provide a few example schemas in the `schemas` folder.You can specify which file to index. By default, it will create schemas for all of the files in `schemas` folder 30 | ``` 31 | python create_schema_index.py //this will index all files in schemas/ folder 32 | python create_schema_index.py --file schemas/github.schema //this will index a particular file 33 | ``` 34 | You can replace github.schema to any schema files. It will be stored to your local `.chromadb/`. 35 | 36 | Note if you add new schema for a tool you are interested in trying, you need to modify the `main.py` in two places in order to use new tools. 37 | - in `def create_tool_choice_prompt`, add new tool's name into the prompt. 38 | - in `main`, follow the logic of other tools, add logic to load index from the index file you just created, and specify endpoint and headers for making queries. 39 | 40 | ``` 41 | python main.py 42 | ``` 43 | 44 | You can then type questions, and if the answers are not good, you can give it feedback to let GPT try again. 45 | Have fun! -------------------------------------------------------------------------------- /schemas/tcg.schema: -------------------------------------------------------------------------------- 1 | directive @locale(lang: String!) on FIELD 2 | 3 | type Query { 4 | cards(filters: CardsFilters, pagination: Pagination): [Card] 5 | sets: [Set] 6 | series: [Serie] 7 | card(id: ID!, set: String): Card 8 | set(id: ID!): Set 9 | serie(id: ID!): Serie 10 | } 11 | 12 | input Pagination { 13 | page: Float! 14 | count: Float! 15 | } 16 | 17 | input CardsFilters { 18 | category: String 19 | description: String 20 | energyType: String 21 | evolveFrom: String 22 | hp: Float 23 | id: ID 24 | localId: String 25 | dexId: Float 26 | illustrator: String 27 | image: String 28 | level: Float 29 | levelId: String 30 | name: String 31 | rarity: String 32 | regulationMark: String 33 | stage: String 34 | suffix: String 35 | trainerType: String 36 | retreat: Float 37 | } 38 | 39 | type Card { 40 | abilities: [AbilitiesListItem] 41 | attacks: [AttacksListItem] 42 | category: String! 43 | description: String 44 | dexId: [Float] 45 | effect: String 46 | energyType: String 47 | evolveFrom: String 48 | hp: Float 49 | id: String! 50 | illustrator: String 51 | image: String 52 | item: Item 53 | legal: Legal! 54 | level: Float 55 | localId: String! 56 | name: String! 57 | rarity: String! 58 | regulationMark: String 59 | resistances: [WeakResListItem] 60 | retreat: Float 61 | set: Set! 62 | stage: String 63 | suffix: String 64 | trainerType: String 65 | types: [String] 66 | variants: Variants 67 | weaknesses: [WeakResListItem] 68 | } 69 | 70 | type AbilitiesListItem { 71 | effect: String 72 | name: String 73 | type: String 74 | } 75 | 76 | type AttacksListItem { 77 | cost: [String] 78 | damage: String 79 | effect: String 80 | name: String! 81 | } 82 | 83 | type Item { 84 | effect: String! 85 | name: String! 86 | } 87 | 88 | type Legal { 89 | expanded: Boolean 90 | standard: Boolean 91 | } 92 | 93 | type WeakResListItem { 94 | type: String! 95 | value: String 96 | } 97 | 98 | type Variants { 99 | firstEdition: Boolean! 100 | holo: Boolean! 101 | normal: Boolean! 102 | reverse: Boolean! 103 | wPromo: Boolean! 104 | } 105 | 106 | type Set { 107 | cardCount: CardCount! 108 | cards: [Card]! 109 | id: String! 110 | logo: String 111 | name: String! 112 | symbol: String 113 | serie: Serie! 114 | releaseDate: String! 115 | tcgOnline: String 116 | } 117 | 118 | type CardCount { 119 | firstEd: Float 120 | holo: Float 121 | normal: Float 122 | official: Float! 123 | reverse: Float 124 | total: Float! 125 | } 126 | 127 | type Serie { 128 | id: String! 129 | logo: String 130 | name: String! 131 | sets: [Set]! 132 | } 133 | 134 | type StringEndpoint { 135 | cards: [Card]! 136 | name: String! 137 | } 138 | -------------------------------------------------------------------------------- /create_schema_index.py: -------------------------------------------------------------------------------- 1 | import chromadb 2 | from chromadb.utils import embedding_functions 3 | from chromadb.config import Settings 4 | import graphql 5 | import os 6 | import argparse 7 | import tiktoken 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("--file", help="schema file to load in to vector DB", type=str, required=False) 11 | args = parser.parse_args() 12 | 13 | def iterdict(d): 14 | for k,v in d.items(): 15 | if isinstance(v, dict): 16 | return iterdict(v) 17 | else: 18 | if k == "value" and v[0].isupper(): 19 | if v not in ["Int", "String", "ID", "Boolean", "Float", "ALL", "Json", "DateTime"]: 20 | return v 21 | 22 | def trim_text_for_context_size(text, token_limit=8000): 23 | encoding = tiktoken.encoding_for_model("text-embedding-ada-002") 24 | text_token_size = len(encoding.encode(text)) 25 | while text_token_size > token_limit: 26 | delta = text_token_size - token_limit 27 | num_chars_to_remove = delta // 4 + 1 28 | text = text[:-num_chars_to_remove] 29 | text_token_size = len(text) 30 | return text 31 | 32 | def main(): 33 | schema_strings = [] 34 | file_names = [] 35 | file_name = args.file 36 | if file_name: 37 | print(f"Parsing {file_name} ...") 38 | with open(file_name) as f: 39 | schema_string = f.read() 40 | schema_strings.append(schema_string) 41 | file_names.append(file_name) 42 | else: 43 | print(f"parsing all files in schemas/ with an extention schema or graphql or gql") 44 | file_names = ["schemas/" + f for f in os.listdir('schemas') if f.endswith((".schema", ".graphql", ".gql"))] 45 | for file_name in file_names: 46 | with open(file_name) as f: 47 | schema_string = f.read() 48 | schema_strings.append(schema_string) 49 | 50 | chroma_client = chromadb.Client( 51 | Settings( 52 | chroma_db_impl="duckdb+parquet", 53 | persist_directory=".chromadb/" # Optional, defaults to .chromadb/ in the current directory 54 | ) 55 | ) 56 | openai_ef = embedding_functions.OpenAIEmbeddingFunction( 57 | api_key=os.getenv('OPENAI_API_KEY'), 58 | model_name="text-embedding-ada-002" 59 | ) 60 | # Parse the schema into an AST using the graphql module 61 | for i, schema_string in enumerate(schema_strings): 62 | file_name = file_names[i] 63 | schema_ast = graphql.parse(schema_string) 64 | documents = [] 65 | metadatas = [] 66 | ids = [] 67 | for d in schema_ast.definitions: 68 | text = schema_string[d.loc.start: d.loc.end] 69 | text = trim_text_for_context_size(text, 8000) 70 | documents.append(text) 71 | schema_definitions = d.to_dict() 72 | metadata = {"fields": ''} 73 | if "fields" in schema_definitions: 74 | for f in schema_definitions['fields']: 75 | field_type = iterdict(f['type']) 76 | if field_type: 77 | metadata['fields'] += field_type + ', ' 78 | metadata['fields'] = metadata['fields'][:-2] 79 | metadatas.append(metadata) 80 | ids.append(schema_definitions['name']['value']) 81 | 82 | collection_name = f"{file_name.split('/')[-1].replace('.','-')}-index" 83 | print(f'Creating {collection_name}') 84 | 85 | collection = chroma_client.create_collection(name=collection_name, embedding_function=openai_ef) 86 | collection.add( 87 | documents=documents, 88 | metadatas=metadatas, 89 | ids=ids 90 | ) 91 | 92 | 93 | if __name__ == '__main__': 94 | main() -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | import chromadb 2 | from chromadb.config import Settings 3 | from chromadb.utils import embedding_functions 4 | import openai 5 | import os 6 | import requests 7 | from langchain import PromptTemplate 8 | from requests.exceptions import HTTPError 9 | import json 10 | import colorama 11 | from termcolor import colored 12 | import tiktoken 13 | import logging 14 | 15 | logging.disable(logging.CRITICAL) 16 | 17 | 18 | 19 | colorama.init() 20 | 21 | openai.organization = os.getenv('OPENAI_ORG') 22 | openai.api_key = os.getenv('OPENAI_API_KEY') 23 | 24 | OPENAI_PARAMS={ 25 | "temperature": 0, 26 | "max_tokens": 1024, 27 | "top_p": 1.0, 28 | } 29 | 30 | chroma_client = chromadb.Client( 31 | Settings( 32 | chroma_db_impl="duckdb+parquet", 33 | persist_directory=".chromadb/" # Optional, defaults to .chromadb/ in the current directory 34 | ) 35 | ) 36 | 37 | def ask_gpt4(input_str, feedback): 38 | messages=[ 39 | {"role": "system", "content": "You are a helpful assistant."}, 40 | {"role": "user", "content": input_str}, 41 | ] 42 | 43 | if feedback: 44 | messages += feedback 45 | 46 | response = openai.ChatCompletion.create( 47 | model="gpt-4", 48 | messages=messages, 49 | temperature=OPENAI_PARAMS.get("temperature", 0), 50 | max_tokens=OPENAI_PARAMS.get("max_tokens", 2048), 51 | top_p=OPENAI_PARAMS.get("top_p", 1.0), 52 | ) 53 | 54 | return response['choices'][0]['message']['content'] 55 | 56 | def ask_chatgpt(input_str): 57 | response = openai.ChatCompletion.create( 58 | model="gpt-3.5-turbo", 59 | messages=[ 60 | {"role": "system", "content": "You are a helpful assistant."}, 61 | {"role": "user", "content": input_str}, 62 | ], 63 | temperature=OPENAI_PARAMS.get("temperature", 0), 64 | max_tokens=OPENAI_PARAMS.get("max_tokens", 2048), 65 | top_p=OPENAI_PARAMS.get("top_p", 1.0), 66 | ) 67 | 68 | return response['choices'][0]['message']['content'] 69 | 70 | def load_schema_files(filename="schemas/yelp.schema"): 71 | with open(filename) as f: 72 | schema = f.read() 73 | return schema 74 | 75 | def load_index(indexname='github-schema-index'): 76 | index = chroma_client.get_collection(indexname) 77 | openai_ef = embedding_functions.OpenAIEmbeddingFunction( 78 | api_key=os.getenv('OPENAI_API_KEY'), 79 | model_name="text-embedding-ada-002" 80 | ) 81 | index._embedding_function = openai_ef 82 | return index 83 | 84 | def get_relevant_schema_from_index(index, user_question): 85 | 86 | results = index.query( 87 | query_texts=[user_question], 88 | n_results=10 89 | ) 90 | current_nodes = results['ids'][0] 91 | num_original_nodes = len(current_nodes) 92 | print(colored(f"DEBUG: find relevant nodes from user questions {current_nodes}", 'light_green', 'on_dark_grey')) 93 | current_documents = results['documents'][0] 94 | # now added related field entities for existing results, and append it to the context. 95 | for m in results['metadatas'][0]: 96 | fields = m["fields"].split(", ") 97 | # print(fields) 98 | for node in fields: 99 | if node and node not in current_nodes: 100 | current_nodes.append(node) 101 | current_documents += index.get(node)['documents'] 102 | print(colored(f"DEBUG: added related entities {current_nodes[num_original_nodes:]}", 'light_green', 'on_dark_grey')) 103 | # Still need to make sure the overall context size does not explode after we do this. 104 | schema = " ".join(current_documents) 105 | schema = trim_text_for_context_size(schema) 106 | # print("DEBUG: schema ", schema) 107 | return schema 108 | 109 | 110 | def create_write_gql_query_prompt(): 111 | template = """ 112 | Write a graphql query to answer the user question: {question}. The results of the query are fed into another large language model to compile the final answer. 113 | Please ensure that the graphql query you write is valid for the provided schema. If such query does not exist, answer N/A. Don't include any comment or explanation or dictionary format.\n 114 | 115 | GraphQL Schema: 116 | {schema} 117 | """ 118 | prompt = PromptTemplate( 119 | input_variables=["question", "schema"], 120 | template=template, 121 | ) 122 | return prompt 123 | 124 | def create_tool_choice_prompt(): 125 | template = """ 126 | Given the user question: {question}, what tools will be helpful? If you don't konw, answer N/A. 127 | Reply with just one word answer: Yelp, TMDB, Pokemon, Github, or N/A. For example: where can I eat? Yelp 128 | """ 129 | prompt = PromptTemplate( 130 | input_variables=["question"], 131 | template=template, 132 | ) 133 | return prompt 134 | 135 | def create_compile_answer_prompt(): 136 | template = """ 137 | Given the results {results}, answer the user question: {question} in plain english with a delightful, helpful tone. 138 | 139 | """ 140 | prompt = PromptTemplate( 141 | input_variables=["results", "question"], 142 | template=template, 143 | ) 144 | return prompt 145 | 146 | 147 | def execute_graphql_command(endpoint, data, headers): 148 | """ 149 | execute a graphql query 150 | """ 151 | try: 152 | r = requests.post(endpoint, data=data, headers=headers) 153 | except HTTPError as e: 154 | print(e.response.text) 155 | return r 156 | 157 | def trim_text_for_context_size(text, token_limit=7000): 158 | encoding = tiktoken.encoding_for_model("text-embedding-ada-002") 159 | text_token_size = len(encoding.encode(text)) 160 | while text_token_size > token_limit: 161 | delta = text_token_size - token_limit 162 | num_chars_to_remove = delta // 4 + 1 163 | text = text[:-num_chars_to_remove] 164 | text_token_size = len(text) 165 | return text 166 | 167 | 168 | def main(): 169 | available_collections = chroma_client.list_collections() 170 | if len(available_collections) == 0: 171 | print("no available collection, please run create_schema_index.py first.") 172 | exit(0) 173 | print(colored(f"availabe indexed schemas in vector DB: {available_collections}", 'light_green', 'on_dark_grey')) 174 | # prompt templates 175 | # 1. choose a tool to use based on user's question, a tool corresponses to a graphql endpoint 176 | tool_choice_prompt = create_tool_choice_prompt() 177 | # 2. given the question and relevant schema, write a gql query 178 | write_gql_query_prompt = create_write_gql_query_prompt() 179 | # 3. given query results and user question, compile an answer 180 | compile_answer_prompt = create_compile_answer_prompt() 181 | 182 | user_question = input("How can I help you today?\n\n") 183 | tool_response = ask_chatgpt(tool_choice_prompt.format(question=user_question)) 184 | 185 | schema = None 186 | endpoint = None 187 | headers = None 188 | print("\n") 189 | if "github" in tool_response.lower(): 190 | index = load_index("github-schema-index") 191 | schema = get_relevant_schema_from_index(index, user_question) 192 | endpoint = "https://api.github.com/graphql" 193 | headers = { 194 | "Authorization": f"bearer {os.getenv('GITHUB_PERSONAL_TOKEN')}" 195 | } 196 | tool = "github" 197 | 198 | elif "yelp" in tool_response.lower(): 199 | # schema = load_schema_files('schemas/yelp.schema') 200 | index = load_index("yelp-schema-index") 201 | schema = get_relevant_schema_from_index(index, user_question) 202 | endpoint = "https://api.yelp.com/v3/graphql" 203 | headers={ 204 | "Authorization": f"Bearer 1RosRHvtDF8zosm9SM-xOz8cUCt0YTp_nVPjqSIwy5PBqFPanbLIQoCPdKH8NMbrGflkpGoS4FqMtjHqx1Fz7IpZ6v8ZqZ338lXXbkC27V8wBPUaSHd4E0yD7ZwKWXYx", 205 | "Content-Type": "application/graphql" 206 | } 207 | tool = "yelp" 208 | 209 | elif 'tmdb' in tool_response.lower(): 210 | index = load_index("tmdb-schema-index") 211 | schema = get_relevant_schema_from_index(index, user_question) 212 | # schema = load_schema_files('schemas/tmdb.schema') 213 | endpoint = "https://tmdb.apps.quintero.io/" 214 | headers={ 215 | "Content-Type": "application/json", 216 | } 217 | tool = "tmdb" 218 | 219 | elif 'pokemon' in tool_response.lower(): 220 | # schema = load_schema_files('schemas/tcg.schema') 221 | index = load_index("tcg-schema-index") 222 | schema = get_relevant_schema_from_index(index, user_question) 223 | endpoint = "https://api.tcgdex.net/v2/graphql" 224 | headers={ 225 | "Content-Type": "application/json", 226 | } 227 | tool = "pokemon" 228 | 229 | else: 230 | print("No available tool for this. ") 231 | exit(0) 232 | 233 | print(colored(f'Using {tool} GraphQL API', 'light_green', 'on_dark_grey')) 234 | 235 | 236 | feedback = None 237 | while True: 238 | response_history = "" 239 | gql_query_response = ask_gpt4(write_gql_query_prompt.format(question=user_question, schema=schema), feedback=feedback) 240 | print(colored(f"Query: \n {gql_query_response}", 'light_green', 'on_dark_grey')) 241 | 242 | ## Execute the query 243 | print(colored(f"Executing the query ...", 'light_green', 'on_dark_grey')) 244 | 245 | data = gql_query_response 246 | if tool != "yelp": 247 | data = json.dumps({"query": gql_query_response}) 248 | response = execute_graphql_command(endpoint=endpoint, data=data, headers=headers) 249 | 250 | print(colored(response.text, 'light_green', 'on_dark_grey')) 251 | 252 | if response.status_code == 200 and response.text != "N/A" and "errors" not in response.text: 253 | response_history += response.text 254 | final_answer = ask_chatgpt(compile_answer_prompt.format( question=user_question, results=response_history)) 255 | print(f"\nAnswer:{final_answer}\n") 256 | else: 257 | error_feedback = input("Retrying the query again, can you provide some feedback? Or type 'quit' to restart a new conversation.\n") 258 | if error_feedback.lower() == "quit": 259 | break 260 | feedback = [ 261 | {"role": "assistant", "content": gql_query_response}, 262 | {"role": "user", "content": f"previous answer: {response.text}, Feedback: {error_feedback}"}, 263 | ] 264 | continue 265 | user_feedback = input("Does this answer look right? Hit enter if Yes. If not, please provide feedback, or type 'quit' to restart a new conversation.\n") 266 | if len(user_feedback) > 4: 267 | feedback = [ 268 | {"role": "assistant", "content": gql_query_response}, 269 | {"role": "user", "content": user_feedback}, 270 | ] 271 | user_question += user_feedback 272 | elif user_feedback.lower() == "quit": 273 | break 274 | else: 275 | print("I'm glad you are happy with the answer!\n") 276 | break 277 | 278 | if __name__ == '__main__': 279 | while True: 280 | main() 281 | 282 | 283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /schemas/tmdb.schema: -------------------------------------------------------------------------------- 1 | type AlternativeTitle { 2 | iso3166_1: String! 3 | title: String! 4 | type: String! 5 | } 6 | 7 | union AnyImage = BackdropSizeDetailImage | PosterSizeDetailImage | ProfileSizeDetailImage | StillSizeDetailImage | LogoSizeDetailImage 8 | 9 | enum BackdropSize { 10 | W300 11 | W1280 12 | Original 13 | W780 14 | } 15 | 16 | type BackdropSizeDetailImage { 17 | aspectRatio: Float! 18 | height: Int! 19 | image(size: BackdropSize!): URL! 20 | iso639_1: String 21 | voteAverage: Float! 22 | voteCount: Int! 23 | width: Int! 24 | } 25 | 26 | type CastCreditWithMovie implements ICreditWithMovie { 27 | character: String! 28 | id: String! 29 | value: Movie! 30 | } 31 | 32 | type CastCreditWithMovieOrTV implements ICreditWithMovieOrTV { 33 | character: String! 34 | id: String! 35 | value: MovieOrTV! 36 | } 37 | 38 | type CastCreditWithPerson implements ICreditWithPerson { 39 | character: String! 40 | id: String! 41 | value: Person! 42 | } 43 | 44 | type CastCreditWithTVShow implements ICreditWithTVShow { 45 | character: String! 46 | id: String! 47 | value: TVShow! 48 | } 49 | 50 | type CreditWithMovie implements ICreditWithMovie { 51 | id: String! 52 | value: Movie! 53 | } 54 | 55 | type CreditWithMovieOrTV implements ICreditWithMovieOrTV { 56 | id: String! 57 | value: MovieOrTV! 58 | } 59 | 60 | type CreditWithPerson implements ICreditWithPerson { 61 | id: String! 62 | value: Person! 63 | } 64 | 65 | type CreditWithTVShow implements ICreditWithTVShow { 66 | id: String! 67 | value: TVShow! 68 | } 69 | 70 | type CreditsWithMovie { 71 | cast: [CastCreditWithMovie!]! 72 | crew: [CrewCreditWithMovie!]! 73 | id: Int! 74 | } 75 | 76 | type CreditsWithMovieOrTV { 77 | cast: [CastCreditWithMovieOrTV!]! 78 | crew: [CrewCreditWithMovieOrTV!]! 79 | id: Int! 80 | } 81 | 82 | type CreditsWithPerson implements ICreditsWithPerson { 83 | cast: [CastCreditWithPerson!]! 84 | crew: [CrewCreditWithPerson!]! 85 | id: Int! 86 | } 87 | 88 | type CreditsWithTVShow { 89 | cast: [CastCreditWithTVShow!]! 90 | crew: [CrewCreditWithTVShow!]! 91 | id: Int! 92 | } 93 | 94 | type CrewCreditWithMovie implements ICreditWithMovie { 95 | department: String! 96 | id: String! 97 | job: String! 98 | value: Movie! 99 | } 100 | 101 | type CrewCreditWithMovieOrTV implements ICreditWithMovieOrTV { 102 | department: String! 103 | id: String! 104 | job: String! 105 | value: MovieOrTV! 106 | } 107 | 108 | type CrewCreditWithPerson implements ICreditWithPerson { 109 | department: String! 110 | id: String! 111 | job: String! 112 | value: Person! 113 | } 114 | 115 | type CrewCreditWithTVShow implements ICreditWithTVShow { 116 | department: String! 117 | id: String! 118 | job: String! 119 | value: TVShow! 120 | } 121 | 122 | scalar Date 123 | 124 | type Discover { 125 | movies(input: MovieDiscoverInput): DiscoverMovies! 126 | tv(input: TVDiscoverInput): DiscoverTV! 127 | } 128 | 129 | input DiscoverDateFilter { 130 | max: Date 131 | min: Date 132 | } 133 | 134 | input DiscoverFloatFilter { 135 | max: Float 136 | min: Float 137 | } 138 | 139 | input DiscoverIncludeExcludeFilter { 140 | exclude: [ID!] 141 | include: [ID!] 142 | } 143 | 144 | input DiscoverIncludeFilter { 145 | include: [ID!]! 146 | } 147 | 148 | input DiscoverInput { 149 | cast: DiscoverIncludeFilter 150 | companies: DiscoverIncludeExcludeFilter 151 | crew: DiscoverIncludeFilter 152 | genres: DiscoverIncludeExcludeFilter 153 | keywords: DiscoverIncludeExcludeFilter 154 | people: DiscoverIncludeFilter 155 | rating: DiscoverFloatFilter 156 | runtime: DiscoverIntFilter 157 | streamingOptions: StreamingOptions 158 | voteCount: DiscoverIntFilter 159 | } 160 | 161 | input DiscoverIntFilter { 162 | max: Int 163 | min: Int 164 | } 165 | 166 | type DiscoverMovies { 167 | latest(first: Int, before: String, after: String, last: Int): MovieConnection! 168 | popular(first: Int, before: String, after: String, last: Int): MovieConnection! 169 | topRated(first: Int, before: String, after: String, last: Int): MovieConnection! 170 | } 171 | 172 | type DiscoverTV { 173 | latest(first: Int, before: String, after: String, last: Int): TVShowConnection! 174 | onTheAir(first: Int, before: String, after: String, last: Int): TVShowConnection! 175 | popular(first: Int, before: String, after: String, last: Int): TVShowConnection! 176 | topRated(first: Int, before: String, after: String, last: Int): TVShowConnection! 177 | } 178 | 179 | type Episode implements IStreamable & Node { 180 | airDate: Date 181 | credits: EpisodeCreditsWithPerson! 182 | crew: [CrewCreditWithPerson!]! 183 | episodeNumber: Int! 184 | externalIds: IExternalIDS! 185 | guestStars: [CastCreditWithPerson!]! 186 | 187 | """The id of the object""" 188 | id: ID! 189 | images: EpisodeImages! 190 | name: String! 191 | next: Episode 192 | overview: String! 193 | previous: Episode 194 | productionCode: String! 195 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 196 | season: Season! 197 | seasonNumber: Int! 198 | show: TVShow! 199 | still(size: StillSize!): URL 200 | streamingOptions(country: ID): [StreamingOption!] 201 | translations: [TranslationWithTranslatedMovieInfo!]! 202 | videos: [Video!]! 203 | voteAverage: Float! 204 | voteCount: Int! 205 | } 206 | 207 | type EpisodeCreditsWithPerson implements ICreditsWithPerson { 208 | cast: [CastCreditWithPerson!]! 209 | crew: [CrewCreditWithPerson!]! 210 | guestStars: [CastCreditWithPerson!]! 211 | id: Int! 212 | } 213 | 214 | type EpisodeImages { 215 | stills: [StillSizeDetailImage!]! 216 | } 217 | 218 | type ExternalIDS implements IExternalIDS { 219 | facebook: String 220 | imdb: String 221 | instagram: String 222 | twitter: String 223 | } 224 | 225 | enum ExternalSource { 226 | Facebook 227 | Instagram 228 | Freebase 229 | Twitter 230 | Tvdb 231 | Tvrage 232 | Imdb 233 | } 234 | 235 | type FromExternalIds { 236 | movies: [Movie!]! 237 | people: [Person!]! 238 | tv: [TVShow!]! 239 | } 240 | 241 | type FullExternalIDS implements IExternalIDS { 242 | facebook: String 243 | imdb: String 244 | instagram: String 245 | tmdb: Int! 246 | twitter: String 247 | } 248 | 249 | enum Gender { 250 | Female 251 | UnknownOrNonBinary 252 | Male 253 | } 254 | 255 | type Genre implements Node { 256 | discover(input: DiscoverInput): Discover! 257 | 258 | """The id of the object""" 259 | id: ID! 260 | name: String! 261 | } 262 | 263 | type GenreConnection { 264 | edges: [GenreEdge] 265 | pageInfo: PageInfo! 266 | totalCount: Int! 267 | } 268 | 269 | type GenreEdge { 270 | cursor: String! 271 | node: Genre 272 | } 273 | 274 | type Genres { 275 | all(after: String, first: Int, last: Int, before: String): GenreConnection! 276 | genre(id: ID!): Genre! 277 | } 278 | 279 | interface ICreditWithMovie { 280 | id: String! 281 | value: Movie! 282 | } 283 | 284 | interface ICreditWithMovieOrTV { 285 | id: String! 286 | value: MovieOrTV! 287 | } 288 | 289 | interface ICreditWithPerson { 290 | id: String! 291 | value: Person! 292 | } 293 | 294 | interface ICreditWithTVShow { 295 | id: String! 296 | value: TVShow! 297 | } 298 | 299 | interface ICreditsWithPerson { 300 | cast: [CastCreditWithPerson!]! 301 | crew: [CrewCreditWithPerson!]! 302 | id: Int! 303 | } 304 | 305 | interface IExternalIDS { 306 | facebook: String 307 | imdb: String 308 | instagram: String 309 | twitter: String 310 | } 311 | 312 | interface IStreamable { 313 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 314 | streamingOptions(country: ID): [StreamingOption!] 315 | } 316 | 317 | type Keyword implements Node { 318 | discover(input: DiscoverInput): Discover! 319 | 320 | """The id of the object""" 321 | id: ID! 322 | name: String! 323 | } 324 | 325 | enum LogoSize { 326 | Original 327 | W185 328 | W45 329 | W500 330 | W92 331 | W154 332 | W300 333 | } 334 | 335 | type LogoSizeDetailImage { 336 | aspectRatio: Float! 337 | height: Int! 338 | image(size: LogoSize!): URL! 339 | iso639_1: String 340 | voteAverage: Float! 341 | voteCount: Int! 342 | width: Int! 343 | } 344 | 345 | type MediaImages { 346 | backdrops: [BackdropSizeDetailImage!]! 347 | posters: [PosterSizeDetailImage!]! 348 | } 349 | 350 | type Movie implements IStreamable & Node { 351 | alternativeTitles: [AlternativeTitle!]! 352 | backdrop(size: BackdropSize!): URL 353 | budget: Int 354 | credits: ICreditsWithPerson! 355 | externalIds: FullExternalIDS! 356 | genres: [Genre!]! 357 | homepage: URL 358 | 359 | """The id of the object""" 360 | id: ID! 361 | images: MediaImages! 362 | imdbID: String! 363 | isAdult: Boolean! 364 | isVideo: Boolean! 365 | keywords: [Keyword!]! 366 | numberOfRatings: Int! 367 | originalLanguage: String! 368 | originalTitle: String! 369 | overview: String! 370 | popularityIndex: Float 371 | poster(size: PosterSize!): URL 372 | productionCompanies: [ProductionCompany!]! 373 | productionCountries: [ProductionCountry!]! 374 | rating: Float! 375 | recommendations(first: Int, before: String, after: String, last: Int): MovieConnection! 376 | releaseDate: Date 377 | revenue: Int 378 | reviews(first: Int, before: String, after: String, last: Int): ReviewConnection! 379 | runtime: Int! 380 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 381 | similar(first: Int, before: String, after: String, last: Int): MovieConnection! 382 | spokenLanguages: [SpokenLanguage!]! 383 | status: Status! 384 | streamingOptions(country: ID): [StreamingOption!] 385 | tagline: String! 386 | title: String! 387 | translations: [TranslationWithTranslatedMovieInfo!]! 388 | videos: [Video!]! 389 | } 390 | 391 | type MovieConnection { 392 | edges: [MovieEdge] 393 | pageInfo: PageInfo! 394 | totalCount: Int! 395 | } 396 | 397 | input MovieDiscoverInput { 398 | includeAdult: Boolean 399 | includeVideo: Boolean 400 | releaseDate: DiscoverDateFilter 401 | } 402 | 403 | type MovieEdge { 404 | cursor: String! 405 | node: Movie 406 | } 407 | 408 | union MovieOrTV = Movie | TVShow 409 | 410 | union MovieOrTVOrPeople = Movie | TVShow | Person 411 | 412 | type MovieOrTVOrPeopleConnection { 413 | edges: [MovieOrTVOrPeopleEdge] 414 | pageInfo: PageInfo! 415 | totalCount: Int! 416 | } 417 | 418 | type MovieOrTVOrPeopleEdge { 419 | cursor: String! 420 | node: MovieOrTVOrPeople 421 | } 422 | 423 | type Movies { 424 | movie(id: ID!): Movie! 425 | nowPlaying(first: Int, before: String, after: String, last: Int): MovieConnection! 426 | popular(first: Int, before: String, after: String, last: Int): MovieConnection! 427 | productionCompany(id: ID!): ProductionCompany! 428 | search(first: Int, before: String, term: String!, after: String, last: Int): MovieConnection! 429 | topRated(first: Int, before: String, after: String, last: Int): MovieConnection! 430 | trending(first: Int, before: String, after: String, timeWindow: TimeWindow! = Day, last: Int): MovieConnection! 431 | upcoming(first: Int, before: String, after: String, last: Int): MovieConnection! 432 | } 433 | 434 | type Network implements Node { 435 | """The id of the object""" 436 | id: ID! 437 | logo(size: LogoSize!): URL 438 | name: String! 439 | originCountry: String! 440 | tv(input: TVDiscoverInput, otherFilters: DiscoverInput): DiscoverTV! 441 | } 442 | 443 | interface Node { 444 | """The id of the object""" 445 | id: ID! 446 | } 447 | 448 | type PageInfo { 449 | endCursor: String 450 | hasNextPage: Boolean! 451 | hasPreviousPage: Boolean! 452 | startCursor: String 453 | } 454 | 455 | type People { 456 | person(id: ID!): Person! 457 | popular(after: String, first: Int, last: Int, before: String): PersonConnection! 458 | search(term: String!, after: String, first: Int, last: Int, before: String): PersonConnection! 459 | trending(timeWindow: TimeWindow! = Day, after: String, first: Int, last: Int, before: String): PersonConnection! 460 | } 461 | 462 | type Person implements Node { 463 | alsoKnownAs: [String!]! 464 | biography: String! 465 | birthday: Date 466 | credits: PersonCredits! 467 | deathday: Date 468 | discover(input: DiscoverInput): Discover! 469 | externalIds: FullExternalIDS! 470 | gender: Gender! 471 | homepage: URL 472 | 473 | """The id of the object""" 474 | id: ID! 475 | images: [ProfileSizeDetailImage!]! 476 | imdbID: String 477 | isAdult: Boolean! 478 | knownFor: [MovieOrTV!]! 479 | knownForDepartment: String! 480 | name: String! 481 | placeOfBirth: String 482 | popularityIndex: Float! 483 | profilePicture(size: ProfileSize!): URL 484 | taggedImages(first: Int, before: String, after: String, last: Int): TaggedImageConnection! 485 | translations: [TranslationWithTranslatedPersonInfo!]! 486 | } 487 | 488 | type PersonConnection { 489 | edges: [PersonEdge] 490 | pageInfo: PageInfo! 491 | totalCount: Int! 492 | } 493 | 494 | type PersonCredits { 495 | all: CreditsWithMovieOrTV! 496 | movies: CreditsWithMovie! 497 | tv: CreditsWithTVShow! 498 | } 499 | 500 | type PersonEdge { 501 | cursor: String! 502 | node: Person 503 | } 504 | 505 | enum PosterSize { 506 | W154 507 | W92 508 | W185 509 | W780 510 | W342 511 | W500 512 | Original 513 | } 514 | 515 | type PosterSizeDetailImage { 516 | aspectRatio: Float! 517 | height: Int! 518 | image(size: PosterSize!): URL! 519 | iso639_1: String 520 | voteAverage: Float! 521 | voteCount: Int! 522 | width: Int! 523 | } 524 | 525 | type Price { 526 | amount: Float! 527 | currency: String! 528 | } 529 | 530 | type ProductionCompany implements Node { 531 | discover(input: DiscoverInput): Discover! 532 | 533 | """The id of the object""" 534 | id: ID! 535 | logo(size: LogoSize!): URL 536 | name: String! 537 | originCountry: String! 538 | } 539 | 540 | type ProductionCountry { 541 | iso3166_1: String! 542 | name: String! 543 | } 544 | 545 | enum ProfileSize { 546 | W45 547 | Original 548 | W185 549 | H632 550 | } 551 | 552 | type ProfileSizeDetailImage { 553 | aspectRatio: Float! 554 | height: Int! 555 | image(size: ProfileSize!): URL! 556 | iso639_1: String 557 | voteAverage: Float! 558 | voteCount: Int! 559 | width: Int! 560 | } 561 | 562 | type Query { 563 | discover(input: DiscoverInput): Discover! 564 | find(externalId: String!, source: ExternalSource!): FromExternalIds! 565 | genres: Genres! 566 | movies: Movies! 567 | 568 | """Fetches an object given its ID""" 569 | node( 570 | """The ID of an object""" 571 | id: ID! 572 | ): Node 573 | people: People! 574 | search(last: Int, term: String!, first: Int, after: String, before: String): MovieOrTVOrPeopleConnection! 575 | streaming: Streaming! 576 | trending(before: String, after: String, timeWindow: TimeWindow! = Day, first: Int, last: Int): MovieOrTVOrPeopleConnection! 577 | tv: TV! 578 | } 579 | 580 | type Review { 581 | author: String! 582 | content: String! 583 | id: String! 584 | url: String! 585 | } 586 | 587 | type ReviewConnection { 588 | edges: [ReviewEdge] 589 | pageInfo: PageInfo! 590 | totalCount: Int! 591 | } 592 | 593 | type ReviewEdge { 594 | cursor: String! 595 | node: Review 596 | } 597 | 598 | type Season implements IStreamable & Node { 599 | airDate: Date 600 | credits: ICreditsWithPerson! 601 | episode(number: Int!): Episode! 602 | episodeCount: Int! 603 | episodes: [Episode!]! 604 | externalIds: IExternalIDS! 605 | 606 | """The id of the object""" 607 | id: ID! 608 | images: MediaImages! 609 | name: String! 610 | overview: String 611 | poster(size: PosterSize!): URL 612 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 613 | seasonNumber: Int! 614 | show: TVShow! 615 | streamingOptions(country: ID): [StreamingOption!] 616 | videos: [Video!]! 617 | } 618 | 619 | type SpokenLanguage { 620 | iso639_1: String! 621 | name: String! 622 | } 623 | 624 | enum Status { 625 | Cancelled 626 | Released 627 | PostProduction 628 | InProduction 629 | Planned 630 | Rumored 631 | } 632 | 633 | enum StillSize { 634 | W300 635 | Original 636 | W185 637 | W92 638 | } 639 | 640 | type StillSizeDetailImage { 641 | aspectRatio: Float! 642 | height: Int! 643 | image(size: StillSize!): URL! 644 | iso639_1: String 645 | voteAverage: Float! 646 | voteCount: Int! 647 | width: Int! 648 | } 649 | 650 | type Streamable implements IStreamable { 651 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 652 | streamingOptions(country: ID): [StreamingOption!] 653 | } 654 | 655 | type Streaming { 656 | allProviders: [StreamingProvider!]! 657 | countries: [StreamingCountry!]! 658 | myCountry: StreamingCountry 659 | providers(country: ID): [StreamingProvider!]! 660 | } 661 | 662 | type StreamingCountry implements Node { 663 | emoji: String! 664 | 665 | """The id of the object""" 666 | id: ID! 667 | iso3166_2: String! 668 | name: String! 669 | } 670 | 671 | type StreamingCountryOption { 672 | country: StreamingCountry! 673 | option: StreamingOption! 674 | } 675 | 676 | type StreamingLinks { 677 | androidTV: URL 678 | fireTV: URL 679 | tvOS: URL 680 | web: URL 681 | } 682 | 683 | enum StreamingMonetizationType { 684 | Rent 685 | Cinema 686 | Buy 687 | Flatrate 688 | Free 689 | Ads 690 | } 691 | 692 | type StreamingOption { 693 | bestOffering: StreamingOptionOffering! 694 | offerings: [StreamingOptionOffering!]! 695 | provider(country: ID): StreamingProvider 696 | } 697 | 698 | type StreamingOptionOffering { 699 | links: StreamingLinks! 700 | price: Price 701 | resolution: VideoResolution! 702 | type: StreamingMonetizationType! 703 | } 704 | 705 | input StreamingOptions { 706 | country: ID 707 | monetizationTypes: [StreamingMonetizationType!] 708 | streamingProviders: [ID!]! 709 | } 710 | 711 | type StreamingProvider implements Node { 712 | iconURL: URL! 713 | 714 | """The id of the object""" 715 | id: ID! 716 | monetizationTypes: [StreamingMonetizationType!]! 717 | name: String! 718 | slug: String! 719 | } 720 | 721 | type StreamingResultForProvideer { 722 | bestOption: StreamingCountryOption! 723 | options: [StreamingCountryOption!]! 724 | provider(country: ID): StreamingProvider 725 | } 726 | 727 | type TV { 728 | airingToday(after: String, first: Int, last: Int, before: String): TVShowConnection! 729 | episode(id: ID!): Episode! 730 | network(id: ID!): Network! 731 | onTheAir(after: String, first: Int, last: Int, before: String): TVShowConnection! 732 | popular(after: String, first: Int, last: Int, before: String): TVShowConnection! 733 | search(term: String!, after: String, first: Int, last: Int, before: String): TVShowConnection! 734 | season(id: ID!): Season! 735 | show(id: ID!): TVShow! 736 | topRated(after: String, first: Int, last: Int, before: String): TVShowConnection! 737 | trending(timeWindow: TimeWindow! = Day, after: String, first: Int, last: Int, before: String): TVShowConnection! 738 | upcoming(after: String, first: Int, last: Int, before: String): TVShowConnection! 739 | } 740 | 741 | input TVDiscoverInput { 742 | airDate: DiscoverDateFilter 743 | firstAirDate: DiscoverDateFilter 744 | networks: DiscoverIncludeFilter 745 | } 746 | 747 | type TVShow implements IStreamable & Node { 748 | alternativeTitles: [AlternativeTitle!]! 749 | backdrop(size: BackdropSize!): URL 750 | createdBy: [ICreditWithPerson!]! 751 | credits: ICreditsWithPerson! 752 | episodeRunTime: [Int!]! 753 | episodes: [Episode!]! 754 | externalIds: FullExternalIDS! 755 | firstAirDate: Date 756 | genres: [Genre!]! 757 | homepage: URL 758 | 759 | """The id of the object""" 760 | id: ID! 761 | images: MediaImages! 762 | inProduction: Boolean! 763 | keywords: [Keyword!]! 764 | languages: [String!]! 765 | lastAirDate: Date 766 | lastEpisodeToAir: Episode 767 | name: String! 768 | networks: [Network!]! 769 | nextEpisodeToAir: Episode 770 | numberOfEpisodes: Int! 771 | numberOfRatings: Int! 772 | numberOfSeasons: Int! 773 | originCountry: [String!]! 774 | originalLanguage: String! 775 | originalName: String! 776 | overview: String! 777 | popularityIndex: Float 778 | poster(size: PosterSize!): URL 779 | productionCompanies: [Network!]! 780 | rating: Float! 781 | recommendations(first: Int, before: String, after: String, last: Int): TVShowConnection! 782 | reviews(first: Int, before: String, after: String, last: Int): ReviewConnection! 783 | searchStreamingOptions(providers: [ID!]!, countries: [ID!]): [StreamingResultForProvideer!]! 784 | season(number: Int!): Season! 785 | seasons: [Season!]! 786 | similar(first: Int, before: String, after: String, last: Int): TVShowConnection! 787 | status: String! 788 | streamingOptions(country: ID): [StreamingOption!] 789 | topRatedEpisode: Episode 790 | translations: [TranslationWithTranslatedMovieInfo!]! 791 | type: String! 792 | videos: [Video!]! 793 | } 794 | 795 | type TVShowConnection { 796 | edges: [TVShowEdge] 797 | pageInfo: PageInfo! 798 | totalCount: Int! 799 | } 800 | 801 | type TVShowEdge { 802 | cursor: String! 803 | node: TVShow 804 | } 805 | 806 | type TaggedImage { 807 | image: AnyImage! 808 | media: MovieOrTV! 809 | } 810 | 811 | type TaggedImageConnection { 812 | edges: [TaggedImageEdge] 813 | pageInfo: PageInfo! 814 | totalCount: Int! 815 | } 816 | 817 | type TaggedImageEdge { 818 | cursor: String! 819 | node: TaggedImage 820 | } 821 | 822 | enum TimeWindow { 823 | Week 824 | Day 825 | } 826 | 827 | type TranslatedMovieInfo { 828 | overview: String! 829 | title: String! 830 | } 831 | 832 | type TranslatedPersonInfo { 833 | biography: String! 834 | } 835 | 836 | type TranslationWithTranslatedMovieInfo { 837 | info: TranslatedMovieInfo! 838 | iso3166_1: String! 839 | iso639_1: String! 840 | language: String 841 | localizedLanguage: String 842 | } 843 | 844 | type TranslationWithTranslatedPersonInfo { 845 | info: TranslatedPersonInfo! 846 | iso3166_1: String! 847 | iso639_1: String! 848 | language: String 849 | localizedLanguage: String 850 | } 851 | 852 | scalar URL 853 | 854 | type Video { 855 | id: String! 856 | iso3166_1: String! 857 | iso639_1: String! 858 | key: String! 859 | links: StreamingLinks 860 | name: String! 861 | site: String! 862 | size: Int! 863 | thumbnail: URL 864 | type: String! 865 | } 866 | 867 | enum VideoResolution { 868 | Theatre 869 | Sd 870 | Bluray 871 | UltraHd 872 | Dvd 873 | Hd 874 | } 875 | -------------------------------------------------------------------------------- /schemas/yelp.schema: -------------------------------------------------------------------------------- 1 | type Query { 2 | """Load information about a specific business.""" 3 | business( 4 | """The Yelp ID for the business you want to load.""" 5 | id: String 6 | ): Business 7 | 8 | """Match detailed business location data to businesses on Yelp.""" 9 | business_match( 10 | """ 11 | Required. The name of the business. Maximum length is 64; only digits, letters, spaces, and !#$%&+,­./:?@'are allowed. 12 | """ 13 | name: String! 14 | 15 | """ 16 | Required. The first line of the business’s address. Maximum length is 64; only digits, letters, spaces, and ­’/#&,.: are allowed. Note that the empty string is allowed; this will specifically match certain service businesses that have no street address. 17 | """ 18 | address1: String! 19 | 20 | """ 21 | Optional. The second line of the business’s address. Maximum length is 64; only digits, letters, spaces, and ­’/#&,.: are allowed. 22 | """ 23 | address2: String 24 | 25 | """ 26 | Optional. The third line of the business’s address. Maximum length is 64; only digits, letters, spaces, and ­’/#&,.: are allowed. 27 | """ 28 | address3: String 29 | 30 | """ 31 | Required. The city of the business. Maximum length is 64; only digits, letters, spaces, and ­’.() are allowed. 32 | """ 33 | city: String! 34 | 35 | """ 36 | Required. The ISO 3166­-2 code for the region/province of the business. Maximum length is 3. 37 | """ 38 | state: String! 39 | 40 | """ 41 | Required. The ISO 3166­-1 alpha­2 country code of the business. Maximum length is 2. 42 | """ 43 | country: String! 44 | 45 | """ 46 | Optional. The WGS84 latitude of the business in decimal degrees. Must be between ­-90 and +90. 47 | """ 48 | latitude: Float 49 | 50 | """ 51 | Optional. The WGS84 longitude of the business in decimal degrees. Must be between ­-180 and +180. 52 | """ 53 | longitude: Float 54 | 55 | """ 56 | Optional. The phone number of the business which can be submitted as (a) locally ­formatted with digits only (e.g., 016703080) or (b) internationally­ formatted with a leading + sign and digits only after (+35316703080). Maximum length is 32. 57 | """ 58 | phone: String 59 | 60 | """Optional. The postal code of the business. Maximum length is 12.""" 61 | postal_code: String 62 | 63 | """Optional. The maximum number of businesses to return.""" 64 | limit: Int = 3 65 | 66 | """ 67 | Optional. A match quality threshold that will determine how closely businesses must match the input to be returned. Defaults to DEFAULT. 68 | """ 69 | match_threshold: MatchThreshold 70 | ): Businesses 71 | 72 | """Load reviews for a specific business.""" 73 | reviews( 74 | """The Yelp ID for the business you want to load.""" 75 | business: String 76 | 77 | """ 78 | Output locale. Show reviews in the same language. See the list of supported locales. 79 | """ 80 | locale: String 81 | limit: Int 82 | offset: Int 83 | ): Reviews 84 | 85 | """Search for businesses on Yelp by their phone number.""" 86 | phone_search( 87 | """ 88 | Required. Phone number of the business you want to search for. It must start with + and include the country code, like +14159083801. 89 | """ 90 | phone: String 91 | ): Businesses 92 | 93 | """Search for businesses on Yelp.""" 94 | search( 95 | """ 96 | Optional. Search term (e.g. "food", "restaurants"). If term isn't included we search everything. The term keyword also accepts business names such as "Starbucks". 97 | """ 98 | term: String 99 | 100 | """ 101 | Required. Specifies the combination of "address, neighborhood, city, state or zip, optional country" to be used when searching for businesses. 102 | """ 103 | location: String 104 | country: String 105 | 106 | """Optional. Offset the list of returned business results by this amount.""" 107 | offset: Int 108 | 109 | """ 110 | Optional. Number of business results to return. By default, it will return 20. Maximum is 50. 111 | """ 112 | limit: Int 113 | 114 | """ 115 | Sort the results by one of the these modes: best_match, rating, review_count or distance. By default it's best_match. The rating sort is not strictly sorted by the rating value, but by an adjusted rating value that takes into account the number of ratings, similar to a Bayesian average. This is so a business with 1 rating of 5 stars doesn't immediately jump to the top. 116 | """ 117 | sort_by: String 118 | 119 | """ 120 | Optional. Specify the locale to return the event information in. See the list of supported locales. 121 | """ 122 | locale: String 123 | 124 | """ 125 | Required if location is not provided. Longitude of the location you want to search nearby. 126 | """ 127 | longitude: Float 128 | 129 | """ 130 | Required if location is not provided. Latitude of the location you want to search nearby. 131 | """ 132 | latitude: Float 133 | 134 | """ 135 | Optional. Categories to filter the search results with. See the list of supported categories. The category filter can be a list of comma delimited categories. For example, "bars,french" will filter by Bars OR French. The category identifier should be used (for example "discgolf", not "Disc Golf"). 136 | """ 137 | categories: String 138 | 139 | """ 140 | Optional. Default to false. When set to true, only return the businesses open now. Notice that open_at and open_now cannot be used together. 141 | """ 142 | open_now: Boolean 143 | 144 | """ 145 | Optional. An integer representing the Unix time in the same timezone of the search location. If specified, it will return business open at the given time. Notice that open_at and open_now cannot be used together. 146 | """ 147 | open_at: Int 148 | 149 | """ 150 | Optional. Pricing levels to filter the search result with: 1 = $, 2 = $$, 3 = $$$, 4 = $$$$. The price filter can be a list of comma delimited pricing levels. For example, "1, 2, 3" will filter the results to show the ones that are $, $$, or $$$. 151 | """ 152 | price: String 153 | 154 | """Additional filters to restrict search results.""" 155 | attributes: [String] 156 | 157 | """ 158 | Optional. Search radius in meters. If the value is too large, a AREA_TOO_LARGE error may be returned. The max value is 40000 meters (25 miles). 159 | """ 160 | radius: Float 161 | ): Businesses 162 | 163 | """Load information about a specific event.""" 164 | event( 165 | """The Yelp ID for the event you want to load.""" 166 | id: String 167 | ): Event 168 | 169 | """Search for events based on search parameters.""" 170 | event_search( 171 | """ 172 | Optional. Specify the locale to return the event information in. See the list of supported locales. 173 | """ 174 | locale: String 175 | 176 | """Optional. Offset the list of returned events results by this amount.""" 177 | offset: Int 178 | 179 | """ 180 | Optional. Number of events results to return. By default, it will return 3. Maximum is 50. 181 | """ 182 | limit: Int 183 | 184 | """ 185 | Optional. Sort by either descending or ascending order. By default, it returns results in descending order. 186 | """ 187 | sort_by: String 188 | 189 | """ 190 | Optional. Sort on popularity or time start. By default, sorts on popularity. 191 | """ 192 | sort_on: String 193 | 194 | """ 195 | Optional. Unix timestamp of the event start time. Will return events that only begin at or after the specified time. 196 | """ 197 | start_date: Int 198 | 199 | """ 200 | Optional. Unix timestamp of the event end time. Will return events that only end at or before the specified time. 201 | """ 202 | end_date: Int 203 | 204 | """ 205 | Optional. The category filter can be a list of comma delimited categories to get OR'd results that include the categories provided. See the list of categories. 206 | """ 207 | categories: [String] 208 | 209 | """ 210 | Optional. Filter whether the events are free to attend. By default no filter is applied so both free and paid events will be returned. 211 | """ 212 | is_free: Boolean 213 | 214 | """ 215 | Optional. Specifies the combination of "address, neighborhood, city, state or zip, optional country" to be used when searching for events. 216 | """ 217 | location: String 218 | 219 | """ 220 | Optional. Latitude of the location you want to search nearby. If latitude is provided, longitude is required too. 221 | """ 222 | latitude: Float 223 | 224 | """ 225 | Optional. Longitude of the location you want to search nearby. If longitude is provided, latitude is required too. 226 | """ 227 | longitude: Float 228 | 229 | """ 230 | Optional. Search radius in meters. If the value is too large, a AREA_TOO_LARGE error may be returned. The max value is 40000 meters (25 miles). 231 | """ 232 | radius: Float 233 | ): Events 234 | categories( 235 | """ 236 | Optional. Alias of the category to search for. If alias is provided, up to one result will be returned. 237 | """ 238 | alias: String 239 | 240 | """ 241 | Optional. Country code used to filter categories available in a given country. 242 | """ 243 | country: String 244 | 245 | """ 246 | Optional. Locale used to localize the title of the category. By default, this is set to en_US. 247 | """ 248 | locale: String = "en_US" 249 | ): Categories 250 | } 251 | 252 | type Business { 253 | """Name of this business.""" 254 | name: String 255 | 256 | """Yelp ID of this business.""" 257 | id: String 258 | 259 | """Yelp alias of this business.""" 260 | alias: String 261 | 262 | """Whether business has been claimed by a business owner.""" 263 | is_claimed: Boolean 264 | 265 | """Whether business has been (permanently) closed.""" 266 | is_closed: Boolean 267 | 268 | """URL for business page on Yelp.""" 269 | url: String 270 | 271 | """Phone number of the business.""" 272 | phone: String 273 | 274 | """ 275 | Phone number of the business formatted nicely to be displayed to users. The format is the standard phone number format for the business's country. 276 | """ 277 | display_phone: String 278 | 279 | """Number of reviews for this business.""" 280 | review_count: Int 281 | 282 | """ 283 | A list of category title and alias pairs associated with this business. 284 | """ 285 | categories: [Category] 286 | 287 | """Rating for this business (value ranges from 1, 1.5, ... 4.5, 5).""" 288 | rating: Float 289 | 290 | """ 291 | Price level of the business. Value is one of $, $$, $$$ and $$$$ or null if we don't have price available for the business. 292 | """ 293 | price: String 294 | 295 | """ 296 | The location of this business, including address, city, state, postal code and country. 297 | """ 298 | location: Location 299 | 300 | """The coordinates of this business.""" 301 | coordinates: Coordinates 302 | 303 | """URLs of up to three photos of the business.""" 304 | photos: [String] 305 | 306 | """Opening hours of the business.""" 307 | hours: [Hours] 308 | 309 | """ 310 | Special hours of the business, these override regular opening hours of the business. 311 | """ 312 | special_hours: [SpecialHours] 313 | 314 | """Review snippets from the business.""" 315 | reviews(limit: Int, offset: Int): [Review] 316 | 317 | """ 318 | When searching, this provides the distance of the business from the search location in meters 319 | """ 320 | distance: Float 321 | 322 | """Business attributes.""" 323 | attributes: BusinessAttributes 324 | 325 | """ 326 | Information and action links for transacting with this business online. 327 | """ 328 | transactions: Transactions 329 | 330 | """ 331 | Information and action links for messaging with this business via Yelp, including requesting quotes. 332 | """ 333 | messaging: BusinessMessaging 334 | } 335 | 336 | type Category { 337 | """Title of a category for display purposes.""" 338 | title: String 339 | 340 | """ 341 | Alias of a category, when searching for business in certain categories, use alias rather than the title. 342 | """ 343 | alias: String 344 | 345 | """List of parent categories.""" 346 | parent_categories: [Category] 347 | 348 | """Countries for which this category is whitelisted.""" 349 | country_whitelist: [Country] 350 | 351 | """Countries for which this category is blacklisted.""" 352 | country_blacklist: [Country] 353 | } 354 | 355 | type Country { 356 | """The ISO 3166-1 alpha-2 code for this country.""" 357 | code: String 358 | 359 | """Supported locales with this country.""" 360 | locales: [Locale] 361 | } 362 | 363 | type Locale { 364 | """ 365 | The code for this locale, in the format of {language_code}_{country_code}. 366 | """ 367 | code: String 368 | 369 | """The language component of this locale.""" 370 | language: Language 371 | 372 | """The country component of this locale.""" 373 | country: Country 374 | } 375 | 376 | type Language { 377 | """ 378 | The ISO 639-1 alpha-2 code for this language. When such a code is unavailable for a language, it will be a ISO 639-2 alpha-3 code instead. 379 | """ 380 | code: String 381 | 382 | """Supported locales with this language.""" 383 | locales: [Locale] 384 | } 385 | 386 | type Location { 387 | """Street address of this business.""" 388 | address1: String 389 | 390 | """Street address of this business, continued.""" 391 | address2: String 392 | 393 | """Street address of this business, continued.""" 394 | address3: String 395 | 396 | """City of this business.""" 397 | city: String 398 | 399 | """ISO 3166-2 (with a few exceptions) state code of this business.""" 400 | state: String 401 | 402 | """Postal code of this business.""" 403 | postal_code: String 404 | 405 | """ISO 3166-1 alpha-2 country code of this business.""" 406 | country: String 407 | 408 | """ 409 | Array of strings that if organized vertically give an address that is in the standard address format for the business's country. 410 | """ 411 | formatted_address: String 412 | } 413 | 414 | type Coordinates { 415 | """The latitude of this business.""" 416 | latitude: Float 417 | 418 | """The longitude of this business.""" 419 | longitude: Float 420 | } 421 | 422 | type Hours { 423 | """ 424 | The type of the opening hours information. Right now, this is always REGULAR. 425 | """ 426 | hours_type: String 427 | 428 | """The specific open hours and days for a business.""" 429 | open: [OpenHours] 430 | 431 | """Describes if the business is open now.""" 432 | is_open_now: Boolean 433 | } 434 | 435 | type OpenHours { 436 | """ 437 | Whether the business opens overnight or not. When this is true, the end time will be lower than the start time. 438 | """ 439 | is_overnight: Boolean 440 | 441 | """ 442 | End of the opening hours in a day, in 24-hour clock notation, like 2130 means 9:30 PM. 443 | """ 444 | end: String 445 | 446 | """ 447 | Start of the opening hours in a day, in 24-hour clock notation, like 1000 means 10 AM. 448 | """ 449 | start: String 450 | 451 | """ 452 | From 0 to 6, representing day of the week from Monday to Sunday. Notice that you may get the same day of the week more than once if the business has more than one opening time slots. 453 | """ 454 | day: Int 455 | } 456 | 457 | type SpecialHours { 458 | """ 459 | Whether the business opens overnight or not. When this is true, the end time will be lower than the start time. 460 | """ 461 | is_overnight: Boolean 462 | 463 | """Whether the business is closed on the indicated date.""" 464 | is_closed: Boolean 465 | 466 | """ 467 | End of the opening hours in a day, in 24-hour clock notation, like 2130 means 9:30 PM. 468 | """ 469 | end: String 470 | 471 | """ 472 | Start of the opening hours in a day, in 24-hour clock notation, like 1000 means 10 AM. 473 | """ 474 | start: String 475 | 476 | """ 477 | The date for which the special hours apply inISO8601 format, AKA YYYY-MM-DD 478 | """ 479 | date: Date 480 | } 481 | 482 | """ 483 | The `Date` scalar type represents a Date 484 | value as specified by 485 | [iso8601](https://en.wikipedia.org/wiki/ISO_8601). 486 | """ 487 | scalar Date 488 | 489 | type Review { 490 | """Yelp ID of this review.""" 491 | id: String 492 | 493 | """Rating of this review.""" 494 | rating: Int 495 | 496 | """The user who wrote the review.""" 497 | user: User 498 | 499 | """Text excerpt of this review.""" 500 | text: String 501 | 502 | """The time that the review was created in PST.""" 503 | time_created: String 504 | 505 | """URL of this review.""" 506 | url: String 507 | 508 | """ 509 | Details about the publicly visible response to this review posted by the business owner. 510 | """ 511 | public_response: PublicReviewResponse 512 | } 513 | 514 | type User { 515 | """The User's ID, a 22 character string""" 516 | id: String 517 | 518 | """User's profile url""" 519 | profile_url: String 520 | 521 | """URL of the user's profile photo.""" 522 | image_url: String 523 | 524 | """Name of the user.""" 525 | name: String 526 | } 527 | 528 | type PublicReviewResponse { 529 | """Text of this public review response.""" 530 | text: String 531 | 532 | """ 533 | The time that this public review response was created in ISO8601 format. 534 | """ 535 | time_created: DateTime 536 | 537 | """ 538 | Details about business user associated with the business who posted this public review response comment. 539 | """ 540 | business_user: BusinessUser 541 | } 542 | 543 | """ 544 | The `DateTime` scalar type represents a DateTime 545 | value as specified by 546 | [iso8601](https://en.wikipedia.org/wiki/ISO_8601). 547 | """ 548 | scalar DateTime 549 | 550 | type BusinessUser { 551 | """Name of the business user.""" 552 | name: String 553 | 554 | """Business role for the business user.""" 555 | role: String 556 | 557 | """URL of the business user's profile photo.""" 558 | photo_url: String 559 | } 560 | 561 | type BusinessAttributes { 562 | """ 563 | Whether business has gender neutral restrooms. See https://www.yelpblog.com/2017/06/find-gender-neutral-restrooms-160000-businesses-yelp for more details. 564 | """ 565 | gender_neutral_restrooms: BusinessAttribute 566 | 567 | """ 568 | Whether business has opted in to the "Open to All" pledge. See https://www.yelpblog.com/2018/07/opentoall for more details. 569 | """ 570 | open_to_all: BusinessAttribute 571 | 572 | """Whether business is wheelchair accessible.""" 573 | wheelchair_accessible: BusinessAttribute 574 | } 575 | 576 | type BusinessAttribute { 577 | """The machine-friendly name of this business attribute.""" 578 | name_code: String 579 | 580 | """The machine-friendly value of this business attribute.""" 581 | value_code: String 582 | } 583 | 584 | type Transactions { 585 | """Online reservations via Yelp Reservations.""" 586 | restaurant_reservations: RestaurantReservations 587 | } 588 | 589 | type RestaurantReservations { 590 | """ 591 | Visit this action link URL to go directly into the Yelp Reservations flow for this business. 592 | """ 593 | url: String 594 | } 595 | 596 | type BusinessMessaging { 597 | """ 598 | Visit this action link URL to go directly into the business messaging flow for this business. 599 | """ 600 | url: String 601 | 602 | """ 603 | The localized text description of the type of messaging this business is enabled for. Example: "Request a Quote" 604 | """ 605 | use_case_text: String 606 | } 607 | 608 | type Businesses { 609 | """A list of business Yelp finds based on the search criteria.""" 610 | business: [Business] 611 | 612 | """Total number of businesses found.""" 613 | total: Int 614 | } 615 | 616 | """An enumeration.""" 617 | enum MatchThreshold { 618 | NONE 619 | DEFAULT 620 | STRICT 621 | } 622 | 623 | type Reviews { 624 | """The reviews objects.""" 625 | review: [Review] 626 | 627 | """Total number of reviews.""" 628 | total: Int 629 | 630 | """A list of languages for which the business has at least one review.""" 631 | possible_languages: [Language] 632 | 633 | """The business associated with the reviews""" 634 | business: Business 635 | } 636 | 637 | type Event { 638 | """Name of this event.""" 639 | name: String 640 | 641 | """Event id.""" 642 | id: String 643 | 644 | """The business tied to this event.""" 645 | business: Business 646 | 647 | """The ID of the related business.""" 648 | business_id: String 649 | 650 | """Number of Yelp users attending this event.""" 651 | attending_count: String 652 | 653 | """The category of this event.""" 654 | category: String 655 | 656 | """Cost of attending this event.""" 657 | cost: Int 658 | 659 | """Maximum cost of this event.""" 660 | cost_max: Int 661 | 662 | """Description excerpt of this event.""" 663 | description: String 664 | 665 | """Yelp page of this event.""" 666 | event_site_url: String 667 | 668 | """Yelp image url of this event.""" 669 | image_url: String 670 | 671 | """Number of Yelp users interested in attending this event.""" 672 | interested_count: String 673 | 674 | """Whether this event is canceled.""" 675 | is_canceled: Boolean 676 | 677 | """Whether this event is free.""" 678 | is_free: Boolean 679 | 680 | """Whether this event is created by a Yelp community manager.""" 681 | is_official: Boolean 682 | 683 | """Latitude of this event.""" 684 | latitude: Float 685 | 686 | """Longitude of this event.""" 687 | longitude: Float 688 | 689 | """ 690 | The location of this business, including address, city, state, postal code and country. 691 | """ 692 | location: Location 693 | 694 | """URL to buy tickets for this event.""" 695 | tickets_url: String 696 | 697 | """ 698 | Time this event ends. Returns time and date in the following format - "YYYY-MM-DD HH-mm". 699 | """ 700 | time_end: String 701 | 702 | """ 703 | Time the event starts. Returns time and date in the following format - "YYYY-MM-DD HH-mm". 704 | """ 705 | time_start: String 706 | } 707 | 708 | type Events { 709 | """List of events found matching search criteria.""" 710 | events: [Event] 711 | 712 | """Total number of events found.""" 713 | total: Int 714 | } 715 | 716 | type Categories { 717 | """The category objects.""" 718 | category: [Category] 719 | 720 | """Total number of categories.""" 721 | total: Int 722 | } 723 | --------------------------------------------------------------------------------