citelynq.websample/Program.cs

262 lines
8.8 KiB
C#

using System.Text;
using System.Text.Json;
var builder = WebApplication.CreateBuilder(args);
// Add services
builder.Services.AddHttpClient();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
app.UseCors();
app.UseDefaultFiles();
app.UseStaticFiles();
// Update this to point to your local API or production API
const string API_BASE_URL = "https://citelynq.com/api";
// Proxy endpoint for full-text search
app.MapGet("/api/search", async (HttpContext context, IHttpClientFactory httpClientFactory, ILogger<Program> logger) =>
{
try
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
{
return Results.BadRequest(new { error = "API key is required" });
}
// Get query parameters
var query = context.Request.Query["q"].FirstOrDefault();
var source = context.Request.Query["source"].FirstOrDefault();
var limit = context.Request.Query["limit"].FirstOrDefault() ?? "20";
if (string.IsNullOrEmpty(query))
{
return Results.BadRequest(new { error = "Search query (q) is required" });
}
// Build URL for CiteLynq API
var httpClient = httpClientFactory.CreateClient();
var url = $"{API_BASE_URL}/search?q={Uri.EscapeDataString(query)}&limit={limit}";
if (!string.IsNullOrEmpty(source))
{
url += $"&source={Uri.EscapeDataString(source)}";
}
logger.LogInformation("Calling CiteLynq API: {Url}", url);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
httpRequest.Headers.Add("X-API-Key", apiKey);
var response = await httpClient.SendAsync(httpRequest);
var responseContent = await response.Content.ReadAsStringAsync();
logger.LogInformation("CiteLynq API Response Status: {StatusCode}", response.StatusCode);
if (!response.IsSuccessStatusCode)
{
logger.LogError("CiteLynq API Error: {Response}", responseContent);
try
{
var errorObj = JsonSerializer.Deserialize<object>(responseContent);
return Results.Json(errorObj, statusCode: (int)response.StatusCode);
}
catch
{
return Results.Json(new { error = responseContent }, statusCode: (int)response.StatusCode);
}
}
return Results.Content(responseContent, "application/json");
}
catch (Exception ex)
{
logger.LogError(ex, "Error in search endpoint");
return Results.Json(new { error = ex.Message, details = ex.ToString() }, statusCode: 500);
}
});
// Proxy endpoint for semantic search
app.MapGet("/api/search/semantic", async (HttpContext context, IHttpClientFactory httpClientFactory, ILogger<Program> logger) =>
{
try
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
{
return Results.BadRequest(new { error = "API key is required" });
}
// Get query parameters
var query = context.Request.Query["q"].FirstOrDefault();
var source = context.Request.Query["source"].FirstOrDefault();
var limit = context.Request.Query["limit"].FirstOrDefault() ?? "20";
if (string.IsNullOrEmpty(query))
{
return Results.BadRequest(new { error = "Search query (q) is required" });
}
// Build URL for CiteLynq API
var httpClient = httpClientFactory.CreateClient();
var url = $"{API_BASE_URL}/search/semantic?q={Uri.EscapeDataString(query)}&limit={limit}";
if (!string.IsNullOrEmpty(source))
{
url += $"&source={Uri.EscapeDataString(source)}";
}
logger.LogInformation("Calling CiteLynq API: {Url}", url);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
httpRequest.Headers.Add("X-API-Key", apiKey);
var response = await httpClient.SendAsync(httpRequest);
var responseContent = await response.Content.ReadAsStringAsync();
logger.LogInformation("CiteLynq API Response Status: {StatusCode}", response.StatusCode);
if (!response.IsSuccessStatusCode)
{
logger.LogError("CiteLynq API Error: {Response}", responseContent);
try
{
var errorObj = JsonSerializer.Deserialize<object>(responseContent);
return Results.Json(errorObj, statusCode: (int)response.StatusCode);
}
catch
{
return Results.Json(new { error = responseContent }, statusCode: (int)response.StatusCode);
}
}
return Results.Content(responseContent, "application/json");
}
catch (Exception ex)
{
logger.LogError(ex, "Error in semantic search endpoint");
return Results.Json(new { error = ex.Message, details = ex.ToString() }, statusCode: 500);
}
});
// Proxy endpoint for date-based search
app.MapGet("/api/search/bydate", async (HttpContext context, IHttpClientFactory httpClientFactory, ILogger<Program> logger) =>
{
try
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
{
return Results.BadRequest(new { error = "API key is required" });
}
// Get query parameters
var query = context.Request.Query["q"].FirstOrDefault();
var month = context.Request.Query["month"].FirstOrDefault();
var day = context.Request.Query["day"].FirstOrDefault();
var source = context.Request.Query["source"].FirstOrDefault();
var limit = context.Request.Query["limit"].FirstOrDefault() ?? "20";
if (string.IsNullOrEmpty(query))
{
return Results.BadRequest(new { error = "Search query (q) is required" });
}
if (string.IsNullOrEmpty(month) || string.IsNullOrEmpty(day))
{
return Results.BadRequest(new { error = "Month and day parameters are required for date search" });
}
// Build URL for CiteLynq API
var httpClient = httpClientFactory.CreateClient();
var url = $"{API_BASE_URL}/search/bydate?q={Uri.EscapeDataString(query)}&month={month}&day={day}&limit={limit}";
if (!string.IsNullOrEmpty(source))
{
url += $"&source={Uri.EscapeDataString(source)}";
}
logger.LogInformation("Calling CiteLynq API: {Url}", url);
var httpRequest = new HttpRequestMessage(HttpMethod.Get, url);
httpRequest.Headers.Add("X-API-Key", apiKey);
var response = await httpClient.SendAsync(httpRequest);
var responseContent = await response.Content.ReadAsStringAsync();
logger.LogInformation("CiteLynq API Response Status: {StatusCode}", response.StatusCode);
if (!response.IsSuccessStatusCode)
{
logger.LogError("CiteLynq API Error: {Response}", responseContent);
try
{
var errorObj = JsonSerializer.Deserialize<object>(responseContent);
return Results.Json(errorObj, statusCode: (int)response.StatusCode);
}
catch
{
return Results.Json(new { error = responseContent }, statusCode: (int)response.StatusCode);
}
}
return Results.Content(responseContent, "application/json");
}
catch (Exception ex)
{
logger.LogError(ex, "Error in date search endpoint");
return Results.Json(new { error = ex.Message, details = ex.ToString() }, statusCode: 500);
}
});
// Proxy endpoint to get article details
app.MapGet("/api/articles/{id}", async (string id, HttpContext context, IHttpClientFactory httpClientFactory) =>
{
try
{
var apiKey = context.Request.Headers["X-API-Key"].FirstOrDefault();
if (string.IsNullOrEmpty(apiKey))
{
return Results.BadRequest(new { error = "API key is required" });
}
var httpClient = httpClientFactory.CreateClient();
var httpRequest = new HttpRequestMessage(HttpMethod.Get, $"{API_BASE_URL}/articles/{id}");
httpRequest.Headers.Add("X-API-Key", apiKey);
var response = await httpClient.SendAsync(httpRequest);
var responseContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
return Results.Json(
JsonSerializer.Deserialize<object>(responseContent),
statusCode: (int)response.StatusCode
);
}
return Results.Content(responseContent, "application/json");
}
catch (Exception ex)
{
return Results.Problem(ex.Message);
}
});
app.Run();