Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ set(SOURCES
src/utils.cpp
src/prompts.cpp
src/config.cpp
src/core/metadata.cpp
)

# Get PostgreSQL version to handle platform-specific naming conventions
Expand Down
42 changes: 42 additions & 0 deletions src/core/metadata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "metadata.hpp"

using json = nlohmann::json;

json extractSources(const std::string& text) {
json sources = json::array();

if (text.find("ST_") != std::string::npos) {
sources.push_back({
{"title", "PostGIS Documentation"},
{"url", "https://postgis.net/docs/"}});
}

if (text.find("SELECT") != std::string::npos) {
sources.push_back({
{"title", "PostgreSQL SELECT"},
{"url", "https://www.postgresql.org/docs/current/sql-select.html"}});
}
Comment on lines +8 to +18
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you only cover select and Postgis queries for documentation, i don't think this should be done this way


return sources;
}

double calculateConfidence(const std::string& text) {
if (text.length() > 150) return 0.9;
if (text.length() > 50) return 0.75;
return 0.6;
}
Comment on lines +23 to +27
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this calculate ai confidence query ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question ... currently the confidence score is a simple heuristic, not derived from the AI model itself.

Right now it’s based on the length of the generated explanation:

  • Longer explanations are assumed to be more detailed → higher confidence
  • Shorter ones → lower confidence

This is just an initial placeholder to provide a basic signal to users.

In future iterations, this could be improved by:

  • Incorporating model-provided confidence (if available)
  • Using response structure/quality signals
  • Integrating external validation or scoring mechanisms

Happy to refine this approach based on suggestions.


json extractTags(const std::string& text) {
json tags = json::array();

if (text.find("ST_") != std::string::npos)
tags.push_back("postgis");

if (text.find("JOIN") != std::string::npos)
tags.push_back("join");

if (text.find("INDEX") != std::string::npos)
tags.push_back("performance");

return tags;
}
7 changes: 7 additions & 0 deletions src/core/metadata.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once
#include <string>
#include <nlohmann/json.hpp>

nlohmann::json extractSources(const std::string& text);
double calculateConfidence(const std::string& text);
nlohmann::json extractTags(const std::string& text);
8 changes: 8 additions & 0 deletions src/core/response_formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <sstream>
#include <string>
#include <nlohmann/json.hpp>
#include "metadata.hpp"

namespace pg_ai {
namespace {
Expand Down Expand Up @@ -72,6 +73,13 @@ std::string ResponseFormatter::createJSONResponse(
response["row_limit_applied"] = true;
}

// ✅ Add AI metadata (only if explanation exists)
if (!result.explanation.empty()) {
response["sources"] = extractSources(result.explanation);
response["confidence"] = calculateConfidence(result.explanation);
response["tags"] = extractTags(result.explanation);
}

return response.dump(2); // Pretty print with 2-space indentation
}

Expand Down
17 changes: 17 additions & 0 deletions tests/unit/test_metadata.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <cassert>
#include "/home/lucifer/Desktop/pg_ai_query/src/core/metadata.hpp"

int main() {
std::string text = "Use ST_Distance in PostGIS";

auto sources = extractSources(text);
assert(!sources.empty());

double conf = calculateConfidence(text);
assert(conf > 0);

auto tags = extractTags(text);
assert(!tags.empty());

return 0;
}
49 changes: 49 additions & 0 deletions tests/unit/test_response_formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,3 +342,52 @@ TEST_F(ResponseFormatterTest, JSONIsPrettyPrinted) {
// Pretty-printed JSON should contain newlines
EXPECT_THAT(output, testing::HasSubstr("\n"));
}

// Test that documentation links appear in formatted response

TEST_F(ResponseFormatterTest, IncludesPostgresDocumentationLink) {
QueryResult result = createBasicResult();

result.explanation =
"PostgreSQL indexes improve query performance. "
"See https://www.postgresql.org/docs/current/indexes.html";

Configuration config = createConfig(false, true, false, false);

std::string formatted =
pg_ai::ResponseFormatter::formatResponse(result, config);

EXPECT_NE(formatted.find("postgresql.org/docs"), std::string::npos);
}

// Test specific documentation page
TEST_F(ResponseFormatterTest, IndexDocumentationLinkPresent) {
QueryResult result = createBasicResult();

result.explanation =
"Documentation: https://www.postgresql.org/docs/current/indexes.html";

Configuration config = createConfig(false, true, false, false);

std::string formatted =
pg_ai::ResponseFormatter::formatResponse(result, config);

EXPECT_NE(formatted.find("indexes.html"), std::string::npos);
}
// Test when no documentation link exists
TEST_F(ResponseFormatterTest, HandlesMissingDocumentationLink) {
QueryResult result = createBasicResult();

result.explanation = "PostgreSQL indexes improve performance.";

Configuration config = createConfig(false, true, false, false);

std::string formatted =
pg_ai::ResponseFormatter::formatResponse(result, config);

EXPECT_EQ(formatted.find("postgresql.org/docs"), std::string::npos);
}