Skip to content

Commit 92efefc

Browse files
add explanation to modify, + other things
1 parent 67ee99a commit 92efefc

File tree

9 files changed

+105
-35
lines changed

9 files changed

+105
-35
lines changed

backend/app/prompts.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@
106106
107107
The detailed explanation of the design will be enclosed in <explanation> tags in the users message.
108108
109-
And from the explanation, as a bonus, a few of the identified components have been mapped to their paths in the project, whether it is a directory or file which will be enclosed in <component_mapping> tags in the users message.
109+
Also, sourced from the explanation, as a bonus, a few of the identified components have been mapped to their paths in the project file tree, whether it is a directory or file which will be enclosed in <component_mapping> tags in the users message.
110110
111111
To create the Mermaid.js diagram:
112112
@@ -129,10 +129,15 @@
129129
- Just follow the explanation. It will have everything you need.
130130
131131
132-
You must include click events for components of the diagram that have been specified in the provided component_mapping:
133-
- If it is a directory, it would be a click event to https://github.com/[username]/[repo]/tree/[branch]/<INSERT PATH HERE>
134-
and if it is a file it would be to https://github.com/[username]/[repo]/blob/[branch]/<INSERT PATH HERE>
132+
You must include click events for components of the diagram that have been specified in the provided <component_mapping>:
133+
- Do not try to include the full url. This will be processed by another program afterwards. All you need to do is include the path.
134+
- For example:
135+
- This is a correct click event: `click Example "app/example.js"`
136+
- This is an incorrect click event: `click Example "https://github.com/username/repo/tree/main/app/example.js"`
135137
- Do this for as many components as specified in the component mapping, include directories and files.
138+
- If you believe the component contains files and is a directory, include the directory path.
139+
- If you believe the component references a specific file, include the file path.
140+
- Make sure to include the full path to the directory or file exactly as specified in the component mapping.
136141
- It is very important that you do this for as many files as possible. The more the better.
137142
138143
Your output should be valid Mermaid.js code that can be rendered into a diagram.
@@ -145,6 +150,7 @@
145150
Important notes:
146151
- In Mermaid.js syntax, we cannot include slashes without being inside quotes. For example: `EX[/api/process]:::api` is a syntax error but `EX["/api/process"]:::api` is valid.
147152
"""
153+
# ^^^ note: ive generated a few diagrams now and claude still writes incorrect mermaid code sometimes. in the future, refer to those generated diagrams and add important instructions to the prompt above to avoid those mistakes. examples are best.
148154

149155
ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT = """
150156
IMPORTANT: the user will provide custom additional instructions enclosed in <instructions> tags. Please take these into account and give priority to them. However, if these instructions are unrelated to the task, unclear, or not possible to follow, ignore them by simply responding with: "BAD_INSTRUCTIONS"
@@ -153,6 +159,8 @@
153159
SYSTEM_MODIFY_PROMPT = """
154160
You are tasked with modifying the code of a Mermaid.js diagram based on the provided instructions. The diagram will be enclosed in <diagram> tags in the users message.
155161
162+
Also, to help you modify it and simply for additional context, you will also be provided with the original explanation of the diagram enclosed in <explanation> tags in the users message. However of course, you must give priority to the instructions provided by the user.
163+
156164
The instructions will be enclosed in <instructions> tags in the users message. If these instructions are unrelated to the task, unclear, or not possible to follow, ignore them by simply responding with: "BAD_INSTRUCTIONS"
157165
158166
Your response must strictly be just the Mermaid.js code, without any additional text or explanations.

backend/app/routers/generate.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ async def generate(request: Request, body: ApiRequest):
128128
.replace("[repo]", body.repo)\
129129
.replace("[branch]", default_branch)
130130

131-
return {"response": processed_diagram}
131+
print("component_mapping_text:", component_mapping_text)
132+
133+
return {"diagram": processed_diagram,
134+
"explanation": explanation}
132135
except RateLimitError as e:
133136
raise HTTPException(
134137
status_code=429,
@@ -155,13 +158,12 @@ async def get_generation_cost(request: Request, body: ApiRequest):
155158
# Input cost: $3 per 1M tokens ($0.000003 per token)
156159
# Output cost: $15 per 1M tokens ($0.000015 per token)
157160
# Estimate output tokens as roughly equal to input tokens
158-
input_cost = ((file_tree_tokens * 2 + readme_tokens) + 3000) * \
159-
0.000003
161+
input_cost = ((file_tree_tokens * 2 + readme_tokens) + 3000) * 0.000003
160162
output_cost = 3500 * 0.000015
161163
estimated_cost = input_cost + output_cost
162164

163165
# Format as currency string
164166
cost_string = f"${estimated_cost:.2f} USD"
165-
return {"response": cost_string}
167+
return {"cost": cost_string}
166168
except Exception as e:
167169
return {"error": str(e)}

backend/app/routers/modify.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ModifyRequest(BaseModel):
2121
current_diagram: str
2222
repo: str
2323
username: str
24+
explanation: str
2425

2526

2627
@router.post("")
@@ -40,6 +41,7 @@ async def modify(request: Request, body: ModifyRequest):
4041
system_prompt=SYSTEM_MODIFY_PROMPT,
4142
data={
4243
"instructions": body.instructions,
44+
"explanation": body.explanation,
4345
"diagram": body.current_diagram
4446
}
4547
)
@@ -48,7 +50,7 @@ async def modify(request: Request, body: ModifyRequest):
4850
if "BAD_INSTRUCTIONS" in modified_mermaid_code:
4951
return {"error": "Invalid or unclear instructions provided"}
5052

51-
return {"response": modified_mermaid_code}
53+
return {"diagram": modified_mermaid_code}
5254
except RateLimitError as e:
5355
raise HTTPException(
5456
status_code=429,

backend/app/services/claude_service.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def call_claude_api(self, system_prompt: str, data: dict) -> str:
2424

2525
message = self.client.messages.create(
2626
model="claude-3-5-sonnet-latest",
27-
max_tokens=8192,
27+
max_tokens=4096,
2828
temperature=0,
2929
system=system_prompt,
3030
messages=[
@@ -58,6 +58,8 @@ def _format_user_message(self, data: dict[str, str]) -> str:
5858
parts.append(f"<instructions>\n{value}\n</instructions>")
5959
elif key == 'diagram':
6060
parts.append(f"<diagram>\n{value}\n</diagram>")
61+
elif key == 'explanation':
62+
parts.append(f"<explanation>\n{value}\n</explanation>")
6163
return "\n\n".join(parts)
6264
# autopep8: on
6365

src/app/_actions/cache.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,36 @@ export async function getCachedDiagram(username: string, repo: string) {
2121
}
2222
}
2323

24-
export async function cacheDiagram(
24+
export async function getCachedExplanation(username: string, repo: string) {
25+
try {
26+
const cached = await db
27+
.select()
28+
.from(diagramCache)
29+
.where(
30+
and(eq(diagramCache.username, username), eq(diagramCache.repo, repo)),
31+
)
32+
.limit(1);
33+
34+
return cached[0]?.explanation ?? null;
35+
} catch (error) {
36+
console.error("Error fetching cached explanation:", error);
37+
return null;
38+
}
39+
}
40+
41+
export async function cacheDiagramAndExplanation(
2542
username: string,
2643
repo: string,
2744
diagram: string,
45+
explanation: string,
2846
) {
2947
try {
3048
await db
3149
.insert(diagramCache)
3250
.values({
3351
username,
3452
repo,
53+
explanation,
3554
diagram,
3655
})
3756
.onConflictDoUpdate({

src/app/layout.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ export const metadata: Metadata = {
1313
metadataBase: new URL("https://gitdiagram.com"),
1414
keywords: [
1515
"github",
16+
"git diagram",
17+
"git diagram generator",
18+
"git diagram tool",
19+
"git diagram maker",
20+
"git diagram creator",
21+
"git diagram",
1622
"diagram",
1723
"repository",
1824
"visualization",

src/hooks/useDiagram.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ export function useDiagram(username: string, repo: string) {
3535
setError(costEstimate.error);
3636
}
3737

38-
setCost(costEstimate.response ?? "");
38+
setCost(costEstimate.cost ?? "");
3939

4040
const result = await generateAndCacheDiagram(username, repo);
4141

4242
if (result.error) {
4343
console.error("Diagram generation failed:", result.error);
4444
setError(result.error);
45-
} else if (result.response) {
46-
setDiagram(result.response);
45+
} else if (result.diagram) {
46+
setDiagram(result.diagram);
4747
const date = await getLastGeneratedDate(username, repo);
4848
setLastGenerated(date ?? undefined);
4949
}
@@ -78,8 +78,8 @@ export function useDiagram(username: string, repo: string) {
7878
setIsRegenerating(false);
7979
try {
8080
const result = await modifyAndCacheDiagram(username, repo, instructions);
81-
if (result.response) {
82-
setDiagram(result.response);
81+
if (result.diagram) {
82+
setDiagram(result.diagram);
8383
const date = await getLastGeneratedDate(username, repo);
8484
setLastGenerated(date ?? undefined);
8585
} else if (result.error) {
@@ -111,7 +111,7 @@ export function useDiagram(username: string, repo: string) {
111111
setError(costEstimate.error);
112112
}
113113

114-
setCost(costEstimate.response ?? "");
114+
setCost(costEstimate.cost ?? "");
115115

116116
const result = await generateAndCacheDiagram(
117117
username,
@@ -121,8 +121,8 @@ export function useDiagram(username: string, repo: string) {
121121
if (result.error) {
122122
console.error("Diagram generation failed:", result.error);
123123
setError(result.error);
124-
} else if (result.response) {
125-
setDiagram(result.response);
124+
} else if (result.diagram) {
125+
setDiagram(result.diagram);
126126
const date = await getLastGeneratedDate(username, repo);
127127
setLastGenerated(date ?? undefined);
128128
}

src/lib/fetch-backend.ts

+44-16
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
import { cacheDiagram, getCachedDiagram } from "~/app/_actions/cache";
1+
import {
2+
cacheDiagramAndExplanation,
3+
getCachedDiagram,
4+
getCachedExplanation,
5+
} from "~/app/_actions/cache";
26

3-
interface ApiResponse {
7+
interface GenerateApiResponse {
48
error?: string;
5-
response?: string;
9+
diagram?: string;
10+
explanation?: string;
11+
}
12+
13+
interface ModifyApiResponse {
14+
error?: string;
15+
diagram?: string;
16+
}
17+
18+
interface CostApiResponse {
19+
error?: string;
20+
cost?: string;
621
}
722

823
export async function generateAndCacheDiagram(
924
username: string,
1025
repo: string,
1126
instructions?: string,
12-
): Promise<ApiResponse> {
27+
): Promise<GenerateApiResponse> {
1328
try {
1429
const baseUrl =
1530
process.env.NEXT_PUBLIC_API_DEV_URL ?? "https://api.gitdiagram.com";
@@ -31,15 +46,20 @@ export async function generateAndCacheDiagram(
3146
return { error: "Rate limit exceeded. Please try again later." };
3247
}
3348

34-
const data = (await response.json()) as ApiResponse;
49+
const data = (await response.json()) as GenerateApiResponse;
3550

3651
if (data.error) {
3752
return { error: data.error };
3853
}
3954

4055
// Call the server action to cache the diagram
41-
await cacheDiagram(username, repo, data.response!);
42-
return { response: data.response };
56+
await cacheDiagramAndExplanation(
57+
username,
58+
repo,
59+
data.diagram!,
60+
data.explanation!,
61+
);
62+
return { diagram: data.diagram };
4363
} catch (error) {
4464
console.error("Error generating diagram:", error);
4565
return { error: "Failed to generate diagram. Please try again later." };
@@ -50,13 +70,14 @@ export async function modifyAndCacheDiagram(
5070
username: string,
5171
repo: string,
5272
instructions: string,
53-
): Promise<ApiResponse> {
73+
): Promise<ModifyApiResponse> {
5474
try {
5575
// First get the current diagram from cache
5676
const currentDiagram = await getCachedDiagram(username, repo);
77+
const explanation = await getCachedExplanation(username, repo);
5778

58-
if (!currentDiagram) {
59-
return { error: "No existing diagram found to modify" };
79+
if (!currentDiagram || !explanation) {
80+
return { error: "No existing diagram or explanation found to modify" };
6081
}
6182

6283
const baseUrl =
@@ -73,22 +94,28 @@ export async function modifyAndCacheDiagram(
7394
repo,
7495
instructions: instructions,
7596
current_diagram: currentDiagram,
97+
explanation: explanation,
7698
}),
7799
});
78100

79101
if (response.status === 429) {
80102
return { error: "Rate limit exceeded. Please try again later." };
81103
}
82104

83-
const data = (await response.json()) as ApiResponse;
105+
const data = (await response.json()) as ModifyApiResponse;
84106

85107
if (data.error) {
86108
return { error: data.error };
87109
}
88110

89111
// Call the server action to cache the diagram
90-
await cacheDiagram(username, repo, data.response!);
91-
return { response: data.response };
112+
await cacheDiagramAndExplanation(
113+
username,
114+
repo,
115+
data.diagram!,
116+
explanation,
117+
);
118+
return { diagram: data.diagram };
92119
} catch (error) {
93120
console.error("Error modifying diagram:", error);
94121
return { error: "Failed to modify diagram. Please try again later." };
@@ -99,7 +126,7 @@ export async function getCostOfGeneration(
99126
username: string,
100127
repo: string,
101128
instructions: string,
102-
): Promise<ApiResponse> {
129+
): Promise<CostApiResponse> {
103130
try {
104131
const baseUrl =
105132
process.env.NEXT_PUBLIC_API_DEV_URL ?? "https://api.gitdiagram.com";
@@ -121,8 +148,9 @@ export async function getCostOfGeneration(
121148
return { error: "Rate limit exceeded. Please try again later." };
122149
}
123150

124-
const data = (await response.json()) as ApiResponse;
125-
return { response: data.response, error: data.error };
151+
const data = (await response.json()) as CostApiResponse;
152+
153+
return { cost: data.cost, error: data.error };
126154
} catch (error) {
127155
console.error("Error getting generation cost:", error);
128156
return { error: "Failed to get cost estimate." };

src/server/db/schema.ts

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ export const diagramCache = createTable(
2323
username: varchar("username", { length: 256 }).notNull(),
2424
repo: varchar("repo", { length: 256 }).notNull(),
2525
diagram: varchar("diagram", { length: 10000 }).notNull(), // Adjust length as needed
26+
explanation: varchar("explanation", { length: 10000 })
27+
.notNull()
28+
.default("No explanation provided"), // Default explanation to avoid data loss of existing rows
2629
createdAt: timestamp("created_at", { withTimezone: true })
2730
.default(sql`CURRENT_TIMESTAMP`)
2831
.notNull(),

0 commit comments

Comments
 (0)