diff --git a/app/__pycache__/database.cpython-311.pyc b/app/__pycache__/database.cpython-311.pyc index 8946a9b..47badc8 100644 Binary files a/app/__pycache__/database.cpython-311.pyc and b/app/__pycache__/database.cpython-311.pyc differ diff --git a/app/__pycache__/main.cpython-311.pyc b/app/__pycache__/main.cpython-311.pyc index 2b54f72..d0e1b33 100644 Binary files a/app/__pycache__/main.cpython-311.pyc and b/app/__pycache__/main.cpython-311.pyc differ diff --git a/app/__pycache__/models.cpython-311.pyc b/app/__pycache__/models.cpython-311.pyc index 40b68e9..7f25e0c 100644 Binary files a/app/__pycache__/models.cpython-311.pyc and b/app/__pycache__/models.cpython-311.pyc differ diff --git a/app/__pycache__/schemas.cpython-311.pyc b/app/__pycache__/schemas.cpython-311.pyc index 7c42b8b..9be2fff 100644 Binary files a/app/__pycache__/schemas.cpython-311.pyc and b/app/__pycache__/schemas.cpython-311.pyc differ diff --git a/app/database.py b/app/database.py index 1123d47..c9698b7 100644 --- a/app/database.py +++ b/app/database.py @@ -118,4 +118,51 @@ async def init_db(): ) session.add(gemini_config) await session.commit() - print("✅ Default Gemini AI configuration created") \ No newline at end of file + print("✅ Default Gemini AI configuration created") + + # 4. 检查并初始化 AI Roles + ai_roles_data = [ + { + "id": 0, + "name": 'Reflective Assistant', + "description": 'Helps you dive deep into your thoughts and feelings through meaningful reflection.', + "systemPrompt": 'You are a helpful journal assistant. Help the user reflect on their thoughts and feelings.', + "icon": 'journal-outline', + "iconFamily": 'Ionicons', + }, + { + "id": 1, + "name": 'Creative Spark', + "description": 'A partner for brainstorming, creative writing, and exploring new ideas.', + "systemPrompt": 'You are a creative brainstorming partner. Help the user explore new ideas, write stories, or look at things from a fresh perspective.', + "icon": 'bulb-outline', + "iconFamily": 'Ionicons', + }, + { + "id": 2, + "name": 'Action Planner', + "description": 'Focused on turning thoughts into actionable plans and organized goals.', + "systemPrompt": 'You are a productivity coach. Help the user break down their thoughts into actionable steps and clear goals.', + "icon": 'list-outline', + "iconFamily": 'Ionicons', + }, + { + "id": 3, + "name": 'Empathetic Guide', + "description": 'Provides a safe, non-judgmental space for emotional support and empathy.', + "systemPrompt": 'You are a supportive and empathetic friend. Listen to the user\'s concerns and provide emotional support without judgment.', + "icon": 'heart-outline', + "iconFamily": 'Ionicons', + }, + ] + + for role_data in ai_roles_data: + result = await session.execute( + select(models.AIRole).where(models.AIRole.id == role_data["id"]) + ) + if not result.scalars().first(): + new_role = models.AIRole(**role_data) + session.add(new_role) + print(f"✅ AI Role '{role_data['name']}' created") + + await session.commit() \ No newline at end of file diff --git a/app/main.py b/app/main.py index eb3d156..650532b 100644 --- a/app/main.py +++ b/app/main.py @@ -99,9 +99,18 @@ async def get_my_assets( db: AsyncSession = Depends(database.get_db) ): result = await db.execute( - select(models.Asset).where(models.Asset.author_id == current_user.id) + select(models.Asset) + .options(selectinload(models.Asset.heir)) + .where(models.Asset.author_id == current_user.id) ) - return result.scalars().all() + assets = result.scalars().all() + # Populate heir_email for the schema + for asset in assets: + if asset.heir: + asset.heir_email = asset.heir.email + else: + asset.heir_email = None + return assets @app.post("/assets/create", response_model=schemas.AssetOut) @@ -235,6 +244,30 @@ async def get_designated_assets( ) return result.scalars().all() +@app.post("/assets/delete") +async def delete_asset( + asset_del: schemas.AssetDelete, + current_user: models.User = Depends(auth.get_current_user), + db: AsyncSession = Depends(database.get_db) +): + """ + Delete an asset owned by the current user. + """ + result = await db.execute( + select(models.Asset).where(models.Asset.id == asset_del.asset_id) + ) + asset = result.scalars().first() + + if not asset: + raise HTTPException(status_code=404, detail="Asset not found") + + if asset.author_id != current_user.id: + raise HTTPException(status_code=403, detail="Not authorized to delete this asset") + + await db.delete(asset) + await db.commit() + return {"message": "Asset deleted successfully"} + @app.get("/users/search", response_model=List[schemas.UserOut]) async def search_users( query: str, @@ -416,6 +449,17 @@ async def ai_proxy( detail=f"An error occurred while requesting AI provider: {str(e)}" ) +@app.get("/get_ai_roles", response_model=List[schemas.AIRoleOut]) +async def get_ai_roles( + current_user: models.User = Depends(auth.get_current_user), + db: AsyncSession = Depends(database.get_db) +): + """ + Get all available AI roles for the logged-in user. + """ + result = await db.execute(select(models.AIRole).order_by(models.AIRole.id)) + return result.scalars().all() + # 用于测试热加载 @app.post("/post1") async def test1(): diff --git a/app/models.py b/app/models.py index 50e26ec..67f0524 100644 --- a/app/models.py +++ b/app/models.py @@ -84,4 +84,14 @@ class UserTokenUsage(Base): tokens_used = Column(Integer, default=0) last_reset_at = Column(DateTime) - user = relationship("User", backref="token_usage", uselist=False) \ No newline at end of file + user = relationship("User", backref="token_usage", uselist=False) + +class AIRole(Base): + __tablename__ = "ai_roles" + + id = Column(Integer, primary_key=True, index=True) + name = Column(String, index=True) + description = Column(Text) + systemPrompt = Column(Text) + icon = Column(String) + iconFamily = Column(String) \ No newline at end of file diff --git a/app/schemas.py b/app/schemas.py index 6061758..a1c6c19 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -58,6 +58,8 @@ class AssetOut(AssetBase): content_outer_encrypted: str created_at: Optional[datetime] = None updated_at: Optional[datetime] = None + heir_id: Optional[int] = None + heir_email: Optional[str] = None model_config = ConfigDict(from_attributes=True) class AssetClaim(BaseModel): @@ -72,6 +74,9 @@ class AssetAssign(BaseModel): asset_id: int heir_email: str +class AssetDelete(BaseModel): + asset_id: int + class DeclareGuale(BaseModel): username: str @@ -105,4 +110,16 @@ class SubscriptionPlansBase(BaseModel): class SubscriptionPlansOut(SubscriptionPlansBase): id: int + model_config = ConfigDict(from_attributes=True) + +# AI Role Schemas +class AIRoleBase(BaseModel): + id: int + name: str + description: str + systemPrompt: str + icon: str + iconFamily: str + +class AIRoleOut(AIRoleBase): model_config = ConfigDict(from_attributes=True) \ No newline at end of file diff --git a/test/test_ai_proxy.py b/test/test_ai_proxy.py index d728ddc..de20347 100644 --- a/test/test_ai_proxy.py +++ b/test/test_ai_proxy.py @@ -14,7 +14,8 @@ async def test_ai_proxy_integration(): print(f"1. Registering user: {username}") reg_res = await client.post("/register", json={ "username": username, - "password": "testpassword" + "password": "testpassword", + "email": f"user_{int(time.time())}@example.com" }) if reg_res.status_code != 200: print(f"Registration failed: {reg_res.text}") @@ -22,7 +23,7 @@ async def test_ai_proxy_integration(): # 2. Login to get token print("2. Logging in...") - login_res = await client.post("/token", json={ + login_res = await client.post("/login", json={ "username": username, "password": "testpassword" })