chat.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package kimi
  2. import (
  3. "context"
  4. "errors"
  5. "git.ttmylife.com/zeuszhao/llm"
  6. "github.com/go-rod/rod"
  7. "github.com/go-rod/rod/lib/proto"
  8. "sync"
  9. "time"
  10. )
  11. type Chat struct {
  12. ai llm.AI
  13. Page *rod.Page
  14. qaSingle chan bool
  15. userContext *llm.UserContext
  16. sync.Mutex
  17. }
  18. func (c *Chat) Ask(ctx context.Context, text string) (string, error) {
  19. c.TryLock()
  20. defer c.Unlock()
  21. ok, err := c.ai.IsLogin(ctx, c.Page)
  22. if err != nil {
  23. return "", err
  24. }
  25. if !ok {
  26. userContext, err := c.ai.Login(ctx, c.Page)
  27. if err != nil {
  28. return "", err
  29. }
  30. c.userContext = userContext
  31. }
  32. inputEle, err := c.Page.Element("#msh-chateditor")
  33. if err != nil {
  34. return "", err
  35. }
  36. err = inputEle.Input(text)
  37. if err != nil {
  38. return "", err
  39. }
  40. sendBtnEle, err := c.Page.Element("#send-button")
  41. if err != nil {
  42. return "", errors.Join(err, errors.New("send btn not fount"))
  43. }
  44. // 等待按钮可用
  45. err = sendBtnEle.WaitWritable()
  46. if err != nil {
  47. return "", errors.Join(err, errors.New("send btn not writable"))
  48. }
  49. err = sendBtnEle.WaitStable(1 * time.Second)
  50. if err != nil {
  51. return "", errors.Join(err, errors.New("send btn not stable"))
  52. }
  53. err = sendBtnEle.Click(proto.InputMouseButtonLeft, 1)
  54. if err != nil {
  55. return "", err
  56. }
  57. select {
  58. case <-c.qaSingle:
  59. case <-ctx.Done():
  60. return "", ctx.Err()
  61. case <-time.After(60 * time.Second):
  62. return "", errors.New("超时")
  63. }
  64. qaEleOk, err := c.Page.Element("button[data-testid='msh-chat-segment-reAnswer']")
  65. if err != nil {
  66. return "", err
  67. }
  68. err = qaEleOk.WaitVisible()
  69. if err != nil {
  70. return "", err
  71. }
  72. qaEle, err := c.Page.Elements(".pop-content")
  73. if err != nil {
  74. return "", err
  75. }
  76. return qaEle.Last().Text()
  77. }
  78. func (c *Chat) Close(ctx context.Context) error {
  79. return c.Page.Close()
  80. }