Cómo Desarrollé MemoMate:与 IA 合作的个人电报
简介
在我的文章中,您可以体验到**MemoMate**,这是一个与个人有关的管理和重要关系的电报。 La idea surgió de una necesidad Personal: tener una forma sencilla de recordar detalles sobre las personas que me importantan - desde cumpleaños hasta conversaciones senseificativas.
什么是 MemoMate?
MemoMate 是 Telegram 机器人,可用于 PRM(个人关系经理)。自然对话的旅行,提供有关接触的信息,并且可以包含所有信息并组织有关未来发展的信息。 Vamos a ver aquí susprinciples conacterísticas。
联系管理
在与机器人对话期间,我会检测到您的联系方式,并在您的情况下进行注册。剑的能力和接触能力存在于数据的基础上,但没有,创造。请参阅有关联系方式或包括消除的所有信息。
联系方式
机器人已做好准备,以便需要记录接触者的情况。我们将提供所有有关迟到咨询的信息。 Vamos a verlo con un ejemplo:
想象一下,你和我的朋友、美洲驼何塞和你的机器人一起注册,并与你联系。 Podrías decirle algo como:
“Ayer estuve con mi amigo José y me comentó que se está planteando dejar su trabajo”
想象一下 3 个月后,你将与我的朋友何塞一起度过。 MemoMate 和 preguntarle 中的 Podrías:
“我和我的朋友何塞·拉乌尔蒂玛维兹有什么关系吗?”
El bot te responderá diciendo:
“José te dijo que se está planteando dejar su trabajo”
唱片公司
机器人和录音机的其他功能也很有趣。 MemoMate 允许注册商记录您的联系方式,并为您提供帮助。例如,以下内容:
“El próximo 15 de diciembre es el cumpleaños de mi amigo José。Recuérdame que le felicite”
该机器人解释了我与何塞的联系和幸福的 15 个月的记录。 Cuando llegue dicha fecha,el bot te enenvará un mensaje como:
“Recuerda felicitar a José por su cumpleaños”
免费与付费
请注意,使用免费形式时,请允许使用限制。 Cada usuario tentrá un número de mensajes que puede envirar bot cada mes。我很高兴您能继续享受我们的优惠,我们将竭诚为您提供优质的信用额度。高级版可以使用多种限制,并且可以无限制使用。
网络平台
Además del bot en Telegram, MemoMate también con una plataforma web que otorga al usuario ciertas function:
建筑与技术
MemoMate 包含 2 个组件(或应用程序)原理:
所用技术
Vamos 是一种技术,他决定实施该产品和产品。
西班牙发展进程
Vamos 是一个明确的阿霍拉科莫塞哈阿博尔达多 el 进程 desarrollo del proyecto, pasando por todos los pasos que se han ido dando para llegar desde una idea inicial hasta unproducto Final。没有任何内容是绝对详细的,因为所有这些都不是完整的,也不是很广泛的文章。通过对不同部分和旁人的不同定义进行解释,并考虑更多有趣的事情。建议您了解项目存储库和实现的更多详细信息。
项目定义
这是一个定义 Claramente el Alcance 和 la arquitectura 的过程。在 ChatGPT 中,我们将进行更多的工作,以完善想法和文档,以实现这一目标。我们的目标是在地毯“文档”中创建不同的火山文档。规划的关键是对未来的愿景和对光标所需信息的正确分配。不同的文档包括:项目的说明、数据基础的定义、建筑等。这允许光标与设计的目的一致,并且可以快速迭代。
结构基础
使用不同组件的单一架构。 Por un lado las 2 aplicaciones que ya mencionamos (el bot y la web) y por otro lado los different paquetes en los que se apoyarán estas aplicaciones. También contamos con una applicación extra que llamamos `infra`。这是一个基于 docker-compose 的应用程序,允许在本地必要的基础设施上使用,并且可以使用 PostgreSQL 数据的基础。
一个关于基础设施服务的解决方案,决定通过 docker-compose 来促进未来可能的服务
En cuanto a los paquetes, tentremos los siguientes:
认证系统
平台和算法的验证系统。如果您想与登录和注册机制保持一致,那么您就可以通过管理方式进行操作。机器人有能力识别用户的交互能力,可以在新的对话中使用新的功能。如果您使用的是网络平台,则需要使用 Bot 所需的设备,而 Bot 则负责一般的链接和临时访问。
为此,我们将提供简单有效的验证系统。流感功能如下:
private async createSessionUrl(userId: string) { const session = await prisma.session.create({ data: { userId: userId, expiresAt: new Date(Date.now() + 1000 * 60 * 10), } }); const link = `${process.env.FRONTEND_URL}/login?token=${session.id}`; return link; }
export async function LoginRoute(request: Request) { const { searchParams } = new URL(request.url); const token = searchParams.get("token"); let errorType = null; try { if (!token) { throw new CustomError({ message: "Token no proporcionado", type: "INVALID_TOKEN", statusCode: 400, }); } const session = await prisma.session.findFirst({ where: { id: token, expiresAt: { gt: new Date(), }, }, include: { user: true, }, }); if (!session) { throw new CustomError({ message: "Sesión inválida o expirada", statusCode: 401, type: "INVALID_TOKEN", }); } // Crear cookie con el ID del usuario cookies().set("userId", session.userId, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", path: "/", maxAge: 60 * 60 * 24 * 30, // 30 días }); // Retornamos una redirección return NextResponse.redirect(new URL("/dashboard", request.url)); } catch (error) { console.error(error); if (error instanceof CustomError) errorType = error.type; else errorType = "INTERNAL_SERVER_ERROR"; } redirect(`/error?type=${errorType}`); }
就形式而言,我们将确保您的安全和有效,并通过 Telegram 网络进行访问。如果您已确定身份,您将在 30 天内简单地访问网络。 Cando la cookie caduque, deberá volver al bot para generic un nuevo link de acceso.
与 OpenAI 集成
与 OpenAI 进行交互的方式是灵活且可重复利用的,是一个专用于“@memomate/openai”的完整 API 的抽象。 Este paquete 实施四类原则:
代理人
“Agent”类代表 OpenAI 的持续性和生命周期的管理。使用 OpenAI 的辅助工具是创建 Uno 的必要条件,可以使用 API 或直接访问平台。在我们的生活中,我们将在平台和其他方面提供直接支持,并为您提供 API 恢复和 API 服务的变量,从“代理”类别开始
OpenAI 的本质是一个特定的提案和操作。其具体型号与扩展器功能一样。
interface Props { id: string; name: string; description: string; instructions: string; model?: string; tools: Array; } export class Agent { // ... async init() { let openAiAssistant = await openaiClient.beta.assistants.retrieve(this.id); const shouldUpdate = this.shouldUpdate(openAiAssistant); if (shouldUpdate) { openAiAssistant = await openaiClient.beta.assistants.update( this.id, this.generateBody() ); } this.assistant = openAiAssistant; } }
该代理将在 OpenAI 或 no 上实现与实现一致的功能。 La idea es que podamos desde el propio código del proyecto especar como debe comportarse el aciente.方法“shouldUpdate”,比较 OpenAI 的持续参数与本地具体情况(模型、指令、工具实施等),以检测差异、实际情况和 OpenAI 的持续性,以确保适当的控制。
private shouldUpdate(openAiAssistant: Assistant): boolean { if (this.name !== openAiAssistant.name) return true; if (this.description !== openAiAssistant.description) return true; if (this.instructions !== openAiAssistant.instructions) return true; if (this.model !== openAiAssistant.model) return true; if (this.tools.length !== openAiAssistant.tools.length) return true; return false; }
工具
您可以使用工具或工具执行操作,但不允许使用任何操作来实现所需的功能。因此,我们需要一个新接触的工具。因此,您可以使用创建接触器和使用工具的工具。 Y,另外,创建用于实现常用创建的 propia 工具。
Para dar soporte a esto, la case Abstracta `Tool` 定义了其结构:
export abstract class Tool { name: string; description: string; parameters: any; constructor({ name, description, parameters }: ToolParams) { this.name = name; this.description = description; this.parameters = parameters; } abstract run(parameters: RunProps): Promise; }
Cada 工具是创建和聚合代理所需的工具,可用于扩展现有类别并实现“运行”以实现功能的方法。
线
这是与 OpenAI 的“Thread”辅助通信相关的概念,是与辅助通信相关的基础对话。 MemoMate 的想法是在 Thread propio 上使用的,可以创建使用的内容并允许进行适当的对话。
“Thread”类的实现是在“@memomate/openai”中实现的,它包含了所有功能的实现。基本许可:
static async create() { const thread = await openaiClient.beta.threads.create(); return thread.id; }
async send(message: string, retries: number = 1): Promise{ if (!this.agent) throw new Error("Assistant not set"); if (!this.thread) await this.init(); await openaiClient.beta.threads.messages.create(this.id, { role: "user", content: message, }); this.run = await openaiClient.beta.threads.runs.create(this.id, { assistant_id: this.agent.id, }); while (true) { await this.waitUntilDone(); if (this.run.status === "completed") { const _message = await this.extractMessage(); return _message; } else if (this.run.status === "requires_action") { await this.processAction(); } else { const err = "Run failed: " + this.run.status; console.log(err); if (retries < MAX_RETRIES) { console.log("Retrying in 30s..."); await new Promise((resolve) => setTimeout(resolve, 30000)); return this.send(message, retries + 1); } const _message = this.generateFailedMessage(); return _message; } } }
使用“发送”方法,可以处理 OpenAI 的响应,并通过发送或发送命令来发送消息。执行任务时,请使用代理工具和执行方法“运行”来执行任务,并持续执行任务并最终获得结果。
private async processAction() { const toolsToExecute = await this.run.required_action.submit_tool_outputs.tool_calls; const toolsResults = []; for (const toolToExecute of toolsToExecute) { const toolName = toolToExecute.function.name; const tool = this.agent.tools.find((t) => t.name === toolName); const toolResult = tool ? await tool.run({ ...JSON.parse(toolToExecute.function.arguments), metadata: this.metadata, }) : "ERROR: no existe ninguna herramienta con el nombre que has indicado. Inténtalo de nuevo con el nombre correcto. La lista de herramientas disponibles es la siguiente: " + this.agent.tools.map((t) => t.name).join(", "); toolsResults.push({ tool_call_id: toolToExecute.id, output: toolResult.toString(), }); } this.run = await openaiClient.beta.threads.runs.submitToolOutputs( this.id, this.run.id, { tool_outputs: toolsResults, }, ); }
嵌入
OpenAI 需要的其他概念是嵌入、文本转换和矢量格式,但不允许实现语义化。这就是我们的联系方式。 Cada vez que se cree o se realice un contacto,generaremos su embedding communications y lo Guardaremos en Pinecone, para poderbuscarlo en el futuro.
嵌入的生成方法是“Embeddings”类别
export class Embeddings { private model = 'text-embedding-3-small'; private dimensions = 1024; async generateEmbedding(text: string): Promise{ const response = await openaiClient.embeddings.create({ model: this.model, dimensions: this.dimensions, input: text, encoding_format: 'float' }); return response.data[0].embedding; } }
从形式上看,“@memomate/openai”协议包含 OpenAI API 的抽象概念,可帮助您使用并允许未来实施的灵活性。
助理实施
我们已同意“@memomate/openai”的协议,并已同意执行程序的处置。在应用程序机器人中,奶油是一个新的“助手”,可以作为一个工具。
使用这些工具,您可以帮助实现所需的不同操作:创建接触器、创建接触器、创建活动等。该工具还可以扩展抽象工具。 “运行”方法是使用该工具执行检测操作。当然,“运行”的方法是根据工具实际情况定义的。
export class CreateContactTool extends Tool { constructor() { super({ name: "CreateContact", description: "Esta herramienta crea un nuevo contacto en la base de datos.", parameters: { type: "object", properties: { name: { type: "string", description: "El nombre del contacto que se desea crear.", }, relation: { type: "string", description: "La relación del contacto con el usuario. Ejemplo: 'Amigo', 'Familiar', 'Trabajo', etc.", }, location: { type: "string", description: "La ubicación del contacto. Puede ser una ciudad, un país, etc. Ejemplos: 'Madrid', 'Asturias', 'Argentina', etc.", }, }, required: ["name"], }, }); } async run(parameters: CreateContactRunProps): Promise{ try { console.log("Creando contacto..."); const { metadata, name, relation, location } = parameters; // Crear el contacto en la base de datos const contact = await prisma.contact.create({ data: { name, relation, location, userId: metadata.userId } }); // Generar el texto para el embedding const contactText = `Nombre: ${name}${relation ? `, Relación: ${relation}` : ''}${location ? `, Ubicación: ${location}` : ''}`; // Generar embedding usando OpenAI const embeddings = new Embeddings(); const embeddingValue = await embeddings.generateEmbedding(contactText); // Indexar en Pinecone await PineconeService.getInstance().upsertContact( metadata.userId, contact.id, embeddingValue ); return `He creado el contacto ${name} correctamente. Su ID es ${contact.id}.`; } catch (e) { console.error(e); return `No se ha podido crear el contacto.`; } } }
继续,奶油化的文本文件“instructions.md”和“description.md”(降价格式),定义描述和新的说明。 Aquí es donde le explicamos a nuestro aciente como debe actuar para llevar a cabo su propósito。
最后,您可以使用“MemoMateAssistant”类别,然后在前面的表格中添加代理程序,并使用“sendMessage”方法来允许环境中的新信息,以在我们的希洛中使用该代理程序。提示。
export class MemoMateAssistant { private agent: Agent; private static instance: MemoMateAssistant; private constructor() { this.agent = new Agent({ id: process.env.OPENAI_ASSISTANT_ID, name: "MemoMate Assistant", description: path.join(__dirname, "description.md"), instructions: path.join(__dirname, "instructions.md"), model: "gpt-4o-mini", tools: [ new CreateContactTool(), new UpdateContactTool(), new DeleteContactTool(), new SearchContactTool(), new CreateEventTool(), new GetCurrentDateTool(), new CreateReminderTool(), new GetContactEventsTool(), ], });; } static getInstance(): MemoMateAssistant { if (!MemoMateAssistant.instance) { MemoMateAssistant.instance = new MemoMateAssistant(); } return MemoMateAssistant.instance; } async init() { try { await this.agent.init(); console.log("Asistente inicializado correctamente"); } catch (error) { console.error("Error al inicializar el asistente:", error); throw error; } } async sendMessage(userId: string,threadId: string, message: string): Promise{ try { const thread = new Thread ({ id: threadId, agent: this.agent, metadata: { userId: userId, }, }); await thread.init(); const response = await thread.send(message); return response; } catch (error) { if (error instanceof Error) { return error.message; } return "Error al enviar mensaje"; } } }
Una cosa a destacar es la inicialización del agente.现在,您可以在前面的评论中进行评论,在 OpenAI 中创建并与 OpenAI 中的内容保持一致,并且可以在直接恢复和实际情况中使用可变的方法。
连接机器人与 Asisente。类 MemoMateProcessor
只要进行配置,您就可以与 Telegram 机器人连接,以进行交互。这是“MemoMateProcessor”类别中的一个内容。在发送 Telegram 的不同事件中,我们定义了不同事件的执行方法,可以使用新的对话,也可以令人羡慕。 Para cada una de estas acciones, Creamos un método en esta clase que lo gestione.例如,使用命令`/help`,可以执行以下方法`handleHelp`:
public async handleHelp(ctx: Context) { const message = helpTemplate(); ctx.reply(message, { parse_mode: 'HTML' }); }
这个方法很简单,定义一个 html 来与我们的用户交互,并与机器人的 ayuda 一起使用。对象上下文的遍历,以 html 格式响应常见的环境信息。
该方法是一个有趣的“handleMessage”类,可以在新的菜单中执行。 Vamos a ver un poco lo que se hace aquí。
public async handleMessage(ctx: TextMessageContext) { try { const telegramUserId = ctx.message.from.id; const chatId = ctx.message.chat.id; const message = ctx.message.text; const user = await this._getOrCreateUser(telegramUserId, chatId); const canSend = user.stripeSubscriptionId || user.credits > 0; if (!canSend) { const link = await this.createSessionUrl(user.id); ctx.reply(limitMessageTemplate(link), { parse_mode: 'HTML' }); return; } await prisma.messageLog.create({ data: { userId: user.id, message: message, direction: MessageLogDirection.INCOMING, } }); const response = await this.assistant.sendMessage(user.id, user.openaiThreadId, message); await prisma.messageLog.create({ data: { userId: user.id, message: response, direction: MessageLogDirection.OUTGOING, } }); if (!user.stripeSubscriptionId) { await prisma.user.update({ where: { id: user.id }, data: { credits: { decrement: 1 } } }); } ctx.reply(response); } catch (error) { console.error(error); } }
在入门指南中,请恢复“上下文”中的数据,以了解常用和令人羡慕的信息。 Llamamos 使用一种私有方法 `_getOrCreateUser` 来恢复数据,但不存在。
这个方法的实现非常有趣`_getOrCreateUser`。请勿使用 Thread 来进行新的对话。 De esta forma ya tentremos todo list para que este nuevo usuario pueda envirar mensajes al astane。
El siguiente paso es analizar si el usuario puede envirar mensajes al aciente o no。 Muy sencillo,podrá enviar si es Premium o,en su defeto,si el número de créditos es Mayor que 0. Si no puede enviar,resolves este método enviando un mensaje estándar que le sugiera al usuario ir a la lataforma Web para hacerse Premium.
相反,您可以单独使用“sendMessage”和“MemoMateAssistant”的内容。如果您使用的是高级版,请放心。 Guardamos ambos mensajes (el del usuario y la respuesta) en un Log de mensajes。 Y,最后,对持续的回应进行回应。
记录期限
您可以免费使用记录器进行更新,并使用“cron”库实施塔雷亚斯系统程序。管理主要工作人员的“CronManager”类别如下:
El parámetro `telegramChatId` que Guardamos en el usuario cuando lo Creamos es lo que necesitamos para poder enmenar un mensaje a ese usuario en Telegram
async processReminders() { const pendingReminders = await prisma.reminder.findMany({ where: { completed: false, remindAt: { lte: new Date() } }, include: { user: true, contact: true } }); for (const reminder of pendingReminders) { let message = `🔔 Recordatorio: ${reminder.message}`; if (reminder.contact) { message += `\nContacto: ${reminder.contact.name}`; } await this.bot.telegram.sendMessage( reminder.user.telegramChatId.toString(), message ); await prisma.reminder.update({ where: { id: reminder.id }, data: { completed: true } }); } }
async renewCredits(): Promise{ const usersToRenew = await prisma.user.findMany({ where: { stripeSubscriptionId: null, renewAt: { lt: new Date() } } }); for (const user of usersToRenew) { await prisma.user.update({ where: { id: user.id }, data: { credits: DEFAULT_CREDITS, renewAt: addMonths(new Date(), 1) } }); } }
实际实施很简单,效果非常好,**在未来的日子里**。例如,在记录程序和信用更新过程中,实现了后续的形式,这是一个具有重要意义的问题。未来,我们将实施一个程序系统,以提高效率。
接触器松果
一些有趣的事情是通过系统来实现的,该系统允许识别正确的联系方式,包括不准确的参考信息。例如,如果“我的朋友胡安·德·马德里”掷骰子,系统将有能力纠正“胡安·加西亚”的接触方式。
在此,使用 Pinecone 实现语义化,是矢量数据的基础,允许与文本中的公共汽车相似。操作过程如下:
// Dentro de CreateContactTool // Generar el texto para el embedding const contactText = `Nombre: ${name}${relation ? `, Relación: ${relation}` : ''}${location ? `, Ubicación: ${location}` : ''}`; // Generar embedding usando OpenAI const embeddings = new Embeddings(); const embeddingValue = await embeddings.generateEmbedding(contactText); // Indexar en Pinecone await PineconeService.getInstance().upsertContact( metadata.userId, contact.id, embeddingValue );
async run(parameters: SearchContactRunProps): Promise{ const searchText = `Nombre: ${name}${relation ? `, Relación: ${relation}` : ''}${location ? `, Ubicación: ${location}` : ''}`; const embeddings = new Embeddings(); const queryEmbedding = await embeddings.generateEmbedding(searchText); const results = await PineconeService.getInstance().searchSimilarContacts( metadata.userId, queryEmbedding, 1 // Solo necesitamos el más similar ); if (results.length > 0 && results[0].score && results[0].score > 0.7) { return `Contacto encontrado con ID: ${results[0].id}`; } return "No se encontró ningún contacto que coincida..."; }
在“PineconeService”类中实现集中化,与 Pinecone 交互的方式如下:
export class PineconeService { private indexName = 'memomate-contacts'; private dimension = 1024; async init() { try { const pinecone = getPineconeClient(); // Verificar si el índice existe const existingIndexes = await pinecone.listIndexes(); const indexExists = existingIndexes?.indexes?.some( (index: IndexModel) => index.name === this.indexName ); if (!indexExists) { // Crear el índice si no existe await pinecone.createIndex({ name: this.indexName, dimension: this.dimension, metric: 'cosine', spec: { serverless: { cloud: 'aws', region: 'us-east-1' } }, }); console.log('Índice de Pinecone creado correctamente'); } } catch (error) { console.error('Error al inicializar Pinecone:', error); throw error; } } async searchSimilarContacts(userId: string, queryEmbedding: number[], limit: number = 5) { try { const pinecone = getPineconeClient(); const index = pinecone.index(this.indexName); const results = await index.query({ vector: queryEmbedding, filter: { userId: userId }, topK: limit, includeMetadata: true }); return results.matches; } catch (error) { console.error('Error al buscar contactos similares:', error); return []; } } }
您可以通过“模糊”接触来实现与文本精确一致的所有操作。该系统涉及上下文和语义关系,允许持续识别正确的联系方式,包括非正式或不完整的形式的使用。
Web 下一步
我已经完成了与 OpenAI 集成的机器人的所有工作。 Vamos a ver ahora muy brevemente la Implementación que hemos hecho en el lado de la Web.
MemoMate Web 应用程序使用 Next.js 14 实现,通过服务器组件和 App Router 进行改进。与 Telegram 机器人的补充相关的实施方法,允许使用多种结构形式的数据进行管理和可视化。
La web consta de las siguientes seccionesprinciples:
最有趣的是,网络实施是通过验证机制实现的,这是前面所解释的。在传统的登录/注册系统中,可以通过 Telegram 机器人的验证来实现访问的一般链接。这并不是简单的中国使用体验,而是机器人与网络的集成。
使用 Tailwind CSS 与 Shadcn/ui 组件结合构建 UI,可以创建现代交互、快速响应且易于维护的界面。
它是 Next.js 的主要实现,但在详细技术方面没有更多的深度。该资源库包含有关探索完整实施的相关信息的存储库。
使用 Stripe 订阅
MemoMate 基本功能的管理,决定了 Premium 功能的访问。实施使用 Stripe 的系统,是 Web 平台的管理和对数据基础的引用,并且可以使用高级服务或实际操作。
报名方式
该页面包含有关使用计划的相关信息。如果您不激活或不使用,请控制 UI 通信。然后,在订阅中进行管理,然后激活取消,然后再重新付款。
与 Bot 集成
机器人,在“MemoMateProcessor”中,验证了进程信息之前的状态:
public async handleMessage(ctx: TextMessageContext) { // const user = await this._getOrCreateUser(telegramUserId, chatId); // Verificar si el usuario puede enviar mensajes const canSend = user.stripeSubscriptionId || user.credits > 0; if (!canSend) { const link = await this.createSessionUrl(user.id); ctx.reply(limitMessageTemplate(link), { parse_mode: 'HTML' }); return; } // Procesar el mensaje... }
Stripe 的 Webhook
为了实现这一目的,我们使用 Webhook 来处理 Stripe 事件。在使用中,我们决定取消订阅,并在使用中取消付费。这就是我们的初始信用和马克莫斯的时刻。
export default async function StripeWebhookRoute(req: Request) { try { const body = await req.text(); const signature = req.headers.get("stripe-signature")!; const event = stripe.webhooks.constructEvent( body, signature, process.env.STRIPE_WEBHOOK_SECRET! ); if (event.type === "customer.subscription.deleted" || event.type === "customer.subscription.updated") { const subscription = event.data.object as Stripe.Subscription; if (subscription.status !== "active") { await prisma.user.updateMany({ where: { stripeSubscriptionId: subscription.id as string, }, data: { stripeSubscriptionId: null, renewAt: addMonths(new Date(), 1), credits: DEFAULT_CREDITS, }, }); } } return NextResponse.json({ received: true }); } catch (error) { console.error(error); if (error instanceof CustomError) return apiError(error); return apiError( new CustomError({ message: "Error interno del servidor", statusCode: 500, }), ); } }
回顾一下,这是不允许的系统:
未来发展及结论
在 MemoMate 的开发过程中,我们提出了一些未来可实现的最佳体验:
这是重要的教育项目。因此,我们不会提及任何关于生产或生产的问题。 Si alguien ve interesante este proyecto y quiere llevar a cabo las acciones necesarias para poner en Marcha este Producto en el marketo, que no dude en contactarme 😉
MemoMate 的开发让我着迷,可以探索和组合不同的现代技术。 OpenAI 的集成已实现了 Pinecone 语义学的实现,该项目的一部分呈现了所需的解决方案和方案。
您可以通过以下方式了解项目和其他方面的事宜:
您可以在 GitHub 上完成新的代码,并进行探索和探索。
Espero que este artículo te haya resultado útil e interestante!如果您有这样的体验,您可以简单地体验一下,然后体验一下。 🚀