Initial commit
This commit is contained in:
+109
@@ -0,0 +1,109 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
### Environment ###
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Virtual environment
|
||||
pythonenv*
|
||||
|
||||
### IDE ###
|
||||
# VS Code
|
||||
.vscode/
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
### Data Files ###
|
||||
# Raw and processed news
|
||||
data/raw_news/
|
||||
data/processed_news/
|
||||
*.csv
|
||||
*.json
|
||||
*.parquet
|
||||
*.feather
|
||||
*.pkl
|
||||
*.pickle
|
||||
*.db
|
||||
*.sqlite
|
||||
|
||||
# Vector database files
|
||||
*.faiss
|
||||
*.index
|
||||
*.bin
|
||||
*.vec
|
||||
|
||||
### Logs ###
|
||||
*.log
|
||||
logs/
|
||||
|
||||
### OS Generated ###
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
### Groq/Cohere Cache ###
|
||||
.cache/
|
||||
model_cache/
|
||||
|
||||
### Test Files ###
|
||||
test_output/
|
||||
benchmark_results/
|
||||
|
||||
### Documentation ###
|
||||
docs/_build/
|
||||
@@ -0,0 +1,78 @@
|
||||
from typing import Dict
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class BrandStyle:
|
||||
def __init__(self):
|
||||
self.style = self._load_style()
|
||||
self.templates = {
|
||||
"email": self._load_template("email"),
|
||||
"social": self._load_template("social"),
|
||||
"general": self._load_template("general")
|
||||
}
|
||||
|
||||
def _load_style(self) -> Dict:
|
||||
path = Path("data/style_guidelines/style.json")
|
||||
if path.exists():
|
||||
return json.loads(path.read_text())
|
||||
else:
|
||||
# Create default style if doesn't exist
|
||||
default_style = {
|
||||
"tone": "professional",
|
||||
"phrases": ["innovative", "results-driven", "empowering", "transformation"],
|
||||
"avoid": ["cheap", "guarantee", "spam", "scam"]
|
||||
}
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(default_style, indent=2))
|
||||
return default_style
|
||||
|
||||
def _load_template(self, name: str) -> str:
|
||||
path = Path(f"data/style_guidelines/{name}_template.txt")
|
||||
if path.exists():
|
||||
return path.read_text()
|
||||
else:
|
||||
# Create default templates if they don't exist
|
||||
templates = {
|
||||
"email": "Write a professional email that engages the reader and includes a clear call-to-action.",
|
||||
"social": "Create an engaging social media post that captures attention and encourages interaction.",
|
||||
"general": "Generate marketing copy that is compelling, authentic, and aligned with brand values."
|
||||
}
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(templates.get(name, ""))
|
||||
return templates.get(name, "")
|
||||
|
||||
def get_prompt(self, request) -> str:
|
||||
# Handle both dict and Pydantic model objects
|
||||
if hasattr(request, 'dict'):
|
||||
# It's a Pydantic model
|
||||
request_dict = request.dict()
|
||||
tone = request.tone or self.style['tone']
|
||||
content_type = request.content_type
|
||||
else:
|
||||
# It's already a dict
|
||||
request_dict = request
|
||||
tone = request_dict.get('tone', self.style['tone'])
|
||||
content_type = request_dict.get('content_type', 'general')
|
||||
|
||||
return f"""
|
||||
You are a marketing assistant for Adriana James. Follow these brand guidelines:
|
||||
|
||||
TONE: {tone}
|
||||
STYLE: Professional, authentic, and empowering
|
||||
|
||||
PREFERRED PHRASES: {', '.join(self.style['phrases'])}
|
||||
AVOID USING: {', '.join(self.style['avoid'])}
|
||||
|
||||
CONTENT TYPE: {content_type}
|
||||
TEMPLATE GUIDANCE: {self.templates.get(content_type, self.templates['general'])}
|
||||
|
||||
Create marketing copy that:
|
||||
1. Reflects Adriana James' brand voice
|
||||
2. Is engaging and authentic
|
||||
3. Includes a clear value proposition
|
||||
4. Has a compelling call-to-action when appropriate
|
||||
5. Feels personal and relatable
|
||||
|
||||
Remember: Focus on transformation, empowerment, and results while maintaining professionalism.
|
||||
"""
|
||||
@@ -0,0 +1,11 @@
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class Config:
|
||||
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
|
||||
COHERE_API_KEY = os.getenv("COHERE_API_KEY")
|
||||
DATA_PATH = "data/past_campaigns/campaigns.json"
|
||||
FAISS_INDEX_PATH = "data/vector_store.index"
|
||||
@@ -0,0 +1,24 @@
|
||||
# backend/copywriter.py
|
||||
from .vector_store import VectorStore
|
||||
from .brand_style import BrandStyle
|
||||
import openai
|
||||
|
||||
class Copywriter:
|
||||
def __init__(self):
|
||||
self.vector_store = VectorStore()
|
||||
self.brand_style = BrandStyle()
|
||||
|
||||
def generate_copy(self, request):
|
||||
# Move the generation logic from main.py here
|
||||
similar = self.vector_store.search(request.prompt, request.content_type)
|
||||
|
||||
response = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[
|
||||
{"role": "system", "content": self.brand_style.get_prompt(request)},
|
||||
{"role": "user", "content": f"Prompt: {request.prompt}\n\nSimilar examples:\n{similar}"}
|
||||
],
|
||||
temperature=0.7
|
||||
)
|
||||
|
||||
return response.choices[0].message.content
|
||||
@@ -0,0 +1,18 @@
|
||||
from config import Config
|
||||
import cohere
|
||||
import openai
|
||||
|
||||
class Embeddings:
|
||||
def __init__(self):
|
||||
self.cohere = cohere.Client(Config.COHERE_API_KEY)
|
||||
|
||||
def get_embedding(self, text: str, engine: str = "cohere"):
|
||||
if engine == "cohere":
|
||||
response = self.cohere.embed(texts=[text], model="small")
|
||||
return response.embeddings[0]
|
||||
else: # OpenAI fallback
|
||||
response = openai.Embedding.create(
|
||||
input=[text],
|
||||
model="text-embedding-ada-002"
|
||||
)
|
||||
return response.data[0].embedding
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
from fastapi import FastAPI, HTTPException, UploadFile, File
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List
|
||||
import json
|
||||
from datetime import datetime
|
||||
from .vector_store import VectorStore
|
||||
from .brand_style import BrandStyle
|
||||
from .config import Config
|
||||
import openai
|
||||
import os
|
||||
|
||||
# Initialize OpenAI
|
||||
openai.api_key = Config.OPENAI_API_KEY
|
||||
|
||||
# Initialize
|
||||
app = FastAPI(title="Marketing Assistant AI", version="0.1.0")
|
||||
vector_store = VectorStore()
|
||||
brand_style = BrandStyle()
|
||||
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Models
|
||||
class CampaignRequest(BaseModel):
|
||||
prompt: str
|
||||
content_type: str = "general"
|
||||
tone: Optional[str] = None
|
||||
|
||||
class Campaign(BaseModel):
|
||||
content: str
|
||||
content_type: str
|
||||
metadata: dict = {}
|
||||
|
||||
# Routes
|
||||
@app.post("/generate")
|
||||
async def generate_copy(request: CampaignRequest):
|
||||
"""Generate marketing copy based on prompt and brand guidelines"""
|
||||
try:
|
||||
# Get similar content from vector store
|
||||
similar = vector_store.search(request.prompt, request.content_type)
|
||||
|
||||
# Format similar content for context
|
||||
similar_content = ""
|
||||
if similar:
|
||||
similar_content = "\n\nSimilar past campaigns for reference:\n"
|
||||
for i, campaign in enumerate(similar[:3], 1):
|
||||
similar_content += f"{i}. {campaign.get('content', '')}\n"
|
||||
|
||||
# Generate with OpenAI
|
||||
system_prompt = brand_style.get_prompt(request)
|
||||
user_prompt = f"Create marketing copy for: {request.prompt}{similar_content}"
|
||||
|
||||
response = openai.ChatCompletion.create(
|
||||
model="gpt-3.5-turbo",
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
],
|
||||
temperature=0.7,
|
||||
max_tokens=500
|
||||
)
|
||||
|
||||
generated_copy = response.choices[0].message.content
|
||||
|
||||
# Store the generated copy for future reference
|
||||
new_campaign = {
|
||||
"content": generated_copy,
|
||||
"content_type": request.content_type,
|
||||
"metadata": {
|
||||
"prompt": request.prompt,
|
||||
"tone": request.tone,
|
||||
"generated_at": datetime.now().isoformat()
|
||||
}
|
||||
}
|
||||
|
||||
# Add to vector store for future similarity searches
|
||||
vector_store.add_campaign(new_campaign)
|
||||
|
||||
return {"result": generated_copy}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in generate_copy: {str(e)}") # For debugging
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/add-campaign")
|
||||
async def add_campaign(campaign: Campaign):
|
||||
"""Add a new campaign to the vector store"""
|
||||
try:
|
||||
# Add timestamp to metadata
|
||||
campaign_data = campaign.dict()
|
||||
campaign_data["metadata"]["added_at"] = datetime.now().isoformat()
|
||||
|
||||
vector_store.add_campaign(campaign_data)
|
||||
return {"status": "success"}
|
||||
except Exception as e:
|
||||
print(f"Error in add_campaign: {str(e)}") # For debugging
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/search")
|
||||
async def search_campaigns(query: str, limit: int = 5):
|
||||
"""Search for similar campaigns"""
|
||||
try:
|
||||
results = vector_store.search(query, k=limit)
|
||||
return {"results": results}
|
||||
except Exception as e:
|
||||
print(f"Error in search_campaigns: {str(e)}") # For debugging
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
"""Health check endpoint"""
|
||||
return {"message": "Marketing Assistant AI is running", "version": "0.1.0"}
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
"""Detailed health check"""
|
||||
return {
|
||||
"status": "healthy",
|
||||
"vector_store_size": len(vector_store.campaigns),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
@@ -0,0 +1,7 @@
|
||||
fastapi
|
||||
uvicorn
|
||||
openai==0.28
|
||||
cohere
|
||||
sentence-transformers
|
||||
faiss-cpu
|
||||
python-dotenv
|
||||
@@ -0,0 +1,37 @@
|
||||
import faiss
|
||||
import numpy as np
|
||||
from sentence_transformers import SentenceTransformer
|
||||
from .config import Config
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class VectorStore:
|
||||
def __init__(self):
|
||||
self.model = SentenceTransformer('all-MiniLM-L6-v2')
|
||||
self.index = faiss.IndexFlatL2(384)
|
||||
self.campaigns = []
|
||||
self._load_data()
|
||||
|
||||
def _load_data(self):
|
||||
if Path(Config.DATA_PATH).exists():
|
||||
with open(Config.DATA_PATH) as f:
|
||||
self.campaigns = json.load(f)
|
||||
if self.campaigns:
|
||||
embeddings = self.model.encode([c["content"] for c in self.campaigns])
|
||||
self.index.add(embeddings)
|
||||
|
||||
def add_campaign(self, campaign: dict):
|
||||
self.campaigns.append(campaign)
|
||||
embedding = self.model.encode([campaign["content"]])
|
||||
self.index.add(embedding)
|
||||
self._save_data()
|
||||
|
||||
def search(self, query: str, content_type: str = None, k: int = 3):
|
||||
query_embedding = self.model.encode([query])
|
||||
distances, indices = self.index.search(query_embedding, k)
|
||||
return [self.campaigns[i] for i in indices[0]]
|
||||
|
||||
def _save_data(self):
|
||||
with open(Config.DATA_PATH, 'w') as f:
|
||||
json.dump(self.campaigns, f)
|
||||
@@ -0,0 +1 @@
|
||||
Write a professional email that engages the reader and includes a clear call-to-action.
|
||||
@@ -0,0 +1 @@
|
||||
Generate marketing copy that is compelling, authentic, and aligned with brand values.
|
||||
@@ -0,0 +1 @@
|
||||
Create an engaging social media post that captures attention and encourages interaction.
|
||||
@@ -0,0 +1,97 @@
|
||||
# Marketing Assistant AI
|
||||
|
||||
## Project Overview
|
||||
|
||||
Marketing Assistant AI is an AI-powered tool designed to streamline the process of ideation, copywriting, and marketing campaign creation. It generates marketing content in line with the brand tone and voice of Adriana James, producing drafts that can be validated and refined by a human marketer.
|
||||
|
||||
## Objectives
|
||||
|
||||
* Reduce the time required to generate marketing copy.
|
||||
* Create content for emails, campaigns, social media, website copy, funnel pages, and more.
|
||||
* Ensure the AI produces copywriting that aligns with the brand tone and voice of Adriana James.
|
||||
* Allow ongoing updates to improve the AI’s performance and accuracy.
|
||||
|
||||
## Deliverables
|
||||
|
||||
* A custom-trained LLM fine-tuned for marketing and copywriting.
|
||||
* Ability to generate copy in the same style and brand tone of Adriana James.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
* **LLM** : Open-source or proprietary LLM fine-tuned for marketing.
|
||||
* **Embeddings & Re-Ranking** : Cohere for embeddings and ranking results.
|
||||
* **Backend** : FastAPI for API services.
|
||||
* **Vector Database** : FAISS for content retrieval.
|
||||
* **Storage** : Local storage for historical marketing data.
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
Marketing_Assistant_AI/
|
||||
│-- backend/
|
||||
│ │-- main.py # FastAPI backend
|
||||
│ │-- copywriter.py # AI-powered copy generation module
|
||||
│ │-- vector_store.py # Manages vector database operations
|
||||
│ │-- embeddings.py # Generates embeddings using Cohere
|
||||
│ │-- brand_style.py # Ensures brand tone consistency
|
||||
│ │-- config.py # Configuration settings
|
||||
│ │-- requirements.txt # Dependencies
|
||||
│
|
||||
│-- data/
|
||||
│ │-- past_campaigns/ # Stores past marketing campaigns
|
||||
│ │-- user_queries/ # Stores past user queries for AI training
|
||||
│ │-- style_guidelines/ # Reference materials for brand tone
|
||||
│
|
||||
│-- docs/
|
||||
│ │-- README.md # Documentation for new developers
|
||||
│ │-- API_Documentation.md # API details
|
||||
│
|
||||
│-- .env # Environment variables
|
||||
│-- .gitignore # Git ignore file
|
||||
│-- LICENSE # License information
|
||||
```
|
||||
|
||||
## Setup & Installation
|
||||
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone http://23.29.118.76:3000/Test/ds_task_marketing_assistant_ai
|
||||
cd marketing-assistant-ai
|
||||
```
|
||||
|
||||
### 2. Set Up the Backend
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
python main.py
|
||||
```
|
||||
|
||||
## AI Copywriting Process
|
||||
|
||||
1. **User Input** : The user submits a request (e.g., "Generate an email campaign for a product launch").
|
||||
2. **Preprocessing** : The AI extracts key details and matches them with past marketing data.
|
||||
3. **Generation** : The fine-tuned LLM creates a draft aligned with Adriana James' brand tone.
|
||||
4. **Refinement** : The AI applies re-ranking to prioritize relevant content.
|
||||
5. **Final Output** : The generated copy is displayed for user review and editing.
|
||||
|
||||
### Example API Usage
|
||||
|
||||
#### Generate Marketing Copy
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
url = "http://localhost:8000/generate-copy"
|
||||
data = {"prompt": "Write a social media post for our new product launch"}
|
||||
response = requests.post(url, json=data)
|
||||
print(response.json())
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
* AI generates copywriting that accurately reflects the brand tone.
|
||||
* AI can be updated with new marketing materials.
|
||||
* CRUD functionality to manage training data.
|
||||
* AI adapts to new marketing trends and user queries.
|
||||
Reference in New Issue
Block a user