rentease/internal/driver/parser/client.go
Ruidy ac94faedb0
refactor: unify ID and API key naming conventions
This commit standardizes the naming of identifier and API key fields
across the codebase to use consistent camel case (e.g., `ID`, `APIKey`,
`DatabaseURL`). This includes updates to struct fields, method names,
function parameters, and environment variable references. The changes
improve code clarity and maintainability by reducing ambiguity and
aligning with Go naming conventions. No functional behavior is changed.
2025-10-03 19:47:41 +02:00

123 lines
3.5 KiB
Go

package parser
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/openai/openai-go"
"github.com/openai/openai-go/responses"
"github.com/rjNemo/rentease/internal/service/booking"
)
type BookingAgentParser struct {
systemPrompt string
llmClient openai.Client
}
func NewBookingAgentParser() *BookingAgentParser {
return &BookingAgentParser{
llmClient: openai.NewClient(),
systemPrompt: ` Extract the following fields from the booking content and return a JSON object with this exact structure (all fields required, use null or empty string if not available):
{
"data": {
"arrival_date": "YYYY-MM-DD",
"booking_fees": "number as string",
"booking_id": "string",
"departure_date": "YYYY-MM-DD",
"stay_length": int,
"guest_email": "string",
"guest_name": "string",
"guest_number": int,
"guest_phone": "string",
"room_booked": "string",
"standard_rate": "number as string",
"special_requests": "string"
}
}
Respond ONLY with the JSON object above, wrapped in a top-level "data" field as shown, no code fences.
Booking content:`,
}
}
// ResponseData is the expected structure returned by the LLM parser.
type ResponseData struct {
ArrivalDate string `json:"arrival_date"`
BookingFees json.Number `json:"booking_fees"`
BookingID string `json:"booking_id"`
DepartureDate string `json:"departure_date"`
StayLength int `json:"stay_length"`
GuestEmail string `json:"guest_email"`
GuestName string `json:"guest_name"`
GuestNumber int `json:"guest_number"`
GuestPhone string `json:"guest_phone"`
RoomBooked string `json:"room_booked"`
StandardRate json.Number `json:"standard_rate"`
SpecialRequests string `json:"special_requests"`
}
func (p *BookingAgentParser) Parse(rawContent string) (*booking.Booking, error) {
log.Println("sending request to OpenAI LLM parser")
ctx := context.Background()
prompt := p.systemPrompt + "\n" + rawContent
resp, err := p.llmClient.Responses.New(ctx, responses.ResponseNewParams{
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String(prompt)},
Model: openai.ChatModelChatgpt4oLatest,
})
if err != nil {
return nil, fmt.Errorf("error sending request to OpenAI: %w", err)
}
var r struct {
Data ResponseData `json:"data"`
}
// The LLM is instructed to return the JSON for ResponseData directly, so parse it
err = json.Unmarshal([]byte(resp.OutputText()), &r)
if err != nil {
return nil, fmt.Errorf("error decoding response from OpenAI: %w", err)
}
var b booking.Booking
b.From, err = time.Parse("2006-01-02", r.Data.ArrivalDate)
if err != nil {
return nil, fmt.Errorf("error parsing arrival_date: %w", err)
}
b.To, err = time.Parse("2006-01-02", r.Data.DepartureDate)
if err != nil {
return nil, fmt.Errorf("error parsing departure_date: %w", err)
}
b.Name = r.Data.GuestName
b.PhoneNumber = r.Data.GuestPhone
b.Email = r.Data.GuestEmail
b.CustomerNumber = r.Data.GuestNumber
bookingFees, err := r.Data.BookingFees.Float64()
if err != nil {
return nil, fmt.Errorf("error parsing booking fees: %w", err)
}
b.Platform = "Booking"
b.PlatformFees = bookingFees
b.ExternalID = &r.Data.BookingID
price, err := r.Data.StandardRate.Float64()
if err != nil {
return nil, fmt.Errorf("error parsing standard rate: %w", err)
}
b.Items = append(b.Items, booking.Item{
Item: r.Data.RoomBooked,
Quantity: r.Data.StayLength,
Price: price,
PaymentMethod: "Card",
})
return &b, nil
}