Add inspiration tab and integrate into generation#106
Add inspiration tab and integrate into generation#106rasulkireev wants to merge 1 commit intomainfrom
Conversation
This commit introduces a new feature that allows users to add and manage inspiration sources for their blog posts. This includes: - A new `Inspiration` model to store inspiration data. - API endpoints for adding and deleting inspirations. - Frontend components and controllers for managing inspirations. - Integration with the agent system to use inspirations for content generation. Co-authored-by: me <me@rasulkireev.com>
|
Cursor Agent can help with this pull request. Just |
WalkthroughIntroduces an inspirations feature enabling users to add source materials (URLs with titles and descriptions) that influence blog post title and content generation. Includes a database model, API endpoints, system prompts, backend views, and a frontend Stimulus controller for managing inspirations. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant Controller as Inspiration<br/>Controller
participant API as /api/<br/>Endpoints
participant Service as Core<br/>Services
participant DB as Database
User->>Controller: Click "Add Inspiration"
Controller->>Controller: toggleForm()
User->>Controller: Enter URL & Submit
Controller->>Controller: Validate URL
Controller->>Controller: getCsrfToken()
Controller->>API: POST /inspirations/add<br/>(project_id, url, csrf)
API->>Service: Validate & Check Duplicate
Service->>Service: Fetch Page Content
Service->>DB: Create Inspiration Record
DB-->>Service: Inspiration Details
Service-->>API: Success + Details
API-->>Controller: AddInspirationOut
Controller->>Controller: showMessage("Added!")
Controller->>Controller: Reload Page
User->>Controller: Click Delete
Controller->>User: Confirm Dialog
User-->>Controller: Confirm
Controller->>API: POST /inspirations/delete<br/>(inspiration_id, csrf)
API->>Service: Find & Delete
Service->>DB: Delete Inspiration
DB-->>Service: Success
Service-->>API: DeleteInspirationOut
API-->>Controller: Success
Controller->>Controller: Reload Page
sequenceDiagram
autonumber
participant User
participant Generator as Content<br/>Generation
participant Prompts as System<br/>Prompts
participant LLM as AI<br/>Model
User->>Generator: Request Title/Content
Generator->>Prompts: Build Generation Context
Prompts->>Prompts: add_inspirations()
Prompts->>Prompts: Format inspirations block<br/>(titles, URLs, descriptions)
Prompts-->>Generator: Enhanced Context
Generator->>LLM: Send Prompt +<br/>Inspiration Sources
LLM->>LLM: Generate with<br/>inspiration reference
LLM-->>Generator: Generated Content
Generator-->>User: Title / Blog Post
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| profile_id=profile.id, | ||
| ) | ||
|
|
||
| return {"status": "success", "message": f"Inspiration deleted successfully"} |
There was a problem hiding this comment.
| return {"status": "success", "message": f"Inspiration deleted successfully"} | |
| return {"status": "success", "message": "Inspiration deleted successfully"} |
f-string is unnecessary here. This can just be a string. Read more.
There was a problem hiding this comment.
Greptile Overview
Greptile Summary
Adds comprehensive inspiration feature allowing users to save blog posts/blogs as style references for AI-generated content.
Key Changes:
- New
Inspirationmodel with URL scraping via Jina Reader API to capture title, description, and markdown content - Integration of inspirations into AI agent context for both title generation and blog post content generation
- Complete CRUD UI with Stimulus.js controller for managing inspirations
- API endpoints for adding/deleting inspirations with proper validation and authorization
- Inspirations automatically included in system prompts for
content_editor_agentand title suggestion agents
Architecture:
The feature follows Django best practices with fat models (business logic in Inspiration.get_page_content()), API layer using django-ninja with Pydantic schemas, and clean separation between backend and frontend via Stimulus controllers.
Confidence Score: 4/5
- Safe to merge with one performance consideration that should be addressed soon
- The implementation is well-structured and follows project conventions. The main concern is the synchronous external API call in
get_page_content()during the request-response cycle, which could cause timeout issues with slow or unresponsive URLs. This should ideally be moved to a background task using django-q2. The rest of the code is solid with proper validation, error handling, and clean integration into existing AI generation flows. - core/api/views.py line 1086 - synchronous external API call should be moved to background task
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| core/models.py | 4/5 | Added Inspiration model and integrated inspirations into blog post generation context across multiple methods |
| core/api/views.py | 5/5 | Added API endpoints for adding and deleting inspirations with proper validation and error handling |
| core/agent_system_prompts.py | 5/5 | Added add_inspirations system prompt function to include inspiration sources in AI generation |
| frontend/src/controllers/inspiration_controller.js | 4/5 | Stimulus controller for managing inspirations with add/delete functionality and UI feedback |
Sequence Diagram
sequenceDiagram
participant User
participant Browser
participant InspirationController
participant API
participant Project
participant Inspiration
participant JinaAPI
participant Agent
User->>Browser: Visit Inspirations Page
Browser->>API: GET /project/{id}/inspirations/
API->>Project: Load project and inspirations
Project-->>Browser: Render inspirations list
User->>InspirationController: Click "Add Inspiration"
InspirationController->>Browser: Show form
User->>InspirationController: Enter URL and submit
InspirationController->>API: POST /api/inspirations/add
API->>Project: Verify user owns project
API->>Inspiration: Create new inspiration record
API->>Inspiration: Call get_page_content()
Inspiration->>JinaAPI: Fetch page content
JinaAPI-->>Inspiration: Return title, description, markdown
Inspiration->>Inspiration: Save scraped data
Inspiration-->>API: Return success
API-->>InspirationController: Return inspiration data
InspirationController->>Browser: Reload page
User->>Agent: Generate blog post titles
Agent->>Project: Load inspirations
Project->>Agent: Include inspiration context
Agent->>Agent: Generate titles using inspiration style
User->>Agent: Generate blog post content
Agent->>Project: Load inspirations
Project->>Agent: Include inspiration context
Agent->>Agent: Generate content emulating inspiration style
12 files reviewed, 2 comments
|
|
||
| inspiration = Inspiration.objects.create(project=project, url=url_to_add) | ||
|
|
||
| inspiration.get_page_content() |
There was a problem hiding this comment.
logic: calling get_page_content() in the request-response cycle can cause timeout issues as it makes external HTTP requests. Consider moving this to a background task using django-q2
| inspiration.get_page_content() | |
| async_task("core.tasks.fetch_inspiration_content", inspiration.id) |
Prompt To Fix With AI
This is a comment left during a code review.
Path: core/api/views.py
Line: 1086:1086
Comment:
**logic:** calling `get_page_content()` in the request-response cycle can cause timeout issues as it makes external HTTP requests. Consider moving this to a background task using django-q2
```suggestion
async_task("core.tasks.fetch_inspiration_content", inspiration.id)
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| export default class extends Controller { | ||
| static targets = ["form", "urlInput", "submitButton", "message", "tableBody", "emptyState"]; | ||
| static values = { projectId: Number }; |
There was a problem hiding this comment.
style: emptyState target is declared but never used in the controller - the template references it but the controller doesn't interact with it
| static values = { projectId: Number }; | |
| static targets = ["form", "urlInput", "submitButton", "message", "tableBody"]; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: frontend/src/controllers/inspiration_controller.js
Line: 5:5
Comment:
**style:** `emptyState` target is declared but never used in the controller - the template references it but the controller doesn't interact with it
```suggestion
static targets = ["form", "urlInput", "submitButton", "message", "tableBody"];
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
core/admin.py (1)
9-9: LGTM! Simple admin registration follows existing patterns.The Inspiration model is registered using the simple registration approach, consistent with other models in this file (Profile, BlogPost, Project, etc.). This provides basic CRUD functionality in the Django admin.
Consider adding a custom admin class for better UX:
@admin.register(Inspiration) class InspirationAdmin(admin.ModelAdmin): list_display = ('project', 'title', 'url', 'date_scraped', 'created_at') list_filter = ('project', 'date_scraped', 'created_at') search_fields = ('title', 'url', 'description') readonly_fields = ('created_at', 'updated_at', 'date_scraped') raw_id_fields = ('project',)This would make it easier to browse and filter inspirations in the admin interface.
Also applies to: 84-84
core/api/schemas.py (1)
267-269: Consider adding URL validation.The
urlfield inAddInspirationIncould benefit from Pydantic's URL validation to ensure valid URLs are provided.Apply this diff to add URL validation:
+from pydantic import HttpUrl + class AddInspirationIn(Schema): project_id: int - url: str + url: HttpUrlAlternatively, if you need to keep it as a string but still validate:
+from pydantic import field_validator +from urllib.parse import urlparse + class AddInspirationIn(Schema): project_id: int url: str + + @field_validator('url') + @classmethod + def validate_url(cls, v): + result = urlparse(v) + if not all([result.scheme, result.netloc]): + raise ValueError('Invalid URL format') + return vfrontend/templates/project/project_inspirations.html (1)
78-159: Consider accessibility improvements for the table.The table structure is generally good, but consider these accessibility enhancements:
- Add
aria-labelto the delete buttons for screen readers:<button data-action="inspiration#deleteInspiration" data-inspiration-id="{{ inspiration.id }}" + aria-label="Delete inspiration: {{ inspiration.title|default:'this inspiration' }}" class="text-red-600 hover:text-red-900" > Delete </button>
Consider adding a confirmation dialog before deletion to prevent accidental data loss. The Stimulus controller could handle this with a confirmation prompt.
The "Loading..." default text (line 103) might be confusing if it persists. Consider adding a visual indicator or different fallback text like "Untitled" or "(No title available)".
core/api/views.py (1)
1114-1144: Remove unnecessary f-string prefix.Line 1134 uses an f-string without placeholders, which is flagged by static analysis.
Apply this diff:
- return {"status": "success", "message": f"Inspiration deleted successfully"} + return {"status": "success", "message": "Inspiration deleted successfully"}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
core/admin.py(2 hunks)core/agent_system_prompts.py(1 hunks)core/agents.py(2 hunks)core/api/schemas.py(1 hunks)core/api/views.py(3 hunks)core/models.py(8 hunks)core/schemas.py(3 hunks)core/urls.py(1 hunks)core/views.py(2 hunks)frontend/src/controllers/inspiration_controller.js(1 hunks)frontend/templates/base_project.html(1 hunks)frontend/templates/project/project_inspirations.html(1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
**/*.html
📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)
**/*.html: Prefer Stimulus JS for adding interactivity to Django templates instead of raw script elements
Leverage Stimulus data attributes to connect HTML elements with JavaScript functionality
Utilize Stimulus targets to reference specific elements within a controller
Employ Stimulus actions to handle user interactions and events
Files:
frontend/templates/base_project.htmlfrontend/templates/project/project_inspirations.html
**/*.{html,htm}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
frontend/templates/base_project.htmlfrontend/templates/project/project_inspirations.html
{**/*.{html,htm,css,scss},**/*_controller.@(js|ts)}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always favor the utility-first Tailwind approach; avoid creating reusable style classes and prefer reuse via template components
Files:
frontend/templates/base_project.htmlfrontend/src/controllers/inspiration_controller.jsfrontend/templates/project/project_inspirations.html
frontend/templates/**/*.html
📄 CodeRabbit inference engine (.cursor/rules/stimulus-events.mdc)
Avoid data-*-outlet links for sibling controller communication when using the event-based approach; keep controllers self-contained
Use semantic HTML elements (e.g., dialog, details/summary) in templates
Files:
frontend/templates/base_project.htmlfrontend/templates/project/project_inspirations.html
**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
**/*.py: Prioritize readability and maintainability; follow PEP 8
Use descriptive variable/function names with underscoresIn Python, use try-except blocks that catch specific exception types; do not catch broad Exception.
**/*.py: Follow PEP 8 for Python code style
Use descriptive variable names with underscores (snake_case) in Python
Prefer Django's built-in features over external libraries
**/*.py: Use structlog for logging in Python code (avoid print and the standard logging module)
Include contextual key-value fields in log messages (e.g., error=str(e), exc_info=True, profile_id=profile.id)
**/*.py: Use descriptive, full-word variable names; avoid abbreviations and single-letter variables in Python
Provide context in variable names when format or type matters (e.g., include_iso_format,date)
Extract unchanging values into UPPER_CASE constants
Use intermediary variables to name parsed groups instead of using index access directly
Naming conventions: use is_/has_/can_ for booleans; include 'date' for dates; snake_case for variables/functions; PascalCase for classes
Define variables close to where they are used to keep lifespan short
Name things after what they do, not how they're used; ensure names make sense without extra context
Avoid generic names like data, info, manager; use specific, intention-revealing names
Function names should include necessary context without being verbose
If naming is hard, split functions into smaller focused parts
Maintain consistency: reuse the same verbs and nouns for the same concepts; name variables after the functions that create them
Use more descriptive names for longer-lived variables
Avoid else statements by using guard clauses for early returns
Replace simple conditionals with direct assignment when both branches call the same function with different values
Use dictionaries as dispatch tables instead of multiple equal-probability elif chains
Validate input before processing to prevent errors propagating in...
Files:
core/agent_system_prompts.pycore/api/schemas.pycore/urls.pycore/admin.pycore/api/views.pycore/views.pycore/agents.pycore/schemas.pycore/models.py
core/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
Leverage Django's ORM; avoid raw SQL when possible
Files:
core/agent_system_prompts.pycore/api/schemas.pycore/urls.pycore/admin.pycore/api/views.pycore/views.pycore/agents.pycore/schemas.pycore/models.py
core/api/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
core/api/**/*.py: django-ninja generate openapi documentation, so make sure to populate views with relevant data in order for it to show up in the OpenAPI docs.
Use Pydantic models for schema validation
Use django-ninja's authentication classesImplement REST APIs with django-ninja using Pydantic schemas under core/api/
Files:
core/api/schemas.pycore/api/views.py
frontend/src/controllers/**/*.js
📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)
frontend/src/controllers/**/*.js: Use Stimulus controllers to encapsulate JavaScript behavior and keep it separate from HTML structure
New controllers should be created in thefrontend/src/controllersdirectoryUse Stimulus.js controllers for interactive frontend behavior
Files:
frontend/src/controllers/inspiration_controller.js
**/*.js
📄 CodeRabbit inference engine (.cursor/rules/stimulus-general.mdc)
**/*.js: Add semicolons at the end of statements in JavaScript files
Use double quotes instead of single quotes for string literals in JavaScript files
Files:
frontend/src/controllers/inspiration_controller.js
{**/*.{css,scss},**/*_controller.@(js|ts)}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Never create new styles without explicitly receiving permission to do so
Files:
frontend/src/controllers/inspiration_controller.js
frontend/src/controllers/**/*_controller.js
📄 CodeRabbit inference engine (.cursor/rules/stimulus-events.mdc)
frontend/src/controllers/**/*_controller.js: Dispatch a CustomEvent from the actor Stimulus controller to signal actions to other controllers
Name custom events descriptively and namespaced (e.g., "suggestion:move")
Set bubbles: true on CustomEvent so ancestor listeners (window/document) can receive it
Include all necessary payload in event.detail (e.g., element and destination)
Dispatch the event from the controller element (this.element.dispatchEvent(event))
In listener controllers, register global event listeners in connect() and remove them in disconnect()
Bind handler methods and keep a reference (e.g., this.boundMove = this.move.bind(this)) to correctly remove listeners
Attach listeners to window or document to catch bubbled custom events from anywhere on the page
Inspect event.detail in the handler and act conditionally based on its contents (e.g., match destination)
Files:
frontend/src/controllers/inspiration_controller.js
core/views.py
📄 CodeRabbit inference engine (CLAUDE.md)
Keep Django views skinny: handle request/response only
Files:
core/views.py
core/models.py
📄 CodeRabbit inference engine (CLAUDE.md)
core/models.py: Place business logic in Django models (fat models pattern)
Validate simple constraints in the database and place complex domain logic in Django models
Files:
core/models.py
🧠 Learnings (1)
📚 Learning: 2025-10-04T08:52:37.437Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T08:52:37.437Z
Learning: Applies to frontend/src/controllers/**/*.js : Use Stimulus.js controllers for interactive frontend behavior
Applied to files:
frontend/src/controllers/inspiration_controller.js
🧬 Code graph analysis (8)
core/agent_system_prompts.py (2)
core/models.py (1)
add_inspirations(635-664)core/schemas.py (1)
BlogPostGenerationContext(191-201)
core/api/schemas.py (1)
frontend/src/controllers/inspiration_controller.js (1)
url(19-19)
core/urls.py (1)
core/views.py (1)
ProjectInspirationsView(866-882)
core/admin.py (1)
core/models.py (1)
Inspiration(2037-2105)
core/api/views.py (3)
core/api/schemas.py (4)
AddInspirationIn(267-269)AddInspirationOut(272-277)DeleteInspirationIn(280-281)DeleteInspirationOut(284-286)core/models.py (5)
Inspiration(2037-2105)get_page_content(456-484)get_page_content(1408-1432)get_page_content(1515-1539)get_page_content(2079-2105)frontend/src/controllers/inspiration_controller.js (5)
response(41-51)response(87-96)data(53-53)data(98-98)url(19-19)
core/views.py (1)
core/models.py (2)
Inspiration(2037-2105)Project(361-871)
core/agents.py (2)
core/agent_system_prompts.py (1)
add_inspirations(156-188)core/models.py (1)
add_inspirations(635-664)
core/models.py (4)
core/agent_system_prompts.py (1)
add_inspirations(156-188)core/schemas.py (4)
TitleSuggestionContext(138-157)InspirationContext(130-135)BlogPostGenerationContext(191-201)ProjectPageContext(180-188)core/base_models.py (2)
BaseModel(6-12)Meta(11-12)core/model_utils.py (1)
get_markdown_content(102-134)
🪛 Flake8 (7.3.0)
core/api/views.py
[error] 1134-1134: f-string is missing placeholders
(F541)
🪛 Ruff (0.14.2)
core/api/views.py
1095-1101: Consider moving this statement to an else block
(TRY300)
1111-1111: Use explicit conversion flag
Replace with conversion flag
(RUF010)
1134-1134: Consider moving this statement to an else block
(TRY300)
1134-1134: f-string without any placeholders
Remove extraneous f prefix
(F541)
1144-1144: Use explicit conversion flag
Replace with conversion flag
(RUF010)
core/models.py
2073-2073: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
🔇 Additional comments (18)
core/urls.py (1)
32-36: LGTM! URL pattern follows existing conventions.The new inspirations URL pattern is consistent with other project-related patterns in this file and uses the same
<int:pk>parameter naming convention.frontend/templates/base_project.html (1)
118-128: LGTM! Navigation item follows established patterns.The new Inspirations navigation item is well-integrated with proper active state styling, appropriate icon (lightbulb), and consistent structure matching other sidebar items.
core/agents.py (1)
7-7: LGTM! System prompt integration is clean and consistent.The
add_inspirationsfunction is imported and applied to thecontent_editor_agentfollowing the same pattern as other system prompt enhancements.Also applies to: 55-55
core/schemas.py (2)
130-136: LGTM! Schema definition follows Pydantic best practices.The
InspirationContextschema is well-defined with clear field descriptions.
155-157: LGTM! Context integration is clean.The
inspirationsfield is properly added to bothTitleSuggestionContextandBlogPostGenerationContextwith appropriate defaults usingdefault_factory=listand clear descriptions.Also applies to: 199-201
core/api/schemas.py (2)
272-277: LGTM! Response schema is well-structured.The
AddInspirationOutschema provides comprehensive response data including the created inspiration details and optional error messaging.
280-286: LGTM! Delete schemas follow API conventions.Both
DeleteInspirationInandDeleteInspirationOutfollow the same pattern as other delete operations in this file.frontend/templates/project/project_inspirations.html (4)
10-11: LGTM! Stimulus controller setup is correct.The controller is properly initialized with the project ID value passed through a data attribute.
42-48: Input field has good accessibility.The URL input has a proper label with
forattribute, placeholder text, and appropriate ARIA attributes through HTML5 input type.
138-157: Empty state is well-designed and user-friendly.The empty state provides clear guidance with an icon, descriptive text, and a call-to-action button. This follows good UX practices.
34-75: CSRF token handling is properly implemented.The controller includes the X-CSRFToken header in both POST requests and implements a robust getCsrfToken() method with dual fallback mechanisms—first checking for the CSRF token in a form element, then in cookies. No action needed.
core/views.py (1)
866-883: LGTM! Clean implementation of the inspirations view.The view correctly filters projects by the user's profile for security, orders inspirations appropriately, and follows Django's class-based view patterns.
core/api/views.py (1)
1066-1112: LGTM! The add_inspiration endpoint is well-implemented.The endpoint includes proper validation, duplicate checking, security via profile-based project lookup, error handling, and structured logging.
frontend/src/controllers/inspiration_controller.js (1)
1-135: LGTM! Well-structured Stimulus controller.The controller follows Stimulus.js patterns correctly, handles CSRF tokens properly, provides appropriate user feedback, and adheres to the JavaScript coding guidelines (semicolons, double quotes). The implementation cleanly integrates with the backend API endpoints.
core/models.py (4)
2037-2105: LGTM! Well-designed Inspiration model.The model follows Django best practices with:
- Proper field definitions and constraints
- Unique constraint on (project, url) to prevent duplicates
- Appropriate Meta configuration
- Clear
__str__representationget_page_content()method that reuses existing infrastructure viaget_markdown_content()The implementation is consistent with other models in the codebase (e.g., Project, Competitor).
634-675: LGTM! Clean integration of inspirations into title generation.The system prompt and context building correctly incorporate inspirations to influence title generation. The implementation:
- Builds InspirationContext from project.inspirations.all()
- Passes it through the generation deps
- System prompt provides clear guidance to the AI model
Also applies to: 686-686
921-938: LGTM! Proper integration of inspirations into blog post generation.The implementation consistently adds inspirations to the blog post generation flow using the same pattern as title generation. The
add_inspirationssystem prompt is imported and registered with the agent.Also applies to: 961-970, 978-978
1147-1180: LGTM! Consistent integration of inspirations into fix context.The
_build_fix_contextmethod correctly includes inspirations, ensuring that when fixing generated blog posts, the AI has access to the same inspiration sources that were used during initial generation.
| def add_inspirations(ctx: RunContext[BlogPostGenerationContext]) -> str: | ||
| if not ctx.deps.inspirations: | ||
| return "" | ||
|
|
||
| inspiration_sections = [] | ||
| inspiration_sections.append( | ||
| """ | ||
| INSPIRATION SOURCES: | ||
| The user has shared the following blog posts and blogs as inspiration sources | ||
| they would like to emulate in style, tone, and structure. | ||
| Use these as reference points when generating content: | ||
| """ | ||
| ) | ||
|
|
||
| for inspiration in ctx.deps.inspirations: | ||
| inspiration_sections.append( | ||
| f""" | ||
| - Title: {inspiration.title} | ||
| URL: {inspiration.url} | ||
| Description: {inspiration.description or 'No description provided'} | ||
| """ | ||
| ) | ||
|
|
||
| inspiration_sections.append( | ||
| """ | ||
| IMPORTANT: Draw inspiration from these sources' writing style, tone, structure, | ||
| and approach while creating content that is unique and appropriate for the current project. | ||
| Consider how these inspirations structure their content, engage their audience, | ||
| and present information. | ||
| """ | ||
| ) | ||
|
|
||
| return "\n".join(inspiration_sections) |
There was a problem hiding this comment.
Code duplication: Similar function exists in core/models.py.
This add_inspirations function is nearly identical to the one in core/models.py (lines 634-663), with only minor differences in the prompt text. Both functions:
- Accept a RunContext with inspirations
- Return empty string if no inspirations
- Build the same markdown structure
- Use the same format string for each inspiration
Consider extracting a shared utility function to avoid duplication:
def format_inspirations_prompt(inspirations: list[InspirationContext], context_type: str = "content") -> str:
"""Format inspirations into a prompt section.
Args:
inspirations: List of inspiration contexts
context_type: Either "content" or "titles" to customize the prompt
"""
if not inspirations:
return ""
sections = [
"""
INSPIRATION SOURCES:
The user has shared the following blog posts and blogs as inspiration sources
they would like to emulate in style, tone, and structure.
Use these as reference points when generating """ + context_type + """:
"""
]
for inspiration in inspirations:
sections.append(
f"""
- Title: {inspiration.title}
URL: {inspiration.url}
Description: {inspiration.description or 'No description provided'}
"""
)
sections.append(
"""
IMPORTANT: Draw inspiration from these sources' writing style, tone, structure,
and approach while creating """ + context_type + """ that are unique and appropriate for the current project.
"""
)
return "\n".join(sections)
def add_inspirations(ctx: RunContext[BlogPostGenerationContext]) -> str:
return format_inspirations_prompt(ctx.deps.inspirations, "content")Then update the similar function in core/models.py to use the same utility.
🤖 Prompt for AI Agents
In core/agent_system_prompts.py around lines 156-188, the add_inspirations
function duplicates logic present in core/models.py (lines ~634-663); extract a
single shared helper (e.g., format_inspirations_prompt) that accepts the
inspirations list and a context_type ("content" vs "titles") and returns the
formatted string, replace the local add_inspirations to call that helper, and
update the similar function in core/models.py to call the same helper so both
modules reuse the shared implementation.
This pull request contains changes generated by a Cursor Cloud Agent
Summary by CodeRabbit