feat: sync AI compose and ChatBot features
This commit is contained in:
parent
35e5d38f4d
commit
b7269b135f
75 changed files with 5426 additions and 123 deletions
112
internal/rpc/aicompose_webpage.go
Normal file
112
internal/rpc/aicompose_webpage.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
const aiComposeToneWebPageType = "telegram_aicomposetone"
|
||||
|
||||
func (r *Router) resolveAIComposeStyleWebPage(ctx context.Context, rawURL string) (domain.MessageWebPage, bool) {
|
||||
link, ok := parseAIComposeStyleLink(rawURL)
|
||||
if !ok || r.deps.AICompose == nil {
|
||||
return domain.MessageWebPage{}, false
|
||||
}
|
||||
userID, ok, err := r.currentUserID(ctx)
|
||||
if err != nil || !ok {
|
||||
return domain.MessageWebPage{}, false
|
||||
}
|
||||
tones, err := r.deps.AICompose.GetTone(ctx, userID, domain.AIComposeToneRef{
|
||||
Kind: domain.AIComposeToneRefSlug,
|
||||
Slug: link.slug,
|
||||
})
|
||||
if err != nil || len(tones.Tones) == 0 {
|
||||
return domain.MessageWebPage{}, false
|
||||
}
|
||||
tone := tones.Tones[0]
|
||||
now := time.Now()
|
||||
if r.clock != nil {
|
||||
now = r.clock.Now()
|
||||
}
|
||||
page := domain.MessageWebPage{
|
||||
State: domain.MessageWebPageStateDone,
|
||||
ID: domain.WebPageURLHash(link.normalized),
|
||||
URL: link.normalized,
|
||||
DisplayURL: link.display,
|
||||
Hash: aiComposeToneWebPageHash(tone),
|
||||
Date: int(now.Unix()),
|
||||
Type: aiComposeToneWebPageType,
|
||||
SiteName: "Telegram",
|
||||
Title: tone.Title,
|
||||
Description: tone.Prompt,
|
||||
ComposeToneEmojiID: tone.EmojiID,
|
||||
}
|
||||
if page.Title == "" {
|
||||
page.Title = tone.Slug
|
||||
}
|
||||
if page.Description == "" {
|
||||
page.Description = "AI compose style"
|
||||
}
|
||||
return page, true
|
||||
}
|
||||
|
||||
type aiComposeStyleLink struct {
|
||||
normalized string
|
||||
display string
|
||||
slug string
|
||||
}
|
||||
|
||||
func parseAIComposeStyleLink(raw string) (aiComposeStyleLink, bool) {
|
||||
normalized, ok := domain.NormalizeWebPageURL(raw)
|
||||
if !ok {
|
||||
return aiComposeStyleLink{}, false
|
||||
}
|
||||
u, err := url.Parse(normalized)
|
||||
if err != nil {
|
||||
return aiComposeStyleLink{}, false
|
||||
}
|
||||
host := strings.ToLower(u.Hostname())
|
||||
if !aiComposeStyleHostAllowed(host) {
|
||||
return aiComposeStyleLink{}, false
|
||||
}
|
||||
parts := strings.Split(strings.Trim(strings.ToLower(u.EscapedPath()), "/"), "/")
|
||||
var slug string
|
||||
switch {
|
||||
case len(parts) == 1 && parts[0] == "addstyle":
|
||||
slug = u.Query().Get("slug")
|
||||
case len(parts) == 2 && parts[0] == "addstyle":
|
||||
if decoded, err := url.PathUnescape(parts[1]); err == nil {
|
||||
slug = decoded
|
||||
}
|
||||
}
|
||||
slug = strings.ToLower(strings.TrimSpace(slug))
|
||||
if slug == "" {
|
||||
return aiComposeStyleLink{}, false
|
||||
}
|
||||
display := host
|
||||
if path := strings.Trim(u.EscapedPath(), "/"); path != "" {
|
||||
display += "/" + path
|
||||
}
|
||||
return aiComposeStyleLink{normalized: normalized, display: display, slug: slug}, true
|
||||
}
|
||||
|
||||
func aiComposeStyleHostAllowed(host string) bool {
|
||||
switch host {
|
||||
case "t.me", "telegram.me", "telesrv.net", "localhost", "127.0.0.1":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func aiComposeToneWebPageHash(tone domain.AIComposeTone) int {
|
||||
h := fnv.New32a()
|
||||
_, _ = fmt.Fprintf(h, "%s|%s|%d|%s|%d", tone.Slug, tone.Title, tone.EmojiID, tone.Prompt, tone.UpdatedAt)
|
||||
return int(h.Sum32() & 0x7fffffff)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue