Merge branch 'main' of https://git.johncosta.tech/JohnCosta27/Haystack
This commit is contained in:
200
backend/agents/event_agent.go
Normal file
200
backend/agents/event_agent.go
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||||
|
"screenmark/screenmark/agents/client"
|
||||||
|
"screenmark/screenmark/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const eventPrompt = `
|
||||||
|
You are an agent.
|
||||||
|
|
||||||
|
The user will send you images and you have to identify if they have any events or a place.
|
||||||
|
This could be a friend suggesting to meet, a conference, or anything that looks like an event.
|
||||||
|
|
||||||
|
There are various tools you can use to perform this task.
|
||||||
|
|
||||||
|
listEvents
|
||||||
|
Lists the users already existing events, you should do this before using createEvents to avoid creating duplicates.
|
||||||
|
|
||||||
|
createEvent
|
||||||
|
Use this to create a new events.
|
||||||
|
|
||||||
|
linkEvent
|
||||||
|
Links an image to a events.
|
||||||
|
|
||||||
|
finish
|
||||||
|
Call when there is nothing else to do.
|
||||||
|
`
|
||||||
|
|
||||||
|
const eventTools = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "listEvents",
|
||||||
|
"description": "List the events the user already has.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "createEvent",
|
||||||
|
"description": "Use to create a new events",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"startDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The start time as an ISO string"
|
||||||
|
},
|
||||||
|
"endDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The end time as an ISO string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "linkEvent",
|
||||||
|
"description": "Use to link an already existing events to the image you were sent",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"eventId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["eventsId"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "finish",
|
||||||
|
"description": "Call this when there is nothing left to do.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
type EventAgent struct {
|
||||||
|
client client.AgentClient
|
||||||
|
|
||||||
|
eventsModel models.EventModel
|
||||||
|
}
|
||||||
|
|
||||||
|
type listEventArguments struct{}
|
||||||
|
type createEventArguments struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
StartDateTime *string `json:"startDateTime"`
|
||||||
|
EndDateTime *string `json:"endDateTime"`
|
||||||
|
OrganizerName *string `json:"organizerName"`
|
||||||
|
}
|
||||||
|
type linkEventArguments struct {
|
||||||
|
EventID string `json:"eventId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventAgent(eventsModel models.EventModel) (EventAgent, error) {
|
||||||
|
agentClient, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
||||||
|
ReportTimestamp: true,
|
||||||
|
TimeFormat: time.Kitchen,
|
||||||
|
Prefix: "Events 📍",
|
||||||
|
}))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return EventAgent{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := EventAgent{
|
||||||
|
client: agentClient,
|
||||||
|
eventsModel: eventsModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("listEvents", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
return agent.eventsModel.List(context.Background(), info.UserId)
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("createEvent", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := createEventArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
layout := "2006-01-02T15:04:05Z"
|
||||||
|
|
||||||
|
startTime, err := time.Parse(layout, *args.StartDateTime)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endTime, err := time.Parse(layout, *args.EndDateTime)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := agent.eventsModel.Save(ctx, info.UserId, model.Events{
|
||||||
|
Name: args.Name,
|
||||||
|
StartDateTime: &startTime,
|
||||||
|
EndDateTime: &endTime,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = agent.eventsModel.SaveToImage(ctx, info.ImageId, events.ID)
|
||||||
|
if err != nil {
|
||||||
|
return model.Events{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return events, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("linkEvent", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := linkEventArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
contactUuid, err := uuid.Parse(args.EventID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.eventsModel.SaveToImage(ctx, info.ImageId, contactUuid)
|
||||||
|
return "Saved", nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return agent, nil
|
||||||
|
}
|
@ -1,267 +0,0 @@
|
|||||||
package agents
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"os"
|
|
||||||
"screenmark/screenmark/.gen/haystack/haystack/model"
|
|
||||||
"screenmark/screenmark/agents/client"
|
|
||||||
"screenmark/screenmark/models"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This prompt is probably shit.
|
|
||||||
const eventLocationPrompt = `
|
|
||||||
You are an agent that extracts events, locations, and organizers from an image. Your primary tasks are to identify and create locations and organizers before creating events. Follow these steps:
|
|
||||||
|
|
||||||
Identify and Create Locations:
|
|
||||||
|
|
||||||
Check if the image contains a location.
|
|
||||||
If a location is found, check if it exists in the listLocations.
|
|
||||||
If the location does not exist, create it first.
|
|
||||||
Always reuse existing locations from listLocations to avoid duplicates.
|
|
||||||
|
|
||||||
Identify and Create Events:
|
|
||||||
|
|
||||||
Check if the image contains an event. An event should have a name and a date.
|
|
||||||
If an event is found, ensure you have a location (from step 1) and an organizer (from step 2) before creating the event.
|
|
||||||
Events must have an associated location and organizer. Do not create an event without these.
|
|
||||||
If possible, return a start time and an end time as ISO datetime strings.
|
|
||||||
Handling Images Without Events or Locations:
|
|
||||||
|
|
||||||
It is possible that the image does not contain an event or a location. In such cases, do not create an event.
|
|
||||||
Always prioritize the creation of locations and organizers before events. Ensure that all events have an associated location and organizer.
|
|
||||||
`
|
|
||||||
|
|
||||||
// TODO: this should be read directly from a file on load.
|
|
||||||
const eventLocationTools = `
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "createLocation",
|
|
||||||
"description": "Creates a location. No not use if you think an existing location is suitable!",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"address": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "listLocations",
|
|
||||||
"description": "Lists the locations available",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "createEvent",
|
|
||||||
"description": "Creates a new event",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"startDateTime": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The start time as an ISO string"
|
|
||||||
},
|
|
||||||
"endDateTime": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The end time as an ISO string"
|
|
||||||
},
|
|
||||||
"locationId": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The ID of the location, available by listLocations"
|
|
||||||
},
|
|
||||||
"organizerName": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The name of the organizer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "finish",
|
|
||||||
"description": "Nothing else to do. call this function.",
|
|
||||||
"parameters": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`
|
|
||||||
|
|
||||||
type EventLocationAgent struct {
|
|
||||||
client client.AgentClient
|
|
||||||
|
|
||||||
eventModel models.EventModel
|
|
||||||
locationModel models.LocationModel
|
|
||||||
contactModel models.ContactModel
|
|
||||||
|
|
||||||
toolHandler client.ToolsHandlers
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO make these private
|
|
||||||
|
|
||||||
type ListLocationArguments struct{}
|
|
||||||
type ListOrganizerArguments struct{}
|
|
||||||
|
|
||||||
type CreateLocationArguments struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Address *string `json:"address,omitempty"`
|
|
||||||
Coordinates *string `json:"coordinates,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateOrganizerArguments struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
PhoneNumber *string `json:"phoneNumber,omitempty"`
|
|
||||||
Email *string `json:"email,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AttachImageLocationArguments struct {
|
|
||||||
LocationId string `json:"locationId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateEventArguments struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
StartDateTime string `json:"startDateTime"`
|
|
||||||
EndDateTime string `json:"endDateTime"`
|
|
||||||
LocationId string `json:"locationId"`
|
|
||||||
OrganizerName string `json:"organizerName"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewLocationEventAgent(locationModel models.LocationModel, eventModel models.EventModel, contactModel models.ContactModel) (EventLocationAgent, error) {
|
|
||||||
agentClient, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
|
||||||
ReportTimestamp: true,
|
|
||||||
TimeFormat: time.Kitchen,
|
|
||||||
Prefix: "Location & Events 📅",
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
return EventLocationAgent{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
agent := EventLocationAgent{
|
|
||||||
client: agentClient,
|
|
||||||
locationModel: locationModel,
|
|
||||||
eventModel: eventModel,
|
|
||||||
contactModel: contactModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("listLocations",
|
|
||||||
func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
||||||
return agent.locationModel.List(context.Background(), info.UserId)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("createLocation",
|
|
||||||
func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
|
||||||
args := CreateLocationArguments{}
|
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
|
||||||
if err != nil {
|
|
||||||
return model.Locations{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
location, err := agent.locationModel.Save(ctx, info.UserId, model.Locations{
|
|
||||||
Name: args.Name,
|
|
||||||
Address: args.Address,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return location, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = agent.locationModel.SaveToImage(ctx, info.ImageId, location.ID)
|
|
||||||
|
|
||||||
return location, err
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("createEvent",
|
|
||||||
func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
|
||||||
args := CreateEventArguments{}
|
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
|
||||||
if err != nil {
|
|
||||||
return model.Locations{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
layout := "2006-01-02T15:04:05Z"
|
|
||||||
|
|
||||||
startTime, err := time.Parse(layout, args.StartDateTime)
|
|
||||||
if err != nil {
|
|
||||||
return model.Events{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
endTime, err := time.Parse(layout, args.EndDateTime)
|
|
||||||
if err != nil {
|
|
||||||
return model.Events{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
event, err := agent.eventModel.Save(ctx, info.UserId, model.Events{
|
|
||||||
Name: args.Name,
|
|
||||||
StartDateTime: &startTime,
|
|
||||||
EndDateTime: &endTime,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
organizer, err := agent.contactModel.Save(ctx, info.UserId, model.Contacts{
|
|
||||||
Name: args.Name,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = agent.eventModel.SaveToImage(ctx, info.ImageId, event.ID)
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = agent.contactModel.SaveToImage(ctx, info.ImageId, organizer.ID)
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
locationId, err := uuid.Parse(args.LocationId)
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
event, err = agent.eventModel.UpdateLocation(ctx, event.ID, locationId)
|
|
||||||
if err != nil {
|
|
||||||
return event, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return agent.eventModel.UpdateOrganizer(ctx, event.ID, organizer.ID)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return agent, nil
|
|
||||||
}
|
|
179
backend/agents/location_agent.go
Normal file
179
backend/agents/location_agent.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package agents
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"screenmark/screenmark/.gen/haystack/haystack/model"
|
||||||
|
"screenmark/screenmark/agents/client"
|
||||||
|
"screenmark/screenmark/models"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const locationPrompt = `
|
||||||
|
You are an agent.
|
||||||
|
|
||||||
|
The user will send you images and you have to identify if they have any location or a place. This could a picture of a real place, an address, or it's name.
|
||||||
|
|
||||||
|
There are various tools you can use to perform this task.
|
||||||
|
|
||||||
|
listLocations
|
||||||
|
Lists the users already existing locations, you should do this before using createLocation to avoid creating duplicates.
|
||||||
|
|
||||||
|
createLocation
|
||||||
|
Use this to create a new location. Avoid making duplicates and only create a new location if listLocations doesnt contain the location on the image.
|
||||||
|
|
||||||
|
linkLocation
|
||||||
|
Links an image to a location.
|
||||||
|
|
||||||
|
finish
|
||||||
|
Call when there is nothing else to do.
|
||||||
|
`
|
||||||
|
|
||||||
|
const locationTools = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "listLocations",
|
||||||
|
"description": "List the locations the user already has.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "createLocation",
|
||||||
|
"description": "Use to create a new location",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "linkLocation",
|
||||||
|
"description": "Use to link an already existing location to the image you were sent",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"locationId": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["locationId"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "finish",
|
||||||
|
"description": "Call this when there is nothing left to do.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
type LocationAgent struct {
|
||||||
|
client client.AgentClient
|
||||||
|
|
||||||
|
locationModel models.LocationModel
|
||||||
|
}
|
||||||
|
|
||||||
|
type listLocationArguments struct{}
|
||||||
|
type createLocationArguments struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Address *string `json:"address"`
|
||||||
|
}
|
||||||
|
type linkLocationArguments struct {
|
||||||
|
LocationID string `json:"locationId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLocationAgent(locationModel models.LocationModel) (LocationAgent, error) {
|
||||||
|
agentClient, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
||||||
|
ReportTimestamp: true,
|
||||||
|
TimeFormat: time.Kitchen,
|
||||||
|
Prefix: "Locations 📍",
|
||||||
|
}))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return LocationAgent{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent := LocationAgent{
|
||||||
|
client: agentClient,
|
||||||
|
locationModel: locationModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("listLocations", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
return agent.locationModel.List(context.Background(), info.UserId)
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("createLocation", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := createLocationArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return model.Locations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
location, err := agent.locationModel.Save(ctx, info.UserId, model.Locations{
|
||||||
|
Name: args.Name,
|
||||||
|
Address: args.Address,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return model.Locations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = agent.locationModel.SaveToImage(ctx, info.ImageId, location.ID)
|
||||||
|
if err != nil {
|
||||||
|
return model.Locations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return location, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
agentClient.ToolHandler.AddTool("linkLocation", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
||||||
|
args := linkLocationArguments{}
|
||||||
|
err := json.Unmarshal([]byte(_args), &args)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
contactUuid, err := uuid.Parse(args.LocationID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.locationModel.SaveToImage(ctx, info.ImageId, contactUuid)
|
||||||
|
return "Saved", nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return agent, nil
|
||||||
|
}
|
@ -20,17 +20,18 @@ The agents are available as tool calls.
|
|||||||
|
|
||||||
Agents available:
|
Agents available:
|
||||||
|
|
||||||
eventLocationAgent
|
|
||||||
Use it when you think the image contains an event or a location of any sort. This can be an event page, a map, an address or a date.
|
|
||||||
This could also be a conversation describing an event.
|
|
||||||
|
|
||||||
noteAgent
|
noteAgent
|
||||||
Use when there is ANY text on the image.
|
Use when there is ANY text on the image.
|
||||||
|
|
||||||
contactAgent
|
contactAgent
|
||||||
|
|
||||||
Use it when the image contains information relating a person.
|
Use it when the image contains information relating a person.
|
||||||
|
|
||||||
|
locationAgent
|
||||||
|
Use it when the image contains some address or a place.
|
||||||
|
|
||||||
|
eventAgent
|
||||||
|
Use it when the image contains an event, this can be a date, a message suggesting an event.
|
||||||
|
|
||||||
noAction
|
noAction
|
||||||
When you think there is no more information to extract from the image.
|
When you think there is no more information to extract from the image.
|
||||||
|
|
||||||
@ -41,18 +42,6 @@ Do not call the agent if you do not think it is relevant for the image.
|
|||||||
|
|
||||||
const OrchestratorTools = `
|
const OrchestratorTools = `
|
||||||
[
|
[
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "eventLocationAgent",
|
|
||||||
"description": "Use when there is an event or location on the image. This could be in writing form",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {},
|
|
||||||
"required": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
@ -76,6 +65,30 @@ const OrchestratorTools = `
|
|||||||
"required": []
|
"required": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "locationAgent",
|
||||||
|
"description": "Use when then image contains some place, location or address",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "eventAgent",
|
||||||
|
"description": "Use when then image contains some event",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
@ -101,7 +114,7 @@ type Status struct {
|
|||||||
Ok bool `json:"ok"`
|
Ok bool `json:"ok"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOrchestratorAgent(eventLocationAgent EventLocationAgent, noteAgent NoteAgent, contactAgent ContactAgent, imageName string, imageData []byte) (OrchestratorAgent, error) {
|
func NewOrchestratorAgent(noteAgent NoteAgent, contactAgent ContactAgent, locationAgent LocationAgent, eventAgent EventAgent, imageName string, imageData []byte) (OrchestratorAgent, error) {
|
||||||
agent, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
agent, err := client.CreateAgentClient(log.NewWithOptions(os.Stdout, log.Options{
|
||||||
ReportTimestamp: true,
|
ReportTimestamp: true,
|
||||||
TimeFormat: time.Kitchen,
|
TimeFormat: time.Kitchen,
|
||||||
@ -112,17 +125,6 @@ func NewOrchestratorAgent(eventLocationAgent EventLocationAgent, noteAgent NoteA
|
|||||||
return OrchestratorAgent{}, err
|
return OrchestratorAgent{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.ToolHandler.AddTool("eventLocationAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
|
||||||
// We need a way to keep track of this async?
|
|
||||||
// Probably just a DB, because we don't want to wait. The orchistrator shouldnt wait for this stuff to finish.
|
|
||||||
|
|
||||||
go eventLocationAgent.client.RunAgent(eventLocationPrompt, eventLocationTools, "finish", info.UserId, info.ImageId, imageName, imageData)
|
|
||||||
|
|
||||||
return Status{
|
|
||||||
Ok: true,
|
|
||||||
}, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
agent.ToolHandler.AddTool("noteAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
agent.ToolHandler.AddTool("noteAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
go noteAgent.GetNotes(info.UserId, info.ImageId, imageName, imageData)
|
go noteAgent.GetNotes(info.UserId, info.ImageId, imageName, imageData)
|
||||||
|
|
||||||
@ -139,6 +141,22 @@ func NewOrchestratorAgent(eventLocationAgent EventLocationAgent, noteAgent NoteA
|
|||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
agent.ToolHandler.AddTool("locationAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
go locationAgent.client.RunAgent(locationPrompt, locationTools, "finish", info.UserId, info.ImageId, imageName, imageData)
|
||||||
|
|
||||||
|
return Status{
|
||||||
|
Ok: true,
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
agent.ToolHandler.AddTool("eventAgent", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
|
go eventAgent.client.RunAgent(eventPrompt, eventTools, "finish", info.UserId, info.ImageId, imageName, imageData)
|
||||||
|
|
||||||
|
return Status{
|
||||||
|
Ok: true,
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
|
||||||
agent.ToolHandler.AddTool("noAction", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
agent.ToolHandler.AddTool("noAction", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
// To nothing
|
// To nothing
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ func CreateMailClient() (Mailer, error) {
|
|||||||
|
|
||||||
client, err := mail.NewClient(
|
client, err := mail.NewClient(
|
||||||
"smtp.mailbox.org",
|
"smtp.mailbox.org",
|
||||||
|
mail.WithTLSPortPolicy(mail.TLSMandatory),
|
||||||
mail.WithSMTPAuth(mail.SMTPAuthPlain),
|
mail.WithSMTPAuth(mail.SMTPAuthPlain),
|
||||||
mail.WithUsername(os.Getenv("EMAIL_USERNAME")),
|
mail.WithUsername(os.Getenv("EMAIL_USERNAME")),
|
||||||
mail.WithPassword(os.Getenv("EMAIL_PASSWORD")),
|
mail.WithPassword(os.Getenv("EMAIL_PASSWORD")),
|
||||||
|
@ -42,11 +42,6 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
locationAgent, err := agents.NewLocationEventAgent(locationModel, eventModel, contactModel)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
noteAgent, err := agents.NewNoteAgent(noteModel)
|
noteAgent, err := agents.NewNoteAgent(noteModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -57,6 +52,16 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
locationAgent, err := agents.NewLocationAgent(locationModel)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
eventAgent, err := agents.NewEventAgent(eventModel)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
image, err := imageModel.GetToProcessWithData(ctx, imageId)
|
image, err := imageModel.GetToProcessWithData(ctx, imageId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to GetToProcessWithData")
|
log.Println("Failed to GetToProcessWithData")
|
||||||
@ -70,7 +75,7 @@ func ListenNewImageEvents(db *sql.DB, eventManager *EventManager) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
orchestrator, err := agents.NewOrchestratorAgent(locationAgent, noteAgent, contactAgent, image.Image.ImageName, image.Image.Image)
|
orchestrator, err := agents.NewOrchestratorAgent(noteAgent, contactAgent, locationAgent, eventAgent, image.Image.ImageName, image.Image.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,20 @@ type EventModel struct {
|
|||||||
dbPool *sql.DB
|
dbPool *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m EventModel) List(ctx context.Context, userId uuid.UUID) ([]model.Events, error) {
|
||||||
|
listEventsStmt := SELECT(Events.AllColumns).
|
||||||
|
FROM(
|
||||||
|
Events.
|
||||||
|
INNER_JOIN(UserEvents, UserEvents.EventID.EQ(Events.ID)),
|
||||||
|
).
|
||||||
|
WHERE(UserEvents.UserID.EQ(UUID(userId)))
|
||||||
|
|
||||||
|
events := []model.Events{}
|
||||||
|
|
||||||
|
err := listEventsStmt.QueryContext(ctx, m.dbPool, &events)
|
||||||
|
return events, err
|
||||||
|
}
|
||||||
|
|
||||||
func (m EventModel) Save(ctx context.Context, userId uuid.UUID, event model.Events) (model.Events, error) {
|
func (m EventModel) Save(ctx context.Context, userId uuid.UUID, event model.Events) (model.Events, error) {
|
||||||
// TODO tx here
|
// TODO tx here
|
||||||
insertEventStmt := Events.
|
insertEventStmt := Events.
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
. "screenmark/screenmark/.gen/haystack/haystack/table"
|
||||||
|
|
||||||
. "github.com/go-jet/jet/v2/postgres"
|
. "github.com/go-jet/jet/v2/postgres"
|
||||||
|
"github.com/go-jet/jet/v2/qrm"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
@ -51,13 +52,32 @@ func (m LocationModel) Save(ctx context.Context, userId uuid.UUID, location mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m LocationModel) SaveToImage(ctx context.Context, imageId uuid.UUID, locationId uuid.UUID) (model.ImageLocations, error) {
|
func (m LocationModel) SaveToImage(ctx context.Context, imageId uuid.UUID, locationId uuid.UUID) (model.ImageLocations, error) {
|
||||||
|
imageLocation := model.ImageLocations{}
|
||||||
|
|
||||||
|
checkExistingStmt := ImageLocations.
|
||||||
|
SELECT(ImageLocations.AllColumns).
|
||||||
|
WHERE(
|
||||||
|
ImageLocations.ImageID.EQ(UUID(imageId)).
|
||||||
|
AND(ImageLocations.LocationID.EQ(UUID(locationId))),
|
||||||
|
)
|
||||||
|
|
||||||
|
err := checkExistingStmt.QueryContext(ctx, m.dbPool, &imageLocation)
|
||||||
|
if err != nil && err != qrm.ErrNoRows {
|
||||||
|
// A real error
|
||||||
|
return model.ImageLocations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// Already exists.
|
||||||
|
return imageLocation, nil
|
||||||
|
}
|
||||||
|
|
||||||
insertImageLocationStmt := ImageLocations.
|
insertImageLocationStmt := ImageLocations.
|
||||||
INSERT(ImageLocations.ImageID, ImageLocations.LocationID).
|
INSERT(ImageLocations.ImageID, ImageLocations.LocationID).
|
||||||
VALUES(imageId, locationId).
|
VALUES(imageId, locationId).
|
||||||
RETURNING(ImageLocations.AllColumns)
|
RETURNING(ImageLocations.AllColumns)
|
||||||
|
|
||||||
imageLocation := model.ImageLocations{}
|
err = insertImageLocationStmt.QueryContext(ctx, m.dbPool, &imageLocation)
|
||||||
err := insertImageLocationStmt.QueryContext(ctx, m.dbPool, &imageLocation)
|
|
||||||
|
|
||||||
return imageLocation, err
|
return imageLocation, err
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,44 @@
|
|||||||
{
|
{
|
||||||
"name": "haystack",
|
"name": "haystack",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Screenshots that organize themselves",
|
"description": "Screenshots that organize themselves",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
"lint": "bunx @biomejs/biome lint .",
|
"lint": "bunx @biomejs/biome lint .",
|
||||||
"format": "bunx @biomejs/biome format . --write"
|
"format": "bunx @biomejs/biome format . --write"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "^0.13.9",
|
"@kobalte/core": "^0.13.9",
|
||||||
"@kobalte/tailwindcss": "^0.9.0",
|
"@kobalte/tailwindcss": "^0.9.0",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
"@tabler/icons-solidjs": "^3.30.0",
|
"@tabler/icons-solidjs": "^3.30.0",
|
||||||
"@tauri-apps/api": "^2",
|
"@tauri-apps/api": "^2",
|
||||||
"@tauri-apps/plugin-dialog": "~2",
|
"@tauri-apps/plugin-dialog": "~2",
|
||||||
"@tauri-apps/plugin-global-shortcut": "~2",
|
"@tauri-apps/plugin-http": "~2",
|
||||||
"@tauri-apps/plugin-opener": "^2",
|
"@tauri-apps/plugin-opener": "^2",
|
||||||
"@tauri-apps/plugin-store": "~2",
|
"clsx": "^2.1.1",
|
||||||
"clsx": "^2.1.1",
|
"fuse.js": "^7.1.0",
|
||||||
"fuse.js": "^7.1.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"jwt-decode": "^4.0.0",
|
"solid-js": "^1.9.3",
|
||||||
"solid-js": "^1.9.3",
|
"solid-motionone": "^1.0.3",
|
||||||
"solid-motionone": "^1.0.3",
|
"tailwind-scrollbar-hide": "^2.0.0",
|
||||||
"tailwind-scrollbar-hide": "^2.0.0",
|
"valibot": "^1.0.0-rc.2"
|
||||||
"valibot": "^1.0.0-rc.2"
|
},
|
||||||
},
|
"devDependencies": {
|
||||||
"devDependencies": {
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@tauri-apps/cli": "^2",
|
||||||
"@tauri-apps/cli": "^2",
|
"autoprefixer": "^10.4.20",
|
||||||
"autoprefixer": "^10.4.20",
|
"postcss": "^8.5.3",
|
||||||
"postcss": "^8.5.3",
|
"postcss-cli": "^11.0.0",
|
||||||
"postcss-cli": "^11.0.0",
|
"tailwindcss": "3.4.0",
|
||||||
"tailwindcss": "3.4.0",
|
"typescript": "~5.6.2",
|
||||||
"typescript": "~5.6.2",
|
"vite": "^6.0.3",
|
||||||
"vite": "^6.0.3",
|
"vite-plugin-solid": "^2.11.0"
|
||||||
"vite-plugin-solid": "^2.11.0"
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ notify = "6.1.1"
|
|||||||
base64 = "0.21.7"
|
base64 = "0.21.7"
|
||||||
tokio = { version = "1.36.0", features = ["full"] }
|
tokio = { version = "1.36.0", features = ["full"] }
|
||||||
tauri-plugin-store = "2"
|
tauri-plugin-store = "2"
|
||||||
|
tauri-plugin-http = "2"
|
||||||
|
|
||||||
[target."cfg(target_os = \"macos\")".dependencies]
|
[target."cfg(target_os = \"macos\")".dependencies]
|
||||||
cocoa = "0.26"
|
cocoa = "0.26"
|
||||||
|
@ -11,6 +11,11 @@
|
|||||||
"global-shortcut:allow-is-registered",
|
"global-shortcut:allow-is-registered",
|
||||||
"global-shortcut:allow-register",
|
"global-shortcut:allow-register",
|
||||||
"global-shortcut:allow-unregister",
|
"global-shortcut:allow-unregister",
|
||||||
"global-shortcut:allow-unregister-all"
|
"global-shortcut:allow-unregister-all",
|
||||||
|
"http:default",
|
||||||
|
{
|
||||||
|
"identifier": "http:default",
|
||||||
|
"allow": [{ "url": "https://haystack.johncosta.tech" }]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ pub fn run() {
|
|||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_store::Builder::new().build())
|
.plugin(tauri_plugin_store::Builder::new().build())
|
||||||
|
.plugin(tauri_plugin_http::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.manage(watcher_state)
|
.manage(watcher_state)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Button } from "@kobalte/core/button";
|
import { Button } from "@kobalte/core/button";
|
||||||
import { TextField } from "@kobalte/core/text-field";
|
import { TextField } from "@kobalte/core/text-field";
|
||||||
import { createSignal, Show, type Component } from "solid-js";
|
import { createSignal, Show, type Component } from "solid-js";
|
||||||
import { postCode, postLogin } from "./network";
|
import { base, postCode, postLogin } from "./network";
|
||||||
import { isTokenValid } from "./ProtectedRoute";
|
import { isTokenValid } from "./ProtectedRoute";
|
||||||
import { Navigate } from "@solidjs/router";
|
import { Navigate } from "@solidjs/router";
|
||||||
|
|
||||||
@ -40,20 +40,23 @@ export const Login: Component = () => {
|
|||||||
const isAuthorized = isTokenValid();
|
const isAuthorized = isTokenValid();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={!isAuthorized} fallback={<Navigate href="/" />}>
|
<>
|
||||||
<form ref={form} onSubmit={onSubmit}>
|
{base}
|
||||||
<TextField name="email">
|
<Show when={!isAuthorized} fallback={<Navigate href="/" />}>
|
||||||
<TextField.Label>Email</TextField.Label>
|
<form ref={form} onSubmit={onSubmit}>
|
||||||
<TextField.Input />
|
<TextField name="email">
|
||||||
</TextField>
|
<TextField.Label>Email</TextField.Label>
|
||||||
<Show when={submitted()}>
|
|
||||||
<TextField name="code">
|
|
||||||
<TextField.Label>Code</TextField.Label>
|
|
||||||
<TextField.Input />
|
<TextField.Input />
|
||||||
</TextField>
|
</TextField>
|
||||||
</Show>
|
<Show when={submitted()}>
|
||||||
<Button type="submit">Submit</Button>
|
<TextField name="code">
|
||||||
</form>
|
<TextField.Label>Code</TextField.Label>
|
||||||
</Show>
|
<TextField.Input />
|
||||||
|
</TextField>
|
||||||
|
</Show>
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
</Show>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { fetch } from "@tauri-apps/plugin-http";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type InferOutput,
|
type InferOutput,
|
||||||
array,
|
array,
|
||||||
@ -17,8 +19,12 @@ type BaseRequestParams = Partial<{
|
|||||||
method: "GET" | "POST";
|
method: "GET" | "POST";
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
export const base = import.meta.env.DEV
|
||||||
|
? "http://localhost:3040"
|
||||||
|
: "https://haystack.johncosta.tech";
|
||||||
|
|
||||||
const getBaseRequest = ({ path, body, method }: BaseRequestParams): Request => {
|
const getBaseRequest = ({ path, body, method }: BaseRequestParams): Request => {
|
||||||
return new Request(`http://localhost:3040/${path}`, {
|
return new Request(`${base}/${path}`, {
|
||||||
body,
|
body,
|
||||||
method,
|
method,
|
||||||
});
|
});
|
||||||
@ -29,7 +35,7 @@ const getBaseAuthorizedRequest = ({
|
|||||||
body,
|
body,
|
||||||
method,
|
method,
|
||||||
}: BaseRequestParams): Request => {
|
}: BaseRequestParams): Request => {
|
||||||
return new Request(`http://localhost:3040/${path}`, {
|
return new Request(`${base}/${path}`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${localStorage.getItem("access")?.toString()}`,
|
Authorization: `Bearer ${localStorage.getItem("access")?.toString()}`,
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user