cevheri commited on
Commit
6b3e14e
Β·
1 Parent(s): e087162

ci:add version

Browse files
Files changed (2) hide show
  1. app.py +6 -3
  2. postgre_mcp_server.py +17 -17
app.py CHANGED
@@ -13,7 +13,7 @@ import logging
13
 
14
  # Load environment variables
15
  load_dotenv()
16
-
17
 
18
  # ======================================= Load DB configs
19
  def load_db_configs():
@@ -120,6 +120,8 @@ with gr.Blocks(css=custom_css, theme=xtheme) as demo:
120
  """
121
  <h1 style='text-align: center; margin-bottom: 1rem'>Talk to Your Data</h1>
122
  <p style='text-align: center'>Ask questions about your database, analyze and visualize data.</p>
 
 
123
  """
124
  )
125
  with gr.Row(elem_classes="container"):
@@ -130,7 +132,8 @@ with gr.Blocks(css=custom_css, theme=xtheme) as demo:
130
  height=1000,
131
  show_label=False,
132
  elem_classes="chat-container",
133
- render_markdown=True
 
134
  ),
135
  textbox=gr.Textbox(
136
  placeholder="Type your questions here...",
@@ -163,7 +166,7 @@ with gr.Blocks(css=custom_css, theme=xtheme) as demo:
163
  - πŸ‘₯ Total number of customers
164
  - πŸ“ˆ Top 10 customers by ticket count
165
  - πŸ“‹ Ticket count by status and visualize
166
- - πŸ“† Average ticket reopen count per month
167
  - 🧹 Clear memory : `/clear-cache`
168
  """)
169
 
 
13
 
14
  # Load environment variables
15
  load_dotenv()
16
+ VERSION = "0.0.1"
17
 
18
  # ======================================= Load DB configs
19
  def load_db_configs():
 
120
  """
121
  <h1 style='text-align: center; margin-bottom: 1rem'>Talk to Your Data</h1>
122
  <p style='text-align: center'>Ask questions about your database, analyze and visualize data.</p>
123
+ <p style='text-align: center; color: #666; font-size: 0.9em; margin-top: -0.5rem'>Version: {}</p>
124
+ """.format(VERSION)
125
  """
126
  )
127
  with gr.Row(elem_classes="container"):
 
132
  height=1000,
133
  show_label=False,
134
  elem_classes="chat-container",
135
+ render_markdown=True,
136
+ type="messages"
137
  ),
138
  textbox=gr.Textbox(
139
  placeholder="Type your questions here...",
 
166
  - πŸ‘₯ Total number of customers
167
  - πŸ“ˆ Top 10 customers by ticket count
168
  - πŸ“‹ Ticket count by status and visualize
169
+ - πŸ“† Average ticket reopened
170
  - 🧹 Clear memory : `/clear-cache`
171
  """)
172
 
postgre_mcp_server.py CHANGED
@@ -41,7 +41,7 @@ class DbContext:
41
  async def db_lifespan(server: FastMCP) -> AsyncIterator[DbContext]:
42
  """Manage database connection lifecycle"""
43
  dsn = os.environ["DB_URL"]
44
- schema = os.environ["DB_SCHEMA"]
45
 
46
  pool = await asyncpg.create_pool(
47
  dsn,
@@ -52,7 +52,7 @@ async def db_lifespan(server: FastMCP) -> AsyncIterator[DbContext]:
52
  command_timeout=300,
53
  )
54
  try:
55
- yield DbContext(pool=pool, schema=schema)
56
  finally:
57
  # Clean up
58
  await pool.close()
@@ -248,9 +248,9 @@ async def execute_query(
248
 
249
 
250
  # Database helper functions
251
- async def get_all_tables(pool, schema):
252
  """Get all tables from the database"""
253
- print(f"schema: {schema}")
254
  async with pool.acquire() as conn:
255
  result = await conn.fetch("""
256
  SELECT c.relname AS table_name
@@ -265,12 +265,12 @@ async def get_all_tables(pool, schema):
265
  AND n.nspname = $1
266
  AND c.relname NOT LIKE 'pg_%'
267
  ORDER BY c.relname;
268
- """, schema)
269
 
270
  return result
271
 
272
 
273
- async def get_table_schema_info(pool, schema, table_name):
274
  """Get schema information for a specific table"""
275
  async with pool.acquire() as conn:
276
  columns = await conn.fetch("""
@@ -284,7 +284,7 @@ async def get_table_schema_info(pool, schema, table_name):
284
  WHERE table_schema = $1
285
  AND table_name = $2
286
  ORDER BY ordinal_position;
287
- """, schema, table_name)
288
 
289
  return columns
290
 
@@ -325,13 +325,13 @@ async def list_tables() -> str:
325
  async def get_table_schema(table_name: str) -> str:
326
  """Get schema information for a specific table"""
327
  try:
328
- schema = os.environ["DB_SCHEMA"]
329
 
330
  async with db_lifespan(mcp) as db_ctx:
331
- columns = await get_table_schema_info(db_ctx.pool, schema, table_name)
332
 
333
  if not columns:
334
- return f"Table '{table_name}' not found in {schema} schema."
335
 
336
  return format_table_schema(table_name, columns)
337
  except asyncpg.exceptions.PostgresError as e:
@@ -348,7 +348,7 @@ def get_foreign_keys(table_name: str) -> str:
348
  table_name: The name of the table to get foreign keys from
349
  schema: The schema name (defaults to 'public')
350
  """
351
- schema = os.environ["DB_SCHEMA"]
352
 
353
  sql = """
354
  SELECT
@@ -366,19 +366,19 @@ def get_foreign_keys(table_name: str) -> str:
366
  JOIN information_schema.constraint_column_usage ccu
367
  ON rc.unique_constraint_name = ccu.constraint_name
368
  WHERE tc.constraint_type = 'FOREIGN KEY'
369
- AND tc.table_schema = {schema}
370
  AND tc.table_name = {table_name}
371
  ORDER BY tc.constraint_name, kcu.ordinal_position
372
  """
373
 
374
- return execute_query(sql, (schema, table_name))
375
 
376
 
377
  @mcp.tool(description="Fetches and formats the schema details for all tables in the configured database schema.")
378
  async def get_all_schemas() -> str:
379
  """Get schema information for all tables in the database"""
380
  try:
381
- schema = os.environ["DB_SCHEMA"]
382
 
383
  async with db_lifespan(mcp) as db_ctx:
384
  tables = await get_all_tables(db_ctx.pool, db_ctx.schema)
@@ -389,7 +389,7 @@ async def get_all_schemas() -> str:
389
  all_schemas = []
390
  for table in tables:
391
  table_name = table['table_name']
392
- columns = await get_table_schema_info(db_ctx.pool, schema, table_name)
393
  table_schema = format_table_schema(table_name, columns)
394
  all_schemas.append(table_schema)
395
  all_schemas.append("") # Add empty line between tables
@@ -447,7 +447,7 @@ async def generate_analytical_query(table_name: str) -> list[PromptMessage]:
447
  Args:
448
  table_name: The name of the table to generate analytical queries for
449
  """
450
- schema = os.environ["DB_SCHEMA"]
451
  try:
452
  async with db_lifespan(mcp) as db_ctx:
453
  pool = db_ctx.pool
@@ -455,7 +455,7 @@ async def generate_analytical_query(table_name: str) -> list[PromptMessage]:
455
  columns = await conn.fetch(f"""
456
  SELECT column_name, data_type
457
  FROM information_schema.columns
458
- WHERE table_schema = {schema} AND table_name = {table_name}
459
  ORDER BY ordinal_position
460
  """, db_ctx.schema, table_name)
461
 
 
41
  async def db_lifespan(server: FastMCP) -> AsyncIterator[DbContext]:
42
  """Manage database connection lifecycle"""
43
  dsn = os.environ["DB_URL"]
44
+ db_schema = os.environ["DB_SCHEMA"]
45
 
46
  pool = await asyncpg.create_pool(
47
  dsn,
 
52
  command_timeout=300,
53
  )
54
  try:
55
+ yield DbContext(pool=pool, schema=db_schema)
56
  finally:
57
  # Clean up
58
  await pool.close()
 
248
 
249
 
250
  # Database helper functions
251
+ async def get_all_tables(pool, db_schema):
252
  """Get all tables from the database"""
253
+ print(f"schema: {db_schema}")
254
  async with pool.acquire() as conn:
255
  result = await conn.fetch("""
256
  SELECT c.relname AS table_name
 
265
  AND n.nspname = $1
266
  AND c.relname NOT LIKE 'pg_%'
267
  ORDER BY c.relname;
268
+ """, db_schema)
269
 
270
  return result
271
 
272
 
273
+ async def get_table_schema_info(pool, db_schema, table_name):
274
  """Get schema information for a specific table"""
275
  async with pool.acquire() as conn:
276
  columns = await conn.fetch("""
 
284
  WHERE table_schema = $1
285
  AND table_name = $2
286
  ORDER BY ordinal_position;
287
+ """, db_schema, table_name)
288
 
289
  return columns
290
 
 
325
  async def get_table_schema(table_name: str) -> str:
326
  """Get schema information for a specific table"""
327
  try:
328
+ db_schema = os.environ["DB_SCHEMA"]
329
 
330
  async with db_lifespan(mcp) as db_ctx:
331
+ columns = await get_table_schema_info(db_ctx.pool, db_schema, table_name)
332
 
333
  if not columns:
334
+ return f"Table '{table_name}' not found in {db_schema} schema."
335
 
336
  return format_table_schema(table_name, columns)
337
  except asyncpg.exceptions.PostgresError as e:
 
348
  table_name: The name of the table to get foreign keys from
349
  schema: The schema name (defaults to 'public')
350
  """
351
+ db_schema = os.environ["DB_SCHEMA"]
352
 
353
  sql = """
354
  SELECT
 
366
  JOIN information_schema.constraint_column_usage ccu
367
  ON rc.unique_constraint_name = ccu.constraint_name
368
  WHERE tc.constraint_type = 'FOREIGN KEY'
369
+ AND tc.table_schema = {db_schema}
370
  AND tc.table_name = {table_name}
371
  ORDER BY tc.constraint_name, kcu.ordinal_position
372
  """
373
 
374
+ return execute_query(sql, (db_schema, table_name))
375
 
376
 
377
  @mcp.tool(description="Fetches and formats the schema details for all tables in the configured database schema.")
378
  async def get_all_schemas() -> str:
379
  """Get schema information for all tables in the database"""
380
  try:
381
+ db_schema = os.environ["DB_SCHEMA"]
382
 
383
  async with db_lifespan(mcp) as db_ctx:
384
  tables = await get_all_tables(db_ctx.pool, db_ctx.schema)
 
389
  all_schemas = []
390
  for table in tables:
391
  table_name = table['table_name']
392
+ columns = await get_table_schema_info(db_ctx.pool, db_schema, table_name)
393
  table_schema = format_table_schema(table_name, columns)
394
  all_schemas.append(table_schema)
395
  all_schemas.append("") # Add empty line between tables
 
447
  Args:
448
  table_name: The name of the table to generate analytical queries for
449
  """
450
+ db_schema = os.environ["DB_SCHEMA"]
451
  try:
452
  async with db_lifespan(mcp) as db_ctx:
453
  pool = db_ctx.pool
 
455
  columns = await conn.fetch(f"""
456
  SELECT column_name, data_type
457
  FROM information_schema.columns
458
+ WHERE table_schema = {db_schema} AND table_name = {table_name}
459
  ORDER BY ordinal_position
460
  """, db_ctx.schema, table_name)
461