-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request: Wechaty Could Support Quote Message #2387
Comments
Thank you very much for the proposal of this great feature, and I agree with you that it is a feature that can be generalized, and should be supported by Wechaty API.
So basically I think your design is OK and please feel free to create a pull request to implement it, and thank you again for helping the Wechaty to improve the API by adding features to it! |
Agree with it. |
Puppet, wechaty, puppet-service & wechaty-grpc, I think this is the order of projects that requires updates for this feature. OK I think I have some answers for myself. Please check the draft later. Update: The draft is ready to be viewed. The test will fail since it relies on the pupet PR. @huan Please review the puppet PR first, then the wechaty PR, and tell me your thoughts. Cheers. Draft: #2390 CC: @su-chang @windmemory |
Thank you very much for creating the pull requests with the draft implementation to the After reviewing & thinking about them carefully, I believe it has been turned out that this feature should be implemented by the new
|
async * [Symbol.asyncIterator] (): AsyncIterableIterator<Sayable> { | |
log.verbose('Post', '[Symbol.asyncIterator]()') | |
if (PUPPET.payloads.isPostServer(this.payload)) { | |
for (const messageId of this.payload.sayableList) { | |
const message = await this.wechaty.Message.find({ id: messageId }) | |
if (message) { | |
const sayable = await message.toSayable() | |
if (sayable) { | |
yield sayable | |
} | |
} | |
} |
2. Post.reply()
wechaty.on('message', msg => {
const post = await wechaty.Post.builder()
.add('this is the reply to a quoted messsage')
.build()
post.reply(msg) // I'm thinking about to rename the `post.reply()` to `post.replyTo()` so that it will be less confusing.
await wechaty.publish(post)
})
Related discussion:
To-be improved
I found there lacks some support from the current code base of the Post
as well as other improvements, below are what I have already figured out, and there might be more:
- The current design of the
Post
WUM do not contain anytalkerId
,listenerId
,roomId
information, I think there has a potential solution by adding atoMessage()
so that we can convert a Post toMessage
so that we can get all the information for that message. - The current Post design does not support call
reply()
with aMessage
instance. This will be easily fixed by allowing passing a Message to it because it just needs themessageId
. - Consider to rename the
post.reply()
topost.replyTo()
- Improve the return data type support for the async iterator of the
Post
Conclusion
By using the new Post WUM implementation with the quoted message feature request, we will use the Message
for simple data structure, and use the Post
with the complex tree data structure.
And the Post API will significantly reduce the Puppet API code complexity, which will be a huge gain compared with the current PR implementation (The current version of PR contains lots of modifications with our current API and add the same options here and there)
Please let me know what you think @hcfw007 , thank you very much.
Sorry for replying late. I have given this topic some thoughts.
So I believe so far we should continue using this message design and maybe some other day we can move to post. |
@huan please check this out so that we can continue working on this subject. |
@huan ping |
Here are my answers:
Start supporting
That's not true. So besides the
I don't think a tree should be bi-directional. According to Wikipedia: In graph theory, a tree is an undirected graph.
The |
@huan Thank you for your explanation, however I still have some questions, could you please explain further more.
wechaty.on('message', msg => {
if (message.type() === puppet.types.Message.MiniProgram) {
const miniProgram = message.toMiniProgram()
}
}) The
wechaty.on('message', msg => {
const post = await wechaty.Post.builder()
.add('this is the reply to a quoted messsage')
.build()
post.setReply(msg) // my preference for naming this method: setReply > replyTo > reply. Because this is only setting the property, not executing the reply process
await message.say(post.toMessage())
}) |
Here are answers to your new questions:
Those two concepts are the same things: "miniProgram of the message" and "miniProgram from the message" You can just focus on the miniProgram instance and work with it, that is what it is designed for.
Those two concepts are the same things: "getting" and "converting to" in this context.
In Wechaty, you can never convert anything to a message. Except that you can
We have implemented it here: wechaty/src/user-modules/message.ts Lines 1065 to 1079 in 4ed646d
Please read the code first: Lines 38 to 48 in 4ed646d
I hope my answers helps. Please feel free to let me know if you have more questions. |
Yeah, we have already supported
From your above description, my understanding is that there has a text message "123", then another message reply it with an image, correct? If so, in this case, the code will be like the following: // Reply to each text message with an image
wechaty.on('message', message => {
if (message.type() !== MessageType.Text) {
return
}
const post = await wechaty.Post.builder()
.add(FileBox.fromUrl('https://user-images.githubusercontent.com/13669999/163317404-d86ca9a3-64dd-45c8-a9a5-47d76a368ceb.png'))
.build()
post.reply(message) // I'm thinking about to rename the `post.reply()` to `post.replyTo()` so that it will be less confusing.
await message.say(post)
}) That's it! Please let me know if this design works for you or not. |
I was asking how do we get the image from the quoting message; wechaty.on('message', message => {
// message is the quoting message, aka the image message
if (message.type() !== MessageType.Post) {
return
}
const post = message.toPost()
for await (const ele of post) {
const image = ele
// ...
}
}) |
Thanks for clarifying your question! The code makes it clear and it's a great question! How to get Images from Postwechaty.on('message', message => {
if (message.type() !== MessageType.Post) {
return
}
const post = message.toPost()
for await (const sayable of post) {
if (!FileBox.valid(sayable)) {
continue
}
const filebox = sayable
// ...
}
}) From the above code, you can see that we can check whether a After we get the FileBox out of the post, we can continue checking its type to filter the Image out. BTW: you can see the Lines 38 to 48 in 4ed646d
And remember to pay attention that: the "Wechaty Sayable" is different from the "Puppet Sayable": the "Puppet Sayable" is a "Redux Action" created by an action creator (typesafe-actions in our code base). I hope the above code and explanations can answer your question. Please feel free to let me know if you have more questions. |
I think I understand most of your design now. This might be the last question bothering me: What's the border between a post and a regular message? |
TL;DR: the Post is a container for containing multiple Messages (sayables), while a message can only contains one. You can learn more from the below issue, by searching "container": I hope those information can make the border clearer. Please feel free to let me know if you have any future questions! |
Got it. I'll rework my quote message design. |
Glad to know that we have answered all your questions!
If you dig into the code, you will realized that the message is the component of the post. So I think the best practice would be:
|
I am aware that. However if the only difference is the number of sayables, why don't we just use post? |
A proposal would be welcome, we can think about it in v2. If you do the proposal, please be aware about the breaking changes and the convenience. |
I just read through the post code in wechaty and wechaty-puppet. It seems there's nothing much need to change beside adding a message type in puppet.types.Post for quoted message and multiple message. Post.reply() and say(Post) has already been implemented. |
As we added this Message type Post, the puppet can handle it properly. There seems no more work required in wechaty / puppet / puppet-service or grpc. The next step is for puppet implementation to handle |
@huan I just noticed that only Post messages can call const messagePost = message.toPost()
const post = bot.Post.builder()
post.add('quoted')
post.reply(messagePost)
post.type(PostType.Message)
message.say(await post.build()) |
It seems that we should add /**
* Huan(202201): numbers must be keep unchanged across versions
*/
enum PostType {
Unspecified = 0,
Moment = 1, // <- WeChat Moments (朋友圈)
Channel = 2, // <- WeChat Channel (视频号)
Message = 3, // Quoted Message or Muitiplepart Message
} |
@huan ping |
We have added this feature in our version of wechaty (@juzi/wechaty). We will start working on merging our version into main comunity version soon. |
It's been a while since last time we talked about this. interface SayOptionsObject {
mentionList?: (ContactInterface | '@all')[],
quoteMessage?: MessageInterface,
}
export const isSayOptionsObject = (target: any) => {
return (typeof target === 'object'
&& ((target.mentionList && target.mentionList.every((c: any) => ContactImpl.valid(c)))
|| (target.quoteMessage && MessageImpl.valid(target.quoteMessage))
)
)
}
type SayOptions = (ContactInterface | '@all') | (ContactInterface | '@all')[] | SayOptionsObject
export type {
SayableSayer,
Sayable,
SayOptions,
SayOptionsObject,
} The reason I insist using regular text message here isntead of post are:
To sum up, I think the key difference, and the reason regualr message is not |
I think @huan has agreed with it, see: #2387 (comment)
In my opinion, using
wechaty.on('message', async msg => {
await msg.say('This is reply msg', { quoteMessage: msg })
})
wechaty.on('message', async msg => {
const messagePost = msg.toPost()
const post = bot.Post.builder()
post.add('This is reply msg')
post.reply(messagePost)
post.type(PostType.Message)
message.say(await post.build())
}) |
How about wechaty.on('message', async msg => {
await msg.reply('This is reply msg')
}) |
After discussion in Wechaty Community Meeting (brief here)
|
Hey @hcfw007 , would like to ask is this quote feature landed in any version of wechaty, if so, is there any example usage that I can reference to see how I can get the quoted original message? |
Hi, @hcfw007, I'm helping the wechaty team manage their backlog and am marking this issue as stale. From what I understand, you raised an issue requesting support for quote messages in Wechaty, with discussions and proposals on the implementation methods, including the use of the Could you please confirm if this issue is still relevant to the latest version of the wechaty repository? If it is, please let the wechaty team know by commenting on the issue. Otherwise, feel free to close the issue yourself, or the issue will be automatically closed in 7 days. Thank you! |
it seems the latest of padlocal still CAN NOT get the original id of the quoted message.
|
@dosubot you should not close an issue which has an assignee. |
The quote feature has indeed been implemented using the To address this, please ensure that you are using the latest versions of the If you're already on the latest versions and still facing issues with accessing the original ID of the quoted message, I recommend raising a specific issue in the repository. When reporting this, include detailed information about the behavior you're encountering, such as any error messages or unexpected outputs. This detailed report will aid the maintainers in investigating and resolving the issue more efficiently.
|
I finally got the correct answer: |
I cannot make it work. |
A lot IMs has quote messages or something like that, e.g. QQ, wechat, wecom, whatsapp and meta messenger, even github! So it would be great for Wechaty to support that.
My early thoughts about this is to add a quote field in message payload which contains the id of the quoted message. The quoted message could be an image or video so save id as reference is good.
For sending a quote message, I'm not sure how to implement it. I'm considering two options:
say()
, likecontact.say(content: Sayable, options?: messageOptions)
message.quote(contactOrRoom: Contact | Room, quotedMessage: Message)
Please tell me if you like this feature, and how you want to implement it. Cheers!
The text was updated successfully, but these errors were encountered: