Skip to content

Commit b340236

Browse files
committed
Rename llm to prompt, add LinkedIn cache
Migrate storage and API from 'llm' to 'prompt': update SQL create table, change all queries/inserts to use prompt, remove tsvector/search_vector usage, and update logging/meta messages. Add drop_llm_table.sql to clean up old table. Enhance POST /prompt/linkedin to check the prompt table for a cached completion by linkedinUrl (returns cached result or a warning if not found). Update prospects endpoint to fetch related prompt_records instead of llm_records and adjust returned fields. Minor docstring and metadata text updates.
1 parent a333948 commit b340236

6 files changed

Lines changed: 84 additions & 35 deletions

File tree

app/api/prompt/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""LLM Routes"""
1+
"""Prompt Routes"""
22

33
from .prompt import router as prompt_router
44
from .linkedin import router as linkedin_router

app/api/prompt/linkedin.py

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,67 @@
1-
from fastapi import APIRouter, Depends
1+
from fastapi import APIRouter, Depends, HTTPException
22

33
from app.utils.api_key_auth import get_api_key
4+
from app.utils.db import get_db_connection_direct
45
from app.utils.make_meta import make_meta
56

67
router = APIRouter()
78

89

910
@router.post("/prompt/linkedin")
10-
def linkedin_prompt_success(api_key: str = Depends(get_api_key)) -> dict:
11-
"""POST /prompt/linkedin: Success stub endpoint."""
12-
return {
13-
"meta": make_meta("success", "LinkedIn prompt endpoint working"),
14-
"message": "LinkedIn prompt endpoint is live.",
15-
}
11+
def linkedin_prompt_success(payload: dict, api_key: str = Depends(get_api_key)) -> dict:
12+
"""POST /prompt/linkedin: return cached completion for linkedinUrl when available."""
13+
linkedin_url = (payload.get("linkedinUrl") or "").strip()
14+
if not linkedin_url:
15+
raise HTTPException(status_code=400, detail="Missing 'linkedinUrl' in request body.")
16+
17+
conn = None
18+
cur = None
19+
try:
20+
conn = get_db_connection_direct()
21+
cur = conn.cursor()
22+
cur.execute(
23+
"""
24+
SELECT id, completion, time, model, data
25+
FROM prompt
26+
WHERE (data->>'linkedinUrl' = %s OR prompt ILIKE %s)
27+
ORDER BY id DESC
28+
LIMIT 1;
29+
""",
30+
(linkedin_url, f"%{linkedin_url}%"),
31+
)
32+
row = cur.fetchone()
33+
34+
if row:
35+
return {
36+
"meta": make_meta("success", "LinkedIn URL already analysed"),
37+
"data": {
38+
"cached": True,
39+
"id": row[0],
40+
"linkedinUrl": linkedin_url,
41+
"completion": row[1],
42+
"time": row[2].isoformat() if row[2] else None,
43+
"model": row[3],
44+
"record_data": row[4],
45+
},
46+
}
47+
48+
return {
49+
"meta": make_meta("warning", "LinkedIn URL not analysed yet"),
50+
"data": {
51+
"cached": False,
52+
"linkedinUrl": linkedin_url,
53+
"completion": None,
54+
},
55+
}
56+
except HTTPException:
57+
raise
58+
except Exception as e:
59+
return {
60+
"meta": make_meta("error", f"DB error: {str(e)}"),
61+
"data": {},
62+
}
63+
finally:
64+
if cur:
65+
cur.close()
66+
if conn:
67+
conn.close()

app/api/prompt/prompt.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def get_prompt_records(
2121
if prospect_id is not None:
2222
# No pagination for single prospect_id lookup
2323
select_query = """
24-
SELECT id, prompt, completion, duration, time, data, model, prospect_id, search_vector
25-
FROM llm
24+
SELECT id, prompt, completion, duration, time, data, model, prospect_id
25+
FROM prompt
2626
WHERE prospect_id = %s
2727
ORDER BY id DESC
2828
"""
@@ -38,7 +38,6 @@ def get_prompt_records(
3838
"data": row[5],
3939
"model": row[6],
4040
"prospect_id": row[7],
41-
"search_vector": str(row[8]) if row[8] is not None else None,
4241
}
4342
for row in rows
4443
]
@@ -58,12 +57,12 @@ def get_prompt_records(
5857
}
5958
else:
6059
offset = (page - 1) * page_size
61-
cur.execute("SELECT COUNT(*) FROM llm;")
60+
cur.execute("SELECT COUNT(*) FROM prompt;")
6261
count_row = cur.fetchone()
6362
total = count_row[0] if count_row and count_row[0] is not None else 0
6463
cur.execute("""
65-
SELECT id, prompt, completion, duration, time, data, model, prospect_id, search_vector
66-
FROM llm
64+
SELECT id, prompt, completion, duration, time, data, model, prospect_id
65+
FROM prompt
6766
ORDER BY id DESC
6867
LIMIT %s OFFSET %s;
6968
""", (page_size, offset))
@@ -77,13 +76,12 @@ def get_prompt_records(
7776
"data": row[5],
7877
"model": row[6],
7978
"prospect_id": row[7],
80-
"search_vector": str(row[8]) if row[8] is not None else None,
8179
}
8280
for row in cur.fetchall()
8381
]
8482
cur.close()
8583
conn.close()
86-
meta = make_meta("success", f"LLM {len(records)} records (page {page})")
84+
meta = make_meta("success", f"Prompt {len(records)} records (page {page})")
8785
return {
8886
"meta": meta,
8987
"data": {
@@ -140,22 +138,21 @@ def llm_post(payload: dict) -> dict:
140138
if not completion:
141139
error_details = " | ".join([f"{k}: {v}" for k, v in errors.items()])
142140
raise Exception(f"No available Gemini model succeeded for generate_content with your API key. Details: {error_details}")
143-
# Insert record into llm table
141+
# Insert record into prompt table
144142
record_id = None
145143
try:
146144
import json
147145
from app import __version__
148146
data_blob = json.dumps({"version": __version__})
149147
conn = get_db_connection_direct()
150148
cur = conn.cursor()
151-
# Generate tsvector from prompt and completion
152149
cur.execute(
153150
"""
154-
INSERT INTO llm (prompt, completion, duration, data, model, prospect_id, search_vector)
155-
VALUES (%s, %s, %s, %s, %s, %s, to_tsvector('english', %s || ' ' || %s))
151+
INSERT INTO prompt (prompt, completion, duration, data, model, prospect_id)
152+
VALUES (%s, %s, %s, %s, %s, %s)
156153
RETURNING id;
157154
""",
158-
(prompt, completion, duration, data_blob, used_model, prospect_id, prompt, completion)
155+
(prompt, completion, duration, data_blob, used_model, prospect_id)
159156
)
160157
record_id_row = cur.fetchone()
161158
record_id = record_id_row[0] if record_id_row else None
@@ -164,7 +161,7 @@ def llm_post(payload: dict) -> dict:
164161
conn.close()
165162
except Exception as db_exc:
166163
# Log DB error but do not fail the API response
167-
logging.error(f"Failed to insert llm record: {db_exc}")
164+
logging.error(f"Failed to insert prompt record: {db_exc}")
168165
meta = make_meta("success", f"Gemini completion received from {used_model}")
169166
return {"meta": meta, "data": {"id": record_id, "prompt": prompt, "completion": completion}}
170167
except Exception as e:

app/api/prompt/sql/create_table.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
CREATE TABLE IF NOT EXISTS llm (
2+
CREATE TABLE IF NOT EXISTS prompt (
33
id SERIAL PRIMARY KEY,
44
vector vector(1536),
55
prompt TEXT NOT NULL,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP TABLE IF EXISTS llm;

app/api/prospects/prospects.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,28 +98,27 @@ def prospects_read_one(id: int = Path(..., description="ID of the prospect to re
9898
if row is not None:
9999
columns = [desc[0] for desc in cur.description]
100100
data = dict(zip(columns, row))
101-
# Fetch related llm records
101+
# Fetch related prompt records
102102
try:
103103
from app.utils.db import get_db_connection_direct
104-
llm_conn = get_db_connection_direct()
105-
llm_cur = llm_conn.cursor()
106-
llm_cur.execute("SELECT id, duration, time, data, model, search_vector FROM llm WHERE prospect_id = %s ORDER BY id DESC;", (id,))
107-
llm_records = [
104+
prompt_conn = get_db_connection_direct()
105+
prompt_cur = prompt_conn.cursor()
106+
prompt_cur.execute("SELECT id, duration, time, data, model FROM prompt WHERE prospect_id = %s ORDER BY id DESC;", (id,))
107+
prompt_records = [
108108
{
109109
"id": r[0],
110110
"duration": r[1],
111111
"time": r[2].isoformat() if r[2] else None,
112112
"data": r[3],
113113
"model": r[4],
114-
"search_vector": str(r[5]) if r[5] is not None else None,
115114
}
116-
for r in llm_cur.fetchall()
115+
for r in prompt_cur.fetchall()
117116
]
118-
llm_cur.close()
119-
llm_conn.close()
120-
data["llm_records"] = llm_records
121-
except Exception as llm_exc:
122-
data["llm_records"] = []
117+
prompt_cur.close()
118+
prompt_conn.close()
119+
data["prompt_records"] = prompt_records
120+
except Exception as prompt_exc:
121+
data["prompt_records"] = []
123122
else:
124123
data = None
125124
meta = make_meta("error", f"No prospect found with id {id}")

0 commit comments

Comments
 (0)