Implement AI analysis trigger endpoint and refactor related components
- Added a new endpoint to trigger on-demand agentic analysis for tenders via the AI service. - Introduced `TriggerAIAnalyze` method in the `TenderHandler` to handle requests and responses for AI analysis. - Updated the `tenderService` to include `TriggerAIAnalyze` method, which validates input and interacts with the AI summarizer client. - Enhanced the `AIAnalyzeResponse` and `AIAnalyzeDocument` structures to support the new analysis feature. - Refactored the `DocumentSummarizationWorker` and `TranslationWorker` to remove deprecated MinIO dependencies, streamlining the AI service interactions. This update improves the functionality of the tender management system by allowing users to trigger AI analysis on-demand, enhancing the overall user experience and system capabilities.
This commit is contained in:
@@ -169,6 +169,118 @@ func (c *Client) TriggerPipelineTranslate(ctx context.Context, languages []strin
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// FetchAnalyzeOnDemand calls POST /ai/analyze for one tender.
|
||||
func (c *Client) FetchAnalyzeOnDemand(ctx context.Context, reqBody AnalyzeRequest) (*AnalyzeResponse, error) {
|
||||
jsonBody, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ai_summarizer: failed to marshal analyze request body: %w", err)
|
||||
}
|
||||
|
||||
url := c.config.APIBaseURL + "/ai/analyze"
|
||||
httpResp, bodyBytes, err := c.doRawPost(ctx, url, jsonBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
if httpResp.StatusCode == http.StatusNotFound {
|
||||
return nil, fmt.Errorf("%w: status 404, body: %s", ErrObjectNotFound, string(bodyBytes))
|
||||
}
|
||||
if httpResp.StatusCode >= 400 {
|
||||
return nil, fmt.Errorf("%w: status %d, body: %s", ErrAPINonSuccess, httpResp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
var result AnalyzeResponse
|
||||
if err := json.Unmarshal(bodyBytes, &result); err != nil {
|
||||
return nil, fmt.Errorf("ai_summarizer: failed to decode analyze response JSON: %w", err)
|
||||
}
|
||||
|
||||
c.logger.Info("AI analyze request succeeded", map[string]interface{}{
|
||||
"contract_folder_id": result.ContractFolderID,
|
||||
"notice_publication_id": result.NoticePublicationID,
|
||||
"iterations": result.Iterations,
|
||||
})
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// TriggerPipelineSync calls POST /pipeline/sync.
|
||||
func (c *Client) TriggerPipelineSync(ctx context.Context) (*PipelineActionResponse, error) {
|
||||
return c.triggerPipelineAction(ctx, "/pipeline/sync", "pipeline sync")
|
||||
}
|
||||
|
||||
// TriggerPipelineScrape calls POST /pipeline/scrape.
|
||||
func (c *Client) TriggerPipelineScrape(ctx context.Context) (*PipelineActionResponse, error) {
|
||||
return c.triggerPipelineAction(ctx, "/pipeline/scrape", "pipeline scrape")
|
||||
}
|
||||
|
||||
// TriggerPipelineSummarize calls POST /pipeline/summarize.
|
||||
func (c *Client) TriggerPipelineSummarize(ctx context.Context) (*PipelineActionResponse, error) {
|
||||
return c.triggerPipelineAction(ctx, "/pipeline/summarize", "pipeline summarize")
|
||||
}
|
||||
|
||||
// TriggerPipelineAnalyze calls POST /pipeline/analyze.
|
||||
func (c *Client) TriggerPipelineAnalyze(ctx context.Context) (*PipelineActionResponse, error) {
|
||||
return c.triggerPipelineAction(ctx, "/pipeline/analyze", "pipeline analyze")
|
||||
}
|
||||
|
||||
// TriggerPipelineDailyRun calls POST /pipeline/daily-run.
|
||||
func (c *Client) TriggerPipelineDailyRun(ctx context.Context) (*PipelineActionResponse, error) {
|
||||
return c.triggerPipelineAction(ctx, "/pipeline/daily-run", "pipeline daily-run")
|
||||
}
|
||||
|
||||
func (c *Client) triggerPipelineAction(ctx context.Context, path, label string) (*PipelineActionResponse, error) {
|
||||
url := c.config.APIBaseURL + path
|
||||
httpResp, bodyBytes, err := c.doRawPost(ctx, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
if httpResp.StatusCode >= 400 {
|
||||
return nil, fmt.Errorf("%w: status %d, body: %s", ErrAPINonSuccess, httpResp.StatusCode, string(bodyBytes))
|
||||
}
|
||||
|
||||
var result PipelineActionResponse
|
||||
if len(bodyBytes) > 0 {
|
||||
if err := json.Unmarshal(bodyBytes, &result); err != nil {
|
||||
return nil, fmt.Errorf("ai_summarizer: failed to decode %s response: %w", label, err)
|
||||
}
|
||||
}
|
||||
|
||||
c.logger.Info("AI pipeline action triggered", map[string]interface{}{
|
||||
"path": path,
|
||||
"status": result.Status,
|
||||
})
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (c *Client) doRawPost(ctx context.Context, url string, jsonBody []byte) (*http.Response, []byte, error) {
|
||||
var body io.Reader
|
||||
if len(jsonBody) > 0 {
|
||||
body = bytes.NewReader(jsonBody)
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("ai_summarizer: failed to create request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
httpResp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("ai_summarizer: request error: %w", err)
|
||||
}
|
||||
|
||||
bodyBytes, err := io.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
httpResp.Body.Close()
|
||||
return nil, nil, fmt.Errorf("ai_summarizer: failed to read response body: %w", err)
|
||||
}
|
||||
return httpResp, bodyBytes, nil
|
||||
}
|
||||
|
||||
// doPost performs a single POST request and parses the response.
|
||||
func (c *Client) doPost(ctx context.Context, url string, jsonBody []byte) (*SummarizeResponse, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(jsonBody))
|
||||
|
||||
Reference in New Issue
Block a user