]> git.giacomolli.uk - onechat/blobdiff - whatsapp_import.go
Order model and chat declarations
[onechat] / whatsapp_import.go
index 1092b4924c0d7640450e433a75ecf8ceefd5ddf8..0021bc8be5904d820375a70e5635eec349ee3143 100644 (file)
@@ -34,6 +34,88 @@ var (
        whatsappImportUnknown = regexp.MustCompile(`^\[WhatsApp\] (.*), [A-Za-z]+ (\d{4}-\d{2}-\d{2})$`)
 )
 
+// WhatsAppImportPlan holds the new chat-day batches and the size of the merged
+// log. Its estimate uses the measured cost of 1.3 calls per message, not a
+// promise about a particular export or compaction retry.
+type WhatsAppImportPlan struct {
+       agent      string
+       cutoffs    map[string]time.Time
+       added      []DatedMessage
+       chats      []string
+       cutoff     time.Time
+       first      time.Time
+       last       time.Time
+       bytes      int
+       messages   int
+       skipped    int
+       ownerKnown bool
+}
+
+// WhatsAppImportOptions selects the target, exports, and plan-only mode.
+type WhatsAppImportOptions struct {
+       planOnly bool
+       agent    string
+       paths    []string
+}
+
+// Write prints the plan without chat text or the owner's profile name.
+func (p WhatsAppImportPlan) Write(out io.Writer) error {
+       cutoff := "none (no live WhatsApp batch)"
+       if !p.cutoff.IsZero() {
+               cutoff = p.cutoff.Format(time.RFC3339)
+       }
+
+       dateRange := "none"
+       if !p.first.IsZero() {
+               dateRange = p.first.Format(time.RFC3339) + " to " + p.last.Format(time.RFC3339)
+       }
+
+       owner := "known (mapped to You)"
+       if !p.ownerKnown {
+               owner = "unknown (sender names kept as written)"
+       }
+
+       _, err := fmt.Fprintf(out, "agent: %s\nchats: %d\n", p.agent, len(p.chats))
+       if err != nil {
+               return fmt.Errorf("write import plan: %w", err)
+       }
+
+       for _, chat := range p.chats {
+               line := "  " + chat
+               cutoff, found := p.cutoffs[chat]
+               if found {
+                       line += " (cutoff: " + cutoff.Format(time.RFC3339) + ")"
+               }
+
+               _, err = fmt.Fprintln(out, line)
+               if err != nil {
+                       return fmt.Errorf("write import plan: %w", err)
+               }
+       }
+
+       estimate := 1.3 * float64(p.messages)
+       if len(p.added) == 0 {
+               estimate = 0
+       }
+
+       lines := []string{
+               fmt.Sprintf("batches: %d (%d chat-days skipped)", len(p.added), p.skipped),
+               "dates: " + dateRange,
+               "cutoff: " + cutoff,
+               "owner: " + owner,
+               fmt.Sprintf("bytes: %d (new batch text)", p.bytes),
+               fmt.Sprintf("messages: %d (merged log)", p.messages),
+               fmt.Sprintf("estimated calls: %.0f (about 1.3 per message, limit %d)", estimate, rebuildCallLimit),
+       }
+
+       _, err = io.WriteString(out, strings.Join(lines, "\n")+"\n")
+       if err != nil {
+               return fmt.Errorf("write import plan: %w", err)
+       }
+
+       return nil
+}
+
 // whatsappImport runs the offline import command. It holds the same token lock
 // as the daemon and probe, even for a plan. The plan reads no credentials for a
 // model and makes no network call. Only a completed rebuild replaces the agent
@@ -156,88 +238,6 @@ func whatsappImport(ctx context.Context, args []string, out io.Writer) (err erro
        return nil
 }
 
-// WhatsAppImportPlan holds the new chat-day batches and the size of the merged
-// log. Its estimate uses the measured cost of 1.3 calls per message, not a
-// promise about a particular export or compaction retry.
-type WhatsAppImportPlan struct {
-       agent      string
-       cutoffs    map[string]time.Time
-       added      []DatedMessage
-       chats      []string
-       cutoff     time.Time
-       first      time.Time
-       last       time.Time
-       bytes      int
-       messages   int
-       skipped    int
-       ownerKnown bool
-}
-
-// Write prints the plan without chat text or the owner's profile name.
-func (p WhatsAppImportPlan) Write(out io.Writer) error {
-       cutoff := "none (no live WhatsApp batch)"
-       if !p.cutoff.IsZero() {
-               cutoff = p.cutoff.Format(time.RFC3339)
-       }
-
-       dateRange := "none"
-       if !p.first.IsZero() {
-               dateRange = p.first.Format(time.RFC3339) + " to " + p.last.Format(time.RFC3339)
-       }
-
-       owner := "known (mapped to You)"
-       if !p.ownerKnown {
-               owner = "unknown (sender names kept as written)"
-       }
-
-       _, err := fmt.Fprintf(out, "agent: %s\nchats: %d\n", p.agent, len(p.chats))
-       if err != nil {
-               return fmt.Errorf("write import plan: %w", err)
-       }
-
-       for _, chat := range p.chats {
-               line := "  " + chat
-               cutoff, found := p.cutoffs[chat]
-               if found {
-                       line += " (cutoff: " + cutoff.Format(time.RFC3339) + ")"
-               }
-
-               _, err = fmt.Fprintln(out, line)
-               if err != nil {
-                       return fmt.Errorf("write import plan: %w", err)
-               }
-       }
-
-       estimate := 1.3 * float64(p.messages)
-       if len(p.added) == 0 {
-               estimate = 0
-       }
-
-       lines := []string{
-               fmt.Sprintf("batches: %d (%d chat-days skipped)", len(p.added), p.skipped),
-               "dates: " + dateRange,
-               "cutoff: " + cutoff,
-               "owner: " + owner,
-               fmt.Sprintf("bytes: %d (new batch text)", p.bytes),
-               fmt.Sprintf("messages: %d (merged log)", p.messages),
-               fmt.Sprintf("estimated calls: %.0f (about 1.3 per message, limit %d)", estimate, rebuildCallLimit),
-       }
-
-       _, err = io.WriteString(out, strings.Join(lines, "\n")+"\n")
-       if err != nil {
-               return fmt.Errorf("write import plan: %w", err)
-       }
-
-       return nil
-}
-
-// WhatsAppImportOptions selects the target, exports, and plan-only mode.
-type WhatsAppImportOptions struct {
-       planOnly bool
-       agent    string
-       paths    []string
-}
-
 // whatsappImportParse accepts GNU-style flags, including --agent=NAME and --
 // before paths that start with a dash.
 func whatsappImportParse(args []string) (WhatsAppImportOptions, error) {