Cloud Run Model Integration for SQL Analysis
Cloud Run Model Integration for SQL Analysis
import requests
import ast
import [Link]
import pandas as pd
import json
import re
import time
from datetime import datetime
from graphviz import Source, Digraph
import certifi
import openpyxl
from openpyxl import load_workbook
from [Link] import Alignment, PatternFill
from [Link] import Image
import tiktoken
# === LLaMA 3.1 Setup ===
import [Link]
from [Link] import default
from [Link] import Request
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough, Runnable
from langchain_core.output_parsers import StrOutputParser
from google.oauth2 import service_account
from langchain_core.runnables import Runnable
print('*'*100)
print('Process Started')
SERVICE_URL = "[Link]
SERVICE_ACCOUNT_FILE = "[Link]"
headers = {
"Authorization": f"Bearer {[Link]}",
"Content-Type": "application/json"
}
payload = {
"prompt": prompt,
"temperature": temperature
}
except Exception as e:
print(f"❌ Error in call_cloud_run_model: {str(e)}")
return {"error": str(e)}
class CloudRunLLM(Runnable):
def invoke(self, input, config=None):
try:
prompt_text = [Link]('formatted_prompt') if isinstance(input, dict)
else str(input)
print("🟢 Prompt sent to Cloud Run:")
print(prompt_text)
response = call_cloud_run_model(prompt_text)
print("🟢 Response from Cloud Run:")
print(response)
if 'error' in response:
return f"Error: {response['error']}"
if isinstance(response, dict):
# Vertex/Custom style
if 'predictions' in response:
preds = response['predictions']
# Some servers nest choices inside predictions, others return a
list of strings
if isinstance(preds, dict) and 'choices' in preds and
preds['choices']:
ch0 = preds['choices'][0]
msg = [Link]('message') or {}
content = ([Link]('content') if isinstance(msg, dict) else
None) or [Link]('text')
if content:
return content
if isinstance(preds, list):
# Try common shapes inside list
first = preds[0] if preds else {}
if isinstance(first, dict):
msg = [Link]('message') or {}
content = ([Link]('content') if isinstance(msg, dict)
else None) or [Link]('text')
if content:
return content
# OpenAI style
if 'choices' in response and response['choices']:
ch0 = response['choices'][0]
msg = [Link]('message') or {}
content = ([Link]('content') if isinstance(msg, dict) else
None) or [Link]('text')
if content:
return content
return str(response)
except Exception as e:
print(f"Error in [Link]: {str(e)}")
return f"Error processing request: {str(e)}"
llm = CloudRunLLM()
def chunk_sql_by_tokens(file_path, token_limit=500):
if not [Link](file_path):
raise FileNotFoundError(f"File not found: {file_path}")
1. Analyse each and every section of the PL/SQL procedure. The PL/SQL
procedure consists of multiple layers of data transformation, designed to optimize
query performance.
Determine the purpose of each section in the data engineering and report
building process. You will utilize this analysis in naming and describing the
sections as well as
in documenting the tables involved in the section. Ensure that each section
has only one concise and high-level description documented under "Description".
2. Identify the variables, tables CTEs and columns in the PL/SQL procedure.
Analyse the insert, update, delete select, from and join statements, aggregations,
select case when and other filter conditions. You will use this analysis to
document the target table name, the columns belonging to the table in a hierarchial
manner of data flow. You will also use this analysis to determine the purpose of
the table and column in the report building process.
For example, in the statement "insert @lins select [Link], case when
[Link] is null then 'O' else 'R' end, [Link], [Link] from @PTRN1 a left
join SOURCE_TABLE b on [Link] = [Link] and
[Link] = [Link] and [Link] !='2' and [Link] = 'B522'":
- "Source Table": "@PTRN1, SOURCE_TABLE" (they have been mapped to aliases
'a' and 'b' respectively)
- "Source Column": "@[Link], SOURCE_TABLE.chdrnum, @[Link],
SOURCE_TABLE.PTRNEFF" ('SOURCE_TABLE.chdrnum', 'SOURCE_TABLE.validflag' and
'SOURCE_TABLE.batctrcde' will not be included in the join columns)
- "Join Statement": "from @PTRN1 a left join SOURCE_TABLE b on [Link] =
[Link] and [Link] = [Link]"
- "Transformation Table": "@PTRN1, SOURCE_TABLE"
- "Transformation Column": "SOURCE_TABLE.chdrnum, SOURCE_TABLE.validflag,
SOURCE_TABLE.batctrcde"
- "Transformation Statement": "insert @lins select [Link], case when
[Link] is null then 'O' else 'R' end, [Link] !='2' and [Link] =
'B522'"
4. You will utilise the analyses from Step 2 and Step 3 to rationalise the
purpose of performing the transformation at each step, in business terms. You will
document this rationalisation
under "Derivation Purpose" for each transformation step.
{context}
Note that, you should not miss capturing any transformation or logic even
if that is simple. All tables used in stored procedure should be captured in result
you will be giving.
The resulting JSON will provide a detailed overview of the PL/SQL script's
operations, data flow, and business logic. It should serve as a reference guide for
data engineers to understand the exact queries and operations applied, and for
business analysts to grasp the purpose and functionality of each section, element
and statements within the script.
Perform the documentation thoroughly and ensure no part of your analysis is
excluded from the JSON output as this documentation is highly critical. Perform as
much of the analysis as you can. Do not include introductions, labels, backticks
and conclusions. Only respond with the table. Each row of the table should end with
a newline character.
you should give all the your analyse in one JSON array, There should not be
multple JSON arrays.
""")
runnable = RunnablePassthrough()
output_parser = StrOutputParser()
chain = runnable | db_schema_prompt | llm | output_parser
df_chunks = []
if not match:
print(f"❌ No JSON array found in chunk {i} response:")
print(f"Response preview: {glossary_clean[:300]}...")
continue
json_string = [Link](0)
except Exception as e:
print(f"❌ Error in chunk {i} (attempt {attempt+1}): {e}")
if attempt == 9: # Last attempt
print(f"🟠 Final raw response for chunk {i}:")
print(f"{glossary[:500]}...")
else:
print(f"⚠️ Skipped chunk {i} after 10 failed attempts.")
if not df_chunks:
print("❌ No data was successfully processed from any chunks")
return {filename: [Link]()}, {filename: [Link]()}
df = [Link](df_chunks)
df_filled = [Link]("S/B", [Link]).ffill()
return {filename: df}, {filename: df_filled}
def process_table_1(table):
rows = []
try:
for line in table:
row = {
"Section": [Link]('Section'),
"Description": [Link]('Description'),
"Target Table": [Link]('Target Table', "").upper() if
[Link]('Target Table') else None,
"Table Description": [Link]('Table Description'),
"Target Column": [Link]('Target Column'),
"Data Type": [Link]('Data Type'),
"Column Description": [Link]('Column Description'),
"Source Table": [Link]('Source Table', "").strip().upper() if
[Link]('Source Table') else "S/B",
"Source Column": [Link]('Source Column', "").strip() if
[Link]('Source Column') else "S/B",
"Join Statement": [Link]('Join Statement', "").strip() if
[Link]('Join Statement') else "S/B",
"Transformation Table": [Link]('Transformation Table',
"").strip().upper() if [Link]('Transformation Table') else "S/B",
"Transformation Column": [Link]('Transformation Column',
"").strip() if [Link]('Transformation Column') else "S/B",
"Transformation Statement": [Link]('Transformation Statement',
"").strip() if [Link]('Transformation Statement') else "S/B",
"Derivation Purpose": [Link]('Derivation Purpose', "").strip() if
[Link]('Derivation Purpose') else "S/B"
}
[Link](row)
return rows
except Exception as e:
print('❌ Error in parsing output in process_table_1:', str(e))
return []
# Chain setup
runnable = RunnablePassthrough()
output_parser = StrOutputParser()
chain = runnable | db_schema_prompt | llm | output_parser
combined_results = []
if not match:
print(f"❌ No JSON found in chunk {i} attempt {attempt+1}")
continue
json_string = [Link](0)
try:
json_val = [Link](json_string)
except [Link]:
json_val = ast.literal_eval(json_string)
except Exception as e:
print(f"⚠️ Error processing chunk {i} attempt {attempt+1}: {e}")
continue
def preprocess_unclean_to_clean(unclean_json):
clean_list = []
step = 1
for item in unclean_json:
sources = [Link]("source_tables", [])
targets = [Link]("target_tables", [])
col_map = [Link]("column_mappings", {})
# Try to infer operation from transformation_logic (very basic heuristic)
trans_logic = [Link]("transformation_logic", "").lower()
if "update" in trans_logic:
operation = "UPDATE"
elif "insert" in trans_logic:
operation = "INSERT"
elif "create" in trans_logic:
operation = "CREATE TABLE AS"
else:
operation = "INSERT" # default fallback
# -------------------------
# 3. Your existing diagram generator (unchanged)
# -------------------------
def generate_interactive_html_diagram(clean_json):
"""Generate an interactive HTML diagram using [Link] with operation & join
details."""
nodes = {}
edges = []
table_details = {}
for idx, item in enumerate(clean_json, 1):
source = [Link]("source")
target = [Link]("target")
columns = [Link]("columns", {})
operation = [Link]("operation", "SELECT")
joins = [Link]("joins", [])
# Add nodes
for tbl, role in [(source, "Source"), (target, "Target")]:
if tbl and tbl not in nodes:
nodes[tbl] = {
"id": tbl,
"label": tbl,
"color": "#ADD8E6" if role == "Source" else "#90EE90",
"title": f"{role} Table: {tbl}"
}
table_details[tbl] = {"type": role, "operations": []}
# Edge tooltip
col_map_str = "\n".join([f"{src} → {tgt}" for src, tgt in [Link]()])
joins_str = "\n".join([f"{j['type']}: {j['left_table']} ↔
{j['right_table']} ON {j['condition']}" for j in joins]) or "No joins"
edge_tooltip = f"Step {idx}: {operation}\n\nColumns:\n{col_map_str or 'No
column mapping'}\n\nJoins:\n{joins_str}"
# Add edge
if source and target:
[Link]({
"id": f"edge_{idx}",
"from": source,
"to": target,
"label": f"Step {idx}: {operation}",
"color": "#00CC00" if [Link]() == "SELECT" else "#FF6600",
"title": edge_tooltip
})
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>Data Lineage Diagram</title>
<script src="[Link]
[Link]"></script>
<style>
body {{ font-family: Arial; margin: 20px; }}
#network {{ width: 100%; height: 800px; border: 1px solid #ccc; }}
.info-panel {{ margin: 20px 0; padding: 15px; background: #f5f5f5; }}
.legend {{ display: flex; gap: 20px; }}
.legend-item {{ display: flex; align-items: center; gap: 5px; }}
.legend-color {{ width: 20px; height: 20px; }}
</style>
</head>
<body>
<h1>Data Lineage Diagram</h1>
<div class="info-panel">
<h3>Legend</h3>
<div class="legend">
<div class="legend-item"><div class="legend-color" style="background:
#ADD8E6;"></div>Source Tables</div>
<div class="legend-item"><div class="legend-color" style="background:
#90EE90;"></div>Target Tables</div>
</div>
</div>
<div id="network"></div>
<div id="table-details" class="info-panel">
<h3>Table Details</h3>
<div id="selected-table">Click on a table to see details</div>
</div>
<script>
const nodes = new [Link]({nodes_json});
const edges = new [Link]({edges_json});
const container = [Link]('network');
const data = {{ nodes: nodes, edges: edges }};
const options = {{
nodes: {{ shape: 'box', font: {{ size: 12 }}, borderWidth: 2 }},
edges: {{ arrows: {{ to: {{ enabled: true }} }} }},
physics: {{ enabled: true, solver: 'forceAtlas2Based' }},
interaction: {{ hover: true }}
}};
const network = new [Link](container, data, options);
const tableDetails = {table_details_json};
[Link]('selectNode', function(params) {{
const nodeId = [Link][0];
const details = tableDetails[nodeId];
let html = `<h4>${{nodeId}}</h4><p>Type: ${{[Link]}}</p><ul>`;
[Link](op => {{
html += `<li><strong>Step:</strong> ${{[Link]}} |
<strong>Op:</strong> ${{[Link]}}<br>`;
if ([Link]([Link]).length) {{
html += "<strong>Columns:</strong><ul>";
for (const [src, tgt] of [Link]([Link])) {{
html += `<li>${{src}} → ${{tgt}}</li>`;
}}
html += "</ul>";
}}
if ([Link]) {{
html += "<strong>Joins:</strong><ul>";
[Link](j => {{
html += `<li>${{[Link]}}: ${{j.left_table}} ↔ $
{{j.right_table}} ON ${{[Link]}}</li>`;
}});
html += "</ul>";
}}
html += "</li>";
}});
html += "</ul>";
[Link]('selected-table').innerHTML = html;
}});
</script>
</body>
</html>
"""
return html_content
if __name__ == "__main__":
file_path = r"/home/gcp8099/demo_app/sp_rq.sql"
chunks = chunk_sql_by_tokens(file_path)
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('[Link]', None)
df_filled[filename].to_csv("./output/etl documentation/[Link]",
index=False)
# Preview DataFrame
print(df_filled[filename])