Skip to content

Commit

Permalink
Merge pull request #483 from phospho-app/fred-fix-chat-completion
Browse files Browse the repository at this point in the history
Create default project
  • Loading branch information
fred3105 committed Jun 7, 2024
2 parents 59e44a0 + 06ce659 commit 71966d9
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 13 deletions.
29 changes: 29 additions & 0 deletions backend/app/api/platform/endpoints/organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from app.core import config
from app.security.authentification import propelauth
from app.services.mongo.emails import email_user_onboarding, send_payment_issue_email
from app.services.mongo.projects import populate_default
from app.services.mongo.organizations import (
create_project_by_org,
get_projects_from_org_id,
Expand Down Expand Up @@ -68,6 +69,34 @@ async def post_create_project(
return project


@router.post(
"/organizations/{org_id}/create-default-project",
response_model=Project,
description="Create a new default project",
)
async def post_create_default_project(
org_id: str,
user: User = Depends(propelauth.require_user),
) -> Project:
org_member_info = propelauth.require_org_member(user, org_id)
project = await create_project_by_org(
org_id=org_id, user_id=user.user_id, project_name="Default Project"
)
await populate_default(project_id=project.id, org_id=org_id)
# Send a notification if it's not a phospho project
if (
config.ENVIRONMENT == "production"
and org_member_info.org_id != "e4M5ZDH2pwXz8ddEbVIR"
):
# Get the user info
logger.info(f"New default project created : {project.project_name}")
await slack_notification(
f"Default project {project.project_name} {project.id} created by user with"
+ f" id {user.email} in organization {org_member_info.org_name}"
)
return project


@router.post(
"/organizations/{org_id}/init",
description="Ininitialize an organization",
Expand Down
71 changes: 70 additions & 1 deletion backend/app/services/mongo/projects.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@
label_sentiment_analysis,
)
from app.services.slack import slack_notification
from app.utils import cast_datetime_or_timestamp_to_timestamp, generate_timestamp
from app.utils import (
cast_datetime_or_timestamp_to_timestamp,
generate_timestamp,
generate_uuid,
)
from fastapi import HTTPException
from loguru import logger
from propelauth_fastapi import User
Expand Down Expand Up @@ -696,3 +700,68 @@ async def collect_languages(
languages = [lang.get("_id") for lang in languages if lang.get("_id") is not None]
logger.info(f"Languages detected in project {project_id}: {languages}")
return languages


async def populate_default(
project_id: str,
org_id: str,
) -> None:
"""
Populate the project with default values
"""
logger.info(f"Populating project {project_id} with default values")
mongo_db = await get_mongo_db()

if config.ENVIRONMENT == "production":
target_project_id = "6a6323d1447a44ddac2dae42d7c39749"
else:
target_project_id = "5383b5ce54314a76a9bb1774839e8417"
target_project = await get_project_by_id(
target_project_id,
)
target_project.org_id = org_id
target_project.id = project_id
await update_project(target_project)

# Add events to the project
default_event_defintiions = (
await mongo_db["event_definitions"]
.find({"project_id": target_project_id})
.to_list(length=10)
)
event_definitions = []
for event_definition in default_event_defintiions:
validated_event_definition = EventDefinition.model_validate(event_definition)
validated_event_definition.id = generate_uuid()
validated_event_definition.project_id = project_id
validated_event_definition.org_id = org_id
event_definitions.append(validated_event_definition)
await mongo_db["event_definitions"].insert_many(
[event_definition.model_dump() for event_definition in event_definitions]
)

# Add tasks to the project
default_tasks = await get_all_tasks(target_project_id)
tasks = []
for task in default_tasks:
task.id = generate_uuid()
task.created_at = generate_timestamp()
task.project_id = project_id
task.org_id = org_id
tasks.append(task)
await mongo_db["tasks"].insert_many([task.model_dump() for task in tasks])

# Add sessions to the project
default_sessions = await get_all_sessions(target_project_id)
sessions = []
for session in default_sessions:
session.id = generate_uuid()
session.created_at = generate_timestamp()
session.project_id = project_id
session.org_id = org_id
sessions.append(session)
await mongo_db["sessions"].insert_many(
[session.model_dump() for session in sessions]
)

return None
18 changes: 9 additions & 9 deletions phospho-python/phospho/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,17 +214,17 @@ def from_previous(cls, project_data: dict) -> "Project":
):
for event_name, event in project_data["settings"]["events"].items():
if "event_name" not in event.keys():
project_data["settings"]["events"][event_name][
"event_name"
] = event_name
project_data["settings"]["events"][event_name]["event_name"] = (
event_name
)
if "org_id" not in event.keys():
project_data["settings"]["events"][event_name][
"org_id"
] = project_data["org_id"]
project_data["settings"]["events"][event_name]["org_id"] = (
project_data["org_id"]
)
if "project_id" not in event.keys():
project_data["settings"]["events"][event_name][
"project_id"
] = project_data["id"]
project_data["settings"]["events"][event_name]["project_id"] = (
project_data["id"]
)

return cls(**project_data)

Expand Down
81 changes: 78 additions & 3 deletions platform/app/onboarding/create-project/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ import {
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useToast } from "@/components/ui/use-toast";
import { navigationStateStore } from "@/store/store";
import { dataStateStore, navigationStateStore } from "@/store/store";
import { zodResolver } from "@hookform/resolvers/zod";
import { useUser } from "@propelauth/nextjs/client";
import { useRouter } from "next/navigation";
Expand All @@ -48,6 +47,9 @@ export default function Page() {
const router = useRouter();
const { user, loading, accessToken } = useUser();
const selectedOrgId = navigationStateStore((state) => state.selectedOrgId);
const setproject_id = navigationStateStore((state) => state.setproject_id);
const setHasTasks = dataStateStore((state) => state.setHasTasks);
const setHasSessions = dataStateStore((state) => state.setHasSessions);
const setSelectedOrgId = navigationStateStore(
(state) => state.setSelectedOrgId,
);
Expand All @@ -62,6 +64,44 @@ export default function Page() {
// },
});

async function defaultProject() {
if (creatingProject) {
return;
}
if (!selectedOrgId) {
// fetch the org id from the user
const orgId = user?.getOrgs()[0].orgId;
if (orgId) {
setSelectedOrgId(orgId);
} else {
// if the user has no orgs, redirect to the auth
router.push("/");
}
}
//Create default project for orgID
fetch(`/api/organizations/${selectedOrgId}/create-default-project`, {
method: "POST",
headers: {
Authorization: "Bearer " + accessToken,
"Content-Type": "application/json",
},
}).then(async (response) => {
const responseBody = await response.json();
if (responseBody.id !== undefined) {
setHasTasks(null);
setHasSessions(null);
setproject_id(responseBody.id);
router.push(`/org`);
} else {
toast.toast({
title: "Error when creating project",
description: responseBody.error,
});
}
// setCreatingProject(false);
});
}

// 2. Define a submit handler.
async function onSubmit(values: z.infer<typeof formSchema>) {
if (creatingProject) {
Expand Down Expand Up @@ -113,7 +153,7 @@ export default function Page() {
<FetchOrgProject />
<Card className="lg:w-1/3 md:w-1/2">
<CardHeader className="pb-0">
<CardTitle>First, let's create your phospho project.</CardTitle>
<CardTitle>Create your phospho project.</CardTitle>
<CardDescription>
You can create multiple projects to keep your app ordered.
</CardDescription>
Expand Down Expand Up @@ -155,6 +195,41 @@ export default function Page() {
</form>
</Form>
</CardContent>
<div className="relative flex items-center">
<div className="flex-grow border-t text-muted-foreground"></div>
<span className="flex-shrink mx-4 text-muted-foreground">Or</span>
<div className="flex-grow border-t text-muted-foreground"></div>
</div>
<div>
<CardHeader className="pb-4">
<CardTitle>Explore sample data</CardTitle>
<CardDescription>
Get a feel for Phospho by exploring a sample project.
</CardDescription>
</CardHeader>
</div>
<CardContent className="space-y-8">
<div className="flex justify-center flex-col">
<img
src="/image/onboarding.svg"
alt="Onboarding Image"
className="mx-4"
/>
</div>
<div className="flex justify-end mr-4">
<Button
onClick={() => {
defaultProject();
}}
disabled={loading || creatingProject}
>
{creatingProject && (
<Icons.spinner className="w-4 h-4 animate-spin" />
)}
Explore sample data
</Button>
</div>
</CardContent>
</Card>
</>
);
Expand Down
24 changes: 24 additions & 0 deletions platform/components/insights/clusters/clusters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ const Clusters: React.FC = () => {
}

const maxCreatedAt = latestClustering?.created_at;
const { data: totalNbTasksData } = useSWR(
[
`/api/explore/${project_id}/aggregated/tasks`,
accessToken,
"total_nb_tasks",
],
([url, accessToken]) =>
authFetcher(url, accessToken, "POST", {
metrics: ["total_nb_tasks"],
}),
{
keepPreviousData: true,
},
);
const totalNbTasks: number | null | undefined =
totalNbTasksData?.total_nb_tasks;

if (!project_id) {
return <></>;
Expand All @@ -65,6 +81,14 @@ const Clusters: React.FC = () => {
<Button
variant="default"
onClick={async () => {
if (totalNbTasks == null || totalNbTasks < 5) {
toast({
title: "Not enough data",
description:
"You need at least 5 tasks to detect clusters.",
});
return;
}
mutateClusterings((data: any) => {
// Add a new clustering to the list
const newClustering: Clustering = {
Expand Down
1 change: 1 addition & 0 deletions platform/public/image/onboarding.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 71966d9

Please sign in to comment.