ASSISTANT
Thanks for clarifying!
---
# Goal:
**Users ask arbitrary questions about the data in your 5 tables (master, relationship, change, problem, incident). Your Streamlit chat box uses GPT-4o to answer questions grounded on your actual DB content.**
---
# Challenges:
- GPT model by itself has no knowledge of your private DB data.
- Need to **feed relevant DB context to GPT** so answers are factual.
- Arbitrary natural language questions → need to dynamically find relevant data in DB → construct prompt → get GPT answer.
---
# Recommended approach:
### 1. **Semantic search or keyword search on your DB tables**
Given the question, search for relevant rows from your 5 tables.
### 2. **Summarize or format relevant rows** into a prompt context.
### 3. **Send prompt + user question to GPT-4o chat completion API.**
### 4. Return GPT response to Streamlit UI.
---
# Implementation strategy (step-by-step):
---
## A. Setup: Sample minimal schema tables for demo (you have yours)
Assuming you have tables like:
- `master(id, name, type, description)`
- `relationship(id, parent_id, child_id, relation_type)`
- `change(id, title, description, status)`
- `problem(id, title, description, severity)`
- `incident(id, description, status, opened_date)`
*(Adjust columns based on your actual schema.)*
---
## B. Writing Python functions for:
- Searching each table with user question keywords.
- Compiling context.
- Asking GPT-4o.
---
## C. Full Streamlit app example below
```python
import streamlit as st
import openai
from sqlalchemy import create_engine, text
import os
# === Configuration ===
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
openai.api_key = OPENAI_API_KEY
DB_USER = 'your_user'
DB_PASSWORD = 'your_password'
DB_HOST = 'localhost'
DB_PORT = '5432'
DB_NAME = 'your_db'
engine = create_engine(f"postgresql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}")
# === DB search functions ===
def search_table(table_name, search_cols, question, limit=3):
"""
Generic function to search keywords in specified columns of a table.
Returns list of rows as dicts.
"""
with engine.connect() as conn:
# Build WHERE clause: col ILIKE %question%
ilike_clauses = " OR ".join([f"{col} ILIKE :pattern" for col in search_cols])
sql = text(f"SELECT * FROM {table_name} WHERE {ilike_clauses} LIMIT :limit")
results = conn.execute(sql, {"pattern": f"%{question}%", "limit": limit}).fetchall()
# Convert results (RowProxy) to dict list
rows = [dict(row) for row in results]
return rows
def gather_context(question):
"""
Search all relevant tables and return a summary string for prompt.
"""
context_sections = []
# Search master table
master_rows = search_table('master', ['name', 'type', 'description'], question)
if master_rows:
section = "Master records:\n"
for row in master_rows:
section += f"- ID {row.get('id')}, Name: {row.get('name')}, Type: {row.get('type')}, Desc: {row.get('description')}\n"
context_sections.append(section)
# Search relationship table (assuming relation_type is descriptive)
rel_rows = search_table('relationship', ['relation_type'], question)
if rel_rows:
section = "Relationship records:\n"
for row in rel_rows:
section += f"- ID {row.get('id')}, Parent: {row.get('parent_id')}, Child: {row.get('child_id')}, Type: {row.get('relation_type')}\n"
context_sections.append(section)
# Search change table
change_rows = search_table('change', ['title', 'description', 'status'], question)
if change_rows:
section = "Change records:\n"
for row in change_rows:
section += f"- ID {row.get('id')}, Title: {row.get('title')}, Status: {row.get('status')}, Desc: {row.get('description')}\n"
context_sections.append(section)
# Search problem table
problem_rows = search_table('problem', ['title', 'description', 'severity'], question)
if problem_rows:
section = "Problem records:\n"
for row in problem_rows:
section += f"- ID {row.get('id')}, Title: {row.get('title')}, Severity: {row.get('severity')}, Desc: {row.get('description')}\n"
context_sections.append(section)
# Search incident table
incident_rows = search_table('incident', ['description', 'status'], question)
if incident_rows:
section = "Incident records:\n"
for row in incident_rows:
section += f"- ID {row.get('id')}, Status: {row.get('status')}, Desc: {row.get('description')}\n"
context_sections.append(section)
if context_sections:
return "\n\n".join(context_sections)
else:
return "No relevant records found in the database."
# GPT prompt construction
def create_prompt(context, user_question):
prompt = f"""
You are an IT support assistant with access to company data.
The following are relevant database records extracted from 5 tables regarding the user's question:
{context}
Using this data, please answer the user's question clearly and factually:
Question: {user_question}
Answer:
"""
return prompt
def get_gpt_response(prompt):
try:
response = openai.chat.completions.create(
model="gpt-4o", # Use the exact model name you have
messages=[
{"role": "system", "content": "You are helpful IT assistant."},
{"role": "user", "content": prompt}
],
temperature=0.2,
max_tokens=500,
)
return response.choices[0].message.content.strip()
except Exception as e:
st.error(f"OpenAI API call failed: {e}")
return "Sorry, I couldn't process your request."
# --- Streamlit app ---
def main():
st.title("ITSM Chat Assistant (GPT-4o + PostgreSQL)")
user_question = st.text_input("Enter your question about master/relationship/change/problem/incident data:")
if st.button("Ask") and user_question:
with st.spinner("Querying database and generating answer..."):
context = gather_context(user_question)
prompt = create_prompt(context, user_question)
answer = get_gpt_response(prompt)
st.markdown("### Answer:")
st.write(answer)
if context != "No relevant records found in the database.":
with st.expander("See extracted data from database"):
st.code(context)
if __name__ == "__main__":
main()
```
---
# Explanation:
- User inputs question.
- The app tries to **find relevant data in all 5 tables** matching any keyword in the question.
- It prepares a **context block** with matching records.
- Sends the context + question to GPT’s chat API.
- Displays GPT answer.
- Shows extracted DB context under expander for transparency.
---
# Next Steps / Improvements
- Use **full-text or semantic search** instead of simple ILIKE for better matching.
- Use **embeddings** + vector search (e.g. pgvector extension) on description fields.
- Implement **chat history** with Streamlit session state.
- Better **prompt engineering** depending on user feedback.
- Add **security** e.g. sanitize inputs, handle sensitive data.
- Create **more detailed DB summaries** or schema description for GPT.
---
If you'd like, I can help build a **full example with embeddings + vector similarity search**, or organize chat history, or further optimize this solution.
---
Just let me know!