构建了一个人工智能工具来帮助我的团队智能地发布推文——告别手动发布,迎接病毒式传播!🫡🚀
在 Composio,我们非常活跃于 Twitter 上发布更新并与用户互动。但每天发布推文并转发,已经变得非常忙碌。
因此,我构建了一个 AI 工具,可以为团队执行所有这些任务,同时团队可以专注于其他重要任务。
Composio——人工智能集成和工具平台
这是我们的简短介绍
Composio 是一个开源 AI 集成平台,可让您创建 AI 代理并将其集成到您的应用程序中。Composio 提供 150 多种工具和集成,可用于构建 AI 驱动的应用程序。我们提供 GitHub、Gmail、Discord、Slack 等第三方服务。
了解有关 Composio 的更多信息,请点击此处

项目描述
该项目可以通过创建 AI 生成的引人入胜的帖子来发布推文、转发和引用其他创作者的转发推文。
项目工作流程:
- 集成工具- 配置 Twitter (X) 工具集成
- 定义操作函数 -创建文件来定义代理将执行的操作,并包含相应的函数
- 访问帐户- AI 工具将请求访问用户的 Twitter 帐户
- 执行操作- 机器人分析收到的输入,并根据输入选择要执行的相关操作
技术栈
我们将使用以下技术:
- 前端——React、Vite、TailwindCSS
- 后端- FastAPI
- 身份验证- Firebase
- AI 代理- Composio 和 CrewAI
快速描述
- Composio - 用于构建 AI 代理和集成工具的开源平台
- CrewAI - 用于构建协作式多 AI 机器人系统的开源框架
- React + Vite - 使用 React 构建 UI,使用 Vite 快速开发和部署应用程序
- FastAPI - 用于更快构建 REST API 的 Python 框架
- Firebase - Google 的云平台,可帮助构建、运行和改进应用程序
先决条件
要创建这个项目,我们需要以下内容:
-
OpenAI API 密钥
要生成 OpenAI API 密钥,请转到他们的网站,创建一个帐户,然后生成一个 API 密钥。
-
Composio API 密钥
-
实体 ID
集成 Twitter 工具并连接帐户后,您将找到实体 ID
-
应用 ID
要获取 App ID,请前往API 部分,然后运行 Composio API Key。您将在结果中获得您的 App ID
让我们开始吧
在这个项目中,我们将
- 设置 Firebase 身份验证
- 使用 Composio 和 CrewAI 构建 AI 代理
- 使用 FastAPI 创建后端
- 使用 React、Vite 和 TailwindCSS 构建前端
首先,克隆这个repo。
要克隆,请运行以下命令:
git clone https://github.com/abhishekpatil4/Tweetify.git
进入后端目录并运行该setup.sh
文件。这是设置代码。
#!/bin/bash
# Create a virtual environment
echo "Creating virtual environment..."
python3 -m venv ~/.venvs/gmail_agent
# Activate the virtual environment
echo "Activating virtual environment..."
source ~/.venvs/gmail_agent/bin/activate
# Install libraries from requirements.txt
echo "Installing libraries from requirements.txt..."
pip install -r requirements.txt
# Login to your account
echo "Login to your Composio account"
composio login
# Add calendar tool
echo "Add Twitter tool"
composio add twitter
# Copy env backup to .env file
if [ -f ".env.example" ]; then
echo "Copying .env.example to .env..."
cp .env.example .env
else
echo "No .env.example file found. Creating a new .env file..."
touch .env
fi
# Prompt user to fill the .env file
echo "Please fill in the .env file with the necessary environment variables."
echo "Setup completed successfully!"
在文件中添加 API 密钥.env
。
要运行安装文件,请运行以下命令:
chmod +x setup.sh
./setup.sh
这将创建一个 Python 虚拟环境并使用文件安装必要的库requirements.txt
。
它会将您重定向到 Composio,使用您的帐户凭据登录。
然后,您将被重定向到 Twitter,使用您的凭据登录,并授予您的 Twitter 帐户的访问权限。
完成集成后,您可以访问 Composio 仪表板并监控您的集成。
Firebase 身份验证
现在,我们将设置 Google 的 Firebase 来进行用户的身份验证和授权。
首先导入必要的库并指定用户凭证。这些凭证将用于身份验证。
import firebase_admin
from firebase_admin import credentials, auth, firestore
from pathlib import Path
import os
from dotenv import load_dotenv
load_dotenv()
creds = {
"type": os.environ.get("type"),
"project_id": os.environ.get("project_id"),
"private_key_id": os.environ.get("private_key_id"),
"private_key": os.environ.get("private_key"),
"client_email": os.environ.get("client_email"),
"client_id": os.environ.get("client_id"),
"auth_uri": os.environ.get("auth_uri"),
"token_uri": os.environ.get("token_uri"),
"auth_provider_x509_cert_url":
os.environ.get("auth_provider_x509_cert_url"),
"client_x509_cert_url": os.environ.get("client_x509_cert_url"),
}
凭证以 JSON 格式指定。
使用Firestore.
firebase_admin.initialize_app(credentials.Certificate(creds))
db = firestore.client()
这使我们能够在 Firestore 中以集合的形式存储文档并对其进行操作。
创建实用函数
实用功能允许我们访问 Firestore 中的文档并根据我们的要求对其进行操作。
def get_user_by_username(username):
users_ref = db.collection('users')
query = users_ref.where('uid', '==', username).limit(1)
docs = query.get()
for doc in docs:
return doc.to_dict()
return False
users
该函数通过根据字段查询集合从 Firestore 检索用户文档uid
。
def update_twitter_integration_id(username: str, twitter_integration_id: str):
users_ref = db.collection('users')
query = users_ref.where('username', '==', username).limit(1)
docs = query.get()
for doc in docs:
try:
doc.reference.update(
{'twitterIntegrationId': twitter_integration_id})
print(f"Successfully updated twitterIntegrationId for user {username}")
return True
except Exception as e:
print(f"Error updating twitterIntegrationId for user {username}: {e}")
return False
print(f"User {username} not found")
return False
该函数通过在集合中搜索匹配项来更新twitterIntegrationId
Firestore 文档中的字段。users
username
def get_twitter_integration_id(username: str) -> str:
users_ref = db.collection('users')
query = users_ref.where('username', '==', username).limit(1)
docs = query.get()
for doc in docs:
user_data = doc.to_dict()
return user_data.get('twitterIntegrationId', '')
print(f"User {username} not found")
return ''
该函数通过在集合中搜索匹配项twitterIntegrationId
来从 Firestore 文档中检索字段。users
username
def get_composio_api_key(username: str) -> str:
users_ref = db.collection('users')
query = users_ref.where('username', '==', username).limit(1)
docs = query.get()
for doc in docs:
user_data = doc.to_dict()
return user_data.get('composio_api_key', '')
print(f"User {username} not found")
return ''
该函数通过查询集合中的匹配项来composio_api_key
从 Firestore 文档中获取字段。users
username
构建AI代理
现在让我们开始构建 AI 代理。
由于我们项目的主要功能是发布新推文、转发和引用推文,我们将创建三个单独的文件来处理这些任务。
发布推文
为了生成新的推文、发布并重新发布,我们将创建new_tweet_repost.py
文件并在其中创建 AI 代理。
从导入必要的库和函数开始。
import os
from composio_crewai import Action, ComposioToolSet
from crewai import Agent, Crew, Task, Process
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
from firebase.init_class import FirebaseService
from twitter_functions import get_user_id_by_username
加载环境变量并启动 Firebase 服务。
load_dotenv()
firebase_service = FirebaseService()
现在,创建一个 OpenAI 实例。这里我们使用gpt-4o
模型。
llm = ChatOpenAI(model="gpt-4o")
现在,我们将创建代理来生成和发布推文。
def post_twitter_message(entity_id: str, message: str) -> str:
comp_api_key = firebase_service.get_composio_api_key(entity_id)
composio_toolset = ComposioToolSet(api_key=comp_api_key, entity_id=entity_id)
tools = composio_toolset.get_actions(actions=[Action.TWITTER_CREATION_OF_A_POST])
在这里,我们初始化了一个post_twitter_message
生成推文的函数。我们使用 Composio API Key 和 Entity Key 来初始化ComposioToolSet
。
composio_toolset
我们正在使用所需的操作get_actions
。TWITTER_CREATION_OF_A_POST
是我们想要使用该工具执行的操作的 ID。
现在,创建执行任务的AI代理。我们将分配背景故事、角色和其他必要参数,以便代理能够更好地理解其任务。
twitter_agent = Agent(
role="Twitter Agent",
goal="Create and post tweets on Twitter",
backstory="You're an AI assistant that crafts and shares tweets on Twitter.",
verbose=True,
llm=llm,
tools=tools,
allow_delegation=False,
)
现在,我们将定义待执行任务的描述。此描述将用于创建AI代理将要执行的任务(Task)。
task_description = f"""
1. Post the following message on Twitter:
"{message}"
2. Return only the tweet ID of the posted tweet.
"""
process_twitter_request = Task(
description=task_description,
agent=twitter_agent,
expected_output="The tweet ID of the posted tweet.",
)
然后,我们将创建团队来定义任务执行、代理协作和整体工作流程的策略。
twitter_processing_crew = Crew(
agents=[twitter_agent],
tasks=[process_twitter_request],
verbose=1,
process=Process.sequential,
)
最后利用这个创建的船员执行任务并返回结果。
result = twitter_processing_crew.kickoff()
return result
我们将按照相同的方法创建转发推文的函数。以下是它的完整代码。
def repost_tweet(admin_entity_id: str, entity_id: str, task_description: str) -> str:
comp_api_key = firebase_service.get_composio_api_key(admin_entity_id)
composio_toolset = ComposioToolSet(api_key=comp_api_key, entity_id=entity_id)
tools = composio_toolset.get_actions(actions=[Action.TWITTER_CREATION_OF_A_POST, Action.TWITTER_CAUSES_THE_USER_IN_THE_PATH_TO_REPOST_THE_SPECIFIED_POST])
twitter_agent = Agent(
role="Twitter Agent",
goal="Repost tweets on Twitter",
backstory="You're an AI assistant that reposts tweets on Twitter, if a quote is provided, add the quote to the tweet, if no quote is provided, repost the tweet without a quote.",
verbose=True,
llm=llm,
tools=tools,
allow_delegation=False,
)
process_twitter_request = Task(
description=task_description,
agent=twitter_agent,
expected_output="Result of the repost",
)
twitter_processing_crew = Crew(
agents=[twitter_agent],
tasks=[process_twitter_request],
verbose=1,
process=Process.sequential,
)
result = twitter_processing_crew.kickoff()
return result
在这个函数中,我们使用了TWITTER_CAUSES_THE_USER_IN_THE_PATH_TO_REPOST_THE_SPECIFIED_POST
将转发用户推文的操作 ID。
现在,我们将创建一个函数来创建推文、发布推文并转发。在这里,我们创建了该函数create_new_tweet_and_repost
,并使用该post_twitter_message
函数生成推文并发布。
def create_new_tweet_and_repost(initial_tweet_entity_id: str, initial_tweet: str, repost_data_list: list):
tweet_id = post_twitter_message(initial_tweet_entity_id, initial_tweet)
要转发,我们必须检查推文中是否包含引用。如果包含引用,我们将连同引用一起转发,否则直接转发。
for repost_data in repost_data_list:
entity_id = repost_data["entity_id"]
quote = repost_data["quote"]
if quote:
task_description = f"""
Repost the tweet with ID {tweet_id} with the following quote:
"{quote}"
"""
else:
user_id = get_user_id_by_username(entity_id)
task_description = f"""
Repost the tweet with ID {tweet_id} without any quote and user ID {user_id}
"""
最后运行repost_tweet
函数并返回结果。
repost_result = repost_tweet(initial_tweet_entity_id, entity_id, task_description)
print(f"Repost result for {entity_id}: {repost_result}")
生成报价
我们将创建一个quote_generator.py
文件来生成引文,以便重新发布带有引文的推文。
首先导入必要的库并初始化环境变量。
import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
使用 OpenAI API 创建客户端并指定 OpenAI API 密钥。
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
现在,创建一个generate_repost_quote
函数并创建quote
数组和user_prompts
字符串。
def generate_repost_quote(prompt: str, tweet_content: str, number_of_quotes: int) -> list[str]:
quotes = []
user_prompt = prompt + " Tweet content: " + tweet_content
number_of_quotes
最后,运行循环来根据用户传递的信息生成报价数量。
for _ in range(number_of_quotes):
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Generate a meaningful repost quote with hashtags and an emoji"},
{"role": "user", "content": user_prompt}
]
)
quote = completion.choices[0].message.content.strip()
quotes.append(quote)
return quotes
此处使用gpt-4o-mini
模型。我们在 中为用户和系统指定了不同的提示content
。生成的报价将附加到数组中,最终返回quotes
结果数组。quotes
重新发布现有帖子
我们将创建一个文件并创建重新发布现有推文的respost_existing_tweet.py
功能。repost_tweet
我们将采用与文件repost_tweet
中函数相同的方法new_tweet_repost.py
。以下是完整的代码repost_existing_tweet.py
:
import os
from composio_crewai import Action, ComposioToolSet
from crewai import Agent, Crew, Task, Process
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
from pathlib import Path
from firebase.init import get_composio_api_key
from twitter_functions import get_user_id_by_username
load_dotenv()
llm = ChatOpenAI(model="gpt-4o")
def repost_tweet(admin_entity_id: str, entity_id: str, task_description: str) -> str:
comp_api_key = get_composio_api_key(admin_entity_id)
composio_toolset = ComposioToolSet(api_key=comp_api_key, entity_id=entity_id)
tools = composio_toolset.get_actions(actions=[Action.TWITTER_CREATION_OF_A_POST, Action.TWITTER_CAUSES_THE_USER_IN_THE_PATH_TO_REPOST_THE_SPECIFIED_POST])
twitter_agent = Agent(
role="Twitter Agent",
goal="Repost tweets on Twitter",
backstory="You're an AI assistant that reposts tweets on Twitter, if a quote is provided, add the quote to the tweet, if no quote is provided, repost the tweet without a quote.",
verbose=True,
llm=llm,
tools=tools,
allow_delegation=False,
)
process_twitter_request = Task(
description=task_description,
agent=twitter_agent,
expected_output="Result of the repost",
)
twitter_processing_crew = Crew(
agents=[twitter_agent],
tasks=[process_twitter_request],
verbose=1,
process=Process.sequential,
)
result = twitter_processing_crew.kickoff()
return result
def repost_existing(admin_entity_id: str, tweet_id: str, repost_data_list: list):
for repost_data in repost_data_list:
entity_id = repost_data["entity_id"]
quote = repost_data["quote"]
if quote:
task_description = f"""
Repost the tweet with ID {tweet_id} with the following quote:
"{quote}"
"""
else:
user_id = get_user_id_by_username(entity_id)
task_description = f"""
Repost the tweet with ID {tweet_id} without any quote and user ID {user_id}
"""
repost_result = repost_tweet(admin_entity_id, entity_id, task_description)
print(f"Repost result for {entity_id}: {repost_result}")
return "Tweeting and reposting process completed."
该repost_tweet
函数将转发推文,并repost_existing
检查是否有该推文的引用。如果有引用,则将包含引用的推文转发;否则,仅转发推文。
设置 FastAPI 后端
现在,我们将设置后端并在main.py
文件中定义所需的端点。这些端点将用于前端连接到后端。
从导入必要的库并创建 FastAPI 应用程序开始。
from fastapi import FastAPI, HTTPException, Request, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
from fastapi.middleware.cors import CORSMiddleware
from firebase.init import auth
from composio_config import createNewEntity, isEntityConnected, createTwitterIntegrationAndInitiateAdminConnection
import logging
from quote_generator import generate_repost_quote
from new_tweet_repost import create_new_tweet_and_repost
from twitter_functions import get_tweet_text_by_id, get_user_data_by_username
from repost_existing_tweet import repost_existing
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
指定来源和中间件。
origins = [
"https://tweetify-three.vercel.app",
"http://localhost:5173",
"http://localhost",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
获取令牌并使用它来进行身份验证。
def verify_token(auth_credentials: HTTPAuthorizationCredentials = Depends(
HTTPBearer())):
token = auth_credentials.credentials
try:
decoded_token = auth.verify_id_token(token)
return decoded_token
except Exception:
raise HTTPException(status_code=401, detail="Invalid or expired token")
定义 Pydantic 模型。
class UserData(BaseModel):
admin_username: str
username: str
appType: str
class TwitterUserData(BaseModel):
username: str
class InitialiseAgentData(BaseModel):
username: str
class TweetData(BaseModel):
prompt: str
tweetContent: str
numberOfQuotes: int
class GetTweetData(BaseModel):
tweet_id: str
class TweetRequestData(BaseModel):
initial_tweet_entity_id: str
post: str
repost_data_list: list
class RepostExistingData(BaseModel):
admin_entity_id: str
tweet_id: str
repost_data_list: list
class NewIntegrationData(BaseModel):
username: str
redirectUrl: str
class NewEntityData(BaseModel):
username: str
newUserId: str
redirectUrl: str
指定端点以及它们将返回的结果。
@app.post("/newintegration")
async def handle_request(user_data: NewIntegrationData,
decoded_token: dict = Depends(verify_token)):
user_id = decoded_token['uid']
username = user_data.username
redirectUrl = user_data.redirectUrl
res = createTwitterIntegrationAndInitiateAdminConnection(username, redirectUrl)
return res
@app.post("/newentity")
async def handle_request(user_data: NewEntityData,
decoded_token: dict = Depends(verify_token)):
user_id = decoded_token['uid']
username = user_data.username
newUserId = user_data.newUserId
redirectUrl = user_data.redirectUrl
res = createNewEntity(username, newUserId, redirectUrl)
return res
@app.post("/checkconnection")
async def handle_request(user_data: UserData,
decoded_token: dict = Depends(verify_token)):
user_id = decoded_token['uid']
admin_username = user_data.admin_username
username = user_data.username
appType = user_data.appType
res = isEntityConnected(admin_username, username, appType)
return res
@app.post("/getquotes")
async def handle_request(tweet_data: TweetData,
decoded_token: dict = Depends(verify_token)):
user_id = decoded_token['uid']
prompt = tweet_data.prompt
tweet_content = tweet_data.tweetContent
number_of_quotes = tweet_data.numberOfQuotes
res = generate_repost_quote(prompt, tweet_content, number_of_quotes)
return {"quotes": res}
@app.post("/newtweetandrepost")
async def handle_request(tweet_request_data: TweetRequestData,
decoded_token: dict = Depends(verify_token)):
initial_tweet_entity_id = tweet_request_data.initial_tweet_entity_id
initial_tweet = tweet_request_data.post
repost_data_list = tweet_request_data.repost_data_list
res = create_new_tweet_and_repost(initial_tweet_entity_id, initial_tweet, repost_data_list)
return {"result": res}
@app.post("/repostexisting")
async def handle_request(tweet_request_data: RepostExistingData,
decoded_token: dict = Depends(verify_token)):
admin_entity_id = tweet_request_data.admin_entity_id
tweet_id = tweet_request_data.tweet_id
repost_data_list = tweet_request_data.repost_data_list
res = repost_existing(admin_entity_id, tweet_id, repost_data_list)
return {"result": res}
@app.post("/gettweet")
async def handle_request(tweet_data: GetTweetData, decoded_token: dict = Depends(verify_token)):
tweet_id = tweet_data.tweet_id
try:
tweet_text = get_tweet_text_by_id(tweet_id)
return {"tweet_text": tweet_text}
except requests.exceptions.RequestException as e:
if e.response.status_code == 400:
return {"error": "An error occurred: 400 Client Error: Bad Request for url: https://api.twitter.com/2/tweets"}, 400
return {"error": str(e)}, 500
@app.post("/getusertwitterdata")
async def handle_request(user_data: TwitterUserData, decoded_token: dict = Depends(verify_token)):
username = user_data.username
try:
res = get_user_data_by_username(username)
if res is None:
return {"error": "An error occurred while fetching user data."}, 500
return res
except requests.exceptions.HTTPError as e:
if e.response.status_code == 404:
return {"error": "Username not found."}, 404
elif e.response.status_code == 429:
return {"error": "Too many requests. Please try again later."}, 429
else:
return {"error": f"HTTP error occurred: {e}"}, e.response.status_code
except requests.exceptions.RequestException as e:
return {"error": f"An error occurred: {e}"}, 500
@app.get("/")
async def handle_request():
return "ok"
这些端点的作用如下:
/newintergation
- 创建新的集成,并将管理员与 Twitter 帐户关联。返回管理员的详细信息/newentity
- 使用提供的用户凭据创建一个新实体,并使用该verify_token
函数使用提供的令牌对用户进行身份验证。/checkconnection
- 检查提供的管理员凭据与新创建的实体之间的连接是否成功建立。/generatequotes
- 使用提供的参数(如提示、tweet_content、number_of_quotes 和用户详细信息)生成多个引文。/newtweetandrepost
- 使用我们创建的 AI 代理生成新查询并提供所有必要的输入/repostexisting
- 使用 entity_id、tweet_id 和 repost_data_list 重新发布现有推文。/gettweet
- 使用推文的 ID 返回推文的内容/getusertwitterdata
- 返回使用令牌进行身份验证的用户的 Twitter 数据/
- 这是测试端点,用于简单检查后端 API 是否成功运行。如果 API 运行成功,它将返回“ok”。
最后,定义 Uvicorn 服务器。
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
要启动服务器,请运行以下命令:
python main.py
您的服务器将在端口上运行8000
构建前端
让我们开始构建项目的前端。为了简单起见,我们不会深入研究每个组件。
主页
这将是我们的主页组件。
import Hero from "../components/Hero";
import Benefits from "../components/Benefits";
import FAQ from "../components/FAQ";
import Working from "../components/Working";
import ActionButton from "../components/ActionButton";
import DemoVideo from "../components/DemoVideo";
const Home = () => {
return <section className="bg-white dark:bg-gray-900 mt-24">
<div className="px-4 mx-auto max-w-screen-xl text-center py-16">
<Hero />
<Benefits />
<DemoVideo />
<Working />
<FAQ />
<div className="mt-32">
<ActionButton displayName={"Get started"} link={"#"} />
</div>
</div>
</section>
}
export default Home;
这将生成如下主页:
一旦您连接了您的 Twitter 帐户,它将把您重定向到“设置”页面。
点击此处查看设置页面的完整代码。
在此页面上,用户可以添加他们的 Composio API 密钥。连接他们的 Twitter 帐户并向其中添加更多用户。
代码如下App.jsx
:
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { onAuthStateChanged } from "firebase/auth";
import { auth } from "./config/firebase";
import Navbar from "./components/Navbar";
import Home from "./pages/Home";
import Footer from "./components/Footer";
import ScrollToTop from "./components/ScrollToTop";
import { useState, useEffect } from "react";
import Login from "./pages/Login";
import Settings from "./pages/Settings";
import NotFound from "./pages/NotFound";
import SkeletonLoader from "./components/SkeletonLoader";
import { SnackbarProvider } from 'notistack'
import CreatePost from "./pages/CreatePost";
import RepostExistingTweet from "./pages/Repost";
const ProtectedRoute = ({ user, children }) => {
if (!user) {
return <Navigate to="/login" replace />;
}
return children;
};
const App = () => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
return () => unsubscribe();
}, []);
if (loading) {
return <SkeletonLoader />
}
return (
<BrowserRouter>
<SnackbarProvider autoHideDuration={3000} preventDuplicate={true} anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}>
<Navbar user={user} />
<ScrollToTop />
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/Settings" element={
<ProtectedRoute user={user}>
<Settings user={user} />
</ProtectedRoute>
} />
<Route path="/createpost" element={
<ProtectedRoute user={user}>
<CreatePost user={user} />
</ProtectedRoute>
} />
<Route path="/repost" element={
<ProtectedRoute user={user}>
<RepostExistingTweet user={user} />
</ProtectedRoute>
} />
<Route path="/" element={<Home />} />
<Route path="*" element={<NotFound />} />
</Routes>
<Footer />
</SnackbarProvider>
</BrowserRouter>
);
}
export default App;
- Firebase 身份验证- 我们用它来
onAuthStateChanged
管理身份验证。它会跟踪身份验证状态。之后,如果用户身份验证成功,它会将用户重定向到下一步,即“设置”页面。 - 路由和重定向- 我们
react-router-dom
在项目中使用路由功能。这使我们能够在跟踪身份验证状态的同时导航到不同的路由(例如/settings
、/login
和)。/
- 骨架加载器- 我们添加了一个骨架加载器,它将在 Firebase 执行身份验证任务和更新身份验证状态时显示。
运行应用
最后,使用以下命令运行该应用程序:
npm run dev
这将在本地主机上部署您的应用程序。
以下是该应用程序的快速演示:
您可以在此处试用该实时应用程序。
下一步是什么?
在本文中,我们构建了一个完整的 AI 工具,它可以连接到您的 Twitter 帐户,并可以发布新推文、转发和引用转发推文。
感谢您阅读本文。查看 Composio 并给我们一个 Star 来表示您的支持⭐
文章来源:https://dev.to/composiodev/built-an-ai-tool-to-help-my-team-tweet-smart-goodbye-manual-posting-hello-viral-hits-5fap