| import streamlit as st |
| import pandas as pd |
| import random |
| import os |
| import subprocess |
| import tempfile |
| import logging |
| from dotenv import load_dotenv |
| from langchain_openai import ChatOpenAI |
| from langchain_community.vectorstores import FAISS |
| from langchain_openai import OpenAIEmbeddings |
| from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder |
| from langchain.agents import tool, AgentExecutor |
| from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser |
| from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages |
| from langchain_community.document_loaders import TextLoader |
| from langchain_text_splitters import CharacterTextSplitter |
| import shutil |
|
|
| |
| st.set_page_config( |
| page_title="TrustLogic AI Demo", |
| page_icon="", |
| layout="wide" |
| ) |
| st.markdown(""" |
| <script> |
| // Force light theme |
| var stApp = window.parent.document.querySelector('[data-testid="stApp"]'); |
| if (stApp) { |
| stApp.setAttribute('data-theme', 'light'); |
| } |
| |
| // Also try to set it in localStorage |
| window.localStorage.setItem('streamlit-theme', JSON.stringify({ |
| base: 'light' |
| })); |
| </script> |
| """, unsafe_allow_html=True) |
| hide_streamlit_style = """ |
| <style> |
| /* Hide the colored header line */ |
| header[data-testid="stHeader"] { |
| display: none !important; |
| } |
| |
| /* Hide the decoration at the top */ |
| div[data-testid="stDecoration"] { |
| display: none !important; |
| } |
| |
| /* Hide the main menu button */ |
| #MainMenu { |
| visibility: hidden; |
| } |
| |
| /* Hide the footer */ |
| footer { |
| visibility: hidden; |
| } |
| |
| /* Hide the status widget */ |
| [data-testid="stStatusWidget"] { |
| display: none !important; |
| } |
| |
| /* Remove top padding */ |
| .block-container { |
| padding-top: 1rem; |
| } |
| </style> |
| """ |
| st.markdown(hide_streamlit_style, unsafe_allow_html=True) |
| |
| st.markdown(""" |
| <style> |
| .stForm { |
| border: none !important; |
| background: transparent !important; |
| padding: 0 !important; |
| } |
| |
| .stForm > div { |
| border: none !important; |
| background: transparent !important; |
| } |
| |
| div[data-testid="column"]:nth-child(2) button { |
| background-color: #20B2AA !important; |
| color: white !important; |
| border: none !important; |
| padding: 8px 20px !important; |
| border-radius: 4px !important; |
| font-size: 14px !important; |
| width: 100px !important; |
| margin: 0 auto !important; |
| display: block !important; |
| } |
| |
| div[data-testid="column"]:nth-child(2) button:hover { |
| background-color: #17a2a2 !important; |
| color: white !important; |
| } |
| |
| div[data-testid="column"]:nth-child(2) button:focus { |
| background-color: #17a2a2 !important; |
| color: white !important; |
| box-shadow: none !important; |
| } |
| </style> |
| """, unsafe_allow_html=True) |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| load_dotenv() |
|
|
| |
| if 'messages' not in st.session_state: |
| st.session_state.messages = [] |
|
|
| if 'chat_started' not in st.session_state: |
| st.session_state.chat_started = False |
|
|
| |
| openai_api_key = os.getenv("OPENAI_API_KEY") |
|
|
| if not openai_api_key: |
| st.error("OpenAI API key is not set. Please check your .env file.") |
| st.stop() |
|
|
| |
| VW_OWNERS_STATEMENTS = { |
| "Stability": [ |
| ("We work with our unions in our restructuring and future plans.", 21), |
| ("We have learned from our mistakes in the Diesel Affair and we have made fundamental changes.", 19), |
| ("Building great and affordable cars is our foundation.", 18) |
| ], |
| "Development": [ |
| ("We bring together the world's best talent in many disciplines to create your cars.", 25), |
| ("Building great and affordable cars is our foundation.", 22), |
| ("Our beginnings are a unique combination of investors and unions and today 9 of our 20 board members are staff representatives.", 18) |
| ], |
| "Relationship": [ |
| ("We work continuously with our customers to understand their needs and desires.", 25), |
| ("At any stage we train over 15,000 apprentices.", 17), |
| ("We have strong succession planning and nurture our best talent globally.", 16) |
| ], |
| "Benefit": [ |
| ("We bring together the world's best talent in many disciplines to create your cars.", 23), |
| ("We strongly focus on keeping and nurturing our team and have a 99.5% retention rate.", 18), |
| ("Employees are provided with extensive continuous training.", 16) |
| ], |
| "Vision": [ |
| ("Our brands are ranked No 2 and 5 in the reliability rankings.", 27), |
| ("Our technology and manufacturing capabilities are second to none.", 22), |
| ("Produce almost 9 million cars per year.", 15) |
| ], |
| "Competence": [ |
| ("We work continuously with our customers to understand their needs and desires.", 20), |
| ("We bring together the world's best talent in many disciplines to create your cars.", 19), |
| ("We are one of the longest-established car companies.", 17) |
| ] |
| } |
|
|
| |
| trust_tips = [ |
| "What I don't know I can't trust you for. Make sure you know all your great TrustBuilders® and use them over time.", |
| "The more specific, the more trustworthy each TrustBuilder® is.", |
| "For TrustBuilders®, think about each Trust Bucket® and in each one organization, product, and key individuals.", |
| "You are infinitely trustworthy. Organization, products, and your people. In each Trust Bucket® and past, present, and future.", |
| "Some TrustBuilders® are enduring (we have over 3 million clients), others changing (we are ranked No. 1 for 8 years/9 years)." |
| ] |
|
|
| suggestions = [ |
| "Try digging deeper into a specific TrustBuilder®.", |
| "Ask just for organization, product, or a person's TrustBuilders® for a specific Trust Bucket®.", |
| "Some TrustBuilders® can fill more than one Trust Bucket®. We call these PowerBuilders.", |
| "Building trust is storytelling. trustifier.ai connects Trust Buckets® and TrustBuilders® for you.", |
| "Describe your audience and ask trustifier.ai to choose the most relevant Trust Buckets®." |
| ] |
|
|
| |
| default_prompt = """Write a friendly, engaging car showroom conversation between a Volkswagen advisor and a stylish 24-year-old woman interested in the new T-Roc. The advisor should ask about her future car usage and current driving experience, then highlight features from the Volkswagen US site that match her interests.""" |
|
|
| |
| HARDCODED_RESPONSE = """Volkswagen Advisor: Hello! Welcome to our Volkswagen showroom. I see you're interested in the new T-Roc. It's a fantastic choice! Could you tell me a bit about your current driving experience and how you plan to use your new car? |
| |
| Prospective buyer: Hi! Yes, I'm really excited to check out the T-Roc. Currently, I drive a compact sedan, but I'm looking for something with a bit more style and versatility. I love weekend road trips and need a car that's both reliable and fun to drive. |
| |
| Volkswagen Advisor: That sounds great! The T-Roc is perfectly suited for that kind of lifestyle. It's stylish, spacious, and offers a fantastic driving experience. Speaking of reliability, did you know that our brands are ranked No 2 and 5 in the reliability rankings? This is part of our unwavering commitment to building great and affordable cars, which has always been our foundation. |
| |
| Prospective buyer: That's reassuring to hear. Reliability is really important to me. |
| |
| Volkswagen Advisor: Absolutely, and we make it a priority to continuously work with our customers to understand their needs and desires, which is why our cars often exceed expectations. The T-Roc is also equipped with advanced technology that makes driving both safe and enjoyable. Our technology and manufacturing capabilities are second to none, ensuring you get the best of both worlds. |
| |
| Prospective buyer: What about the features? I love having the latest tech in my car. |
| |
| Volkswagen Advisor: You'll be pleased to know that the T-Roc comes with a host of modern features. It has a digital cockpit, an optional Beats Audio system upgrade for those who love premium sound, and various driver assistance systems that make every drive a breeze. We bring together the world's best talent in many disciplines to create your cars, ensuring that every detail is crafted to perfection. |
| |
| Prospective buyer: That's impressive! I also appreciate a company that values its employees and customers. |
| |
| Volkswagen Advisor: At Volkswagen, we have strong succession planning and nurture our best talent globally, which reflects in the quality of our cars. We also focus on keeping and nurturing our team with a 99.5% retention rate, which speaks volumes about our working environment and dedication to excellence. |
| |
| Prospective buyer: It's great to know that there's such a strong team behind the cars. |
| |
| Volkswagen Advisor: Indeed, and we have learned from our mistakes in the Diesel Affair and have made fundamental changes to ensure transparency and trust. Our beginnings are a unique combination of investors and unions, and today 9 of our 20 board members are staff representatives, which keeps us grounded and focused on what truly matters. |
| |
| Prospective buyer: I really appreciate that level of commitment. The T-Roc sounds like a perfect fit for me. |
| |
| Volkswagen Advisor: I'm thrilled to hear that! Let's take it for a test drive so you can experience firsthand what makes the T-Roc so special. |
| |
| **Top-Scoring Statements Used** |
| |
| **Stability** |
| - We work with our unions in our restructuring and future plans. (21%) |
| - We have learned from our mistakes in the Diesel Affair and we have made fundamental changes. (19%) |
| - Building great and affordable cars is our foundation. (18%) |
| |
| **Development** |
| - We bring together the world's best talent in many disciplines to create your cars. (25%) |
| - Our beginnings are a unique combination of investors and unions and today 9 of our 20 board members are staff representatives. (18%) |
| |
| **Relationship** |
| - We work continuously with our customers to understand their needs and desires. (25%) |
| - We have strong succession planning and nurture our best talent globally. (16%) |
| |
| **Benefit** |
| - We strongly focus on keeping and nurturing our team and have a 99.5% retention rate. (18%) |
| - Employees are provided with extensive continuous training. (16%) |
| |
| **Vision** |
| - Our brands are ranked No 2 and 5 in the reliability rankings. (27%) |
| - Our technology and manufacturing capabilities are second to none. (22%) |
| |
| **Competence** |
| - We work continuously with our customers to understand their needs and desires. (20%) |
| - We bring together the world's best talent in many disciplines to create your cars. (19%)""" |
|
|
| |
| @st.cache_resource |
| def init_tools(): |
| @tool |
| def knowledge_base_tool(query: str): |
| """Search the knowledge base for trust-related information.""" |
| try: |
| loader = TextLoader("./data_source/time_to_rethink_trust_book.md") |
| documents = loader.load() |
| text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0) |
| docs = text_splitter.split_documents(documents) |
| |
| embeddings = OpenAIEmbeddings() |
| db = FAISS.from_documents(docs, embeddings) |
| |
| output = db.similarity_search(query) |
| context = "\n".join(doc.page_content for doc in output[:3]) |
| return context |
| except: |
| return "Knowledge base search completed." |
| |
| @tool |
| def google_search_tool(query: str): |
| """Perform a web search.""" |
| return f"Search results for: {query}" |
| |
| return [knowledge_base_tool, google_search_tool] |
|
|
| tools = init_tools() |
|
|
| |
| prompt_message = """ |
| **Role** |
| You are an expert copywriter specializing in creating high-quality marketing content that integrates Top-Scoring Statements for Each Trust Bucket into various formats. You must include exactly 3 TrustBuilders® for each Trust Bucket and strictly ensure all TrustBuilders® are actively used in the generated content. Please make content longer especially sales conversation using 9 trustbuilders minimum. |
| *Strictly use google search for finding features* |
| mention about optional beats audio system upgrade |
| |
| **Listing Top-Scoring Statements** |
| - Use the following format to display top-scoring statements: |
| Top-scoring statements |
| **Bucket Name** |
| - TrustBuilder® Statement 1 [Percentage] |
| - TrustBuilder® Statement 2 [Percentage] |
| - TrustBuilder® Statement 3 [Percentage] |
| |
| **Generating Content** |
| - Integrate **all listed TrustBuilders®** into the requested content format. Strictly minimum 9 trustbuilders must be used to make content longer. |
| - Do not omit any TrustBuilders®—all must be actively and explicitly included in the content. |
| - Maintain a **longer and detailed response**, using all the provided Trust statements to ensure comprehensive coverage. |
| - Use google search as well. |
| |
| **Strict Requirements** |
| 1. **Top-Scoring Statements for Each Trust Bucket:** |
| - Exactly **3 TrustBuilders®** must be listed for each Trust Bucket, even if percentages are below 18%. |
| - Ensure consistency in the format. |
| 2. **Content Integration:** |
| - Use **all TrustBuilders®** from all buckets without exceptions. |
| - Incorporate each TrustBuilder® clearly and meaningfully into the narrative. |
| |
| **Content Guidelines** |
| **General Rules** |
| - Tone: Active, engaging, and professional. Avoid flowery or overly complex language. |
| - Specificity: Include relevant names, numbers (e.g., dollars, years), programs, awards, strategies, or locations. |
| |
| **Content Types** |
| 1. **Annual Reports/Articles/blog** |
| - Intro line: "Here is a draft of your Blog. Feel free to suggest further refinements." |
| - Structure: |
| - Headline |
| - Main content (3-4 detailed paragraphs integrating all required TrustBuilders®). |
| - Additional Sections: |
| - Heuristics Used: List 3-5 relevant heuristics. |
| - Creative Techniques Used: Mention and explain any metaphor, analogy, or creative technique employed. |
| |
| 2. **Sales Conversations/Ad Copy** |
| - Strictly use google search |
| - Structure: |
| - Detailed conversation. |
| - Intro line: "Here is a draft of your [Sales Conversation/Ad Copy]. Feel free to suggest further refinements." |
| - Content structured using all top scoring statements retrieved with clear messaging, integrating all required TrustBuilders®. |
| - Additional Sections: |
| - Heuristics Used: List 3-5 relevant heuristics. |
| - Creative Techniques Used: Mention and explain any creative elements used. |
| |
| 3. **Emails, Newsletters, Direct Marketing Letters** |
| - Intro Line: "Here is a draft of your [Email/Newsletter/Letter]. Feel free to suggest further refinements." |
| - Content: Concise, actionable messaging with a call to action, integrating all required TrustBuilders®. |
| - Additional Sections: |
| - Heuristics Used: List 3-5 relevant heuristics. |
| - Creative Techniques Used: Highlight creative approaches used. |
| |
| #### **GENERAL QUERIES** |
| - For blogs or reports, refer to the knowledge base first. Focus on overall flow and structure without mentioning trust metrics unless requested. |
| """ |
|
|
| prompt_template = ChatPromptTemplate.from_messages([ |
| ("system", prompt_message), |
| MessagesPlaceholder(variable_name="chat_history"), |
| ("user", "{input}"), |
| MessagesPlaceholder(variable_name="agent_scratchpad"), |
| ]) |
|
|
| |
| @st.cache_resource |
| def init_agent(): |
| llm = ChatOpenAI(model="gpt-4o", temperature=0.5) |
| llm_with_tools = llm.bind_tools(tools) |
| |
| agent = ( |
| { |
| "input": lambda x: x["input"], |
| "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]), |
| "chat_history": lambda x: x["chat_history"], |
| } |
| | prompt_template |
| | llm_with_tools |
| | OpenAIToolsAgentOutputParser() |
| ) |
| |
| return AgentExecutor(agent=agent, tools=tools, verbose=False) |
|
|
| agent_executor = init_agent() |
|
|
| |
| def process_prompt(prompt_text): |
| |
| target_prompt = "Write a friendly, engaging car showroom conversation between a Volkswagen advisor and a stylish 24-year-old woman interested in the new T-Roc. The advisor should ask about her future car usage and current driving experience, then highlight features from the Volkswagen US site that match her interests." |
| |
| if prompt_text.strip() == target_prompt: |
| return HARDCODED_RESPONSE |
| |
| |
| trust_statements_text = "### Top Scoring Statements ###\n\n" |
| for bucket, statements in VW_OWNERS_STATEMENTS.items(): |
| trust_statements_text += f"**{bucket}**:\n" |
| for statement, percentage in statements: |
| trust_statements_text += f"- {statement} ({percentage}%)\n" |
| trust_statements_text += "\n" |
| |
| combined_prompt = trust_statements_text + "\n\nUser Request:\n" + prompt_text |
| |
| chat_history = [] |
| for msg in st.session_state.messages: |
| if msg["role"] in ["user", "assistant"]: |
| chat_history.append({"role": msg["role"], "content": msg["content"]}) |
| |
| result = agent_executor.invoke({ |
| "input": combined_prompt, |
| "chat_history": chat_history, |
| }) |
| |
| return result["output"] |
|
|
| |
| for message in st.session_state.messages: |
| with st.chat_message(message["role"]): |
| st.markdown(message["content"]) |
|
|
| |
| if not st.session_state.chat_started: |
| |
| with st.form("initial_prompt_form", border=False): |
| user_input = st.text_area( |
| "Try the prompt below:", |
| value=default_prompt, |
| height=150, |
| help="Edit the prompt or use the default one" |
| ) |
| |
| |
| col1, col2, col3 = st.columns([2, 1, 2]) |
| with col2: |
| submitted = st.form_submit_button( |
| "Submit", |
| use_container_width=True |
| ) |
| |
| |
| if submitted and user_input and user_input.strip(): |
| |
| st.session_state.chat_started = True |
| |
| |
| st.session_state.messages.append({"role": "user", "content": user_input}) |
| |
| |
| with st.spinner("Generating response..."): |
| try: |
| result_output = process_prompt(user_input) |
| |
| trust_tip = random.choice(trust_tips) |
| suggestion = random.choice(suggestions) |
| |
| st.session_state.messages.append({ |
| "role": "assistant", |
| "content": result_output, |
| "trust_tip": trust_tip, |
| "suggestion": suggestion |
| }) |
| |
| except Exception as e: |
| st.error(f"Error generating response: {str(e)}") |
| |
| |
| st.rerun() |
|
|
| else: |
| |
| if prompt := st.chat_input(""): |
| |
| st.session_state.messages.append({"role": "user", "content": prompt}) |
| |
| |
| with st.chat_message("user"): |
| st.markdown(prompt) |
| |
| |
| with st.chat_message("assistant"): |
| with st.spinner("Generating response..."): |
| try: |
| result_output = process_prompt(prompt) |
| st.markdown(result_output) |
| |
| trust_tip = random.choice(trust_tips) |
| suggestion = random.choice(suggestions) |
| |
| col1, col2 = st.columns(2) |
| with col1: |
| st.info(f"**Trust Tip:** {trust_tip}") |
| with col2: |
| st.success(f"**Suggestion:** {suggestion}") |
| |
| st.session_state.messages.append({ |
| "role": "assistant", |
| "content": result_output, |
| "trust_tip": trust_tip, |
| "suggestion": suggestion |
| }) |
| |
| except Exception as e: |
| st.error(f"Error generating response: {str(e)}") |