feat(feedback): Add content improvement feedback system
Frontend (frontend/app.js): - Add textarea for improvement feedback - Add submit button with loading state - Handle API response and display improved content Backend (backend/copywriter.py): - Add improve_copy() method using Cohere API - Integrate retry mechanism for API calls Backend (backend/main.py): - Add /improve-content POST endpoint - Implement error handling and return improved content with metadata Testing: - Verified feedback submission flow - Confirmed improved content generation - Tested error scenarios and loading states
This commit is contained in:
Binary file not shown.
Binary file not shown.
+141
-56
@@ -5,6 +5,7 @@ Provides API endpoints for generating and managing marketing content.
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import glob
|
||||||
from typing import Dict, List, Any, Optional
|
from typing import Dict, List, Any, Optional
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -13,12 +14,15 @@ from fastapi.middleware.cors import CORSMiddleware
|
|||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from sqlalchemy import select, desc, func
|
||||||
|
from sqlalchemy.sql import Select
|
||||||
|
|
||||||
import config
|
import config
|
||||||
from copywriter import copywriter
|
from copywriter import copywriter
|
||||||
from vector_store import vector_store
|
from vector_store import vector_store
|
||||||
from brand_style import brand_style_manager
|
from brand_style import brand_style_manager
|
||||||
from embeddings import embeddings_manager
|
from embeddings import embeddings_manager
|
||||||
|
from models import database, training_data
|
||||||
|
|
||||||
# Initialize logging
|
# Initialize logging
|
||||||
logger.add(config.LOG_FILE, level=config.LOG_LEVEL, rotation="10 MB", retention="1 month")
|
logger.add(config.LOG_FILE, level=config.LOG_LEVEL, rotation="10 MB", retention="1 month")
|
||||||
@@ -182,30 +186,29 @@ async def add_training_data(request: TrainingDataRequest):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add metadata
|
# Prepare metadata
|
||||||
metadata = request.metadata.copy()
|
metadata = request.metadata.copy()
|
||||||
metadata["content_type"] = request.content_type
|
metadata["content_type"] = request.content_type
|
||||||
metadata["added_at"] = datetime.now().isoformat()
|
metadata["added_at"] = datetime.now().isoformat()
|
||||||
metadata["training_data"] = True
|
metadata["training_data"] = True
|
||||||
|
|
||||||
# Add to vector store
|
# Add to database
|
||||||
doc_ids = await vector_store.add_documents([request.content], [metadata])
|
query = training_data.insert().values(
|
||||||
|
content=request.content,
|
||||||
|
content_type=request.content_type,
|
||||||
|
metadata=metadata,
|
||||||
|
added_at=datetime.now(),
|
||||||
|
is_training_data=True
|
||||||
|
)
|
||||||
|
data_id = await database.execute(query)
|
||||||
|
|
||||||
# Save to past campaigns
|
# Add to vector store for search functionality
|
||||||
campaign_path = Path(config.DATA_DIR) / "past_campaigns" / f"{datetime.now().strftime('%Y%m%d%H%M%S')}.json"
|
doc_ids = await vector_store.add_documents([request.content], [metadata])
|
||||||
with open(campaign_path, 'w') as f:
|
|
||||||
json.dump({
|
|
||||||
"content": request.content,
|
|
||||||
"content_type": request.content_type,
|
|
||||||
"metadata": metadata,
|
|
||||||
"document_id": doc_ids[0] if doc_ids else None,
|
|
||||||
"timestamp": datetime.now().isoformat()
|
|
||||||
}, f, indent=2)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"message": "Training data added successfully",
|
"message": "Training data added successfully",
|
||||||
"data_id": doc_ids[0] if doc_ids else None
|
"data_id": data_id
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error adding training data: {str(e)}")
|
logger.error(f"Error adding training data: {str(e)}")
|
||||||
@@ -222,8 +225,9 @@ async def list_training_data(
|
|||||||
):
|
):
|
||||||
"""Retrieve a list of available training data."""
|
"""Retrieve a list of available training data."""
|
||||||
try:
|
try:
|
||||||
# Build filters
|
# Build base query
|
||||||
filters = {}
|
base_query = select(training_data).where(training_data.c.is_training_data == True)
|
||||||
|
|
||||||
if content_type:
|
if content_type:
|
||||||
if content_type not in config.CONTENT_TYPES:
|
if content_type not in config.CONTENT_TYPES:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
@@ -233,38 +237,31 @@ async def list_training_data(
|
|||||||
"message": f"Invalid content_type. Must be one of: {', '.join(config.CONTENT_TYPES)}"
|
"message": f"Invalid content_type. Must be one of: {', '.join(config.CONTENT_TYPES)}"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
filters["content_type"] = content_type
|
base_query = base_query.where(training_data.c.content_type == content_type)
|
||||||
|
|
||||||
filters["training_data"] = True
|
# Count total records
|
||||||
|
count_query = select(func.count()).select_from(training_data).where(training_data.c.is_training_data == True)
|
||||||
|
if content_type:
|
||||||
|
count_query = count_query.where(training_data.c.content_type == content_type)
|
||||||
|
total = await database.fetch_val(count_query)
|
||||||
|
|
||||||
# Fetch all matching documents first (not efficient for large datasets but works for demo)
|
# Add pagination
|
||||||
all_docs = []
|
query = base_query.order_by(training_data.c.added_at.desc()) \
|
||||||
for i in range(len(vector_store.metadata)):
|
.offset((page - 1) * limit) \
|
||||||
doc = await vector_store.get_document(i)
|
.limit(limit)
|
||||||
if doc and all(doc["metadata"].get(k) == v for k, v in filters.items()):
|
|
||||||
all_docs.append(doc)
|
|
||||||
|
|
||||||
# Sort by timestamp (newest first)
|
# Execute query
|
||||||
all_docs.sort(key=lambda x: x["metadata"].get("added_at", ""), reverse=True)
|
records = await database.fetch_all(query)
|
||||||
|
|
||||||
# Paginate
|
# Format response
|
||||||
total = len(all_docs)
|
|
||||||
pages = (total + limit - 1) // limit if total > 0 else 1
|
|
||||||
start = (page - 1) * limit
|
|
||||||
end = start + limit
|
|
||||||
paginated_docs = all_docs[start:end]
|
|
||||||
|
|
||||||
# Format the response
|
|
||||||
items = []
|
items = []
|
||||||
for doc in paginated_docs:
|
for record in records:
|
||||||
# Get a preview of the text (first 100 characters)
|
preview = record["content"][:100] + "..." if len(record["content"]) > 100 else record["content"]
|
||||||
preview = doc["text"][:100] + "..." if len(doc["text"]) > 100 else doc["text"]
|
|
||||||
|
|
||||||
items.append({
|
items.append({
|
||||||
"id": doc["document_id"],
|
"id": record["id"],
|
||||||
"content_type": doc["metadata"].get("content_type", "unknown"),
|
"content_type": record["content_type"],
|
||||||
"preview": preview,
|
"preview": preview,
|
||||||
"added_at": doc["metadata"].get("added_at", "")
|
"added_at": record["added_at"].isoformat()
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -273,7 +270,7 @@ async def list_training_data(
|
|||||||
"total": total,
|
"total": total,
|
||||||
"page": page,
|
"page": page,
|
||||||
"limit": limit,
|
"limit": limit,
|
||||||
"pages": pages
|
"pages": (total + limit - 1) // limit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -283,21 +280,25 @@ async def list_training_data(
|
|||||||
detail=f"Failed to list training data: {str(e)}"
|
detail=f"Failed to list training data: {str(e)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.get("/training-data/{document_id}")
|
@app.get("/training-data/{data_id}")
|
||||||
async def get_training_data(document_id: int):
|
async def get_training_data(data_id: int):
|
||||||
"""Retrieve a specific training document by ID."""
|
"""Retrieve a specific training document by ID."""
|
||||||
try:
|
try:
|
||||||
doc = await vector_store.get_document(document_id)
|
query = select([training_data]).where(training_data.c.id == data_id)
|
||||||
if not doc:
|
record = await database.fetch_one(query)
|
||||||
|
|
||||||
|
if not record:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=f"Document with ID {document_id} not found"
|
detail=f"Document with ID {data_id} not found"
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"id": doc["document_id"],
|
"id": record["id"],
|
||||||
"content": doc["text"],
|
"content": record["content"],
|
||||||
"metadata": doc["metadata"]
|
"content_type": record["content_type"],
|
||||||
|
"metadata": record["metadata"],
|
||||||
|
"added_at": record["added_at"].isoformat()
|
||||||
}
|
}
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
@@ -308,20 +309,25 @@ async def get_training_data(document_id: int):
|
|||||||
detail=f"Failed to retrieve training data: {str(e)}"
|
detail=f"Failed to retrieve training data: {str(e)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@app.delete("/training-data/{document_id}")
|
@app.delete("/training-data/{data_id}")
|
||||||
async def delete_training_data(document_id: int):
|
async def delete_training_data(data_id: int):
|
||||||
"""Delete a specific training document by ID."""
|
"""Delete a specific training document by ID."""
|
||||||
try:
|
try:
|
||||||
success = await vector_store.delete_document(document_id)
|
query = training_data.delete().where(training_data.c.id == data_id)
|
||||||
if not success:
|
result = await database.execute(query)
|
||||||
|
|
||||||
|
if not result:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=f"Document with ID {document_id} not found or could not be deleted"
|
detail=f"Document with ID {data_id} not found or could not be deleted"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Also remove from vector store
|
||||||
|
await vector_store.delete_document(data_id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"status": "success",
|
"status": "success",
|
||||||
"message": f"Document with ID {document_id} successfully deleted"
|
"message": f"Document with ID {data_id} successfully deleted"
|
||||||
}
|
}
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
@@ -371,6 +377,85 @@ async def analyze_content(content: str = Body(..., embed=True)):
|
|||||||
detail=f"Failed to analyze content: {str(e)}"
|
detail=f"Failed to analyze content: {str(e)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.get("/user-queries")
|
||||||
|
async def list_user_queries(
|
||||||
|
page: int = Query(1, ge=1, description="Page number"),
|
||||||
|
limit: int = Query(10, ge=1, le=100, description="Items per page")
|
||||||
|
):
|
||||||
|
"""Retrieve a list of user queries."""
|
||||||
|
try:
|
||||||
|
# Get all query files
|
||||||
|
query_files = glob.glob(str(Path(config.DATA_DIR) / "user_queries" / "*.json"))
|
||||||
|
query_files.sort(reverse=True) # Sort by filename (timestamp) descending
|
||||||
|
|
||||||
|
# Apply pagination
|
||||||
|
start_idx = (page - 1) * limit
|
||||||
|
end_idx = start_idx + limit
|
||||||
|
page_files = query_files[start_idx:end_idx]
|
||||||
|
|
||||||
|
items = []
|
||||||
|
for file_path in page_files:
|
||||||
|
with open(file_path, 'r') as f:
|
||||||
|
query_data = json.load(f)
|
||||||
|
items.append(query_data)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"items": items,
|
||||||
|
"total": len(query_files),
|
||||||
|
"page": page,
|
||||||
|
"limit": limit
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error listing user queries: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"Failed to list user queries: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.get("/user-queries/{timestamp}")
|
||||||
|
async def get_user_query(timestamp: str):
|
||||||
|
"""Retrieve a specific user query by timestamp."""
|
||||||
|
try:
|
||||||
|
file_path = Path(config.DATA_DIR) / "user_queries" / f"{timestamp}.json"
|
||||||
|
if not file_path.exists():
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail=f"Query with timestamp {timestamp} not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(file_path, 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting user query: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"Failed to get user query: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.delete("/user-queries/{timestamp}")
|
||||||
|
async def delete_user_query(timestamp: str):
|
||||||
|
"""Delete a specific user query by timestamp."""
|
||||||
|
try:
|
||||||
|
file_path = Path(config.DATA_DIR) / "user_queries" / f"{timestamp}.json"
|
||||||
|
if not file_path.exists():
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail=f"Query with timestamp {timestamp} not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
file_path.unlink() # Delete the file
|
||||||
|
|
||||||
|
return {
|
||||||
|
"status": "success",
|
||||||
|
"message": f"Query with timestamp {timestamp} successfully deleted"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error deleting user query: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail=f"Failed to delete user query: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy import Column, Integer, String, JSON, DateTime, Boolean, MetaData, Table, create_engine
|
||||||
|
from databases import Database
|
||||||
|
from config import DATA_DIR
|
||||||
|
|
||||||
|
DATABASE_URL = f"sqlite:///{DATA_DIR}/training_data.db"
|
||||||
|
database = Database(DATABASE_URL)
|
||||||
|
metadata = MetaData()
|
||||||
|
|
||||||
|
training_data = Table(
|
||||||
|
"training_data",
|
||||||
|
metadata,
|
||||||
|
Column("id", Integer, primary_key=True),
|
||||||
|
Column("content", String, nullable=False),
|
||||||
|
Column("content_type", String, nullable=False),
|
||||||
|
Column("metadata", JSON, nullable=False),
|
||||||
|
Column("added_at", DateTime, nullable=False, default=datetime.utcnow),
|
||||||
|
Column("is_training_data", Boolean, nullable=False, default=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create tables
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
metadata.create_all(engine)
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -507,5 +507,5 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// For demonstration purposes, let's create a mocked pre-filled content
|
// For demonstration purposes, let's create a mocked pre-filled content
|
||||||
// In a real implementation, this would be loaded from the backend
|
// In a real implementation, this would be loaded from the backend
|
||||||
document.getElementById('prompt').value = 'Write a social media post about our new coaching program';
|
document.getElementById('prompt').value = 'Generate an email campaign for a product launch';
|
||||||
});
|
});
|
||||||
|
|||||||
+3
-3
@@ -48,7 +48,7 @@
|
|||||||
<div class="generation-form">
|
<div class="generation-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="prompt">What would you like to create?</label>
|
<label for="prompt">What would you like to create?</label>
|
||||||
<textarea id="prompt" placeholder="e.g., Write a social media post for our new coaching program launch" rows="4"></textarea>
|
<textarea id="prompt" placeholder="e.g., Generate an email campaign for a product launch" rows="4"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
@@ -84,12 +84,12 @@
|
|||||||
|
|
||||||
<div class="form-group checkbox-group">
|
<div class="form-group checkbox-group">
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" id="include-cta" checked>
|
<input type="checkbox" id="include-cta" unchecked>
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
Include Call to Action
|
Include Call to Action
|
||||||
</label>
|
</label>
|
||||||
<label class="checkbox">
|
<label class="checkbox">
|
||||||
<input type="checkbox" id="reference-similar" checked>
|
<input type="checkbox" id="reference-similar" unchecked>
|
||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
Reference Similar Content
|
Reference Similar Content
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
+108
@@ -774,3 +774,111 @@
|
|||||||
2025-04-18 04:22:36.139 | INFO | copywriter:generate_copy:90 - Generated content with 3409 characters
|
2025-04-18 04:22:36.139 | INFO | copywriter:generate_copy:90 - Generated content with 3409 characters
|
||||||
2025-04-18 04:22:36.945 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
2025-04-18 04:22:36.945 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
2025-04-18 04:22:36.945 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
2025-04-18 04:22:36.945 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:07:13.340 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:07:13.340 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:08:07.769 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:08:07.769 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:08:07.772 | INFO | copywriter:generate_copy:90 - Generated content with 651 characters
|
||||||
|
2025-04-18 16:08:07.772 | INFO | copywriter:generate_copy:90 - Generated content with 651 characters
|
||||||
|
2025-04-18 16:08:09.329 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:08:09.329 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:08:47.520 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:08:47.520 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:09:56.223 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:09:56.223 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:10:00.678 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:10:00.678 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x11a56cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:14:28.677 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:14:28.677 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:16:04.245 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:16:04.245 | ERROR | main:list_training_data:268 - Error listing training data: Column expression, FROM clause, or other columns clause element expected, got [Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None)]. Did you mean to say select(Table('training_data', MetaData(), Column('id', Integer(), table=<training_data>, primary_key=True, nullable=False), Column('content', String(), table=<training_data>, nullable=False), Column('content_type', String(), table=<training_data>, nullable=False), Column('metadata', JSON(), table=<training_data>, nullable=False), Column('added_at', DateTime(), table=<training_data>, nullable=False, default=CallableColumnDefault(<function datetime.utcnow at 0x110e7cea0>)), Column('is_training_data', Boolean(), table=<training_data>, nullable=False, default=ScalarElementColumnDefault(True)), schema=None))?
|
||||||
|
2025-04-18 16:19:37.169 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:19:37.169 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:22:09.127 | WARNING | vector_store:delete_document:246 - Invalid document ID: 1
|
||||||
|
2025-04-18 16:22:09.127 | WARNING | vector_store:delete_document:246 - Invalid document ID: 1
|
||||||
|
2025-04-18 16:22:27.719 | WARNING | vector_store:delete_document:246 - Invalid document ID: 2
|
||||||
|
2025-04-18 16:22:27.719 | WARNING | vector_store:delete_document:246 - Invalid document ID: 2
|
||||||
|
2025-04-18 16:30:22.904 | INFO | vector_store:search:212 - Found 1 matching documents for query
|
||||||
|
2025-04-18 16:30:22.904 | INFO | vector_store:search:212 - Found 1 matching documents for query
|
||||||
|
2025-04-18 16:30:31.859 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:30:31.859 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:30:31.859 | INFO | copywriter:generate_copy:90 - Generated content with 604 characters
|
||||||
|
2025-04-18 16:30:31.859 | INFO | copywriter:generate_copy:90 - Generated content with 604 characters
|
||||||
|
2025-04-18 16:30:32.289 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:30:32.289 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:32:33.304 | INFO | vector_store:search:212 - Found 2 matching documents for query
|
||||||
|
2025-04-18 16:32:33.304 | INFO | vector_store:search:212 - Found 2 matching documents for query
|
||||||
|
2025-04-18 16:32:42.281 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:32:42.281 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 16:32:42.283 | INFO | copywriter:generate_copy:90 - Generated content with 632 characters
|
||||||
|
2025-04-18 16:32:42.283 | INFO | copywriter:generate_copy:90 - Generated content with 632 characters
|
||||||
|
2025-04-18 16:32:42.750 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 16:32:42.750 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:12:33.909 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:12:33.909 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:12:33.912 | INFO | copywriter:generate_copy:90 - Generated content with 2740 characters
|
||||||
|
2025-04-18 17:12:33.912 | INFO | copywriter:generate_copy:90 - Generated content with 2740 characters
|
||||||
|
2025-04-18 17:12:37.538 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:12:37.538 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:13:04.600 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:13:04.600 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:13:17.051 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:13:17.051 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:13:17.052 | INFO | copywriter:generate_copy:90 - Generated content with 577 characters
|
||||||
|
2025-04-18 17:13:17.052 | INFO | copywriter:generate_copy:90 - Generated content with 577 characters
|
||||||
|
2025-04-18 17:13:17.652 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:13:17.652 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:14:08.039 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:14:08.039 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:14:33.729 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:14:33.729 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:14:33.741 | INFO | copywriter:generate_copy:90 - Generated content with 1717 characters
|
||||||
|
2025-04-18 17:14:33.741 | INFO | copywriter:generate_copy:90 - Generated content with 1717 characters
|
||||||
|
2025-04-18 17:14:34.184 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:14:34.184 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:28:38.798 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:28:38.798 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:28:38.800 | INFO | copywriter:generate_copy:90 - Generated content with 1962 characters
|
||||||
|
2025-04-18 17:28:38.800 | INFO | copywriter:generate_copy:90 - Generated content with 1962 characters
|
||||||
|
2025-04-18 17:28:39.569 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:28:39.569 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:29:13.466 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:29:13.466 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:29:30.844 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:29:30.844 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:29:30.845 | INFO | copywriter:generate_copy:90 - Generated content with 1416 characters
|
||||||
|
2025-04-18 17:29:30.845 | INFO | copywriter:generate_copy:90 - Generated content with 1416 characters
|
||||||
|
2025-04-18 17:29:31.237 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:29:31.237 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:31:18.658 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T16:32:42.751434 not found
|
||||||
|
2025-04-18 17:31:18.658 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T16:32:42.751434 not found
|
||||||
|
2025-04-18 17:31:40.805 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp "2025-04-18T16:32:42.751434" not found
|
||||||
|
2025-04-18 17:31:40.805 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp "2025-04-18T16:32:42.751434" not found
|
||||||
|
2025-04-18 17:32:24.114 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T17:12:37.541148 not found
|
||||||
|
2025-04-18 17:32:24.114 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T17:12:37.541148 not found
|
||||||
|
2025-04-18 17:34:18.118 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T171237541148 not found
|
||||||
|
2025-04-18 17:34:18.118 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T171237541148 not found
|
||||||
|
2025-04-18 17:34:40.614 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T035226 not found
|
||||||
|
2025-04-18 17:34:40.614 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T035226 not found
|
||||||
|
2025-04-18 17:35:36.594 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418171317. not found
|
||||||
|
2025-04-18 17:35:36.594 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418171317. not found
|
||||||
|
2025-04-18 17:36:13.263 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T17:13:17 not found
|
||||||
|
2025-04-18 17:36:13.263 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 2025-04-18T17:13:17 not found
|
||||||
|
2025-04-18 17:36:23.158 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T171317 not found
|
||||||
|
2025-04-18 17:36:23.158 | ERROR | main:get_user_query:429 - Error getting user query: 404: Query with timestamp 20250418T171317 not found
|
||||||
|
2025-04-18 17:40:24.503 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:40:24.503 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:40:54.614 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:40:54.614 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:40:54.615 | INFO | copywriter:generate_copy:90 - Generated content with 2080 characters
|
||||||
|
2025-04-18 17:40:54.615 | INFO | copywriter:generate_copy:90 - Generated content with 2080 characters
|
||||||
|
2025-04-18 17:40:55.135 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:40:55.135 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:41:16.349 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:41:16.349 | INFO | vector_store:search:212 - Found 3 matching documents for query
|
||||||
|
2025-04-18 17:41:55.042 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:41:55.042 | INFO | copywriter:_generate_headline_suggestions:188 - Generated 3 headline suggestions
|
||||||
|
2025-04-18 17:41:55.046 | INFO | copywriter:generate_copy:90 - Generated content with 2070 characters
|
||||||
|
2025-04-18 17:41:55.046 | INFO | copywriter:generate_copy:90 - Generated content with 2070 characters
|
||||||
|
2025-04-18 17:41:55.458 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
2025-04-18 17:41:55.458 | INFO | vector_store:add_documents:131 - Added 1 documents to vector store
|
||||||
|
|||||||
Reference in New Issue
Block a user