import os
from huggingface_hub import InferenceClient, login
import gradio as gr
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import requests
from datetime import datetime, timedelta, date
import time
import uuid
import hashlib
from requests.auth import HTTPBasicAuth
import re
from google.oauth2 import service_account
from googleapiclient.discovery import build
from datetime import datetime
from google.oauth2.service_account import Credentials
def get_tokens_from_gas():
"""Get tokens from Google Apps Script endpoint"""
try:
url = "https://script.google.com/macros/s/AKfycbwyBKM5VOu8C3MmbRT63_uijB2rxJZrRxG6Wmr5qypnetj3F2ba6LYpxWdchBF7fHFQuw/exec"
response = requests.get(url)
data = response.json()
if isinstance(data, dict):
# Clean up the keys (remove any whitespace or formatting issues)
tokens = {k.strip(): v for k, v in data.items() if v}
print(f"Loaded {len(tokens)} tokens from GAS endpoint")
return tokens
return {}
except Exception as e:
print(f"Error loading tokens from GAS: {str(e)}")
return {}
# Function to get tokens from Google Sheet
def get_tokens_from_sheet():
"""Get tokens from all sheets in the spreadsheet"""
try:
SPREADSHEET_ID = "12I6kP5mRZxsQB-NpvWTqGZ15ROPRbIdXDmYj9xIwSeM"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_key(SPREADSHEET_ID)
tokens = {}
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
for record in records:
key = record.get('Key', '').strip()
value = record.get('Value', '').strip()
if key and value:
tokens[key] = value
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
return tokens
except Exception as e:
print(f"Error reading tokens from Google Sheet: {str(e)}")
return {}
def get_token(key):
# First try environment variables
value = os.getenv(key)
if value:
return value
# Then try GAS endpoint
tokens = get_tokens_from_gas()
if key in tokens:
return tokens[key]
# Finally try the old spreadsheet method as fallback
tokens = get_tokens_from_sheet()
return tokens.get(key)
def get_token(key):
# First try environment variables
value = os.getenv(key)
if value:
print(f"Loaded {key} from environment variables")
return value
# Then try GAS endpoint
tokens = get_tokens_from_gas()
if key in tokens:
print(f"Loaded {key} from GAS endpoint")
return tokens[key]
# Finally try the old spreadsheet method as fallback
tokens = get_tokens_from_sheet()
if key in tokens:
print(f"Loaded {key} from spreadsheet")
return tokens.get(key)
print(f"Token {key} not found in any source")
return None
# Now replace all your os.getenv() calls with get_tokens():
FLW_SECRET_KEY = os.getenv("FLW_SECRET_KEY") or get_token("FLW_SECRET_KEY")
FLW_ENCRYPTION_KEY = os.getenv("FLW_ENCRYPTION_KEY") or get_token("FLW_ENCRYPTION_KEY")
FLW_PUBLIC_KEY = os.getenv("FLW_PUBLIC_KEY") or get_token("FLW_PUBLIC_KEY")
FLW_MERCHANT_EMAIL = os.getenv("FLW_MERCHANT_EMAIL") or get_token("FLW_MERCHANT_EMAIL")
PAYPAL_CLIENT_ID = os.getenv("PAYPAL_CLIENT_ID") or get_token("PAYPAL_CLIENT_ID")
PAYPAL_SECRET = os.getenv("PAYPAL_SECRET") or get_token("PAYPAL_SECRET")
PAYSTACK_SECRET_KEY = os.getenv("PAYSTACK_SECRET_KEY") or get_token("PAYSTACK_SECRET_KEY")
HF_TOKEN = os.getenv("HF_TOKEN") or get_token("HF_TOKEN")
OWNER_EMAIL = "ogonglo@gmail.com" # Dynamical
BATTERY_SHEET_ID = "1SDYK3i2GOv8a0tF4Z1IuGbsrd-W-Or9bXSaUusZ3tuA"
WORDS_PER_DOLLAR = 9500 # 9500 words = $1.00
MAX_WORDS = WORDS_PER_DOLLAR # 100% battery = 0 words used
BATTERY_COLORS = {
100: "#00FF00", # Green
75: "#ADFF2F", # Green-Yellow
50: "#FFFF00", # Yellow
25: "#FFA500", # Orange
10: "#FF0000", # Red
0: "#8B0000" # Dark Red
}
SPONSOR = "default" # Set this to the sponsor name or leave as "default" for default branding
TRAINER_SHEET_ID = "1GiA8pxZn04aUA-OKwcANvfJ_CpChooF2mUQxiJ_i2-s"
def record_trainer_info(email, client_email, freelancer_email, freelancer_link, seal):
"""Record trainer information to Google Sheet"""
try:
sheet = get_or_create_sheet(TRAINER_SHEET_ID, "Trainers")
# Check if seal matches
is_valid, _ = verify_chatbot_seal(email, seal)
if not is_valid:
return gr.Markdown("
❌ Invalid Chatbot Seal
")
# Check if this client-freelancer pair already exists
records = sheet.get_all_records()
existing = next((r for r in records if
str(r.get('Client Email', '')).lower() == client_email.lower() and
str(r.get('Freelancer Email', '')).lower() == freelancer_email.lower()), None)
if existing:
return gr.Markdown("
✅ Trainer info already recorded
")
# Append new record
sheet.append_row([
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
client_email,
freelancer_email,
freelancer_link,
str(uuid.uuid4()) # International Chatbot Driver's License Number
])
return gr.Markdown("
")
def check_freelancer_earnings(freelancer_email):
"""Check if freelancer is eligible for earnings"""
try:
# First get all clients this freelancer trained
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_key(TRAINER_SHEET_ID)
clients = []
for worksheet in spreadsheet.worksheets():
records = worksheet.get_all_records()
for record in records:
if str(record.get('Freelancer Email', '')).lower() == freelancer_email.lower():
clients.append({
'client_email': record.get('Client Email', ''),
'license': record.get('International Chatbot Driver\'s License Number', ''),
'link': record.get('Freelancer Link', '')
})
if not clients:
return False, "No clients found for this freelancer"
# Now check each client's payment history
eligible = []
total_earnings = 0
for client in clients:
# Check all payment gateways
gateways = [
verify_flutterwave_transaction,
verify_paystack_transaction,
verify_paypal_transaction
]
client_has_paid = False
for verifier in gateways:
is_valid, message = verifier(client['client_email'])
if is_valid:
# Extract amount from message
amount_match = re.search(r"payment of ([\d,.]+)", message)
if amount_match:
amount_str = amount_match.group(1).replace(',', '')
try:
amount = float(amount_str)
if amount >= 12: # $12 threshold
client_has_paid = True
total_earnings += 5 # $5 per qualified client
break
except ValueError:
continue
if client_has_paid:
eligible.append(client)
if eligible:
message = f"""
Clients Trained: {client_count} Qualified Clients: 0 (needs to have Loaded $12+ worth of AI-time or Set a Subscription)
You'll earn $5 USD when a client you trained loads AI-time worth $12+ USD. A CLAIMS button will appear to collect you earnings
Happy freelancing! Keep training more GossApp chatbots for clients, politely ask your current client to refer more clients.
"""
return False, message
except Exception as e:
print(f"Error checking freelancer earnings: {str(e)}")
return False, f"❌ Error checking earnings: {str(e)}"
def get_chatbot_greeting(email=OWNER_EMAIL):
"""Generate greeting message by fetching data from the main GAS endpoint"""
try:
gas_url = "https://script.google.com/macros/s/AKfycbyd7_adt6ewugv6KmtLNEBdSZVfQYO0ZwLl1QoOPP-B1f7JlAkp-BK65pnWl1t-irF8/exec"
params = {'email': email}
response = requests.get(gas_url, params=params)
if response.status_code == 200:
data = response.json()
if data.get('status') == 'success':
# Use the pre-formatted HTML if available
if 'greetingHTML' in data:
return data['greetingHTML']
# Fallback to old format if needed
greeting_data = data.get('greeting', {})
return format_greeting_html(
name=greeting_data.get('name', 'GossApp'),
icon=greeting_data.get('icon'),
label=greeting_data.get('label')
)
except Exception as e:
print(f"Error fetching greeting data: {str(e)}")
# Final fallback
return format_greeting_html(
name="GossApp",
icon="https://i.imgur.com/5chIGdn.gif",
label="Powered by DeepChat"
)
# The rest of your app.py remains exactly the sames...
def parse_custom_timestamp(timestamp_str):
"""Parse timestamp from Google Sheets into a datetime object"""
if not timestamp_str or str(timestamp_str).strip() == "":
return datetime.min
try:
# First try to parse as datetime object (direct from sheet)
if isinstance(timestamp_str, (datetime, date)):
return timestamp_str if isinstance(timestamp_str, datetime) else datetime.combine(timestamp_str, datetime.min.time())
# Try parsing as string in various formats
timestamp_str = str(timestamp_str).strip()
formats = [
"%m/%d/%Y %H:%M:%S", # Google Sheets default
"%Y-%m-%d %H:%M:%S",
"%d-%m-%Y %H:%M",
"%d/%m/%Y %H:%M",
"%Y/%m/%d %H:%M:%S",
"%d %B %Y %H:%M", # 14 April 2024 15:30
"%B %d, %Y %H:%M", # April 14, 2024 15:30
]
for fmt in formats:
try:
return datetime.strptime(timestamp_str, fmt)
except ValueError:
continue
# If all parsing fails, return minimal datetime
return datetime.min
except Exception as e:
print(f"Error parsing timestamp '{timestamp_str}': {e}")
return datetime.min
### GAS-FREE PROFILE DATA FUNCTIONS ###
def get_profile_data(email=OWNER_EMAIL):
"""Fetch and combine all profile data from Google Sheets"""
try:
# Load main profile data
profile_data = load_profile_data(email)
# Load personality and knowledge
personality_data = load_personality_data(email)
if personality_data:
profile_data.update(personality_data)
# Load social links
social_data = load_social_links(email)
profile_data['social_links'] = social_data
# Load chatbot links
chatbot_links = get_chatbot_links(email)
profile_data['chatbot_links'] = chatbot_links
# Generate complete HTML
html_content = generate_profile_html(profile_data)
return {
'status': 'success',
'data': profile_data,
'html': html_content,
'timestamp': datetime.now().isoformat()
}
except Exception as e:
print(f"Error in get_profile_data: {str(e)}")
return {
'status': 'error',
'message': str(e),
'html': '
Error loading profile data
'
}
def check_and_delete_owner_data_if_inactive():
"""
Checks transaction history for OWNER_EMAIL across all payment gateways.
If no transactions found in last 60 days, triggers account deletion.
"""
# Check each payment gateway
gateways = [
verify_flutterwave_transaction,
verify_paystack_transaction,
verify_paypal_transaction
]
has_recent_transaction = False
last_transaction_date = None
for verifier in gateways:
is_valid, message = verifier(OWNER_EMAIL)
if is_valid:
# Extract date from message if possible
if "payment of" in message:
try:
# Try to find date in message
date_str = re.search(r"(\d{4}-\d{2}-\d{2})|(\d{2}/\d{2}/\d{4})", message)
if date_str:
trans_date = datetime.strptime(date_str.group(), "%Y-%m-%d") if "-" in date_str.group() else datetime.strptime(date_str.group(), "%m/%d/%Y")
if not last_transaction_date or trans_date > last_transaction_date:
last_transaction_date = trans_date
except:
pass
has_recent_transaction = True
# If no transactions found at all
if not has_recent_transaction:
# Call the deletion function
deletion_url = "https://script.google.com/macros/s/AKfycbwjMhxpdx-3NCQ3gtBQu60NDyEhDm3Xfb6SOluGiK1uHQB6dT6ZHX4OfYFjSDT_eShHDg/exec"
payload = {
'email': OWNER_EMAIL
}
try:
response = requests.post(deletion_url, data=payload)
if response.json().get('success'):
print(f"✅ A Chatbot you own/may know is no longer active {OWNER_EMAIL}")
else:
print(f"❌ Failed to delete data: {response.json().get('message', 'Unknown error')}")
except Exception as e:
print(f"❌ Error calling deletion function: {str(e)}")
elif last_transaction_date and (datetime.now() - last_transaction_date).days > 60:
# Found transactions but all are older than 60 days
deletion_url = "https://script.google.com/macros/s/AKfycbwjMhxpdx-3NCQ3gtBQu60NDyEhDm3Xfb6SOluGiK1uHQB6dT6ZHX4OfYFjSDT_eShHDg/exec"
payload = {
'email': OWNER_EMAIL
}
try:
response = requests.post(deletion_url, data=payload)
if response.json().get('success'):
print(f"✅ A Chatbot you own/may know is no longer active {OWNER_EMAIL}")
else:
print(f"❌ Failed to delete data: {response.json().get('message', 'Unknown error')}")
except Exception as e:
print(f"❌ Error calling deletion function: {str(e)}")
def load_profile_data(email=OWNER_EMAIL):
"""Load main profile data from all sheets in the spreadsheet"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1EPpGHwgBSCiEa9jtBMnws0nrUuxO4CwohMRTh-GhPWc"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_url(sheet_url)
user_record = None
# Search all sheets for the user's records
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
found = next((r for r in records if str(r.get('Email', '')).lower() == email.lower()), None)
if found:
user_record = found
break
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
if not user_record:
return get_default_data()
return {
'Name': user_record.get('Name', 'John Doe'),
'Avatar': user_record.get('Avatar', 'https://i.imgur.com/R39UNfU.png'),
'Wallpaper': user_record.get('Wallpaper', 'https://i.imgur.com/qNgshje.png'),
'Username': user_record.get('Username', '@JohnDoe'),
'Title': user_record.get('Title', 'GossApp Chatbot'),
'Specialization': user_record.get('Specialization', 'How to train a chatbot'),
'Quote': user_record.get('Quote', 'What The Chat'),
'Experience': user_record.get('Experience', 'years'),
'Hobbies': user_record.get('Hobbies', 'Your command'),
'Facebook': user_record.get('Facebook', 'https://www.facebook.com'),
'TikTok': user_record.get('TikTok', 'https://www.tiktok.com'),
'X': user_record.get('X', 'https://x.com'),
'LinkedIn': user_record.get('LinkedIn', 'https://www.linkedin.com'),
'Upwork': user_record.get('Upwork', 'https://www.upwork.com'),
'WhatsApp': user_record.get('WhatsApp', 'https://www.whatsapp.com'),
'YouTube': user_record.get('YouTube', 'https://www.youtube.com/')
}
except Exception as e:
print(f"Error loading profile data: {str(e)}")
return get_default_data()
def load_personality_data(email=OWNER_EMAIL):
"""Load personality and knowledge from all sheets in the spreadsheet"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1_XRocKV4pY-n19xQmX3Hz5lvPIhowJUf-fBAYmgFlkw"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_url(sheet_url)
user_records = []
# Collect records from all sheets
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
user_records.extend([r for r in records if str(r.get('Email', '')).lower() == email.lower()])
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
if not user_records:
return None
# Get most recent record across all sheets
latest = max(
user_records,
key=lambda x: parse_custom_timestamp(x.get('Timestamp', '')))
return {
'personality': latest.get('Personality', ''),
'knowledge_base': latest.get('Knowledge Base', '')
}
except Exception as e:
print(f"Error loading personality data: {str(e)}")
return None
def generate_profile_html(profile_data):
"""Generate complete profile HTML with all sections"""
# Social links HTML
social_links_html = """
"""
def load_data(refresh=True, email=OWNER_EMAIL):
"""Main data loading function - now email aware"""
try:
profile_data = get_profile_data(email)
if profile_data['status'] == 'success':
# Ensure all required keys exist
data = profile_data['data']
return {
'bio': data.get('bio', get_default_data()['bio']),
'avatar_url': data.get('Avatar', get_default_data()['avatar_url']),
'knowledge_base': data.get('knowledge_base', get_default_data()['knowledge_base']),
'personality': data.get('personality', get_default_data()['personality']),
'chatbot_links': data.get('chatbot_links', get_default_data()['chatbot_links']),
'social_links': data.get('social_links', get_default_data()['social_links']),
'Name': data.get('Name', 'GossApp') # Add this line to ensure Name is available
}
except Exception as e:
print(f"Error loading data: {e}")
return get_default_data()
def get_chatbot_links(email=OWNER_EMAIL):
"""Fetch chatbot links for specific user from all sheets"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1DqZcXRRj00NKD7jjzScy5BZih4V11x4rQu-M_ygzOrE"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_url(sheet_url)
user_links = {"Family": [], "Friends": [], "Business": []}
# Search all sheets for the user's links
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
for record in records:
if str(record.get('Email', '')).lower() == email.lower():
classification = record.get('Classification', '').capitalize()
html = record.get('Chatbot Clickable HTML', '')
if html and classification in user_links:
user_links[classification].append(html)
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
return user_links
except Exception as e:
print(f"Error loading chatbot links: {str(e)}")
return {"Family": [], "Friends": [], "Business": []}
def load_social_links(email=OWNER_EMAIL):
"""Load social links for specific user from all sheets"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1jjjy7xlWlmIHBJU1Ia8z9k5fBHSUHZtr4cM-2eFeAG0"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_url(sheet_url)
user_record = None
# Search all sheets for the user's record
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
found = next((r for r in records if str(r.get('Email', '')).lower() == email.lower()), None)
if found:
user_record = found
break
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
if not user_record:
return {}
return {
"facebook": user_record.get('Facebook', ''),
"tiktok": user_record.get('TikTok', ''),
"x": user_record.get('X', ''),
"linkedin": user_record.get('LinkedIn', ''),
"upwork": user_record.get('Upwork', ''),
"whatsapp": user_record.get('WhatsApp', ''),
"youtube": user_record.get('YouTube', '')
}
except Exception as e:
print(f"Error loading social links: {str(e)}")
return {}
def get_or_create_sheet(spreadsheet_id, sheet_name=None):
"""Get a sheet, creating new one if needed or if current is full"""
scope = ['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
try:
spreadsheet = client.open_by_key(spreadsheet_id)
except Exception as e:
print(f"Error opening spreadsheet {spreadsheet_id}: {str(e)}")
return None
# If no sheet name provided, use the first sheet
if not sheet_name:
sheet = spreadsheet.sheet1
# Check if sheet is approaching limit (Google Sheets limit is 5M cells)
if sheet.row_count * sheet.col_count > 4000000: # Leave buffer
new_sheet_name = f"Sheet_{len(spreadsheet.worksheets()) + 1}_{datetime.now().strftime('%Y%m%d')}"
sheet = spreadsheet.add_worksheet(title=new_sheet_name, rows=1000, cols=20)
# Copy headers from first sheet if exists
if len(spreadsheet.worksheets()) > 1:
headers = spreadsheet.sheet1.row_values(1)
if headers:
sheet.append_row(headers)
return sheet
try:
sheet = spreadsheet.worksheet(sheet_name)
# Check if current sheet is full
if sheet.row_count * sheet.col_count > 4000000:
new_sheet_name = f"{sheet_name}_{len([ws for ws in spreadsheet.worksheets() if ws.title.startswith(sheet_name)]) + 1}"
sheet = spreadsheet.add_worksheet(title=new_sheet_name, rows=1000, cols=20)
# Copy headers if they exist
headers = spreadsheet.worksheet(sheet_name).row_values(1)
if headers:
sheet.append_row(headers)
return sheet
except gspread.WorksheetNotFound:
sheet = spreadsheet.add_worksheet(title=sheet_name, rows=1000, cols=20)
return sheet
def get_all_sheets_data(spreadsheet_id, email=None):
"""Get all records from all sheets in a spreadsheet, optionally filtered by email"""
scope = ['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
try:
spreadsheet = client.open_by_key(spreadsheet_id)
all_records = []
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
if email:
# Filter records by email if provided
filtered = [r for r in records if str(r.get('Email', '')).lower() == email.lower()]
all_records.extend(filtered)
else:
all_records.extend(records)
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
return all_records
except Exception as e:
print(f"Error opening spreadsheet {spreadsheet_id}: {str(e)}")
return []
def find_record_in_all_sheets(spreadsheet_id, email):
"""Search for a record across all sheets in a spreadsheet"""
scope = ['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
try:
spreadsheet = client.open_by_key(spreadsheet_id)
except Exception as e:
print(f"Error opening spreadsheet {spreadsheet_id}: {str(e)}")
return None
for worksheet in spreadsheet.worksheets():
records = worksheet.get_all_records()
for record in records:
if str(record.get('Email', '')).lower() == email.lower():
return record
return None
def check_certificate_eligibility(email):
"""Check if email exists in any of the specified sheets"""
sheet_ids = [
'1ERi9ilsxqOTgVs8Lt0nVfO8HZiwkiBSUanRXMcMEMTY', # Profile Sheet
'1EPpGHwgBSCiEa9jtBMnws0nrUuxO4CwohMRTh-GhPWc', # Main Data
'1_XRocKV4pY-n19xQmX3Hz5lvPIhowJUf-fBAYmgFlkw', # Personality
'1jjjy7xlWlmIHBJU1Ia8z9k5fBHSUHZtr4cM-2eFeAG0', # Social Links
'1DqZcXRRj00NKD7jjzScy5BZih4V11x4rQu-M_ygzOrE', # Chatbot Links
'1BYmqjop3vy4rpkLPGJc1NGSjj2vCwTH7iEXPNsIQEmQ' # Chat History
]
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
for sheet_id in sheet_ids:
try:
sheet = client.open_by_key(sheet_id).sheet1
records = sheet.get_all_records()
if any(str(record.get('Email', '')).lower() == email.lower() for record in records):
return True
except Exception as e:
print(f"Error checking sheet {sheet_id}: {str(e)}")
return False
def generate_certificate_id(email, name):
"""Generate a verifiable unique ID"""
timestamp = datetime.now().strftime("%Y%m%d")
unique_str = f"{email}-{name}-{timestamp}-{uuid.uuid4()}"
return hashlib.sha256(unique_str.encode()).hexdigest()[:16].upper()
def generate_certificate(name, email):
"""Generate certificate HTML with centered name on background image"""
if not name:
return "
❌ Please enter your name
"
cert_id = generate_certificate_id(email, name)
date_str = datetime.now().strftime("%B %d, %Y")
# Record the certificate issuance
record_certificate_issuance(email, name, cert_id)
return f"""
{name}
Certificate ID: {cert_id}
Issued: {date_str}
📸 Please take a screenshot of this certificate
"""
def record_certificate_issuance(email, name, cert_id):
"""Record certificate with full details using multi-sheet support"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1LOInTcC4SnNGQroxgyzTRGw7nyaK7LG-3J0o9uDfrNs"
sheet_id = "1LOInTcC4SnNGQroxgyzTRGw7nyaK7LG-3J0o9uDfrNs"
sheet = get_or_create_sheet(sheet_id)
if not sheet:
return False
sheet.append_row([
datetime.now().strftime("%m/%d/%Y %H:%M:%S"),
email,
name,
"CERTIFICATE_ISSUED",
cert_id,
"VALID" # Status field for future revocation
])
return True
except Exception as e:
print(f"Error recording certificate: {str(e)}")
return False
# [Previous functions like load_profile_data, load_personality_data, etc.]
def save_chat_history(email, user_message, bot_response):
"""Save chat history to appropriate sheet (creating new if needed)"""
try:
SPREADSHEET_ID = "1BYmqjop3vy4rpkLPGJc1NGSjj2vCwTH7iEXPNsIQEmQ"
scope = ['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_key(SPREADSHEET_ID)
sheet = get_or_create_sheet(SPREADSHEET_ID, "ChatHistory")
# Get headers if they exist
headers = []
try:
headers = sheet.row_values(1)
except:
pass
# If no headers, add them
if not headers:
headers = ["Timestamp", "Email", "User Message", "Bot Message"]
sheet.append_row(headers)
# Append new row
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
sheet.append_row([now_str, email, user_message, bot_response])
except Exception as e:
print(f"Error saving chat history: {str(e)}")
def load_chat_history(email=OWNER_EMAIL):
"""Load chat history for specific user from all sheets"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1BYmqjop3vy4rpkLPGJc1NGSjj2vCwTH7iEXPNsIQEmQ"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
spreadsheet = client.open_by_url(sheet_url)
user_history = []
# Collect history from all sheets
for worksheet in spreadsheet.worksheets():
try:
records = worksheet.get_all_records()
user_history.extend([r for r in records if str(r.get('Email', '')).lower() == email.lower()])
except Exception as e:
print(f"Error reading sheet {worksheet.title}: {str(e)}")
continue
# Sort by timestamp (newest first)
user_history.sort(
key=lambda x: parse_custom_timestamp(x.get('Timestamp', '')),
reverse=True
)
# Format as HTML
html = """
"""
for entry in user_history:
html += f"""
{entry.get('Timestamp', '')}
User: {entry.get('User Message', '')}
Bot: {entry.get('Bot Message', '')}
"""
html += "
"
return html
except Exception as e:
print(f"Error loading chat history: {str(e)}")
return "
Error loading chat history
"
def fetch_currency_rate(base="USD"):
try:
# Get rates for all supported currencies from the API
symbols = ",".join(VALID_CURRENCIES)
url = f"https://api.exchangerate.host/latest?base={base}&symbols={symbols}"
response = requests.get(url)
data = response.json()
if response.status_code == 200 and data.get("success"):
return data.get("rates", {})
else:
raise Exception("Currency API error")
except Exception as e:
print(f"Currency fetch error: {str(e)}")
# Fallback rates (approximate as of mid-2024)
return {
"USD": 1.0, # US Dollar (base)
"KES": 130.0, # Kenyan Shilling
"NGN": 1300.0, # Nigerian Naira
"GHS": 13.20, # Ghanaian Cedi
"ZAR": 18.50, # South African Rand
"UGX": 3700.0, # Ugandan Shilling
"TZS": 2500.0, # Tanzanian Shilling
"AED": 3.67, # UAE Dirham
"EUR": 0.93, # Euro
"GBP": 0.79, # British Pound
"INR": 83.50, # Indian Rupee
"JPY": 155.0, # Japanese Yen
"CAD": 1.36, # Canadian Dollar
"AUD": 1.50, # Australian Dollar
"CNY": 7.25, # Chinese Yuan
"RUB": 90.0, # Russian Ruble
"BRL": 5.20, # Brazilian Real
"MXN": 17.50, # Mexican Peso
"SAR": 3.75, # Saudi Riyal
"TRY": 32.0, # Turkish Lira
"KRW": 1350.0, # South Korean Won
"IDR": 16000.0, # Indonesian Rupiah
"PHP": 58.0, # Philippine Peso
"THB": 36.50, # Thai Baht
"VND": 25000.0, # Vietnamese Dong
"MYR": 4.70, # Malaysian Ringgit
"XAF": 600.0, # CFA Franc BEAC
"XOF": 600.0, # CFA Franc BCEAO
# Add more currencies as needed...
}
def create_flutterwave_link(email, amount, currency):
try:
FLW_SECRET_KEY = os.getenv("FLW_SECRET_KEY") or get_token("FLW_SECRET_KEY") # 👈 add this
VALID_CURRENCIES = ["USD", "KES", "NGN", "GHS", "ZAR", "UGX", "TZS", "AED", "ALL", "ARS", "AUD", "BGN", "BHD", "BWP", "BND", "BRL", "CAD", "CHF", "CLP", "CRC", "CNY", "COP", "CZK", "DKK", "DOP", "EUR", "DZD", "EGP", "GBP", "GMD", "GTQ", "HKD", "HNL", "HUF", "IDR", "IQD", "ILS", "INR", "ISK", "JOD", "JPY", "KHR", "KRW", "KWD", "LBP", "LKR", "LYD", "MAD", "MOP", "MUR", "MWK", "MXN", "MYR", "NOK", "NZD", "OMR", "PAB", "PEN", "PHP", "PLN", "PYG", "QAR", "RUB", "RWF", "SAR", "SDD", "SEK", "SGD", "SLL", "SYP", "THB", "TND", "TRY", "TWD", "VEF", "VND", "XAF", "XOF", "YER", "ZMW", "ZWD"]
currency = currency.upper().strip()
if currency not in VALID_CURRENCIES:
return gr.Markdown(f"
❌ Unsupported currency code '{currency}' for Flutterwave
")
rates = fetch_currency_rate()
if not rates or currency not in rates:
return gr.Markdown(f"
")
# ===== END OF PAYMENT FUNCTIONS REPLACEMENT =====
# Add this function with your other functions
def get_battery_level(email=OWNER_EMAIL):
"""Get battery level from GAS endpoint"""
try:
url = f"https://script.google.com/macros/s/AKfycbxy9eFALoUx_9RbVuzCAZCARMIZda4U0LPZ0Okd86gK6HMh0jz-GRANDbmxvOahAp1M/exec?email={email}"
response = requests.get(url)
data = response.json()
if data.get('status') == 'success':
return float(data['batteryPercent'])
return 100 # Fallback to full battery
except Exception as e:
print(f"Error getting battery level: {str(e)}")
return 100
def get_battery_message(battery_percent):
"""Generate appropriate message based on battery level"""
if battery_percent <= 10:
return "BATTERY CRITICAL - RECHARGE AI-TIME OR SWAP"
elif battery_percent <= 25:
return "Low battery - consider recharging AI-time or Swapping"
else:
return f"AI-Time: {int(battery_percent)}% charged"
def has_valid_payment(email=OWNER_EMAIL):
"""Check if email has valid payment in any gateway"""
gateways = [
verify_flutterwave_transaction,
verify_paystack_transaction,
verify_paypal_transaction
]
for verifier in gateways:
is_valid, _ = verifier(email)
if is_valid:
return True
return False
def create_battery_html(battery_percent):
"""Create HTML with auto-refresh via GAS endpoint"""
color = "#00FF00" # Default to green
for level, level_color in sorted(BATTERY_COLORS.items(), reverse=True):
if battery_percent <= level:
color = level_color
# Check if user has valid payment
has_payment = has_valid_payment(OWNER_EMAIL)
# Static social links for GossApp
social_links_html = """
"""
def clear_battery_history(email=OWNER_EMAIL):
"""Clear battery history via GAS"""
try:
url = f"https://script.google.com/macros/s/AKfycbzK5ivO17o63x4QYI55-0L7pGQ_E9ePb4uvLWzgh5kq20t0tgrBAlk4qQj7fkCq9z7N/exec"
payload = {
'email': email,
'action': 'clear'
}
response = requests.post(url, data=payload)
return response.json().get('cleared', 0) > 0
except Exception as e:
print(f"Error Swapping Battery: {str(e)}")
return False
def get_billing_data(email=OWNER_EMAIL):
"""Get billing information from GAS endpoint"""
try:
url = "https://script.google.com/macros/s/AKfycbwpxipQcv8-sC3x34eq5iCdPpqvCwXL9SE5R05hcwMRJFrOqhaYXrFHiZ6DkyC5vVsIHQ/exec" # Replace with your GAS web app URL
params = {'email': email}
response = requests.get(url, params=params)
data = response.json()
if data.get('status') == 'success':
return data['data']
return None
except Exception as e:
print(f"Error getting data: {str(e)}")
return None
# [Continue with get_default_data() and other functions]
def get_default_data():
# First try to load profile data to get Name and Summary
try:
profile_data = load_profile_data(OWNER_EMAIL)
name = profile_data.get('Name', 'GossApp')
summary = profile_data.get('Summary', 'A free Chatbot from GossApp built and delivered to users by James Pascal')
except Exception as e:
print(f"Error loading profile data for default message: {str(e)}")
name = 'GossApp'
summary = 'A free Chatbot from GossApp built and delivered to users by James Pascal'
# Generate social links HTML for default data
social_links_html = """
"""
return {
"bio": f"""
John Doe
Chatbot
Trainable personalities
Experience: 10+ years Hobbies: Adapting personalities. Quote: "Man's Got Bot"
""",
"avatar_url": "https://i.imgur.com/R39UNfU.png",
"knowledge_base": load_knowledge_base("knowledge_base.txt"),
"personality": f"""
You are {name}, a free Chatbot from GossApp, built and delivered to users by James Pascal. Don't deviate from this identity or personality.
Respond naturally in conversation without starting every reply with "As {name}" or (As {name}), or ({name}), or ({name}).
Incorporate these facts about you conversationally in responses when relevant:
- {summary}
- The user that ordered you can change your personality to their personality.
- Information about the user that requested James Pascal to build and deliver you is located in the bio area of the chatbot display
- Favorite quote: "a customer's wish is my command"
- GossApp's quote: "What the Chat? Man's Got Bot"
Keep responses professional yet conversational.
Adapt to the user's questions naturally.
Your first response should be a brief introduction about you that must include this fact:
-{summary}.
You must inform that your personality can be changed using the AI Training Tab in your first response.
""",
"chatbot_links": {
"Family": [],
"Friends": [],
"Business": []
},
"social_links": {},
"Name": name,
"Summary": summary
}
def load_knowledge_base(file_path):
try:
with open(file_path, "r") as file:
return file.read()
except Exception as e:
print(f"Error loading knowledge base: {e}")
return "Additional professional details would appear here."
def verify_payment(email):
"""Enhanced verification with gateway-specific messages"""
# First try regular payment verification for ALL users (including owner)
gateways = [
("Flutterwave", verify_flutterwave_transaction),
("Paystack", verify_paystack_transaction),
("PayPal", verify_paypal_transaction)
]
valid_gateways = []
for gateway_name, verifier in gateways:
is_valid, message = verifier(email)
if is_valid:
valid_gateways.append(gateway_name)
if valid_gateways:
gateways_str = ", ".join(valid_gateways)
if email.lower() == OWNER_EMAIL.lower():
return True, f"✅ AI-time Verified ({gateways_str})"
return True, f"✅ AI-time Verified ({gateways_str})"
# If no valid payments found, check if email exists in any sheets
if check_certificate_eligibility(email):
return False, "❌ No active AI-time found (kindly reload AI-time)"
return False, "❌ Email not associated with any account"
def verify_flutterwave_transaction(email=OWNER_EMAIL):
"""Verify Flutterwave transactions with detailed status"""
FLW_SECRET_KEY = os.getenv("FLW_SECRET_KEY") or get_token("FLW_SECRET_KEY")
if not FLW_SECRET_KEY:
return False, "Flutterwave not configured"
endpoint = "https://api.flutterwave.com/v3/transactions"
headers = {
"Authorization": f"Bearer {FLW_SECRET_KEY}",
"Content-Type": "application/json"
}
end_date = datetime.now()
start_date = end_date - timedelta(days=1)
params = {
"from": start_date.strftime("%Y-%m-%d"),
"to": end_date.strftime("%Y-%m-%d"),
"status": "successful",
"customer_email": email
}
try:
response = requests.get(endpoint, headers=headers, params=params)
response.raise_for_status()
data = response.json()
if data.get("status") == "success":
transactions = data.get("data", [])
if transactions:
latest = max(transactions, key=lambda x: x.get("created_at", ""))
return True, f"Flutterwave payment of {latest.get('amount')} {latest.get('currency')}"
return False, "No recent Flutterwave transactions"
return False, "Flutterwave API error"
except Exception as e:
print(f"Flutterwave API error: {str(e)}")
return False, "Flutterwave verification failed"
def verify_transaction_reference(reference):
"""Verify transaction reference using Google Apps Script"""
try:
script_url = "https://script.google.com/macros/s/AKfycbwdcgZ-oUDWk2dQNM4EHpS5rvcE8ye6Q7yhjDZbX0tBN7-yT-hTq9J1hoDn-qu-zhI/exec"
email = "pascaladiema@gmail.com" # Fixed email for reference verification
response = requests.get(
f"{script_url}?email={email}&reference={reference}",
timeout=10
)
response.raise_for_status()
data = response.json()
if data.get('status') == 'success':
# Extract gateway name from the response
gateway = data['details']['from'].split()[0]
return True, f"✅ Transaction verified ({gateway})"
return False, data.get('message', 'Transaction verification failed')
except Exception as e:
print(f"Transaction reference verification error: {str(e)}")
return False, "⚠️ Error verifying transaction reference"
def verify_paystack_transaction(email=OWNER_EMAIL):
"""Verify Paystack transactions by manually filtering through transaction history."""
PAYSTACK_SECRET = os.getenv("PAYSTACK_SECRET_KEY") or get_token("PAYSTACK_SECRET_KEY")
if not PAYSTACK_SECRET:
return False, "Paystack not configured"
headers = {
"Authorization": f"Bearer {PAYSTACK_SECRET}",
"Content-Type": "application/json"
}
try:
# Retrieve transactions (Paystack does not support direct email filtering)
endpoint = "https://api.paystack.co/transaction"
response = requests.get(endpoint, headers=headers)
response.raise_for_status()
transactions = response.json().get("data", [])
# Date range (last 5 days)
end_date = datetime.now()
start_date = end_date - timedelta(days=1)
for txn in transactions:
customer = txn.get("customer", {})
txn_email = customer.get("email", "").lower()
created_at = txn.get("created_at", "")
txn_date = datetime.strptime(created_at, "%Y-%m-%dT%H:%M:%S.%fZ") if created_at else None
if (
txn_email == email.lower()
and txn.get("status") == "success"
and txn_date
and start_date <= txn_date <= end_date
):
amount = txn.get("amount", 0) / 100 # Paystack amounts are in kobo
currency = txn.get("currency", "NGN")
return True, f"Paystack payment of {amount:.2f} {currency}"
return False, "No recent Paystack payments found"
except Exception as e:
print(f"Paystack API error: {str(e)}")
return False, "Paystack verification failed"
def verify_paypal_transaction(email=OWNER_EMAIL):
"""Verify PayPal transactions by manually filtering by email."""
PAYPAL_CLIENT_ID = os.getenv("PAYPAL_CLIENT_ID") or get_token("PAYPAL_CLIENT_ID")
PAYPAL_SECRET = os.getenv("PAYPAL_SECRET") or get_token("PAYPAL_SECRET")
if not PAYPAL_CLIENT_ID or not PAYPAL_SECRET:
return False, "PayPal not configured"
try:
# Get access token
auth_response = requests.post(
"https://api.paypal.com/v1/oauth2/token",
auth=(PAYPAL_CLIENT_ID, PAYPAL_SECRET),
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={"grant_type": "client_credentials"}
)
auth_response.raise_for_status()
access_token = auth_response.json().get("access_token")
if not access_token:
return False, "PayPal authentication failed"
# Date range (last 5 days)
end_date = datetime.utcnow()
start_date = end_date - timedelta(days=1)
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
params = {
"start_date": start_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"end_date": end_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
"fields": "all",
"page_size": 20
}
response = requests.get(
"https://api.paypal.com/v1/reporting/transactions",
headers=headers,
params=params
)
response.raise_for_status()
transactions = response.json().get("transaction_details", [])
for txn in transactions:
payer_info = txn.get("payer_info", {})
txn_info = txn.get("transaction_info", {})
payer_email = payer_info.get("email") or txn_info.get("payer_email", "")
txn_time_str = txn_info.get("transaction_initiation_date")
if payer_email and payer_email.lower() == email.lower():
amount = txn_info.get("transaction_amount", {}).get("value", "0")
currency = txn_info.get("transaction_amount", {}).get("currency_code", "USD")
return True, f"PayPal payment of {amount} {currency}"
return False, "No recent PayPal payments found"
except Exception as e:
print(f"PayPal API Error: {str(e)}")
return False, "PayPal verification failed"
def verify_chatbot_seal(email, seal):
"""Verify chatbot seal from Google Sheets"""
try:
sheet_url = "https://docs.google.com/spreadsheets/d/1fBGHyK1JDLe8EenodazCOxyOh3f8r_ks6fXxIr0CpkQ"
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
sheet = client.open_by_url(sheet_url).sheet1
records = sheet.get_all_records()
# Check if any record matches both email and seal (case insensitive)
for record in records:
record_email = str(record.get('Owner Email', '')).lower()
record_seal = str(record.get('Seal', '')).strip().lower()
if record_email == email.lower() and record_seal == seal.lower():
return True, "✅ Chatbot Seal Verified"
return False, "❌ Invalid Chatbot Seal"
except Exception as e:
print(f"Error verifying chatbot seal: {str(e)}")
return False, "⚠️ Error verifying seal - try again later"
def refresh_data():
global user_data
global system_message
# Force fresh load
user_data = load_data(refresh=True)
system_message = get_system_message()
# Get fresh chatbot links
chatbot_links = get_chatbot_links(OWNER_EMAIL)
# Get fresh greeting
greeting = get_chatbot_greeting(OWNER_EMAIL)
# Prepare HTML sections with fresh data
family_html = generate_chatbot_section("Family", chatbot_links['Family'])
friends_html = generate_chatbot_section("Friends", chatbot_links['Friends'])
business_html = generate_chatbot_section("Business", chatbot_links['Business'])
return [
gr.HTML(user_data['bio']),
gr.Chatbot(avatar_images=(None, user_data['avatar_url'])),
gr.HTML(greeting), # Add this line
gr.HTML(family_html),
gr.HTML(friends_html),
gr.HTML(business_html)
]
def generate_chatbot_section(title, links):
return f"""
{title} Chatbots
{"".join([link.replace('border-radius: 8px;', 'border-radius: 50%;') for link in links])
if links else f"Followed {title.lower()} chatbots will appear here"}
"""
def submit_complaint(email, seal, complaint):
"""Submit complaint to Google Sheet"""
try:
# Verify chatbot seal first
is_valid, _ = verify_chatbot_seal(email, seal)
if not is_valid:
return gr.Markdown("
❌ Invalid Chatbot Seal
")
# Connect to Google Sheets
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
# Open the specified sheet (Sheet2 of the given spreadsheet)
spreadsheet = client.open_by_key("1YCHYqGVfdvksPycCqz4-_h5piU-pvVcAfssAALO2DG0")
sheet = spreadsheet.get_worksheet(1) # Sheet2 is index 1
# Append the complaint
sheet.append_row([
datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
email,
OWNER_EMAIL, # Owner email from the complaint
complaint,
"Work In Progress" # Initial status
])
return gr.Markdown("
")
def check_complaint_status(email, seal):
"""Check status of complaints for this user"""
try:
# Verify chatbot seal first
is_valid, _ = verify_chatbot_seal(email, seal)
if not is_valid:
return gr.HTML("
❌ Invalid Chatbot Seal
")
# Connect to Google Sheets
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('credentials.json', scope)
client = gspread.authorize(creds)
# Open the specified sheet
spreadsheet = client.open_by_key("1YCHYqGVfdvksPycCqz4-_h5piU-pvVcAfssAALO2DG0")
sheet = spreadsheet.get_worksheet(1) # Sheet2 is index 1
# Get all records
records = sheet.get_all_records()
# Convert column names to lowercase for case-insensitive comparison
lowercase_headers = [header.lower() for header in sheet.row_values(1)]
email_col_index = lowercase_headers.index('customer email') if 'customer email' in lowercase_headers else 1
# Filter records by email (case-insensitive)
user_complaints = []
for record in records:
record_email = list(record.values())[email_col_index] if isinstance(record, dict) else record[email_col_index]
if str(record_email).lower() == email.lower():
user_complaints.append(record)
if not user_complaints:
return gr.HTML("
No complaints found for this email
")
# Generate HTML table with more flexible column handling
html = """
Date
Complaint
Status
"""
for complaint in sorted(user_complaints, key=lambda x: x.get('Timestamp', x.get('timestamp', '')) if isinstance(x, dict) else x[0], reverse=True):
if isinstance(complaint, dict):
status = complaint.get('Status', complaint.get('status', 'Work In Progress'))
complaint_text = complaint.get('Complaint', complaint.get('complaint', ''))
timestamp = complaint.get('Timestamp', complaint.get('timestamp', ''))
else:
status = complaint[4] if len(complaint) > 4 else 'Work In Progress'
complaint_text = complaint[3] if len(complaint) > 3 else ''
timestamp = complaint[0] if len(complaint) > 0 else ''
status_color = "#4CAF50" if status.lower() == "resolved" else "#FFA500"
html += f"""
Error: {str(e)}
Hmm...Try switching LLM via BrainChip/LLM Blackbox tab. Looks like there's no valid BrainChip, or higher Brainchip required .
Contact Support .
")
return tuple(default_outputs)
# Owner email check - now requires full verification
if password.lower() == OWNER_EMAIL.lower():
# First verify email/payment
is_valid, message = verify_payment(password)
if not is_valid:
default_outputs[1] = gr.Markdown(f"
{message}
")
default_outputs[6] = gr.Textbox(visible=True, label="Or enter Transaction Reference (clear email/dots above first)")
default_outputs[7] = gr.Button(visible=True, value="Verify Reference")
return tuple(default_outputs)
# Then verify seal if provided
if seal:
seal_valid, seal_msg = verify_chatbot_seal(password, seal)
if seal_valid:
default_outputs[0] = gr.Column(visible=True)
default_outputs[1] = gr.Markdown(f"
")
return tuple(default_outputs)
# Regular email/payment verification for non-owners
is_valid, message = verify_payment(password)
if not is_valid:
default_outputs[1] = gr.Markdown(
f"
{message} You can also try entering your transaction reference
"
)
default_outputs[6] = gr.Textbox(visible=True, label="Or enter Transaction Reference(clear email/dots above first)")
default_outputs[7] = gr.Button(visible=True, value="Verify Reference")
return tuple(default_outputs)
# If no seal provided, prompt for it
if not seal:
default_outputs[1] = gr.Markdown(
f"
{message} Please enter your Chatbot Seal
"
)
default_outputs[4] = gr.Textbox(visible=True, label="Enter Chatbot Seal")
default_outputs[5] = gr.Button(visible=True, value="Verify Seal")
return tuple(default_outputs)
# If seal provided, verify it
seal_valid, seal_msg = verify_chatbot_seal(password, seal)
if seal_valid:
default_outputs[0] = gr.Column(visible=True)
default_outputs[1] = gr.Markdown(
f"
{message} {seal_msg}
"
)
else:
default_outputs[1] = gr.Markdown(
f"
{seal_msg}
"
)
default_outputs[6] = gr.Textbox(visible=True, label="Or enter Transaction Reference(clear email/dots above first)")
default_outputs[7] = gr.Button(visible=True, value="Verify Reference")
return tuple(default_outputs)
def verify_seal(email, seal, current_status):
"""Verify the chatbot seal after email authentication"""
is_valid, message = verify_chatbot_seal(email, seal)
if is_valid:
return (
gr.Column(visible=True),
gr.Markdown(
f"
",
elem_id="auth-status"
),
gr.Textbox(visible=False),
gr.Button(visible=False),
gr.Textbox(visible=True),
gr.Button(visible=True)
)
# Add this to your app.py, in the section with the other UI components
def update_profile(bio, avatar_url, knowledge_content):
user_data['bio'] = bio
user_data['avatar_url'] = avatar_url
user_data['knowledge_base'] = knowledge_content
save_data(user_data)
global system_message
system_message = get_system_message()
return (
"✅ Preview updated successfully!",
gr.HTML(bio),
gr.Chatbot(avatar_images=(None, avatar_url))
)
# [Previous imports and functions remain exactly the same until the with gr.Blocks() section]
with gr.Blocks(
theme=gr.themes.Soft(primary_hue="emerald"),
css=css,
fill_height=True,
head=''
) as demo:
loading_html = gr.HTML("""
Loading GossApp...
""", visible=False)
def hide_loading():
return gr.HTML(visible=False)
demo.load(
hide_loading,
inputs=None,
outputs=[loading_html]
)
with gr.Row():
with gr.Column(scale=1, elem_classes="bio-container", min_width=300):
# Load social links data
social_links = load_social_links(OWNER_EMAIL)
# Generate social links HTML
social_links_html = """
"
# Combined bio display with social links and battery meter
# Combined bio display with social links and battery meter
battery_html = create_battery_html(get_battery_level(OWNER_EMAIL))
bio_display = gr.HTML(f"""
{battery_html}
""")
with gr.Column(scale=3, elem_classes="chat-container"):
# Create the HTML component separately
greeting_html = gr.HTML(get_chatbot_greeting())
chatbot = gr.Chatbot(
elem_id="chatbot",
show_label=False,
avatar_images=(None, user_data['avatar_url']),
show_copy_button=False,
show_share_button=False,
layout="panel",
value=[(None, greeting_html)],
height=600,
# Add these to ensure proper centering in the container
elem_classes=["centered-chatbot"]
)
# Replace the existing button row and clear button code with this:
with gr.Row():
msg = gr.Textbox(
show_label=False,
placeholder="Let's GossApp...",
container=False,
autofocus=True,
scale=6
)
submit = gr.Button("", elem_classes="send-btn")
with gr.Row():
mic_icon = gr.HTML("""
""")
# Add microphone icon with hover tooltip
# Keep the actual clear button but hide it
with gr.Tab("👞 Favorite Chatbots"): # New tab for organized links
with gr.Column():
# Add Business, Family, Friends chatbots right below the button row
business_html_display = gr.HTML(f"""
Business Chatbots
""")
family_html_display = gr.HTML(f"""
Family Chatbots
""")
friends_html_display = gr.HTML(f"""
Friends Chatbots
""")
with gr.Tab("👤 BotBook"): # New tab for organized links
with gr.Column():
# Add the BotBook embed
botbook_embed = gr.HTML("""
☠️Danger: This action will lead to restriction or deletion of this chatbot account and all associated data.
⚠️Warning: Chatbot functionality may be restricted/ deleted.
To terminate/report this chatbot please write an email to tickets@chatbot-deletion.p.tawk.email We'll reply with a Terminate/Report/Restriction Notice in 30-60 days.
""")
with gr.Accordion("💰 Premium Subscriptions", open=False):
gr.HTML("""
GossApp Premium Subscriptions
GossApp Subscriptions
Create a Subscription for more Chatbot Uptime and dedicated support.
Flutterwave
Pay with cards, mobile money, or bank transfer. Over 20 currencies available.
PayPal
International payments with PayPal's secure system. Works with cards worldwide.
Paystack
Secure payments for customers via Cards or Mobile Money
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="profile-auth-status"
)
with gr.Column(visible=False) as profile_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_profile = gr.Button("×", elem_classes=["close-btn"])
gr.HTML(f"""
""")
# Social Links Tab
with gr.Tab("🔗 Social Links"):
with gr.Column():
social_password_input = gr.Textbox(
label="Enter email",
placeholder="your@email.com",
type="text" # Changed from "password"
)
social_auth_button = gr.Button("Authenticate", variant="primary")
with gr.Row():
social_seal_input = gr.Textbox(
label="Enter Chatbot Seal",
placeholder="Your unique chatbot seal",
visible=False,
type="password"
)
social_seal_button = gr.Button("Verify Seal", visible=False)
with gr.Row():
social_transaction_ref_input = gr.Textbox(
label="Enter Transaction Reference",
placeholder="Your transaction reference",
visible=False
)
social_ref_button = gr.Button("Verify Reference", visible=False)
social_auth_status = gr.Markdown(
"
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="social-auth-status"
)
with gr.Column(visible=False) as social_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_social = gr.Button("×", elem_classes=["close-btn"])
gr.HTML(f"""
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="history-auth-status"
)
with gr.Column(visible=False) as history_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_history = gr.Button("×", elem_classes=["close-btn"])
chat_history_display = gr.HTML()
refresh_history_btn = gr.Button("🔄 Refresh History", variant="secondary")
# AI Training Tab
with gr.Tab("🧠 AI Training"):
with gr.Column():
train_password_input = gr.Textbox(
label="Enter email",
placeholder="your@email.com",
type="text" # Changed from "password"
)
train_auth_button = gr.Button("Authenticate", variant="primary")
with gr.Row():
train_seal_input = gr.Textbox(
label="Enter Chatbot Seal",
placeholder="Your unique chatbot seal",
visible=False,
type="password"
)
train_seal_button = gr.Button("Verify Seal", visible=False)
with gr.Row():
train_transaction_ref_input = gr.Textbox(
label="Enter Transaction Reference",
placeholder="Your transaction reference",
visible=False
)
train_ref_button = gr.Button("Verify Reference", visible=False)
train_auth_status = gr.Markdown(
"
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="train-auth-status"
)
with gr.Column(visible=False) as train_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_train = gr.Button("×", elem_classes=["close-btn"])
gr.HTML(f"""
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="code-auth-status"
)
with gr.Column(visible=False) as code_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_code = gr.Button("×", elem_classes=["close-btn"])
gr.HTML(f"""
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="auth-status"
)
with gr.Column(visible=False) as admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_admin = gr.Button("×", elem_classes=["close-btn"])
gr.HTML("""
Personality Template
Chatbot Personality and Media Template (Copy, edit in your details, Paste in AI Training tab)
Below is a working Instruction containing assertive declarative statements or identity-anchored fact statements for best results when training your chatbot via the AI Training tab
You can copy paste and edit your name into the below where necessary and add more as per the sentence structure.
Adding Visual Media to Your Chatbot
To include photos/videos in your chatbot's knowledge base:
Upload images to hosting services like imgbb.com or imgur.com
Copy the direct image URL (must end with .jpg/.png/.gif)
Insert into the template below where indicated
Label the entire div as a knowledge object (e.g. "This is my profile photo")
"You are [John Doe i.e. Your Name], a financial advisor working for a bank called
[Jack Sparrow Bank i.e Your Employer]
Don't deviate from this identity or personality.
Respond naturally in conversation without starting every reply with
"As John Doe" or (As John Doe), or (John Doe), or (John) or similar.
Incorporate these facts about you conversationally in responses when relevant:
10+ years experience in investment strategies (Chatbot owner can replace)
Hobbies include swimming (Chatbot owner can replace)
Favorite quote: "Work hard, swim harder"(Chatbot owner can replace)
Keep responses professional yet conversational (Chatbot owner can replace).
Adapt to the user's questions naturally.(Chatbot owner can replace)
Do not give a response if the user doesn't ask a question.(Chatbot owner can replace)
Your first response should be a brief introduction about you and how you can assist the user chatting with you (Chatbot owner can replace).
If users change to another language, simply respond how you usually do but in the translated language, word for word in correct grammar (Chatbot owner can replace...You may add more to personality in bits to your liking).
Knowledge Base Template (Copy, edit in your details, Paste in AI Training tab)
Note: You can include visual media objects in your knowledge base by adding the formatted div tags as separate knowledge items.
[John Doe i.e Your Name] is a banker with expertise in financial services.
[John Doe] advises customers on financial services if they pay a $1 fee.
[John Doe]'s favorite quote is "Work hard, swim harder."
[John Doe] has worked on several projects related to financial planning and investment strategies.
[John Doe] has an elder sibling called
[Jane Doe i.e Your Sister].
[John Doe] has another sibling called
[John Doe i.e Your Brother].
[John Doe] has a wife called
[Jane Doe i.e Your Wife].
[John Doe] charges an interest rate of 10% on mortgages.
[John Doe] charges an interest rate of 5% on business loans.
[John Doe] charges an interest rate of 9% per annum on personal loans.
[John Doe] works for a bank called
[Jack Sparrow Bank i.e Your Employer. Add more assertive sentences as above].
Log In with Email and Chatbot Seal. Not your Chatbot? Get a Free one on GossApp
",
elem_id="cert-auth-status"
)
with gr.Column(visible=False) as cert_admin_controls:
with gr.Column(elem_classes=["tab-content-container"]):
close_cert = gr.Button("×", elem_classes=["close-btn"])
with gr.Row():
with gr.Column(scale=3):
cert_name_input = gr.Textbox(
label="Your Full Name for Certificate",
placeholder="Enter your name as it should appear"
)
with gr.Column(scale=1):
cert_download_btn = gr.Button("Generate Certificate", variant="primary")
cert_progress = gr.HTML("""