diff --git a/go.mod b/go.mod
index dc3b7f9..ef64a46 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ toolchain go1.23.6
require (
code.gitea.io/sdk/gitea v0.20.0
github.com/a-h/templ v0.3.833
- github.com/bornholm/genai v0.0.0-20250222092500-1076426da67c
+ github.com/bornholm/genai v0.0.0-20250227201654-4c93b20ee628
github.com/caarlos0/env/v11 v11.2.2
github.com/gabriel-vasile/mimetype v1.4.7
github.com/google/go-github/v69 v69.2.0
diff --git a/go.sum b/go.sum
index 74724fe..70f124a 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU=
github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk=
github.com/bornholm/genai v0.0.0-20250222092500-1076426da67c h1:bI0ebsgO1/7Jx6+ZQdDF/I6tTZxyB5hODYz7x/XxwK8=
github.com/bornholm/genai v0.0.0-20250222092500-1076426da67c/go.mod h1:MnuvwSsBEWv/joeK/WgUyfZfOLcLTpd81NJdWoRpRfI=
+github.com/bornholm/genai v0.0.0-20250227201654-4c93b20ee628 h1:YsrF9+NUdwYPLfpJUUfD0h/yH0jvpnaMxtM/sPsFsPg=
+github.com/bornholm/genai v0.0.0-20250227201654-4c93b20ee628/go.mod h1:kgZb50LiE3cLjyGdUzNwDtpxL5QRllZIsWT2Ub24fIM=
github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg=
github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
diff --git a/internal/core/service/issue_manager.go b/internal/core/service/issue_manager.go
index 7b8199b..a9380e3 100644
--- a/internal/core/service/issue_manager.go
+++ b/internal/core/service/issue_manager.go
@@ -85,8 +85,13 @@ func (m *IssueManager) GetUserProjects(ctx context.Context, user *model.User) ([
return projects, nil
}
-func (m *IssueManager) GenerateIssue(ctx context.Context, user *model.User, projectID string, issueSummary string) (string, string, string, error) {
- systemPrompt, err := m.getIssueSystemPrompt(ctx, user, projectID)
+type GeneratIssueOptions struct {
+ IssueSummary string
+ IssueTemplate string
+}
+
+func (m *IssueManager) GenerateIssue(ctx context.Context, user *model.User, projectID string, issueSummary string, overwrittenIssueTemplate string) (string, string, string, error) {
+ systemPrompt, err := m.getIssueSystemPrompt(ctx, user, projectID, overwrittenIssueTemplate)
if err != nil {
return "", "", "", errors.WithStack(err)
}
@@ -135,15 +140,19 @@ func (m *IssueManager) GenerateIssue(ctx context.Context, user *model.User, proj
return title, body, tips, nil
}
-func (m *IssueManager) getIssueSystemPrompt(ctx context.Context, user *model.User, projectID string) (string, error) {
- forge, err := m.getUserForge(ctx, user)
- if err != nil {
- return "", errors.WithStack(err)
- }
+func (m *IssueManager) getIssueSystemPrompt(ctx context.Context, user *model.User, projectID string, issueTemplate string) (string, error) {
+ if issueTemplate == "" {
+ forge, err := m.getUserForge(ctx, user)
+ if err != nil {
+ return "", errors.WithStack(err)
+ }
- issueTemplate, err := forge.GetIssueTemplate(ctx, projectID)
- if err != nil && !errors.Is(err, port.ErrFileNotFound) {
- return "", errors.WithStack(err)
+ repoIssueTemplate, err := forge.GetIssueTemplate(ctx, projectID)
+ if err != nil && !errors.Is(err, port.ErrFileNotFound) {
+ return "", errors.WithStack(err)
+ }
+
+ issueTemplate = repoIssueTemplate
}
if issueTemplate == "" {
diff --git a/internal/http/handler/webui/issue/component/issue_page.templ b/internal/http/handler/webui/issue/component/issue_page.templ
index 6a63f60..54c2df1 100644
--- a/internal/http/handler/webui/issue/component/issue_page.templ
+++ b/internal/http/handler/webui/issue/component/issue_page.templ
@@ -31,6 +31,10 @@ const bodyPlaceholder = `
Une fois votre demande générée, vous pourrez l'éditer puis la créer directement en cliquant sur le bouton 'Créer' ci-dessous.
`
+const issueTemplatePlaceholder = `
+Vous pouvez surcharger le modèle de demande fourni par le projet en remplissant ce champ.
+`
+
func NewIssueSummaryForm() *form.Form {
return form.New(
form.NewField(
@@ -47,6 +51,14 @@ func NewIssueSummaryForm() *form.Form {
},
form.NonEmpty("Ce champ ne doit pas être vide."),
),
+ form.NewField(
+ "template",
+ form.Attrs{
+ "type": "textarea",
+ "rows": "20",
+ "placeholder": strings.TrimSpace(issueTemplatePlaceholder),
+ },
+ ),
)
}
@@ -127,6 +139,15 @@ templ IssuePage(vmodel IssuePageVModel) {
"hx-on:change", "onSummaryChange(event)",
),
)
+
+ Paramètres avancés
+ @common.FormTextarea(
+ vmodel.SummaryForm, "issue-template", "template", "Surcharger le modèle de demande",
+ common.WithTextareaAttrs(
+ "hx-on:change", "onIssueTemplateChange(event)",
+ ),
+ )
+
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, " ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if vmodel.IssueTips != "" {
html := markdownToHTML(ctx, vmodel.IssueTips)
if html != "" {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "Utilisez ces quelques questions pour réfléchir aux éléments d'informations nécessaire à la bonne rédaction de votre demande:
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
Utilisez ces quelques questions pour réfléchir aux éléments d'informations nécessaire à la bonne rédaction de votre demande:
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -236,13 +261,13 @@ func IssuePage(vmodel IssuePageVModel) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/internal/http/handler/webui/issue/issue_page.go b/internal/http/handler/webui/issue/issue_page.go
index 263e1c3..f60792c 100644
--- a/internal/http/handler/webui/issue/issue_page.go
+++ b/internal/http/handler/webui/issue/issue_page.go
@@ -3,6 +3,7 @@ package issue
import (
"context"
"net/http"
+ "strings"
"forge.cadoles.com/wpetit/clearcase/internal/core/service"
httpCtx "forge.cadoles.com/wpetit/clearcase/internal/http/context"
@@ -99,13 +100,21 @@ func (h *Handler) handleIssueSummaryForm(w http.ResponseWriter, r *http.Request)
return
}
- summary, err := form.FormFieldAttr[string](issueSummaryForm, "summary", "value")
+ issueSummary, err := form.FormFieldAttr[string](issueSummaryForm, "summary", "value")
if err != nil {
h.handleError(w, r, errors.WithStack(err))
return
}
- issueTitle, issueBody, issueTips, err := h.issueManager.GenerateIssue(ctx, httpCtx.User(ctx), projectID, summary)
+ issueTemplate, err := form.FormFieldAttr[string](issueSummaryForm, "template", "value")
+ if err != nil {
+ h.handleError(w, r, errors.WithStack(err))
+ return
+ }
+
+ issueTemplate = strings.TrimSpace(issueTemplate)
+
+ issueTitle, issueBody, issueTips, err := h.issueManager.GenerateIssue(ctx, httpCtx.User(ctx), projectID, issueSummary, issueTemplate)
if err != nil {
h.handleError(w, r, errors.WithStack(err))
return
diff --git a/internal/setup/issue_manager.go b/internal/setup/issue_manager.go
index 0a215b6..febecdd 100644
--- a/internal/setup/issue_manager.go
+++ b/internal/setup/issue_manager.go
@@ -13,13 +13,13 @@ import (
)
func NewIssueManagerFromConfig(ctx context.Context, conf *config.Config) (*service.IssueManager, error) {
- llmCtx := provider.FromMap(ctx, "", map[string]string{
- string(provider.ContextKeyAPIBaseURL): conf.LLM.Provider.BaseURL,
- string(provider.ContextKeyAPIKey): conf.LLM.Provider.Key,
- string(provider.ContextKeyModel): conf.LLM.Provider.Model,
- })
-
- client, err := provider.Create(llmCtx, provider.Name(conf.LLM.Provider.Name))
+ client, err := provider.Create(ctx,
+ provider.WithConfig(&provider.Config{
+ Provider: provider.Name(conf.LLM.Provider.Name),
+ BaseURL: conf.LLM.Provider.BaseURL,
+ Key: conf.LLM.Provider.Key,
+ Model: conf.LLM.Provider.Model,
+ }))
if err != nil {
return nil, errors.Wrapf(err, "could not create llm client '%s'", conf.LLM.Provider.Name)
}