mirror of
https://github.com/StanGirard/quivr.git
synced 2024-12-24 03:41:56 +03:00
feat: allow users to chat with apis (#1612)
You can now create a brain which can fetch data from external APIs with or without authentification - POST query example with authentification https://github.com/StanGirard/quivr/assets/63923024/15013ba9-dedb-4f24-9e06-49daad9de7f3 - Get query example with authentification and search params https://github.com/StanGirard/quivr/assets/63923024/1763875d-a8e9-4478-b07c-e99ca7337942 - Get query without authentification and search params https://github.com/StanGirard/quivr/assets/63923024/f2742963-790d-4cb2-864a-8173979b650a
This commit is contained in:
parent
addcd27fce
commit
db5a6e4b9b
@ -2,16 +2,12 @@ import json
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from langchain.schema import FunctionMessage
|
||||
from fastapi import HTTPException
|
||||
from litellm import completion
|
||||
from models.chats import ChatQuestion
|
||||
from models.databases.supabase.chats import CreateChatHistory
|
||||
from repository.brain.get_brain_by_id import get_brain_by_id
|
||||
from repository.chat.format_chat_history import (
|
||||
format_chat_history,
|
||||
format_history_to_openai_mesages,
|
||||
)
|
||||
from repository.chat.get_chat_history import get_chat_history
|
||||
from repository.chat.get_chat_history import GetChatHistoryOutput, get_chat_history
|
||||
from repository.chat.update_chat_history import update_chat_history
|
||||
from repository.chat.update_message_by_id import update_message_by_id
|
||||
|
||||
@ -22,7 +18,9 @@ from llm.utils.get_api_brain_definition_as_json_schema import (
|
||||
)
|
||||
|
||||
|
||||
class APIBrainQA(QABaseBrainPicking):
|
||||
class APIBrainQA(
|
||||
QABaseBrainPicking,
|
||||
):
|
||||
user_id: UUID
|
||||
|
||||
def __init__(
|
||||
@ -30,11 +28,14 @@ class APIBrainQA(QABaseBrainPicking):
|
||||
model: str,
|
||||
brain_id: str,
|
||||
chat_id: str,
|
||||
user_id: UUID,
|
||||
streaming: bool = False,
|
||||
prompt_id: Optional[UUID] = None,
|
||||
**kwargs,
|
||||
):
|
||||
user_id = kwargs.get("user_id")
|
||||
if not user_id:
|
||||
raise HTTPException(status_code=400, detail="Cannot find user id")
|
||||
|
||||
super().__init__(
|
||||
model=model,
|
||||
brain_id=brain_id,
|
||||
@ -45,48 +46,100 @@ class APIBrainQA(QABaseBrainPicking):
|
||||
)
|
||||
self.user_id = user_id
|
||||
|
||||
async def generate_stream(self, chat_id: UUID, question: ChatQuestion):
|
||||
if not question.brain_id:
|
||||
raise Exception("No brain id provided")
|
||||
|
||||
history = get_chat_history(self.chat_id)
|
||||
prompt_content = self.prompt_to_use.content if self.prompt_to_use else ""
|
||||
brain = get_brain_by_id(question.brain_id)
|
||||
if not brain:
|
||||
raise Exception("No brain found")
|
||||
|
||||
messages = format_history_to_openai_mesages(
|
||||
format_chat_history(history),
|
||||
prompt_content,
|
||||
question.question,
|
||||
)
|
||||
|
||||
async def make_completion(
|
||||
self,
|
||||
messages,
|
||||
functions,
|
||||
brain_id: UUID,
|
||||
):
|
||||
response = completion(
|
||||
model=self.model,
|
||||
temperature=self.temperature,
|
||||
max_tokens=self.max_tokens,
|
||||
messages=messages,
|
||||
functions=[get_api_brain_definition_as_json_schema(brain)],
|
||||
functions=functions,
|
||||
stream=True,
|
||||
function_call="auto",
|
||||
)
|
||||
|
||||
if response.choices[0].finish_reason == "function_call":
|
||||
arguments = json.load(
|
||||
response.choices[0].message["function_call"]["arguments"]
|
||||
function_call = {
|
||||
"name": None,
|
||||
"arguments": "",
|
||||
}
|
||||
for chunk in response:
|
||||
finish_reason = chunk.choices[0].finish_reason
|
||||
|
||||
if finish_reason == "stop":
|
||||
break
|
||||
|
||||
if "function_call" in chunk.choices[0].delta:
|
||||
if "name" in chunk.choices[0].delta["function_call"]:
|
||||
function_call["name"] = chunk.choices[0].delta["function_call"][
|
||||
"name"
|
||||
]
|
||||
if "arguments" in chunk.choices[0].delta["function_call"]:
|
||||
function_call["arguments"] += chunk.choices[0].delta[
|
||||
"function_call"
|
||||
]["arguments"]
|
||||
|
||||
elif finish_reason == "function_call":
|
||||
try:
|
||||
arguments = json.loads(function_call["arguments"])
|
||||
except Exception:
|
||||
arguments = {}
|
||||
|
||||
api_call_response = call_brain_api(
|
||||
brain_id=brain_id,
|
||||
user_id=self.user_id,
|
||||
arguments=arguments,
|
||||
)
|
||||
|
||||
messages.append(
|
||||
{
|
||||
"role": "function",
|
||||
"name": function_call["name"],
|
||||
"content": api_call_response,
|
||||
}
|
||||
)
|
||||
async for value in self.make_completion(
|
||||
messages=messages,
|
||||
functions=functions,
|
||||
brain_id=brain_id,
|
||||
):
|
||||
yield value
|
||||
|
||||
else:
|
||||
content = chunk.choices[0].delta.content
|
||||
yield content
|
||||
|
||||
async def generate_stream(self, chat_id: UUID, question: ChatQuestion):
|
||||
if not question.brain_id:
|
||||
raise HTTPException(
|
||||
status_code=400, detail="No brain id provided in the question"
|
||||
)
|
||||
|
||||
content = call_brain_api(
|
||||
brain_id=question.brain_id, user_id=self.user_id, arguments=arguments
|
||||
)
|
||||
messages.append(FunctionMessage(name=brain.name, content=content))
|
||||
brain = get_brain_by_id(question.brain_id)
|
||||
|
||||
response = completion(
|
||||
model=self.model,
|
||||
temperature=self.temperature,
|
||||
max_tokens=self.max_tokens,
|
||||
messages=messages,
|
||||
stream=True,
|
||||
)
|
||||
if not brain:
|
||||
raise HTTPException(status_code=404, detail="Brain not found")
|
||||
|
||||
prompt_content = "You'are a helpful assistant which can call APIs. Feel free to call the API when you need to. Don't force APIs call, do it when necessary. If it seems like you should call the API and there are missing parameters, ask user for them."
|
||||
|
||||
if self.prompt_to_use:
|
||||
prompt_content += self.prompt_to_use.content
|
||||
|
||||
messages = [{"role": "system", "content": prompt_content}]
|
||||
|
||||
history = get_chat_history(self.chat_id)
|
||||
|
||||
for message in history:
|
||||
formatted_message = [
|
||||
{"role": "user", "content": message.user_message},
|
||||
{"role": "assistant", "content": message.assistant},
|
||||
]
|
||||
messages.extend(formatted_message)
|
||||
|
||||
messages.append({"role": "user", "content": question.question})
|
||||
|
||||
streamed_chat_history = update_chat_history(
|
||||
CreateChatHistory(
|
||||
@ -99,7 +152,7 @@ class APIBrainQA(QABaseBrainPicking):
|
||||
}
|
||||
)
|
||||
)
|
||||
streamed_chat_history = get_chat_history.GetChatHistoryOutput(
|
||||
streamed_chat_history = GetChatHistoryOutput(
|
||||
**{
|
||||
"chat_id": str(chat_id),
|
||||
"message_id": streamed_chat_history.message_id,
|
||||
@ -112,13 +165,14 @@ class APIBrainQA(QABaseBrainPicking):
|
||||
"brain_name": brain.name if brain else None,
|
||||
}
|
||||
)
|
||||
|
||||
response_tokens = []
|
||||
|
||||
for chunk in response:
|
||||
new_token = chunk["choices"][0]["delta"]
|
||||
streamed_chat_history.assistant = new_token
|
||||
response_tokens.append(new_token)
|
||||
async for value in self.make_completion(
|
||||
messages=messages,
|
||||
functions=[get_api_brain_definition_as_json_schema(brain)],
|
||||
brain_id=question.brain_id,
|
||||
):
|
||||
streamed_chat_history.assistant = value
|
||||
response_tokens.append(value)
|
||||
yield f"data: {json.dumps(streamed_chat_history.dict())}"
|
||||
|
||||
update_message_by_id(
|
||||
|
@ -1,28 +1,30 @@
|
||||
from uuid import UUID
|
||||
|
||||
from llm.utils.extract_brain_api_params_values_from_llm_output import (
|
||||
extract_brain_api_params_values_from_llm_output,
|
||||
from fastapi import HTTPException
|
||||
from llm.utils.extract_api_brain_definition_values_from_llm_output import (
|
||||
extract_api_brain_definition_values_from_llm_output,
|
||||
)
|
||||
from llm.utils.make_api_request import make_api_request
|
||||
from llm.utils.make_api_request import get_api_call_response_as_text
|
||||
from repository.api_brain_definition.get_api_brain_definition import (
|
||||
get_api_brain_definition,
|
||||
)
|
||||
from repository.external_api_secret.read_secret import read_secret
|
||||
|
||||
|
||||
def call_brain_api(brain_id: UUID, user_id: UUID, arguments: dict):
|
||||
def call_brain_api(brain_id: UUID, user_id: UUID, arguments: dict) -> str:
|
||||
brain_definition = get_api_brain_definition(brain_id)
|
||||
if brain_definition is None:
|
||||
raise Exception("Brain definition not found")
|
||||
|
||||
brain_params = brain_definition.params.properties
|
||||
brain_params_values = extract_brain_api_params_values_from_llm_output(
|
||||
brain_params, arguments
|
||||
if brain_definition is None:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Brain definition {brain_id} not found"
|
||||
)
|
||||
|
||||
brain_params_values = extract_api_brain_definition_values_from_llm_output(
|
||||
brain_definition.params, arguments
|
||||
)
|
||||
|
||||
brain_search_params = brain_definition.search_params.properties
|
||||
brain_search_params_values = extract_brain_api_params_values_from_llm_output(
|
||||
brain_search_params, arguments
|
||||
brain_search_params_values = extract_api_brain_definition_values_from_llm_output(
|
||||
brain_definition.search_params, arguments
|
||||
)
|
||||
|
||||
secrets = brain_definition.secrets
|
||||
@ -34,9 +36,10 @@ def call_brain_api(brain_id: UUID, user_id: UUID, arguments: dict):
|
||||
)
|
||||
secrets_values[secret.name] = secret_value
|
||||
|
||||
return make_api_request(
|
||||
return get_api_call_response_as_text(
|
||||
api_url=brain_definition.url,
|
||||
params=brain_params_values,
|
||||
search_params=brain_search_params_values,
|
||||
secrets=secrets_values,
|
||||
method=brain_definition.method,
|
||||
)
|
||||
|
@ -0,0 +1,25 @@
|
||||
from fastapi import HTTPException
|
||||
from models.ApiBrainDefinition import ApiBrainDefinitionSchema
|
||||
|
||||
|
||||
def extract_api_brain_definition_values_from_llm_output(
|
||||
brain_schema: ApiBrainDefinitionSchema, arguments: dict
|
||||
) -> dict:
|
||||
params_values = {}
|
||||
properties = brain_schema.properties
|
||||
required_values = brain_schema.required
|
||||
for property in properties:
|
||||
if property.name in arguments:
|
||||
if property.type == "number":
|
||||
params_values[property.name] = float(arguments[property.name])
|
||||
else:
|
||||
params_values[property.name] = arguments[property.name]
|
||||
continue
|
||||
|
||||
if property.name in required_values:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Required parameter {property.name} not found in arguments",
|
||||
)
|
||||
|
||||
return params_values
|
11
backend/llm/utils/extract_api_definition.py
Normal file
11
backend/llm/utils/extract_api_definition.py
Normal file
@ -0,0 +1,11 @@
|
||||
from models.ApiBrainDefinition import ApiBrainDefinitionSchemaProperty
|
||||
|
||||
|
||||
def format_api_brain_property(property: ApiBrainDefinitionSchemaProperty):
|
||||
property_data: dict = {
|
||||
"type": property.type,
|
||||
"description": property.description,
|
||||
}
|
||||
if property.enum:
|
||||
property_data["enum"] = property.enum
|
||||
return property_data
|
@ -1,17 +0,0 @@
|
||||
from models.ApiBrainDefinition import ApiBrainDefinitionSchemaProperty
|
||||
|
||||
|
||||
def extract_brain_api_params_values_from_llm_output(
|
||||
params: list[ApiBrainDefinitionSchemaProperty], arguments: dict
|
||||
):
|
||||
params_values = {}
|
||||
|
||||
for param in params:
|
||||
if param.name in arguments:
|
||||
params_values[param.name] = arguments[param.name]
|
||||
continue
|
||||
|
||||
if param.required:
|
||||
raise Exception(f"Missing param {param.name}")
|
||||
|
||||
return params_values
|
@ -1,3 +1,8 @@
|
||||
from fastapi import HTTPException
|
||||
from llm.utils.extract_api_definition import (
|
||||
format_api_brain_property,
|
||||
)
|
||||
from llm.utils.sanitize_function_name import sanitize_function_name
|
||||
from models.brain_entity import BrainEntity
|
||||
from repository.api_brain_definition.get_api_brain_definition import (
|
||||
get_api_brain_definition,
|
||||
@ -5,22 +10,24 @@ from repository.api_brain_definition.get_api_brain_definition import (
|
||||
|
||||
|
||||
def get_api_brain_definition_as_json_schema(brain: BrainEntity):
|
||||
if not brain:
|
||||
raise Exception("No brain found")
|
||||
|
||||
api_brain_definition = get_api_brain_definition(brain.id)
|
||||
if not api_brain_definition:
|
||||
raise Exception("No api brain definition found")
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"Brain definition {brain.id} not found"
|
||||
)
|
||||
|
||||
required = []
|
||||
required.extend(api_brain_definition.params.required)
|
||||
required.extend(api_brain_definition.search_params.required)
|
||||
|
||||
properties = {}
|
||||
for property in api_brain_definition.params.properties:
|
||||
properties[property.name] = property
|
||||
for property in api_brain_definition.search_params.properties:
|
||||
properties[property.name] = property
|
||||
|
||||
api_properties = (
|
||||
api_brain_definition.params.properties
|
||||
+ api_brain_definition.search_params.properties
|
||||
)
|
||||
|
||||
for property in api_properties:
|
||||
properties[property.name] = format_api_brain_property(property)
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
@ -28,7 +35,7 @@ def get_api_brain_definition_as_json_schema(brain: BrainEntity):
|
||||
"required": required,
|
||||
}
|
||||
schema = {
|
||||
"name": brain.name,
|
||||
"name": sanitize_function_name(brain.name),
|
||||
"description": brain.description,
|
||||
"parameters": parameters,
|
||||
}
|
||||
|
@ -1,18 +1,36 @@
|
||||
import json
|
||||
|
||||
import requests
|
||||
from logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
def make_api_request(api_url, params, search_params, secrets) -> str:
|
||||
def get_api_call_response_as_text(
|
||||
method, api_url, params, search_params, secrets
|
||||
) -> str:
|
||||
headers = {}
|
||||
|
||||
api_url_with_search_params = api_url + "?"
|
||||
for search_param in search_params:
|
||||
api_url_with_search_params += f"{search_param}={search_params[search_param]}&"
|
||||
api_url_with_search_params = api_url
|
||||
if search_params:
|
||||
api_url_with_search_params += "?"
|
||||
for search_param in search_params:
|
||||
api_url_with_search_params += (
|
||||
f"{search_param}={search_params[search_param]}&"
|
||||
)
|
||||
|
||||
for secret in secrets:
|
||||
headers[secret] = secrets[secret]
|
||||
|
||||
response = requests.get(
|
||||
url=api_url_with_search_params, params=params, headers=headers
|
||||
)
|
||||
|
||||
return str(response.json())
|
||||
try:
|
||||
response = requests.request(
|
||||
method,
|
||||
url=api_url_with_search_params,
|
||||
params=search_params or None,
|
||||
headers=headers or None,
|
||||
data=json.dumps(params) or None,
|
||||
)
|
||||
return response.text
|
||||
except Exception as e:
|
||||
logger.error(f"Error calling API: {e}")
|
||||
return str(e)
|
||||
|
7
backend/llm/utils/sanitize_function_name.py
Normal file
7
backend/llm/utils/sanitize_function_name.py
Normal file
@ -0,0 +1,7 @@
|
||||
import re
|
||||
|
||||
|
||||
def sanitize_function_name(string):
|
||||
sanitized_string = re.sub(r"[^a-zA-Z0-9_-]", "", string)
|
||||
|
||||
return sanitized_string
|
@ -1,19 +1,26 @@
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
|
||||
class ApiBrainDefinitionSchemaProperty(BaseModel):
|
||||
class ApiBrainDefinitionSchemaProperty(BaseModel, extra=Extra.forbid):
|
||||
type: str
|
||||
description: str
|
||||
enum: list
|
||||
enum: Optional[list]
|
||||
name: str
|
||||
required: bool
|
||||
|
||||
def dict(self, **kwargs):
|
||||
result = super().dict(**kwargs)
|
||||
if "enum" in result and result["enum"] is None:
|
||||
del result["enum"]
|
||||
return result
|
||||
|
||||
|
||||
class ApiBrainDefinitionSchema(BaseModel):
|
||||
properties: list[ApiBrainDefinitionSchemaProperty]
|
||||
required: list[str]
|
||||
class ApiBrainDefinitionSchema(BaseModel, extra=Extra.forbid):
|
||||
properties: list[ApiBrainDefinitionSchemaProperty] = []
|
||||
required: list[str] = []
|
||||
|
||||
|
||||
class ApiBrainDefinitionSecret(BaseModel):
|
||||
@ -21,9 +28,16 @@ class ApiBrainDefinitionSecret(BaseModel):
|
||||
type: str
|
||||
|
||||
|
||||
class ApiBrainDefinition(BaseModel):
|
||||
class ApiBrainAllowedMethods(str, Enum):
|
||||
GET = "GET"
|
||||
POST = "POST"
|
||||
PUT = "PUT"
|
||||
DELETE = "DELETE"
|
||||
|
||||
|
||||
class ApiBrainDefinition(BaseModel, extra=Extra.forbid):
|
||||
brain_id: UUID
|
||||
method: str
|
||||
method: ApiBrainAllowedMethods
|
||||
url: str
|
||||
params: ApiBrainDefinitionSchema
|
||||
search_params: ApiBrainDefinitionSchema
|
||||
|
@ -2,9 +2,13 @@ from enum import Enum
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from models.ApiBrainDefinition import ApiBrainDefinition
|
||||
from models.ApiBrainDefinition import (
|
||||
ApiBrainDefinition,
|
||||
ApiBrainDefinitionSchema,
|
||||
ApiBrainDefinitionSecret,
|
||||
)
|
||||
from models.databases.repository import Repository
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
|
||||
class ApiMethod(str, Enum):
|
||||
@ -14,13 +18,12 @@ class ApiMethod(str, Enum):
|
||||
DELETE = "DELETE"
|
||||
|
||||
|
||||
class CreateApiBrainDefinition(BaseModel):
|
||||
brain_id: UUID
|
||||
class CreateApiBrainDefinition(BaseModel, extra=Extra.forbid):
|
||||
method: ApiMethod
|
||||
url: str
|
||||
params: dict
|
||||
search_params: dict
|
||||
secrets: dict
|
||||
params: Optional[ApiBrainDefinitionSchema] = ApiBrainDefinitionSchema()
|
||||
search_params: ApiBrainDefinitionSchema = ApiBrainDefinitionSchema()
|
||||
secrets: Optional[list[ApiBrainDefinitionSecret]] = []
|
||||
|
||||
|
||||
class ApiBrainDefinitions(Repository):
|
||||
@ -40,10 +43,12 @@ class ApiBrainDefinitions(Repository):
|
||||
return ApiBrainDefinition(**response.data[0])
|
||||
|
||||
def add_api_brain_definition(
|
||||
self, brain_id: UUID, config: CreateApiBrainDefinition
|
||||
self, brain_id: UUID, api_brain_definition: CreateApiBrainDefinition
|
||||
) -> Optional[ApiBrainDefinition]:
|
||||
response = self.db.table("api_brain_definition").insert(
|
||||
[{"brain_id": str(brain_id), **config.dict()}]
|
||||
response = (
|
||||
self.db.table("api_brain_definition")
|
||||
.insert([{"brain_id": str(brain_id), **api_brain_definition.dict()}])
|
||||
.execute()
|
||||
)
|
||||
if len(response.data) == 0:
|
||||
return None
|
||||
|
@ -4,12 +4,15 @@ from uuid import UUID
|
||||
from logger import get_logger
|
||||
from models.brain_entity import BrainEntity, BrainType, MinimalBrainEntity, PublicBrain
|
||||
from models.databases.repository import Repository
|
||||
from pydantic import BaseModel
|
||||
from models.databases.supabase.api_brain_definition import (
|
||||
CreateApiBrainDefinition,
|
||||
)
|
||||
from pydantic import BaseModel, Extra
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class CreateBrainProperties(BaseModel):
|
||||
class CreateBrainProperties(BaseModel, extra=Extra.forbid):
|
||||
name: Optional[str] = "Default brain"
|
||||
description: Optional[str] = "This is a description"
|
||||
status: Optional[str] = "private"
|
||||
@ -19,6 +22,8 @@ class CreateBrainProperties(BaseModel):
|
||||
openai_api_key: Optional[str] = None
|
||||
prompt_id: Optional[UUID] = None
|
||||
brain_type: Optional[BrainType] = BrainType.DOC
|
||||
brain_definition: Optional[CreateApiBrainDefinition]
|
||||
brain_secrets_values: dict = {}
|
||||
|
||||
def dict(self, *args, **kwargs):
|
||||
brain_dict = super().dict(*args, **kwargs)
|
||||
@ -53,7 +58,12 @@ class Brain(Repository):
|
||||
self.db = supabase_client
|
||||
|
||||
def create_brain(self, brain: CreateBrainProperties):
|
||||
response = (self.db.table("brains").insert(brain.dict())).execute()
|
||||
response = (
|
||||
self.db.table("brains").insert(
|
||||
brain.dict(exclude={"brain_definition", "brain_secrets_values"})
|
||||
)
|
||||
).execute()
|
||||
|
||||
return BrainEntity(**response.data[0])
|
||||
|
||||
def get_user_brains(self, user_id) -> list[MinimalBrainEntity]:
|
||||
|
@ -7,8 +7,8 @@ from models.settings import get_supabase_db
|
||||
|
||||
|
||||
def add_api_brain_definition(
|
||||
brain_id: UUID, api_brain_configs: CreateApiBrainDefinition
|
||||
brain_id: UUID, api_brain_definition: CreateApiBrainDefinition
|
||||
) -> None:
|
||||
supabase_db = get_supabase_db()
|
||||
|
||||
supabase_db.add_api_brain_definition(brain_id, api_brain_configs)
|
||||
supabase_db.add_api_brain_definition(brain_id, api_brain_definition)
|
||||
|
@ -1,8 +1,45 @@
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import HTTPException
|
||||
from models import BrainEntity, get_supabase_db
|
||||
from models.brain_entity import BrainType
|
||||
from models.databases.supabase.brains import CreateBrainProperties
|
||||
|
||||
from repository.api_brain_definition.add_api_brain_definition import (
|
||||
add_api_brain_definition,
|
||||
)
|
||||
from repository.external_api_secret.create_secret import create_secret
|
||||
|
||||
|
||||
def create_brain(brain: CreateBrainProperties, user_id: UUID) -> BrainEntity:
|
||||
if brain.brain_type == BrainType.API:
|
||||
if brain.brain_definition is None:
|
||||
raise HTTPException(status_code=404, detail="Brain definition not found")
|
||||
|
||||
if brain.brain_definition.url is None:
|
||||
raise HTTPException(status_code=404, detail="Brain url not found")
|
||||
|
||||
if brain.brain_definition.method is None:
|
||||
raise HTTPException(status_code=404, detail="Brain method not found")
|
||||
|
||||
def create_brain(brain: CreateBrainProperties) -> BrainEntity:
|
||||
supabase_db = get_supabase_db()
|
||||
|
||||
return supabase_db.create_brain(brain)
|
||||
created_brain = supabase_db.create_brain(brain)
|
||||
|
||||
if brain.brain_type == BrainType.API and brain.brain_definition is not None:
|
||||
add_api_brain_definition(
|
||||
brain_id=created_brain.brain_id,
|
||||
api_brain_definition=brain.brain_definition,
|
||||
)
|
||||
|
||||
secrets_values = brain.brain_secrets_values
|
||||
|
||||
for secret_name in secrets_values:
|
||||
create_secret(
|
||||
user_id=user_id,
|
||||
brain_id=created_brain.brain_id,
|
||||
secret_name=secret_name,
|
||||
secret_value=secrets_values[secret_name],
|
||||
)
|
||||
|
||||
return created_brain
|
||||
|
@ -1,6 +1,6 @@
|
||||
pymupdf==1.22.3
|
||||
langchain==0.0.304
|
||||
litellm==0.1.816
|
||||
langchain==0.0.332
|
||||
litellm==0.13.2
|
||||
Markdown==3.4.4
|
||||
openai==0.27.8
|
||||
GitPython==3.1.36
|
||||
|
@ -24,6 +24,7 @@ from repository.brain import (
|
||||
update_brain_by_id,
|
||||
)
|
||||
from repository.prompt import delete_prompt_by_id, get_prompt_by_id
|
||||
|
||||
from routes.authorizations.brain_authorization import has_brain_authorization
|
||||
from routes.authorizations.types import RoleEnum
|
||||
|
||||
@ -91,7 +92,10 @@ async def create_new_brain(
|
||||
detail=f"Maximum number of brains reached ({user_settings.get('max_brains', 5)}).",
|
||||
)
|
||||
|
||||
new_brain = create_brain(brain)
|
||||
new_brain = create_brain(
|
||||
brain,
|
||||
user_id=current_user.id,
|
||||
)
|
||||
if get_user_default_brain(current_user.id):
|
||||
logger.info(f"Default brain already exists for user {current_user.id}")
|
||||
create_brain_user(
|
||||
|
@ -1,3 +1,4 @@
|
||||
from fastapi import HTTPException
|
||||
from llm.api_brain_qa import APIBrainQA
|
||||
from llm.qa_base import QABaseBrainPicking
|
||||
from models.brain_entity import BrainType
|
||||
@ -46,7 +47,7 @@ class BrainfulChat(ChatInterface):
|
||||
brain = get_brain_by_id(brain_id)
|
||||
|
||||
if not brain:
|
||||
raise Exception("No brain found")
|
||||
raise HTTPException(status_code=404, detail="Brain not found")
|
||||
|
||||
if (
|
||||
brain.brain_type == BrainType.DOC
|
||||
@ -62,6 +63,7 @@ class BrainfulChat(ChatInterface):
|
||||
streaming=streaming,
|
||||
prompt_id=prompt_id,
|
||||
)
|
||||
|
||||
return APIBrainQA(
|
||||
chat_id=chat_id,
|
||||
model=model,
|
||||
|
@ -21,5 +21,6 @@ class ChatInterface(ABC):
|
||||
user_openai_api_key,
|
||||
streaming,
|
||||
prompt_id,
|
||||
user_id,
|
||||
):
|
||||
pass
|
||||
|
@ -173,7 +173,6 @@ async def create_question_handler(
|
||||
try:
|
||||
check_user_requests_limit(current_user)
|
||||
is_model_ok = (brain_details or chat_question).model in userSettings.get("models", ["gpt-3.5-turbo"]) # type: ignore
|
||||
gpt_answer_generator: HeadlessQA | QABaseBrainPicking
|
||||
gpt_answer_generator = chat_instance.get_answer_generator(
|
||||
chat_id=str(chat_id),
|
||||
model=chat_question.model if is_model_ok else "gpt-3.5-turbo", # type: ignore
|
||||
|
Loading…
Reference in New Issue
Block a user