- Add gitignore and prettier configuration files for project scaffolding - Implement room access control service with project member verification - Create user access key management with CRUD operations and activity logging - Add accordion UI component for frontend expandable sections - Implement room AI configuration with list, upsert, and delete operations - Add AI event types for agent join/leave/status change tracking - Create streaming AI processing services for mode and react patterns - Build room AI service with model detection and idempotency handling - Integrate chat service orchestration for AI message processing - Add typing indicators and stream cancellation for AI interactions - Implement mention parsing and context extraction for AI agents
84 lines
2.4 KiB
Rust
84 lines
2.4 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct RichTextBlock {
|
|
pub block_type: BlockType,
|
|
pub content: String,
|
|
pub attributes: Option<serde_json::Value>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum BlockType {
|
|
Text,
|
|
Code,
|
|
Quote,
|
|
Link,
|
|
Mention,
|
|
Emoji,
|
|
Image,
|
|
}
|
|
|
|
pub struct RichTextRenderer {
|
|
}
|
|
|
|
impl RichTextRenderer {
|
|
pub fn new() -> Self {
|
|
Self {}
|
|
}
|
|
|
|
pub fn parse_markdown(&self, content: &str) -> Vec<RichTextBlock> {
|
|
let mut blocks = Vec::new();
|
|
|
|
blocks.push(RichTextBlock {
|
|
block_type: BlockType::Text,
|
|
content: content.to_string(),
|
|
attributes: None,
|
|
});
|
|
|
|
blocks
|
|
}
|
|
|
|
pub fn parse_mentions(&self, content: &str) -> Vec<Uuid> {
|
|
let mut mentions = Vec::new();
|
|
|
|
for word in content.split_whitespace() {
|
|
if word.starts_with('@') {
|
|
if let Ok(uuid) = Uuid::parse_str(&word[1..]) {
|
|
mentions.push(uuid);
|
|
}
|
|
}
|
|
}
|
|
|
|
mentions
|
|
}
|
|
|
|
pub fn highlight_code(&self, code: &str, language: &str) -> String {
|
|
format!("```{}\n{}\n```", language, code)
|
|
}
|
|
|
|
pub fn render_to_html(&self, blocks: &[RichTextBlock]) -> String {
|
|
blocks.iter()
|
|
.map(|block| match block.block_type {
|
|
BlockType::Text => format!("<p>{}</p>", html_escape(&block.content)),
|
|
BlockType::Code => format!("<pre><code>{}</code></pre>", html_escape(&block.content)),
|
|
BlockType::Quote => format!("<blockquote>{}</blockquote>", html_escape(&block.content)),
|
|
BlockType::Link => format!("<a href=\"{}\">{}</a>", html_escape(&block.content), html_escape(&block.content)),
|
|
BlockType::Mention => format!("<span class=\"mention\">@{}</span>", html_escape(&block.content)),
|
|
BlockType::Emoji => format!("<span class=\"emoji\">{}</span>", html_escape(&block.content)),
|
|
BlockType::Image => format!("<img src=\"{}\" />", html_escape(&block.content)),
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.join("\n")
|
|
}
|
|
}
|
|
|
|
fn html_escape(s: &str) -> String {
|
|
s.replace('&', "&")
|
|
.replace('<', "<")
|
|
.replace('>', ">")
|
|
.replace('"', """)
|
|
.replace('\'', "'")
|
|
}
|