From f7c2bb5a8665ba8603ac371f4bfaeb91ecfbe032 Mon Sep 17 00:00:00 2001 From: Vokturz Date: Thu, 15 Feb 2024 22:35:16 -0300 Subject: [PATCH] v2 update --- CHANGELOG.md | 4 +- README.md | 290 +++++++---------------- pyproject.toml | 3 +- setup.cfg | 1 + setup.py | 2 +- src/judini/__init__.py | 1 + src/judini/codegpt.py | 414 +++++++++++++++++++++++++++++++++ src/judini/codegpt/__init__.py | 0 src/judini/codegpt/agent.py | 63 ----- src/judini/codegpt/chat.py | 67 ------ src/judini/codegpt/document.py | 126 ---------- src/judini/codegpt/user.py | 29 --- src/judini/types.py | 59 +++++ src/judini/utils.py | 38 +++ streamlit.py | 55 +++++ 15 files changed, 662 insertions(+), 490 deletions(-) create mode 100644 src/judini/codegpt.py delete mode 100644 src/judini/codegpt/__init__.py delete mode 100644 src/judini/codegpt/agent.py delete mode 100644 src/judini/codegpt/chat.py delete mode 100644 src/judini/codegpt/document.py delete mode 100644 src/judini/codegpt/user.py create mode 100644 src/judini/types.py create mode 100644 src/judini/utils.py create mode 100644 streamlit.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f0f6ae..aa0a8d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - +## [0.1.0] - 15-02-2023 +### Changed +- Updated to new API version ## [0.0.24] - 12-20-2023 diff --git a/README.md b/README.md index fbba5df..7ddcef5 100644 --- a/README.md +++ b/README.md @@ -20,235 +20,121 @@ pip install judini 5. Copy and replace your **AGENT KEY** -## How to Usage -### Import Judini SDK -```python -import os -from judini.codegpt.agent import Agent -from judini.codegpt.chat import Completion -from judini.codegpt.document import Document -import dotenv - -# Load environment variables -dotenv.load_dotenv() - -# CodeGPT Environment Variables API Key -CODEGPT_API_KEY = os.getenv("CODEGPT_API_KEY") -AGENT_ID = os.getenv("CODEGPT_AGENT_ID") -``` +## How to use ### Chat Completion + ```python -def chat_completion(agent_id, messages): - """ - Chat completion by Agent ID - Parameters: - agent_id (str): Agent ID - messages (dict): Messages [{ "role": "user", "content": "user prompt" }] - Returns: - Chat completion result - """ - completion = Completion(CODEGPT_API_KEY) - return completion.create(agent_id, messages) - -# Example +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) + +AGENT_ID = "0000000-0000-0000-0000-000000000000" messages = [{"role": "user", "content": "What is the meaning of life?"}] -chat = chat_completion(AGENT_ID, messages) + +# No streaming +chat = codegpt.chat_completion(agent_id=AGENT_ID, + messages=messages) print(chat) -``` -### All Agent -```python -def getAllAgent(): - """ - Retrieves a list of all available agents - Returns: - A list of agents. - """ - agent = Agent(CODEGPT_API_KEY) - return agent.getAll() +# Streaming +for chunk in codegpt.chat_completion(agent_id=AGENT_ID, + messages=messages, + stream=True): + print(chunk, end="") +``` -# Example -my_agents = getAllAgent() -print(my_agents) +### Agents +#### List all agents +```python +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.get_agents() +>> [Agent(id='0000000-0000-0000-0000-000000000000', ...), +>> Agent(id='0000000-0000-0000-0000-000000000001', ...)] ``` -### Get agent data by ID +#### Get agent by ID ```python -def getAgentById(agent_id): - """ - Retrieves details of a specific agent by Agent ID - Parameters: - agent_id (str): Agent ID - Returns: - Agent details - """ - agent = Agent(CODEGPT_API_KEY) - return agent.getAgentById(agent_id) - -# Example -AGENT_ID = os.getenv("CODEGPT_AGENT_ID") -my_agent = getAgentById(AGENT_ID) -print(my_agent) +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +agent = codegpt.get_agent(agent_id='0000000-0000-0000-0000-000000000000') +agent +>> Agent(id='0000000-0000-0000-0000-000000000000', +>> name='Agent name', model='gpt-3.5-turbo', +>> prompt='You are a helpful assistant.', +>> welcome='Hello, how can I help you?', +>> ...) ``` -### Update Agent +#### Create Agent ```python -def updateAgent(agent_id, data): - """ - Updates information for a specific agent. - Parameters: - agent_id (str): Agent ID - data (dict) : Agent data to update - Returns: - Updated agent details - """ - agent = Agent(CODEGPT_API_KEY) - return agent.update(agent_id, data) - -# Example -AGENT_ID = os.getenv("CODEGPT_AGENT_ID") -new_data = { - 'status': 'published', - 'name': 'DevSuper2', - 'documentId': [], - 'description': 'Dev Super 2', - 'prompt': 'You are an expert senior multilanguage programmer and you must help with the code and questions they ask of you.', - 'topk': 100, - 'temperature': 0.0, - 'model': 'gpt-3.5-turbo', - 'welcome': '', - 'maxTokens': None, -} -update = updateAgent(AGENT_ID, new_data) -print (update) +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.create_agent(name='Agent name', model='gpt-3.5-turbo', + prompt='You are a helpful assistant.', + welcome='Hello, how can I help you?') +>> Agent(id='0000000-0000-0000-0000-000000000000', +>> name='Agent name', model='gpt-3.5-turbo', ...) ``` -### Link document to an agent +#### Update Agent info ```python -def linkDocument(agent_id, documentId): - """ - Links a document to a specific agent. - Parameters: - agent_id (str): Agent ID - documentId (str): Document ID to link. - Returns: - Response object indicating the result of the operation. - """ - agent = Agent(CODEGPT_API_KEY) - return agent.linkDocument(agent_id, documentId) - -# Example -AGENT_ID = os.getenv("CODEGPT_AGENT_ID") -documentId = '123456' # replace with your document id -link_document = linkDocument(AGENT_ID, documentId) -print(link_document) +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.update_agent(agent_id='0000000-0000-0000-0000-000000000000', + name='Agent name updated', + model='gpt-4-turbo-preview') +>> Agent(id='0000000-0000-0000-0000-000000000000', +>> name='Agent name updated', model='gpt-3.5-turbo', ...) ``` -### Unlink document to an agent +### Delete Agent ```python -def unlinkDocument(agent_id, documentId): - """ - Unlinks a document from a specific agent. - Parameters: - agent_id (str): Agent ID to unlink the document from. - documentId (str): Document ID to unlink. - Returns: - Response object indicating the result of the operation. - """ - agent = Agent(CODEGPT_API_KEY) - return agent.unlinkDocument(agent_id, documentId) - -# Example -AGENT_ID = os.getenv("CODEGPT_AGENT_ID") -documentId = '123456' # replace with your document id -unlink_document = unlinkDocument(AGENT_ID, documentId) -print(unlink_document) +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.delete_agent('0000000-0000-0000-0000-000000000000') +>> Agent deleted successfully ``` -### Get All Document -```python -def getAllDocument(): - """ - Get all documents - Returns: - An object with all the account documents - """ - document = Document(CODEGPT_API_KEY) - return document.getAll() - -#example -my_documents = getAllDocument() -print(my_documents) -``` - -### Get Document by ID -```python -def getDocumentById(documentId): - """ - Get Document by ID - Returns: - A response object that contains the document data - """ - document = Document(CODEGPT_API_KEY) - return document.getDocumentById(documentId) - -#example -documentId = 'YOUR_DOCUMENT_ID' -my_document = getDocumentById() -print(my_document) -``` - -### Load Document +### Documents +#### List all documents ```python -def loadDocument(): - """ - Load document file. - Returns: - A response object containing the document's data. - """ - document = Document(CODEGPT_API_KEY) - return document.load() - -#example -file = "example.txt" # path of your file -my_documents = loadDocument(file) -print(my_documents) -``` +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.get_documents() +>> [Document(id='0000000-0000-0000-0000-000000000000', ...), +>> Document(id='0000000-0000-0000-0000-000000000001', ...)] +``` -### Training Document +#### Get document by ID ```python -def trainingDocument(documentId): - """ - Training document file. - Returns: - A response object containing the document's data. - """ - document = Document(CODEGPT_API_KEY) - return document.training(documentId) +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +document = codegpt.get_document_by_id('0000000-0000-0000-0000-000000000000') +document +>> Document(id='0000000-0000-0000-0000-000000000000', + user_id='...', + name='My Document', + metadata='...', + content='Document content', ...) +``` -#example -documentId = 'YOUR_DOCUMENT_ID' -document_to_training = trainingDocument(documentId) -print(document_to_training) -``` +#### Upload a document +**Currently, only text documents are supported** +```python +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.upload_document('path/to/file.txt') +>> {'id': '0000000-0000-0000-0000-000000000000'} +``` -### Load and Training Document +#### Delete a document ```python -def loadToTrainingDocument(file): - """ - Load and Training a Document - Returns: - A response object that contains the document data - """ - document = Document(CODEGPT_API_KEY) - return document.loadAndTraining(file) - -#example -file = "example.txt" # path to your file -document = loadToTrainingDocument(file) -print(document) -``` +from judini import CodeGPTPlus +codegpt = CodeGPTPlus(api_key=CODEGPT_API_KEY) +codegpt.delete_document('0000000-0000-0000-0000-000000000000') +>> Document deleted successfully +``` ## MORE EXAMPLES You can review more examples in our [Cookbook Repository](https://github.com/judinilabs/cookbook/) diff --git a/pyproject.toml b/pyproject.toml index 225f2a1..b102127 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,8 @@ [build-system] requires = [ "setuptools>=42", - "wheel" + "wheel", + "pydantic" ] diff --git a/setup.cfg b/setup.cfg index ffc999d..3480fd2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -22,6 +22,7 @@ install_requires = aiohttp asyncio python-dotenv + pydantic [options.packages.find] where = src diff --git a/setup.py b/setup.py index 04710cb..ae80d1a 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,6 @@ ], python_requires=">=3.5", install_requires=[ - "requests", "aiohttp", "asyncio", "python-dotenv" + "requests", "aiohttp", "asyncio", "python-dotenv", "pydantic" ], ) \ No newline at end of file diff --git a/src/judini/__init__.py b/src/judini/__init__.py index e69de29..79a87d6 100644 --- a/src/judini/__init__.py +++ b/src/judini/__init__.py @@ -0,0 +1 @@ +from .codegpt import CodeGPTPlus \ No newline at end of file diff --git a/src/judini/codegpt.py b/src/judini/codegpt.py new file mode 100644 index 0000000..422af33 --- /dev/null +++ b/src/judini/codegpt.py @@ -0,0 +1,414 @@ +import os +import mimetypes +import json +import requests +from typing import List, Dict, Literal, Optional +from .utils import handle_non_stream, handle_stream +from .types import Agent, Document, DocumentMetadata + +base_url = 'https://api-beta.codegpt.co/api/v1' +JUDINI_TUTORIAL = 'https://api-beta.codegpt.co/api/v1/docs' + +class CodeGPTPlus: + def __init__(self, api_key: Optional[str] = None, org_id: Optional[str] = None): + + if not api_key: + api_key = os.getenv("CODEGPT_API_KEY") + if not api_key: + raise Exception('JUDINI: API key not found. Please set the CODEGPT_API_KEY' + + ' environment variable or pass it as an argument.') + self.headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + api_key + } + if not org_id: + org_id = os.getenv("CODEGPT_ORG_ID") + + if org_id: + self.headers['CodeGPT-Org-Id'] = org_id + + self.is_streaming = False + + ####################### + ### CHAT COMPLETION ### + ####################### + + def chat_completion(self, agent_id: str, messages: List[Dict[str, str]], + stream: bool = False, format: Literal['json', 'text'] = 'text' + ) -> str | Dict[str, str]: + """ + Initiates a chat with the specified agent and handles the streaming of + responses. + + Parameters + ---------- + + agent_id: The ID of the agent to chat with. + messages: An array of message objects to be sent to the agent. Each + object should have a `role` (which can be 'system', 'user', + or 'assistant') and `content` which is the actual message. + stream: Whether to stream the response or not. + format: The format of the response. Can be either 'json' or 'text'. + + Example: + >>> from judini import CodeGPTPlus + >>> codegpt = CodeGPTPlus(api_key, org_id) + >>> agent_id = '00000000-0000-0000-0000-000000000000' + >>> messages = [{'role': 'user', 'content': 'Hello, World!'}] + >>> codegpt.chat_completion(agent_id, messages, stream=True, format='text') + 'Hello, World!' + """ + + if len(messages) == 0: + raise ValueError('JUDINI: messages array should not be empty') + + if not agent_id: + raise ValueError('JUDINI: agent_id should not be empty') + + if format not in ['json', 'text']: + raise ValueError('JUDINI: format should be either "json" or "text"') + + headers = self.headers.copy() + headers['media_type'] = 'text/event-stream' + + payload = json.dumps({ + "agentId": agent_id, + "messages": messages, + "stream": stream, + "format": "json" # By default always json + }) + + response = requests.post(f"{base_url}/chat/completions", headers=headers, + data=payload, stream=stream) + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + if stream: + return handle_stream(response, format) + else: + return handle_non_stream(response, format) + + + ############## + ### AGENTS ### + ############## + + def get_agents(self) -> List[Agent]: + """ + Retrieves a list of all the agents from the CodeGPTPlus API. + + Returns an array of json objects representing agents with the following properties: + id: str = The ID of the agent + name: str = The name of the agent + prompt: str = The prompt of the agent + model: str = The model of the agent + agent_documents: Optional[List[str]] = The list of documents associated with the agent + welcome: str = The welcome message of the agent + pincode: Optional[str] = The pincode of the agent + is_public: bool = Whether the agent is public or not + agent_type: str = The type of the agent + """ + + response = requests.get(f"{base_url}/agent", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + agent_lists = response.json() + return [Agent(**agent_dict) for agent_dict in agent_lists] + + def get_agent(self, agent_id: str) -> Agent: + """ + Retrieves a specific agent from the CodeGPTPlus API. + + Parameters + ---------- + agent_id: The ID of the agent to retrieve. + + Returns a json object representing the agent with the following properties: + id: str = The ID of the agent + name: str = The name of the agent + prompt: str = The prompt of the agent + model: str = The model of the agent + agent_documents: Optional[List[str]] = The list of documents associated with the agent + welcome: str = The welcome message of the agent + pincode: Optional[str] = The pincode of the agent + is_public: bool = Whether the agent is public or not + agent_type: str = The type of the agent + """ + + response = requests.get(f"{base_url}/agent/{agent_id}?populate=agent_documents", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + return Agent(**response.json()) + + def create_agent(self, + name: str, + model: str="gpt-3.5-turbo", + prompt: str = "You are a helpful assistant.", + welcome: str = "Hello, how can I help you today?", + topk: int=3, + temperature: int=0.7, + ) -> Agent: + """ + Creates a new agent in the CodeGPTPlus API. + + Parameters + ---------- + name: The name of the agent. + model: The model to be used by the agent. For example, 'gpt-3.5-turbo'. + prompt: The prompt of the agent. + welcome: The welcome message of the agent. + topk: The number of elements to retrieve from the documents + temperature: The temperature of the agent. + + Returns a json object representing the agent with the following properties: + id: str = The ID of the agent + name: str = The name of the agent + prompt: str = The prompt of the agent + model: str = The model of the agent + agent_documents: Optional[List[str]] = The list of documents associated with the agent + welcome: str = The welcome message of the agent + pincode: Optional[str] = The pincode of the agent + is_public: bool = Whether the agent is public or not + agent_type: str = The type of the agent + """ + + payload = json.dumps({ + "name": name, + "model": model, + "prompt": prompt, + "welcome": welcome, + "topk": topk, + "temperature": temperature + }) + response = requests.post(f"{base_url}/agent", headers=self.headers, + data=payload) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + return Agent(**response.json()) + + def update_agent(self, + agent_id: str, + name: Optional[str] = None, + model: Optional[str] = None, + prompt: Optional[str] = None, + welcome: Optional[str] = None, + topk: Optional[int] = None, + temperature: Optional[int] = None, + is_public: Optional[bool] = None, + pincode: Optional[str] = None + ) -> Agent: + """ + Updates an existing agent in the CodeGPTPlus API. + Apart from the agent ID, at least one parameter is required. + + Parameters + ---------- + agent_id: The ID of the agent to update. + name: (optional) The updated name of the agent. + model: (optional) The updated model to be used by the agent. + prompt: (optional) The updated prompt of the agent. + welcome: (optional) The updated welcome message of the agent. + topk: (optional) The updated number of elements to retrieve from the documents + temperature: (optional) The updated temperature of the agent. + is_public: (optional) The updated visibility of the agent. + pincode: (optional) The updated pincode of the agent. + + Returns a json object representing the agent with the following properties: + id: str = The ID of the agent + name: str = The name of the agent + prompt: str = The prompt of the agent + model: str = The model of the agent + agent_documents: Optional[List[str]] = The list of documents associated with the agent + welcome: str = The welcome message of the agent + pincode: Optional[str] = The pincode of the agent + is_public: bool = Whether the agent is public or not + agent_type: str = The type of the agent + """ + + if not agent_id: + raise ValueError('JUDINI: agent_id should not be empty') + + payload = {} + if name: + payload['name'] = name + if model: + payload['model'] = model + if prompt: + payload['prompt'] = prompt + if welcome: + payload['welcome'] = welcome + if topk: + payload['topk'] = topk + if temperature: + payload['temperature'] = temperature + if is_public: + payload['is_public'] = is_public + if pincode: + payload['pincode'] = pincode + + if not payload: + raise ValueError('JUDINI: At least one parameter should be provided') + + payload = json.dumps(payload) + + response = requests.patch(f"{base_url}/agent/{agent_id}", headers=self.headers, + data=payload) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + return Agent(**response.json()) + + + def delete_agent(self, agent_id: str) -> None: + """ + Deletes an agent from the CodeGPTPlus API. + + Parameters + ---------- + agent_id: The ID of the agent to delete. + """ + + response = requests.delete(f"{base_url}/agent/{agent_id}", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + print('Agent deleted successfully') + return + + def update_agent_documents(self, agent_id: str, document_ids: List[str]) -> None: + """ + Updates the documents associated with an agent in the CodeGPTPlus API. + + Parameters + ---------- + agent_id: The ID of the agent to update. + document_ids: The IDs of the documents to associate with the agent. + """ + raise NotImplementedError('JUDINI: update_agent_documents is not implemented') + # payload = json.dumps({ "agent_documents": document_ids}) + # response = requests.patch(f"{base_url}/agent/{agent_id}/documents", headers=self.headers, + # data=payload) + + # if response.status_code != 200: + # raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + # print('Agent documents updated successfully') + # return response.json() + + ################# + ### DOCUMENTS ### + ################# + + def get_documents(self) -> List[Document]: + """ + Retrieves a list of all the documents from the CodeGPTPlus API. + + Returns an array of json objects representing documents with the following properties: + id: str = The ID of the document + user_id: str = The ID of the user who created the document + name: str = The name of the document + content: str = The content of the document + file_type: str = The type of the document + metadata: Optional[DocumentMetadata] = The metadata of the document + tokens: int = The number of tokens in the document + chunks_count: int = The number of chunks the document was split into + """ + + response = requests.get(f"{base_url}/document", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + document_lists = response.json() + return [Document(**document_dict) for document_dict in document_lists] + + def get_document(self, document_id: str) -> Document: + """ + Retrieves a specific document from the CodeGPTPlus API. + + Parameters + ---------- + document_id: The ID of the document to retrieve. + + Returns a json object representing the document with the following properties: + id: str = The ID of the document + user_id: str = The ID of the user who created the document + name: str = The name of the document + content: str = The content of the document + file_type: str = The type of the document + metadata: Optional[DocumentMetadata] = The metadata of the document + tokens: int = The number of tokens in the document + chunks_count: int = The number of chunks the document was split into + """ + + response = requests.get(f"{base_url}/document/{document_id}", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + return Document(**response.json()) + + def update_document_metadata(self, document_id: str, + title: Optional[str] = None, + description: Optional[str] = None, + summary: Optional[str] = None, + keywords: Optional[str] = None, + language: Optional[str] = None) -> DocumentMetadata: + raise NotImplementedError('JUDINI: update_document_metadata is not implemented') + + def upload_document(self, file_path: str) -> Dict[str, str]: + """ + Uploads a document to the CodeGPTPlus API. + + Parameters + ---------- + file_path: The path to the file to upload. + + Returns + ------- + response_json: A dictionary containing the document ID of the uploaded document. + """ + + if not os.path.exists(file_path): + raise FileNotFoundError(f'JUDINI: File not found: {file_path}') + + file_type = mimetypes.guess_type(file_path)[0] + + headers = self.headers.copy() + del headers['Content-Type'] + + with open(file_path, 'rb') as file: + response = requests.post(f"{base_url}/document", + headers=headers, + files={'file': (os.path.basename(file_path), file, file_type)}) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + response_json = response.json() + return {'id' : response_json['documentId']} + + def delete_document(self, document_id: str) -> None: + """ + Deletes a document from the CodeGPTPlus API. + + Parameters + ---------- + document_id: The ID of the document to delete. + """ + + response = requests.delete(f"{base_url}/document/{document_id}", headers=self.headers) + + if response.status_code != 200: + raise Exception(f'JUDINI: API Response was: {response.status_code} {response.text} {JUDINI_TUTORIAL}') + + print('Document deleted successfully') + return \ No newline at end of file diff --git a/src/judini/codegpt/__init__.py b/src/judini/codegpt/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/judini/codegpt/agent.py b/src/judini/codegpt/agent.py deleted file mode 100644 index 8709daa..0000000 --- a/src/judini/codegpt/agent.py +++ /dev/null @@ -1,63 +0,0 @@ -import requests - -base_url = "https://api-beta.codegpt.co/api/v1/" - -class Agent: - def __init__(self, api_key): - self.api_key = api_key - - - def getAll(self): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/agent" - - try: - response = requests.get(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response: {response.status_code} {response.reason}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - def getAgentById(self,agent_id): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/agent/{agent_id}" - - try: - response = requests.get(url, headers=headers) - if response.status_code != 200: - error_message = f"API CODEGPT Response: {response.status_code} {response.reason}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - def update(self,agent_id, data): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - url = f"{base_url}/agent/{agent_id}" - try: - response = requests.patch(url, json=data, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") \ No newline at end of file diff --git a/src/judini/codegpt/chat.py b/src/judini/codegpt/chat.py deleted file mode 100644 index 4e6aa9b..0000000 --- a/src/judini/codegpt/chat.py +++ /dev/null @@ -1,67 +0,0 @@ -import json -import requests -from typing import List, Dict, Literal - -base_url = "https://api-beta.codegpt.co/api/v1" - -class Completion: - def __init__(self, api_key): - self.api_key = api_key - - def create(self, agent_id: str, messages: List[Dict[str, str]], - stream: bool = False, format: Literal['json', 'text'] = 'text') -> str: - headers = { - "Content-Type": "application/json", - "media_type": "text/event-stream", - "Authorization": f"Bearer {self.api_key}" - } - - payload = json.dumps({ - "agentId": agent_id, - "messages": messages, - "stream": stream, - "format": "json" # By default always json - }) - - response = requests.post(f"{base_url}/chat/completions", headers=headers, - data=payload, stream=stream) - - if stream: - return self._handle_stream(response, format) - else: - return self._handle_non_stream(response, format) - - def _handle_stream(self, response: requests.Response, - format: Literal['json', 'text']) -> List[str]: - try: - for chunk in response.iter_lines(): - if chunk: - chunk_str = chunk.decode("utf-8") - data_array = chunk_str.replace('\n','').split('data: ')[1:] - for jd_str in data_array: - if jd_str == '[DONE]': - break - json_data = json.loads(jd_str) - if format == 'json': - yield json_data - elif format == 'text': - for item in json_data['choices']: - yield item['delta']['content'] - except Exception as e: - print(f"Error occurred: {e}", jd_str) - finally: - response.close() - - def _handle_non_stream(self, response: requests.Response, - format: Literal['json', 'text']) -> str: - try: - json_data = response.json() - if format == 'json': - return json_data - elif format == 'text': - return json_data['choices'][0]['message']['content'] - except Exception as e: - print(f"Error occurred: {e}") - finally: - response.close() - \ No newline at end of file diff --git a/src/judini/codegpt/document.py b/src/judini/codegpt/document.py deleted file mode 100644 index d8fb8e7..0000000 --- a/src/judini/codegpt/document.py +++ /dev/null @@ -1,126 +0,0 @@ -import requests - -base_url = "https://api-beta.codegpt.co/api/v1" - -class Document: - def __init__(self, api_key): - self.api_key = api_key - - - def getAll(self): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document" - - try: - response = requests.get(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - def getDocumentById(self,documentId): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document/"+documentId - - try: - response = requests.get(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - def delete(self,documentId): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document/"+documentId - - try: - response = requests.delete(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - def load(self,file): - headers = { - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document/load" - - try: - with open(file, "rb") as f: - response = requests.post(url,files={"file" : f},headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - - def training(self,documentId): - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document/training/{documentId}" - - try: - response = requests.post(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - - - def loadAndTraining(self,file): - headers = { - "Authorization": f"Bearer {self.api_key}" - } - - url = f"{base_url}/document/load-and-training" - - try: - with open(file, "rb") as f: - response = requests.post(url, files={"file" : f},headers=headers) - - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response} {url_documentation}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") \ No newline at end of file diff --git a/src/judini/codegpt/user.py b/src/judini/codegpt/user.py deleted file mode 100644 index 128a051..0000000 --- a/src/judini/codegpt/user.py +++ /dev/null @@ -1,29 +0,0 @@ -import requests - -base_url = "https://api-beta.codegpt.co/api/v1/" - -class CodeGPT: - def __init__(self, api_key): - self.api_key = api_key - - - def me(self): - try: - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {self.api_key}" - } - - url = base_url + "/user" - response = requests.get(url, headers=headers) - if response.status_code != 200: - error_message = f"API Response was: {response.status_code} {response.reason}" - raise Exception(error_message) - else: - return response.json() - - except Exception as e: - print(f"An error occurred: {e}") - - - diff --git a/src/judini/types.py b/src/judini/types.py new file mode 100644 index 0000000..1772b03 --- /dev/null +++ b/src/judini/types.py @@ -0,0 +1,59 @@ +from pydantic import BaseModel, field_validator +from typing import Optional, List +import json + +class Agent(BaseModel): + id: str + """The ID of the agent""" + name: str + """The name of the agent""" + prompt: str + """The prompt of the agent""" + model: str + """The model of the agent""" + agent_documents: Optional[List[str]] = None + """The list of documents associated with the agent""" + welcome: str + """The welcome message of the agent""" + pincode: Optional[str] = None + """The pincode of the agent""" + is_public: bool + """Whether the agent is public or not""" + agent_type: str + """The type of the agent""" + +class DocumentMetadata(BaseModel): + title: Optional[str] = None + """The title of the document""" + description: Optional[str] = None + """The description of the document""" + summary: Optional[str] = None + """The summary of the document""" + keywords: Optional[str] = None + """The keywords of the document, separated by commas""" + language: Optional[str] = None + """The language of the document""" + + +class Document(BaseModel): + id: str + """The ID of the document""" + user_id: str + """The ID of the user who created the document""" + name: str + """The name of the document""" + file_type: str + """The type of the document""" + metadata: Optional[DocumentMetadata] = None + """The metadata of the document""" + tokens: int + """The number of tokens in the document""" + chunks_count: Optional[int] = None + """The number of chunks the document was split into""" + content: Optional[str] = None + """The content of the document""" + + @field_validator("metadata", mode="before") + def json_loads(cls, v): + if v: + return json.loads(v) \ No newline at end of file diff --git a/src/judini/utils.py b/src/judini/utils.py new file mode 100644 index 0000000..7495cbb --- /dev/null +++ b/src/judini/utils.py @@ -0,0 +1,38 @@ +import json +from typing import List, Dict, Literal, Generator, Any +import requests + +def handle_stream(response: requests.Response, + format: Literal['json', 'text']) -> Generator[Any, Any, Any]: + try: + for chunk in response.iter_lines(): + if chunk: + chunk_str = chunk.decode("utf-8") + data_array = chunk_str.replace('\n','').split('data: ')[1:] + for jd_str in data_array: + if jd_str == '[DONE]': + break + json_data = json.loads(jd_str) + if format == 'json': + yield json_data + elif format == 'text': + for item in json_data['choices']: + yield item['delta']['content'] + except Exception as e: + print(f"Error occurred: {e}") + finally: + response.close() + +def handle_non_stream(response: requests.Response, + format: Literal['json', 'text']) -> str | Dict[Any, Any]: + try: + json_data = response.json() + if format == 'json': + return json_data + elif format == 'text': + return json_data['choices'][0]['message']['content'] + except Exception as e: + print(f"Error occurred: {e}") + finally: + response.close() + \ No newline at end of file diff --git a/streamlit.py b/streamlit.py new file mode 100644 index 0000000..7fc5e5a --- /dev/null +++ b/streamlit.py @@ -0,0 +1,55 @@ +from judini.codegpt.chat import Completion +import streamlit as st + + +st.set_page_config(page_title="CodeGPT Chat", layout="wide") +st.title("CodeGPT Chat") + +if "codegpt_api_key" not in st.session_state: + st.session_state["openai_api_key"] = None + +if "agent_id" not in st.session_state: + st.session_state["agent_id"] = None + +if "messages" not in st.session_state: + st.session_state["messages"] = [] + +CODEGPT_API_KEY = st.sidebar.text_input("CodeGPT API Key", type="password", value=st.session_state.get("codegpt_api_key")) +if not CODEGPT_API_KEY: + st.sidebar.info("Please enter your CodeGPT API key.") + st.stop() +AGENT_ID = st.sidebar.text_input("Agent ID", value=st.session_state.get("agent_id")) +if not AGENT_ID: + st.sidebar.info("Please enter an Agent ID.") + st.stop() +enable_stream = st.sidebar.checkbox("Enable Stream", value=True) +if st.sidebar.button("Clear message history"): + st.session_state["messages"] = [] + st.rerun() + +completion = Completion(api_key=CODEGPT_API_KEY) + + +for msg in st.session_state["messages"]: + st.chat_message(msg["role"]).write(msg["content"]) + +if user_query := st.chat_input("How can I help you?"): + st.chat_message("user").write(user_query) + + with st.chat_message("assistant"): + st.session_state["messages"].append({"role": "user", "content": user_query}) + msgs = st.session_state["messages"] + ai_response = "" + if enable_stream: + message_placeholder = st.empty() + with st.spinner("Wait for it..."): + response = completion.create(AGENT_ID, msgs, stream=True) + for chunk in response: + ai_response += chunk + message_placeholder.markdown(ai_response) + + else: + with st.spinner("Wait for it..."): + ai_response = completion.create(AGENT_ID, msgs, stream=False) + st.markdown(ai_response) + st.session_state["messages"].append({"role": "assistant", "content": ai_response}) \ No newline at end of file