- IntelligenceModule: proxy tenant-scoped catre intelligence-api
(/companies/search, /companies/{id}); ceo-web nu vorbeste niciodata
direct cu intelligence-api (blueprint 10.3/16).
- SavedSegments: salveaza o cautare Apollo si o ruleaza din nou oricand.
- ResearchBriefs: dovezi curatate manual per companie, cu sursa Apollo
implicita plus surse suplimentare -- explicit fara rezumat generat de
AI (AI Gateway inca neconstruit, blueprint 14).
- BriefingService: /v1/briefing/today, agregare deterministica de
taskuri restante/viitoare + activitate saptamanala; campul
aiExplanation ramane null si vizibil in raspuns, nu simulat.
55 lines
2 KiB
TypeScript
55 lines
2 KiB
TypeScript
import { BadGatewayException, Injectable, NotFoundException } from '@nestjs/common';
|
|
import type { CompanySearchResponse, CompanySearchResult } from './intelligence.types';
|
|
|
|
const REQUEST_TIMEOUT_MS = 8000;
|
|
|
|
/**
|
|
* Client subtire catre intelligence-api. Blueprint 10.3/16: "company search prin
|
|
* Intelligence API, nu SQL direct" -- ceo-web nu vorbeste niciodata direct cu
|
|
* intelligence-api, ca sa putem adauga aici audit, quotas si viitorul AI Gateway
|
|
* fara sa schimbam contractul catre frontend.
|
|
*/
|
|
@Injectable()
|
|
export class IntelligenceService {
|
|
private readonly baseUrl = process.env.INTELLIGENCE_API_URL ?? 'http://localhost:8000';
|
|
|
|
async searchCompanies(query: string, limit: number): Promise<CompanySearchResponse> {
|
|
const response = await this.request('/companies/search', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ query, limit }),
|
|
});
|
|
return (await response.json()) as CompanySearchResponse;
|
|
}
|
|
|
|
async getCompany(organizationId: string): Promise<CompanySearchResult> {
|
|
const response = await this.request(`/companies/${encodeURIComponent(organizationId)}`);
|
|
const data = (await response.json()) as CompanySearchResult | { error: string };
|
|
if ('error' in data) {
|
|
throw new NotFoundException('Company not found in intelligence data');
|
|
}
|
|
return data;
|
|
}
|
|
|
|
private async request(path: string, init: RequestInit = {}): Promise<Response> {
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
try {
|
|
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
...init,
|
|
headers: { 'Content-Type': 'application/json', ...init.headers },
|
|
signal: controller.signal,
|
|
});
|
|
if (!response.ok) {
|
|
throw new BadGatewayException('intelligence-api request failed');
|
|
}
|
|
return response;
|
|
} catch (error) {
|
|
if (error instanceof BadGatewayException) {
|
|
throw error;
|
|
}
|
|
throw new BadGatewayException('intelligence-api unreachable');
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
}
|