feat: tools integration

This commit is contained in:
Timothy J. Baek 2024-06-10 21:33:46 -07:00
parent c5683dd24c
commit b434ebf3ad
8 changed files with 146 additions and 42 deletions

View File

@ -41,7 +41,7 @@ class ToolModel(BaseModel):
user_id: str
name: str
content: str
specs: dict
specs: List[dict]
meta: ToolMeta
updated_at: int # timestamp in epoch
created_at: int # timestamp in epoch
@ -74,7 +74,7 @@ class ToolsTable:
self.db.create_tables([Tool])
def insert_new_tool(
self, user_id: str, form_data: ToolForm, specs: dict
self, user_id: str, form_data: ToolForm, specs: List[dict]
) -> Optional[ToolModel]:
tool = ToolModel(
**{

View File

@ -52,7 +52,18 @@ def load_toolkit_module_from_path(tools_id, tools_path):
@router.get("/", response_model=List[ToolResponse])
async def get_toolkits(user=Depends(get_current_user)):
toolkits = [ToolResponse(**toolkit) for toolkit in Tools.get_tools()]
toolkits = [toolkit for toolkit in Tools.get_tools()]
return toolkits
############################
# ExportToolKits
############################
@router.get("/export", response_model=List[ToolModel])
async def get_toolkits(user=Depends(get_current_user)):
toolkits = [toolkit for toolkit in Tools.get_tools()]
return toolkits
@ -77,7 +88,7 @@ async def create_new_toolkit(form_data: ToolForm, user=Depends(get_admin_user)):
toolkit = Tools.insert_new_tool(user.id, form_data, specs)
if toolkit:
return ToolResponse(**toolkit)
return toolkit
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
@ -91,7 +102,7 @@ async def create_new_toolkit(form_data: ToolForm, user=Depends(get_admin_user)):
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.NAME_TAG_TAKEN,
detail=ERROR_MESSAGES.ID_TAKEN,
)
@ -105,7 +116,7 @@ async def get_toolkit_by_id(id: str, user=Depends(get_admin_user)):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
return ToolResponse(**toolkit)
return toolkit
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
@ -137,7 +148,7 @@ async def update_toolkit_by_id(
)
if toolkit:
return ToolResponse(**toolkit)
return toolkit
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,

View File

@ -32,6 +32,7 @@ class ERROR_MESSAGES(str, Enum):
COMMAND_TAKEN = "Uh-oh! This command is already registered. Please choose another command string."
FILE_EXISTS = "Uh-oh! This file is already registered. Please choose another file."
ID_TAKEN = "Uh-oh! This id is already registered. Please choose another id string."
MODEL_ID_TAKEN = "Uh-oh! This model id is already registered. Please choose another model id string."
NAME_TAG_TAKEN = "Uh-oh! This name tag is already registered. Please choose another name tag string."

View File

@ -8,6 +8,7 @@
import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts';
import { goto } from '$app/navigation';
import { deleteToolById, getTools } from '$lib/apis/tools';
const i18n = getContext('i18n');
@ -78,7 +79,12 @@
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<a href={`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`}>
<div class=" flex-1 self-center pl-5">
<div class=" font-bold">{tool.name}</div>
<div class=" font-bold flex items-center gap-1.5">
<div>
{tool.name}
</div>
<div class=" text-gray-500 text-xs font-medium">{tool.id}</div>
</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{tool.meta.description}
</div>
@ -89,7 +95,7 @@
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
href={`/workspace/tools/edit?command=${encodeURIComponent(tool.id)}`}
href={`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
@ -134,9 +140,16 @@
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
// deletePrompt(prompt.command);
// deleteTool
on:click={async () => {
const res = await deleteToolById(localStorage.token, tool.id).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Tool deleted successfully');
tools.set(await getTools(localStorage.token));
}
}}
>
<svg

View File

@ -7,9 +7,10 @@
export let value = '';
let codeEditor;
let boilerplate = `from datetime import datetime
let boilerplate = `import os
import requests
import os
from datetime import datetime
class Tools:
def __init__(self):
@ -27,7 +28,9 @@ class Tools:
"""
value = os.getenv(variable_name)
if value is not None:
return f"The value of the environment variable '{variable_name}' is '{value}'"
return (
f"The value of the environment variable '{variable_name}' is '{value}'"
)
else:
return f"The environment variable '{variable_name}' does not exist."
@ -62,38 +65,35 @@ class Tools:
:param city: The name of the city to get the weather for.
:return: The current weather information or an error message.
"""
api_key = os.getenv('OPENWEATHER_API_KEY')
api_key = os.getenv("OPENWEATHER_API_KEY")
if not api_key:
return "API key is not set in the environment variable 'OPENWEATHER_API_KEY'."
return (
"API key is not set in the environment variable 'OPENWEATHER_API_KEY'."
)
base_url = "http://api.openweathermap.org/data/2.5/weather"
params = {
'q': city,
'appid': api_key,
'units': 'metric' # Optional: Use 'imperial' for Fahrenheit
"q": city,
"appid": api_key,
"units": "metric", # Optional: Use 'imperial' for Fahrenheit
}
try:
response = requests.get(base_url, params=params)
response.raise_for_status() # Raise HTTPError for bad responses (4xx and 5xx)
data = response.json()
if data.get('cod') != 200:
if data.get("cod") != 200:
return f"Error fetching weather data: {data.get('message')}"
weather_description = data['weather'][0]['description']
temperature = data['main']['temp']
humidity = data['main']['humidity']
wind_speed = data['wind']['speed']
return (f"Weather in {city}:\n"
f"Description: {weather_description}\n"
f"Temperature: {temperature}°C\n"
f"Humidity: {humidity}%\n"
f"Wind Speed: {wind_speed} m/s")
weather_description = data["weather"][0]["description"]
temperature = data["main"]["temp"]
humidity = data["main"]["humidity"]
wind_speed = data["wind"]["speed"]
return f"Weather in {city}: {temperature}°C"
except requests.RequestException as e:
return f"Error fetching weather data: {str(e)}"
`;
export const formatHandler = async () => {

View File

@ -8,15 +8,18 @@
const dispatch = createEventDispatcher();
let formElement = null;
let loading = false;
let id = '';
let name = '';
let meta = {
export let edit = false;
export let id = '';
export let name = '';
export let meta = {
description: ''
};
let content = '';
export let content = '';
$: if (name) {
id = name.replace(/\s+/g, '_').toLowerCase();
@ -49,6 +52,7 @@
<div class=" flex flex-col justify-between w-full overflow-y-auto h-full">
<div class="mx-auto w-full md:px-0 h-full">
<form
bind:this={formElement}
class=" flex flex-col max-h-[100dvh] h-full"
on:submit|preventDefault={() => {
submitHandler();
@ -60,6 +64,7 @@
on:click={() => {
goto('/workspace/tools');
}}
type="button"
>
<div class=" self-center">
<svg
@ -96,6 +101,7 @@
placeholder="Toolkit ID (e.g. my_toolkit)"
bind:value={id}
required
disabled={edit}
/>
</div>
<input
@ -112,8 +118,9 @@
bind:value={content}
bind:this={codeEditor}
on:save={() => {
// submit form
submitHandler();
if (formElement) {
formElement.requestSubmit();
}
}}
/>
</div>

View File

@ -1,8 +1,28 @@
<script>
import { goto } from '$app/navigation';
import { createNewTool, getTools } from '$lib/apis/tools';
import ToolkitEditor from '$lib/components/workspace/Tools/ToolkitEditor.svelte';
import { tools } from '$lib/stores';
import { toast } from 'svelte-sonner';
const saveHandler = async (data) => {
console.log(data);
const res = await createNewTool(localStorage.token, {
id: data.id,
name: data.name,
meta: data.meta,
content: data.content
}).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Tool created successfully');
tools.set(await getTools(localStorage.token));
await goto('/workspace/tools');
}
};
</script>

View File

@ -1,5 +1,57 @@
<script>
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { getToolById, getTools, updateToolById } from '$lib/apis/tools';
import ToolkitEditor from '$lib/components/workspace/Tools/ToolkitEditor.svelte';
import { tools } from '$lib/stores';
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
let tool = null;
const saveHandler = async (data) => {
console.log(data);
const res = await updateToolById(localStorage.token, tool.id, {
id: data.id,
name: data.name,
meta: data.meta,
content: data.content
}).catch((error) => {
toast.error(error);
return null;
});
if (res) {
toast.success('Tool updated successfully');
tools.set(await getTools(localStorage.token));
await goto('/workspace/tools');
}
};
onMount(async () => {
console.log('mounted');
const id = $page.url.searchParams.get('id');
if (id) {
tool = await getToolById(localStorage.token, id).catch((error) => {
toast.error(error);
goto('/workspace/tools');
return null;
});
}
});
</script>
<ToolkitEditor />
{#if tool}
<ToolkitEditor
edit={true}
id={tool.id}
name={tool.name}
meta={tool.meta}
content={tool.content}
on:save={(e) => {
saveHandler(e.detail);
}}
/>
{/if}